Bug Summary

File:s/coreconf/nsinstall/nsinstall.c
Warning:line 137, column 11
Null pointer passed to 1st parameter expecting 'nonnull'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name nsinstall.c -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 -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/var/lib/jenkins/workspace/nss-scan-build/nss/coreconf/nsinstall -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/var/lib/jenkins/workspace/nss-scan-build/nss/coreconf/nsinstall -resource-dir /usr/lib/llvm-19/lib/clang/19 -D HAVE_STRERROR -D LINUX -D linux -D XP_UNIX -D XP_UNIX -D DEBUG -U NDEBUG -D _DEFAULT_SOURCE -D _BSD_SOURCE -D _POSIX_SOURCE -D SDB_MEASURE_USE_TEMP_DIR -D _REENTRANT -D DEBUG -U NDEBUG -D _DEFAULT_SOURCE -D _BSD_SOURCE -D _POSIX_SOURCE -D SDB_MEASURE_USE_TEMP_DIR -D _REENTRANT -D NSS_DISABLE_SSE3 -D NSS_NO_INIT_SUPPORT -D USE_UTIL_DIRECTLY -D NO_NSPR_10_SUPPORT -D SSL_DISABLE_DEPRECATED_CIPHER_SUITE_NAMES -I ../../../dist/Linux6.12_x86_64_gcc_glibc_PTH_64_DBG.OBJ/include -I ../../../dist/public/coreconf -I ../../../dist/private/coreconf -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -std=c99 -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2025-01-06-222215-268153-1 -x c nsinstall.c
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5/*
6** Netscape portable install command.
7*/
8#include <stdio.h> /* OSF/1 requires this before grp.h, so put it first */
9#include <assert.h>
10#include <fcntl.h>
11#include <string.h>
12#if defined(_WINDOWS)
13#include <windows.h>
14typedef unsigned int mode_t;
15#else
16#include <grp.h>
17#include <pwd.h>
18#include <errno(*__errno_location ()).h>
19#include <stdlib.h>
20#include <unistd.h>
21#include <utime.h>
22#endif
23#include <sys/types.h>
24#include <sys/stat.h>
25#include "pathsub.h"
26
27#define HAVE_LCHOWN
28
29#if defined(AIX) || defined(HPUX) || defined(LINUX1) || defined(NTO) || defined(DARWIN) || defined(__riscos__)
30#undef HAVE_LCHOWN
31#endif
32
33#define HAVE_FCHMOD
34
35#ifdef LINUX1
36#include <getopt.h>
37#endif
38
39#if defined(NCR)
40#if !defined(S_ISLNK) && defined(S_IFLNK0120000)
41#define S_ISLNK(a)((((a)) & 0170000) == (0120000)) (((a) & S_IFMT0170000) == S_IFLNK0120000)
42#endif
43#endif
44
45#ifdef GETCWD_CANT_MALLOC
46/*
47 * this should probably go into a utility library in case other applications
48 * need it.
49 */
50static char *
51getcwd_do_malloc(char *path, int len) {
52
53 if (!path) {
54 path = malloc(PATH_MAX4096 +1);
55 if (!path) return NULL((void*)0);
56 }
57 return getcwd(path, PATH_MAX4096);
58}
59#define GETCWDgetcwd getcwd_do_malloc
60#else
61#define GETCWDgetcwd getcwd
62#endif
63
64
65static void
66usage(void)
67{
68 fprintf(stderrstderr,
69 "usage: %s [-C cwd] [-L linkprefix] [-m mode] [-o owner] [-g group]\n"
70 " %*s [-DdltR] file [file ...] directory\n",
71 program, (int)strlen(program), "");
72 exit(2);
73}
74
75/* this is more-or-less equivalent to mkdir -p */
76static int
77mkdirs(char *path, mode_t mode)
78{
79 char * cp;
80 int rv;
81 struct stat sb;
82
83 if (!path || !path[0])
84 fail("Null pointer or empty string passed to mkdirs()");
85 while (*path == '/' && path[1] == '/')
86 path++;
87 for (cp = strrchr(path, '/'); cp && cp != path && *(cp - 1) == '/'; cp--);
88 if (cp && cp != path) {
89 *cp = '\0';
90 if ((stat(path, &sb) < 0 || !S_ISDIR(sb.st_mode)((((sb.st_mode)) & 0170000) == (0040000))) &&
91 mkdirs(path, mode) < 0) {
92 return -1;
93 }
94 *cp = '/';
95 }
96 rv = mkdir(path, mode);
97 if (rv) {
98 if (errno(*__errno_location ()) != EEXIST17)
99 fail("mkdirs cannot make %s", path);
100 fprintf(stderrstderr, "directory creation race: %s\n", path);
101 if (!stat(path, &sb) && S_ISDIR(sb.st_mode)((((sb.st_mode)) & 0170000) == (0040000)))
102 rv = 0;
103 }
104 return rv;
105}
106
107static uid_t
108touid(char *owner)
109{
110 struct passwd *pw;
111 uid_t uid;
112 char *cp;
113
114 if (!owner || !owner[0])
115 fail("Null pointer or empty string passed to touid()");
116 pw = getpwnam(owner);
117 if (pw)
118 return pw->pw_uid;
119 uid = strtol(owner, &cp, 0);
120 if (uid == 0 && cp == owner)
121 fail("cannot find uid for %s", owner);
122 return uid;
123}
124
125static gid_t
126togid(char *group)
127{
128 struct group *gr;
129 gid_t gid;
130 char *cp;
131
132 if (!group || !group[0])
1
Assuming 'group' is null
133 fail("Null pointer or empty string passed to togid()");
134 gr = getgrnam(group);
135 if (gr)
2
Assuming 'gr' is null
3
Taking false branch
136 return gr->gr_gid;
137 gid = strtol(group, &cp, 0);
4
Null pointer passed to 1st parameter expecting 'nonnull'
138 if (gid == 0 && cp == group)
139 fail("cannot find gid for %s", group);
140 return gid;
141}
142
143void * const uninit = (void *)0xdeadbeef;
144
145int
146main(int argc, char **argv)
147{
148 char * base = uninit;
149 char * bp = uninit;
150 char * cp = uninit;
151 char * cwd = 0;
152 char * group = 0;
153 char * linkname = 0;
154 char * linkprefix = 0;
155 char * name = uninit;
156 char * owner = 0;
157 char * todir = uninit;
158 char * toname = uninit;
159
160 int bnlen = -1;
161 int cc = 0;
162 int dodir = 0;
163 int dolink = 0;
164 int dorelsymlink = 0;
165 int dotimes = 0;
166 int exists = 0;
167 int fromfd = -1;
168 int len = -1;
169 int lplen = 0;
170 int onlydir = 0;
171 int opt = -1;
172 int tdlen = -1;
173 int tofd = -1;
174 int wc = -1;
175
176 mode_t mode = 0755;
177
178 uid_t uid = -1;
179 gid_t gid = -1;
180
181 struct stat sb;
182 struct stat tosb;
183 struct utimbuf utb;
184 char buf[BUFSIZ8192];
185
186 program = strrchr(argv[0], '/');
187 if (!program)
188 program = strrchr(argv[0], '\\');
189 program = program ? program+1 : argv[0];
190
191
192 while ((opt = getopt(argc, argv, "C:DdlL:Rm:o:g:t")) != EOF(-1)) {
193 switch (opt) {
194 case 'C': cwd = optarg; break;
195 case 'D': onlydir = 1; break;
196 case 'd': dodir = 1; break;
197 case 'l': dolink = 1; break;
198 case 'L':
199 linkprefix = optarg;
200 lplen = strlen(linkprefix);
201 dolink = 1;
202 break;
203 case 'R': dolink = dorelsymlink = 1; break;
204 case 'm':
205 mode = strtoul(optarg, &cp, 8);
206 if (mode == 0 && cp == optarg)
207 usage();
208 break;
209 case 'o': owner = optarg; break;
210 case 'g': group = optarg; break;
211 case 't': dotimes = 1; break;
212 default: usage();
213 }
214 }
215
216 argc -= optind;
217 argv += optind;
218 if (argc < 2 - onlydir)
219 usage();
220
221 todir = argv[argc-1];
222 if ((stat(todir, &sb) < 0 || !S_ISDIR(sb.st_mode)((((sb.st_mode)) & 0170000) == (0040000))) &&
223 mkdirs(todir, 0777) < 0) {
224 fail("cannot mkdir -p %s", todir);
225 }
226 if (onlydir)
227 return 0;
228
229 if (!cwd) {
230 cwd = GETCWDgetcwd(0, PATH_MAX4096);
231 if (!cwd)
232 fail("could not get CWD");
233 }
234
235 /* make sure we can get into todir. */
236 xchdir(todir);
237 todir = GETCWDgetcwd(0, PATH_MAX4096);
238 if (!todir)
239 fail("could not get CWD in todir");
240 tdlen = strlen(todir);
241
242 /* back to original directory. */
243 xchdir(cwd);
244
245 uid = owner ? touid(owner) : -1;
246 gid = group ? togid(group) : -1;
247
248 while (--argc > 0) {
249 name = *argv++;
250 len = strlen(name);
251 base = xbasename(name);
252 bnlen = strlen(base);
253 size_t toname_len = tdlen + 1 + bnlen + 1;
254 toname = (char*)xmalloc(toname_len);
255 snprintf(toname, toname_len, "%s/%s", todir, base);
256retry:
257 exists = (lstat(toname, &tosb) == 0);
258
259 if (dodir) {
260 /* -d means create a directory, always */
261 if (exists && !S_ISDIR(tosb.st_mode)((((tosb.st_mode)) & 0170000) == (0040000))) {
262 int rv = unlink(toname);
263 if (rv)
264 fail("cannot unlink %s", toname);
265 exists = 0;
266 }
267 if (!exists && mkdir(toname, mode) < 0) {
268 /* we probably have two nsinstall programs in a race here. */
269 if (errno(*__errno_location ()) == EEXIST17 && !stat(toname, &sb) &&
270 S_ISDIR(sb.st_mode)((((sb.st_mode)) & 0170000) == (0040000))) {
271 fprintf(stderrstderr, "directory creation race: %s\n", toname);
272 goto retry;
273 }
274 fail("cannot make directory %s", toname);
275 }
276 if ((owner || group) && chown(toname, uid, gid) < 0)
277 fail("cannot change owner of %s", toname);
278 } else if (dolink) {
279 if (*name == '/') {
280 /* source is absolute pathname, link to it directly */
281 linkname = 0;
282 } else {
283 if (linkprefix) {
284 /* -L implies -l and prefixes names with a $cwd arg. */
285 len += lplen + 1;
286 linkname = (char*)xmalloc(len + 1);
287 snprintf(linkname, len+1, "%s/%s", linkprefix, name);
288 } else if (dorelsymlink) {
289 /* Symlink the relative path from todir to source name. */
290 linkname = (char*)xmalloc(PATH_MAX4096);
291
292 if (*todir == '/') {
293 /* todir is absolute: skip over common prefix. */
294 lplen = relatepaths(todir, cwd, linkname);
295 strcpy(linkname + lplen, name);
296 } else {
297 /* todir is named by a relative path: reverse it. */
298 reversepath(todir, name, len, linkname);
299 xchdir(cwd);
300 }
301
302 len = strlen(linkname);
303 }
304 name = linkname;
305 }
306
307 /* Check for a pre-existing symlink with identical content. */
308 if (exists &&
309 (!S_ISLNK(tosb.st_mode)((((tosb.st_mode)) & 0170000) == (0120000)) ||
310 readlink(toname, buf, sizeof buf) != len ||
311 strncmp(buf, name, len) != 0)) {
312 int rmrv;
313 rmrv = (S_ISDIR(tosb.st_mode)((((tosb.st_mode)) & 0170000) == (0040000)) ? rmdir : unlink)(toname);
314 if (rmrv < 0) {
315 fail("destination exists, cannot remove %s", toname);
316 }
317 exists = 0;
318 }
319 if (!exists && symlink(name, toname) < 0) {
320 if (errno(*__errno_location ()) == EEXIST17) {
321 fprintf(stderrstderr, "symlink creation race: %s\n", toname);
322 fail("symlink was attempted in working directory %s "
323 "from %s to %s.\n", cwd, name, toname);
324 goto retry;
325 }
326 diagnosePath(toname);
327 fail("cannot make symbolic link %s", toname);
328 }
329#ifdef HAVE_LCHOWN
330 if ((owner || group) && lchown(toname, uid, gid) < 0)
331 fail("cannot change owner of %s", toname);
332#endif
333
334 if (linkname) {
335 free(linkname);
336 linkname = 0;
337 }
338 } else {
339 /* Copy from name to toname, which might be the same file. */
340 fromfd = open(name, O_RDONLY00);
341 if (fromfd < 0 || fstat(fromfd, &sb) < 0)
342 fail("cannot access %s", name);
343 if (exists &&
344 (!S_ISREG(tosb.st_mode)((((tosb.st_mode)) & 0170000) == (0100000)) || access(toname, W_OK2) < 0)) {
345 int rmrv;
346 rmrv = (S_ISDIR(tosb.st_mode)((((tosb.st_mode)) & 0170000) == (0040000)) ? rmdir : unlink)(toname);
347 if (rmrv < 0) {
348 fail("destination exists, cannot remove %s", toname);
349 }
350 }
351 tofd = open(toname, O_CREAT0100 | O_WRONLY01, 0666);
352 if (tofd < 0)
353 fail("cannot create %s", toname);
354
355 bp = buf;
356 while ((cc = read(fromfd, bp, sizeof buf)) > 0) {
357 while ((wc = write(tofd, bp, cc)) > 0) {
358 if ((cc -= wc) == 0)
359 break;
360 bp += wc;
361 }
362 if (wc < 0)
363 fail("cannot write to %s", toname);
364 }
365 if (cc < 0)
366 fail("cannot read from %s", name);
367
368 if (ftruncate(tofd, sb.st_size) < 0)
369 fail("cannot truncate %s", toname);
370 if (dotimes) {
371 utb.actime = sb.st_atimest_atim.tv_sec;
372 utb.modtime = sb.st_mtimest_mtim.tv_sec;
373 if (utime(toname, &utb) < 0)
374 fail("cannot set times of %s", toname);
375 }
376#ifdef HAVE_FCHMOD
377 if (fchmod(tofd, mode) < 0)
378#else
379 if (chmod(toname, mode) < 0)
380#endif
381 fail("cannot change mode of %s", toname);
382
383 if ((owner || group) && fchown(tofd, uid, gid) < 0)
384 fail("cannot change owner of %s", toname);
385
386 /* Must check for delayed (NFS) write errors on close. */
387 if (close(tofd) < 0)
388 fail("close reports write error on %s", toname);
389 close(fromfd);
390 }
391
392 free(toname);
393 }
394
395 free(cwd);
396 free(todir);
397 return 0;
398}
399