Bug Summary

File:src/libexec/fingerd/fingerd.c
Warning:line 203, column 10
Call to function 'vfork' is insecure as it can lead to denial of service situations in the parent process. Replace calls to vfork with calls to the safer 'posix_spawn' function

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name fingerd.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/libexec/fingerd/obj -resource-dir /usr/local/lib/clang/13.0.0 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/libexec/fingerd/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/libexec/fingerd/fingerd.c
1/* $OpenBSD: fingerd.c,v 1.42 2021/07/12 15:09:18 beck Exp $ */
2
3/*
4 * Copyright (c) 1983, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <sys/socket.h>
33#include <netinet/in.h>
34#include <arpa/inet.h>
35#include <errno(*__errno()).h>
36
37#include <err.h>
38#include <unistd.h>
39#include <syslog.h>
40#include <netdb.h>
41#include <stdio.h>
42#include <stdlib.h>
43#include <string.h>
44#include <stdarg.h>
45#include <limits.h>
46#include "pathnames.h"
47
48__dead__attribute__((__noreturn__)) void logerr(const char *, ...);
49__dead__attribute__((__noreturn__)) void usage(void);
50
51void
52usage(void)
53{
54 syslog(LOG_ERR3,
55 "usage: fingerd [-lMmpSsu] [-P filename]");
56 exit(2);
57}
58
59
60int
61main(int argc, char *argv[])
62{
63 FILE *fp;
64 int ch, ac = 2;
65 int p[2], logging, secure, user_required, short_list;
66#define ENTRIES50 50
67 char **comp, *prog;
68 char **ap, *av[ENTRIES50 + 1], line[8192], *lp, *hname;
69 char hostbuf[HOST_NAME_MAX255+1];
70
71 prog = _PATH_FINGER"/usr/bin/finger";
72 logging = secure = user_required = short_list = 0;
73 openlog("fingerd", LOG_PID0x01, LOG_DAEMON(3<<3));
74 opterr = 0;
75 while ((ch = getopt(argc, argv, "sluSmMpP:")) != -1)
76 switch (ch) {
77 case 'l':
78 logging = 1;
79 break;
80 case 'P':
81 prog = optarg;
82 break;
83 case 's':
84 secure = 1;
85 break;
86 case 'u':
87 user_required = 1;
88 break;
89 case 'S':
90 if (ac < ENTRIES50) {
91 short_list = 1;
92 av[ac++] = "-s";
93 }
94 break;
95 case 'm':
96 if (ac < ENTRIES50)
97 av[ac++] = "-m";
98 break;
99 case 'M':
100 if (ac < ENTRIES50)
101 av[ac++] = "-M";
102 break;
103 case 'p':
104 if (ac < ENTRIES50)
105 av[ac++] = "-p";
106 break;
107 default:
108 usage();
109 }
110
111 if (unveil(prog, "x") == -1)
112 err(1, "unveil %s", prog);
113 if (pledge("stdio inet dns proc exec", NULL((void *)0)) == -1)
114 err(1, "pledge");
115
116 if (logging) {
117 struct sockaddr_storage ss;
118 struct sockaddr *sa;
119 socklen_t sval;
120
121 sval = sizeof(ss);
122 if (getpeername(0, (struct sockaddr *)&ss, &sval) == -1)
123 err(1, "getpeername");
124 sa = (struct sockaddr *)&ss;
125
126 if (pledge("stdio dns proc exec", NULL((void *)0)) == -1)
127 err(1, "pledge");
128
129 if (getnameinfo(sa, sa->sa_len, hostbuf, sizeof(hostbuf),
130 NULL((void *)0), 0, 0) != 0) {
131 strlcpy(hostbuf, "?", sizeof(hostbuf));
132 }
133 hname = hostbuf;
134 }
135
136 if (pledge("stdio proc exec", NULL((void *)0)) == -1)
137 err(1, "pledge");
138
139 if (fgets(line, sizeof(line), stdin(&__sF[0])) == NULL((void *)0)) {
140 if (logging)
141 syslog(LOG_NOTICE5, "query from %s: %s", hname,
142 feof(stdin)(!__isthreaded ? ((((&__sF[0]))->_flags & 0x0020) !=
0) : (feof)((&__sF[0])))
? "EOF" : strerror(errno(*__errno())));
143 exit(1);
144 }
145
146 if (logging)
147 syslog(LOG_NOTICE5, "query from %s: `%.*s'", hname,
148 (int)strcspn(line, "\r\n"), line);
149
150 /*
151 * Note: we assume that finger(1) will treat "--" as end of
152 * command args (ie: that it uses getopt(3)).
153 */
154 av[ac++] = "--";
155 comp = &av[1];
156 for (lp = line, ap = &av[ac]; ac < ENTRIES50;) {
157 size_t len;
158
159 if ((*ap = strtok(lp, " \t\r\n")) == NULL((void *)0))
160 break;
161 lp = NULL((void *)0);
162 if (secure && strchr(*ap, '@')) {
163 (void) puts("forwarding service denied\r");
164 exit(1);
165 }
166
167 len = strlen(*ap);
168 while (len > 0 && (*ap)[len - 1] == '@')
169 (*ap)[--len] = '\0';
170 if (**ap == '\0')
171 continue;
172
173 /* RFC1196: "/[Ww]" == "-l" */
174 if ((*ap)[0] == '/' && ((*ap)[1] == 'W' || (*ap)[1] == 'w')) {
175 if (!short_list) {
176 av[1] = "-l";
177 comp = &av[0];
178 }
179 } else {
180 ap++;
181 ac++;
182 }
183 }
184 av[ENTRIES50 - 1] = NULL((void *)0);
185
186 if ((lp = strrchr(prog, '/')))
187 *comp = ++lp;
188 else
189 *comp = prog;
190
191 if (user_required) {
192 for (ap = comp + 1; strcmp("--", *(ap++)); )
193 ;
194 if (*ap == NULL((void *)0)) {
195 (void) puts("must provide username\r");
196 exit(1);
197 }
198 }
199
200 if (pipe(p) == -1)
201 logerr("pipe: %s", strerror(errno(*__errno())));
202
203 switch (vfork()) {
Call to function 'vfork' is insecure as it can lead to denial of service situations in the parent process. Replace calls to vfork with calls to the safer 'posix_spawn' function
204 case 0:
205 (void) close(p[0]);
206 if (p[1] != 1) {
207 (void) dup2(p[1], 1);
208 (void) close(p[1]);
209 }
210 execv(prog, comp);
211 syslog(LOG_ERR3, "execv: %s: %s", prog, strerror(errno(*__errno())));
212 _exit(1);
213 case -1:
214 logerr("fork: %s", strerror(errno(*__errno())));
215 }
216 if (pledge("stdio", NULL((void *)0)) == -1)
217 err(1, "pledge");
218
219 (void) close(p[1]);
220 if (!(fp = fdopen(p[0], "r")))
221 logerr("fdopen: %s", strerror(errno(*__errno())));
222 while ((ch = getc(fp)(!__isthreaded ? (--(fp)->_r < 0 ? __srget(fp) : (int)(
*(fp)->_p++)) : (getc)(fp))
) != EOF(-1)) {
223 if (ch == '\n')
224 putchar('\r')(!__isthreaded ? __sputc('\r', (&__sF[1])) : (putc)('\r',
(&__sF[1])))
;
225 putchar(ch)(!__isthreaded ? __sputc(ch, (&__sF[1])) : (putc)(ch, (&
__sF[1])))
;
226 }
227 exit(0);
228}
229
230void
231logerr(const char *fmt, ...)
232{
233 va_list ap;
234
235 va_start(ap, fmt)__builtin_va_start(ap, fmt);
236 (void) vsyslog(LOG_ERR3, fmt, ap);
237 va_end(ap)__builtin_va_end(ap);
238 exit(1);
239}