Bug Summary

File:src/usr.sbin/mtree/spec.c
Warning:line 246, column 10
Null pointer passed as 1st argument to string length 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 spec.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/usr.sbin/mtree/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/usr.sbin/mtree/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/usr.sbin/mtree/spec.c
1/* $NetBSD: spec.c,v 1.6 1995/03/07 21:12:12 cgd Exp $ */
2/* $OpenBSD: spec.c,v 1.29 2018/09/16 02:41:16 millert Exp $ */
3
4/*-
5 * Copyright (c) 1989, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#include <sys/types.h>
34#include <sys/stat.h>
35#include <pwd.h>
36#include <grp.h>
37#include <errno(*__errno()).h>
38#include <unistd.h>
39#include <stdio.h>
40#include <ctype.h>
41#include <vis.h>
42#include "mtree.h"
43#include "extern.h"
44
45int lineno; /* Current spec line number. */
46
47static void set(char *, NODE *);
48static void unset(char *, NODE *);
49
50NODE *
51spec(void)
52{
53 NODE *centry, *last;
54 char *p;
55 NODE ginfo, *root;
56 int c_cur, c_next;
57 char *buf, *tbuf = NULL((void *)0);
58 size_t len;
59
60 last = root = NULL((void *)0);
61 bzero(&ginfo, sizeof(ginfo));
62 centry = &ginfo;
63 c_cur = c_next = 0;
64 for (lineno = 1; (buf = fgetln(stdin(&__sF[0]), &len));
1
Loop condition is true. Entering loop body
65 ++lineno, c_cur = c_next, c_next = 0) {
66 /* Null-terminate the line. */
67 if (buf[len - 1] == '\n') {
2
Assuming the condition is true
3
Taking true branch
68 buf[--len] = '\0';
69 } else {
70 /* EOF with no newline. */
71 tbuf = malloc(len + 1);
72 memcpy(tbuf, buf, len);
73 tbuf[len] = '\0';
74 buf = tbuf;
75 }
76
77 /* Skip leading whitespace. */
78 for (p = buf; isspace((unsigned char)*p); p++)
4
Loop condition is false. Execution continues on line 82
79 ;
80
81 /* If nothing but whitespace or comment char, continue. */
82 if (*p == '\0' || *p == '#')
5
Assuming the condition is false
6
Assuming the condition is false
7
Taking false branch
83 continue;
84
85 /* See if next line is continuation line. */
86 if (buf[len - 1] == '\\') {
8
Assuming the condition is false
9
Taking false branch
87 c_next = 1;
88 if (--len == 0)
89 continue;
90 buf[len] = '\0';
91 }
92
93#ifdef DEBUG
94 (void)fprintf(stderr(&__sF[2]), "line %d: {%s}\n", lineno, p);
95#endif
96 if (c_cur
9.1
'c_cur' is 0
) {
10
Taking false branch
97 set(p, centry);
98 continue;
99 }
100
101 /* Grab file name, "$", "set", or "unset". */
102 if ((p = strtok(p, "\n\t ")) == NULL((void *)0))
11
Assuming the condition is false
12
Taking false branch
103 error("missing field");
104
105 if (p[0] == '/')
13
Assuming the condition is true
14
Taking true branch
106 switch(p[1]) {
15
Control jumps to 'case 115:' at line 107
107 case 's':
108 if (strcmp(p + 1, "set"))
16
Assuming the condition is false
17
Taking false branch
109 break;
110 set(NULL((void *)0), &ginfo);
18
Calling 'set'
111 continue;
112 case 'u':
113 if (strcmp(p + 1, "unset"))
114 break;
115 unset(NULL((void *)0), &ginfo);
116 continue;
117 }
118
119 if (strchr(p, '/'))
120 error("slash character in file name");
121
122 if (!strcmp(p, "..")) {
123 /* Don't go up, if haven't gone down. */
124 if (!root)
125 goto noparent;
126 if (last->type != F_DIR0x004 || last->flags & F_DONE0x000002) {
127 if (last == root)
128 goto noparent;
129 last = last->parent;
130 }
131 last->flags |= F_DONE0x000002;
132 continue;
133
134noparent: error("no parent node");
135 }
136
137 len = strlen(p) + 1; /* NUL in struct _node */
138 if ((centry = calloc(1, sizeof(NODE) + len - 1)) == NULL((void *)0))
139 error("%s", strerror(errno(*__errno())));
140 *centry = ginfo;
141#define MAGIC"?*[" "?*["
142 if (strpbrk(p, MAGIC"?*["))
143 centry->flags |= F_MAGIC0x000020;
144 if (strunvis(centry->name, p) == -1) {
145 fprintf(stderr(&__sF[2]),
146 "mtree: filename (%s) encoded incorrectly\n", p);
147 strlcpy(centry->name, p, len);
148 }
149 set(NULL((void *)0), centry);
150
151 if (!root) {
152 last = root = centry;
153 root->parent = root;
154 } else if (last->type == F_DIR0x004 && !(last->flags & F_DONE0x000002)) {
155 centry->parent = last;
156 last = last->child = centry;
157 } else {
158 centry->parent = last->parent;
159 centry->prev = last;
160 last = last->next = centry;
161 }
162 }
163 free(tbuf);
164 return (root);
165}
166
167static void
168set(char *t, NODE *ip)
169{
170 int type;
171 char *kw, *val = NULL((void *)0);
19
'val' initialized to a null pointer value
172 void *m;
173 int value;
174 u_int32_t fset, fclr;
175 char *ep;
176 size_t len;
177
178 for (; (kw = strtok(t, "= \t\n")); t = NULL((void *)0)) {
20
Loop condition is true. Entering loop body
179 ip->flags |= type = parsekey(kw, &value);
180 if (value && (val = strtok(NULL((void *)0), " \t\n")) == NULL((void *)0))
21
Assuming 'value' is 0
181 error("missing value");
182 switch(type) {
22
Control jumps to 'case 8192:' at line 245
183 case F_CKSUM0x000001:
184 ip->cksum = strtoul(val, &ep, 10);
185 if (*ep)
186 error("invalid checksum %s", val);
187 break;
188 case F_MD50x000040:
189 ip->md5digest = strdup(val);
190 if (!ip->md5digest)
191 error("%s", strerror(errno(*__errno())));
192 break;
193 case F_FLAGS0x080000:
194 if (!strcmp(val, "none")) {
195 ip->file_flags = 0;
196 break;
197 }
198 if (strtofflags(&val, &fset, &fclr))
199 error("%s", strerror(errno(*__errno())));
200 ip->file_flags = fset;
201 break;
202 case F_GID0x000004:
203 ip->st_gid = strtoul(val, &ep, 10);
204 if (*ep)
205 error("invalid gid %s", val);
206 break;
207 case F_GNAME0x000008:
208 if (gid_from_group(val, &ip->st_gid) == -1)
209 error("unknown group %s", val);
210 break;
211 case F_IGN0x000010:
212 /* just set flag bit */
213 break;
214 case F_MODE0x000080:
215 if ((m = setmode(val)) == NULL((void *)0))
216 error("invalid file mode %s", val);
217 ip->st_mode = getmode(m, 0);
218 free(m);
219 break;
220 case F_NLINK0x000100:
221 ip->st_nlink = strtoul(val, &ep, 10);
222 if (*ep)
223 error("invalid link count %s", val);
224 break;
225 case F_RMD1600x000400:
226 ip->rmd160digest = strdup(val);
227 if (!ip->rmd160digest)
228 error("%s", strerror(errno(*__errno())));
229 break;
230 case F_SHA10x000800:
231 ip->sha1digest = strdup(val);
232 if (!ip->sha1digest)
233 error("%s", strerror(errno(*__errno())));
234 break;
235 case F_SHA2560x200000:
236 ip->sha256digest = strdup(val);
237 if (!ip->sha256digest)
238 error("%s", strerror(errno(*__errno())));
239 break;
240 case F_SIZE0x001000:
241 ip->st_size = strtoll(val, &ep, 10);
242 if (*ep)
243 error("invalid size %s", val);
244 break;
245 case F_SLINK0x002000:
246 len = strlen(val) + 1;
23
Null pointer passed as 1st argument to string length function
247 if ((ip->slink = malloc(len)) == NULL((void *)0))
248 error("%s", strerror(errno(*__errno())));
249 if (strunvis(ip->slink, val) == -1) {
250 fprintf(stderr(&__sF[2]),
251 "mtree: filename (%s) encoded incorrectly\n", val);
252 strlcpy(ip->slink, val, len);
253 }
254 break;
255 case F_TIME0x004000:
256 ip->st_mtimespecst_mtim.tv_sec = strtoul(val, &ep, 10);
257 if (*ep != '.')
258 error("invalid time %s", val);
259 val = ep + 1;
260 ip->st_mtimespecst_mtim.tv_nsec = strtoul(val, &ep, 10);
261 if (*ep)
262 error("invalid time %s", val);
263 break;
264 case F_TYPE0x008000:
265 switch(*val) {
266 case 'b':
267 if (!strcmp(val, "block"))
268 ip->type = F_BLOCK0x001;
269 break;
270 case 'c':
271 if (!strcmp(val, "char"))
272 ip->type = F_CHAR0x002;
273 break;
274 case 'd':
275 if (!strcmp(val, "dir"))
276 ip->type = F_DIR0x004;
277 break;
278 case 'f':
279 if (!strcmp(val, "file"))
280 ip->type = F_FILE0x010;
281 if (!strcmp(val, "fifo"))
282 ip->type = F_FIFO0x008;
283 break;
284 case 'l':
285 if (!strcmp(val, "link"))
286 ip->type = F_LINK0x020;
287 break;
288 case 's':
289 if (!strcmp(val, "socket"))
290 ip->type = F_SOCK0x040;
291 break;
292 default:
293 error("unknown file type %s", val);
294 }
295 break;
296 case F_UID0x010000:
297 ip->st_uid = strtoul(val, &ep, 10);
298 if (*ep)
299 error("invalid uid %s", val);
300 break;
301 case F_UNAME0x020000:
302 if (uid_from_user(val, &ip->st_uid) == -1)
303 error("unknown user %s", val);
304 break;
305 }
306 }
307}
308
309static void
310unset(char *t, NODE *ip)
311{
312 char *p;
313
314 while ((p = strtok(t, "\n\t ")))
315 ip->flags &= ~parsekey(p, NULL((void *)0));
316}