Bug Summary

File:s/coreconf/nsinstall/nsinstall.c
Warning:line 245, column 13
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-18/lib/clang/18 -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/Linux4.19_x86_64_gcc_glibc_PTH_64_DBG.OBJ/include -I ../../../dist/public/coreconf -I ../../../dist/private/coreconf -internal-isystem /usr/lib/llvm-18/lib/clang/18/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 -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2024-05-18-082241-28900-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(BSDI) || defined(HPUX) || defined(LINUX1) || defined(SUNOS4) || defined(SCO) || defined(UNIXWARE) || 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(SCO) || defined(UNIXWARE) || defined(SNI) || defined(NCR) || defined(NEC)
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#if defined(SNI)
46extern int fchmod(int fildes, mode_t mode);
47#endif
48
49
50#ifdef GETCWD_CANT_MALLOC
51/*
52 * this should probably go into a utility library in case other applications
53 * need it.
54 */
55static char *
56getcwd_do_malloc(char *path, int len) {
57
58 if (!path) {
59 path = malloc(PATH_MAX4096 +1);
60 if (!path) return NULL((void*)0);
61 }
62 return getcwd(path, PATH_MAX4096);
63}
64#define GETCWDgetcwd getcwd_do_malloc
65#else
66#define GETCWDgetcwd getcwd
67#endif
68
69
70static void
71usage(void)
72{
73 fprintf(stderrstderr,
74 "usage: %s [-C cwd] [-L linkprefix] [-m mode] [-o owner] [-g group]\n"
75 " %*s [-DdltR] file [file ...] directory\n",
76 program, (int)strlen(program), "");
77 exit(2);
78}
79
80/* this is more-or-less equivalent to mkdir -p */
81static int
82mkdirs(char *path, mode_t mode)
83{
84 char * cp;
85 int rv;
86 struct stat sb;
87
88 if (!path || !path[0])
89 fail("Null pointer or empty string passed to mkdirs()");
90 while (*path == '/' && path[1] == '/')
91 path++;
92 for (cp = strrchr(path, '/'); cp && cp != path && *(cp - 1) == '/'; cp--);
93 if (cp && cp != path) {
94 *cp = '\0';
95 if ((stat(path, &sb) < 0 || !S_ISDIR(sb.st_mode)((((sb.st_mode)) & 0170000) == (0040000))) &&
96 mkdirs(path, mode) < 0) {
97 return -1;
98 }
99 *cp = '/';
100 }
101 rv = mkdir(path, mode);
102 if (rv) {
103 if (errno(*__errno_location ()) != EEXIST17)
104 fail("mkdirs cannot make %s", path);
105 fprintf(stderrstderr, "directory creation race: %s\n", path);
106 if (!stat(path, &sb) && S_ISDIR(sb.st_mode)((((sb.st_mode)) & 0170000) == (0040000)))
107 rv = 0;
108 }
109 return rv;
110}
111
112static uid_t
113touid(char *owner)
114{
115 struct passwd *pw;
116 uid_t uid;
117 char *cp;
118
119 if (!owner || !owner[0])
120 fail("Null pointer or empty string passed to touid()");
121 pw = getpwnam(owner);
122 if (pw)
123 return pw->pw_uid;
124 uid = strtol(owner, &cp, 0);
125 if (uid == 0 && cp == owner)
126 fail("cannot find uid for %s", owner);
127 return uid;
128}
129
130static gid_t
131togid(char *group)
132{
133 struct group *gr;
134 gid_t gid;
135 char *cp;
136
137 if (!group || !group[0])
138 fail("Null pointer or empty string passed to togid()");
139 gr = getgrnam(group);
140 if (gr)
141 return gr->gr_gid;
142 gid = strtol(group, &cp, 0);
143 if (gid == 0 && cp == group)
144 fail("cannot find gid for %s", group);
145 return gid;
146}
147
148void * const uninit = (void *)0xdeadbeef;
149
150int
151main(int argc, char **argv)
152{
153 char * base = uninit;
154 char * bp = uninit;
155 char * cp = uninit;
156 char * cwd = 0;
157 char * group = 0;
158 char * linkname = 0;
159 char * linkprefix = 0;
160 char * name = uninit;
161 char * owner = 0;
162 char * todir = uninit;
163 char * toname = uninit;
164
165 int bnlen = -1;
166 int cc = 0;
167 int dodir = 0;
168 int dolink = 0;
169 int dorelsymlink = 0;
170 int dotimes = 0;
171 int exists = 0;
172 int fromfd = -1;
173 int len = -1;
174 int lplen = 0;
175 int onlydir = 0;
176 int opt = -1;
177 int tdlen = -1;
178 int tofd = -1;
179 int wc = -1;
180
181 mode_t mode = 0755;
182
183 uid_t uid = -1;
184 gid_t gid = -1;
185
186 struct stat sb;
187 struct stat tosb;
188 struct utimbuf utb;
189 char buf[BUFSIZ8192];
190
191 program = strrchr(argv[0], '/');
192 if (!program)
1
Assuming 'program' is non-null
193 program = strrchr(argv[0], '\\');
194 program = program
2.1
'program' is non-null
? program+1 : argv[0];
2
Taking false branch
3
'?' condition is true
195
196
197 while ((opt = getopt(argc, argv, "C:DdlL:Rm:o:g:t")) != EOF(-1)) {
4
Assuming the condition is false
5
Loop condition is false. Execution continues on line 221
198 switch (opt) {
199 case 'C': cwd = optarg; break;
200 case 'D': onlydir = 1; break;
201 case 'd': dodir = 1; break;
202 case 'l': dolink = 1; break;
203 case 'L':
204 linkprefix = optarg;
205 lplen = strlen(linkprefix);
206 dolink = 1;
207 break;
208 case 'R': dolink = dorelsymlink = 1; break;
209 case 'm':
210 mode = strtoul(optarg, &cp, 8);
211 if (mode == 0 && cp == optarg)
212 usage();
213 break;
214 case 'o': owner = optarg; break;
215 case 'g': group = optarg; break;
216 case 't': dotimes = 1; break;
217 default: usage();
218 }
219 }
220
221 argc -= optind;
222 argv += optind;
223 if (argc < 2 - onlydir)
6
Assuming the condition is false
7
Taking false branch
224 usage();
225
226 todir = argv[argc-1];
227 if ((stat(todir, &sb) < 0 || !S_ISDIR(sb.st_mode)((((sb.st_mode)) & 0170000) == (0040000))) &&
8
Assuming the condition is false
9
Assuming the condition is true
228 mkdirs(todir, 0777) < 0) {
229 fail("cannot mkdir -p %s", todir);
230 }
231 if (onlydir
9.1
'onlydir' is 0
)
10
Taking false branch
232 return 0;
233
234 if (!cwd
10.1
'cwd' is null
) {
11
Taking true branch
235 cwd = GETCWDgetcwd(0, PATH_MAX4096);
236 if (!cwd)
12
Assuming 'cwd' is non-null
13
Taking false branch
237 fail("could not get CWD");
238 }
239
240 /* make sure we can get into todir. */
241 xchdir(todir);
242 todir = GETCWDgetcwd(0, PATH_MAX4096);
14
Value assigned to 'todir'
243 if (!todir)
15
Assuming 'todir' is null
16
Taking true branch
244 fail("could not get CWD in todir");
245 tdlen = strlen(todir);
17
Null pointer passed to 1st parameter expecting 'nonnull'
246
247 /* back to original directory. */
248 xchdir(cwd);
249
250 uid = owner ? touid(owner) : -1;
251 gid = group ? togid(group) : -1;
252
253 while (--argc > 0) {
254 name = *argv++;
255 len = strlen(name);
256 base = xbasename(name);
257 bnlen = strlen(base);
258 size_t toname_len = tdlen + 1 + bnlen + 1;
259 toname = (char*)xmalloc(toname_len);
260 snprintf(toname, toname_len, "%s/%s", todir, base);
261retry:
262 exists = (lstat(toname, &tosb) == 0);
263
264 if (dodir) {
265 /* -d means create a directory, always */
266 if (exists && !S_ISDIR(tosb.st_mode)((((tosb.st_mode)) & 0170000) == (0040000))) {
267 int rv = unlink(toname);
268 if (rv)
269 fail("cannot unlink %s", toname);
270 exists = 0;
271 }
272 if (!exists && mkdir(toname, mode) < 0) {
273 /* we probably have two nsinstall programs in a race here. */
274 if (errno(*__errno_location ()) == EEXIST17 && !stat(toname, &sb) &&
275 S_ISDIR(sb.st_mode)((((sb.st_mode)) & 0170000) == (0040000))) {
276 fprintf(stderrstderr, "directory creation race: %s\n", toname);
277 goto retry;
278 }
279 fail("cannot make directory %s", toname);
280 }
281 if ((owner || group) && chown(toname, uid, gid) < 0)
282 fail("cannot change owner of %s", toname);
283 } else if (dolink) {
284 if (*name == '/') {
285 /* source is absolute pathname, link to it directly */
286 linkname = 0;
287 } else {
288 if (linkprefix) {
289 /* -L implies -l and prefixes names with a $cwd arg. */
290 len += lplen + 1;
291 linkname = (char*)xmalloc(len + 1);
292 snprintf(linkname, len+1, "%s/%s", linkprefix, name);
293 } else if (dorelsymlink) {
294 /* Symlink the relative path from todir to source name. */
295 linkname = (char*)xmalloc(PATH_MAX4096);
296
297 if (*todir == '/') {
298 /* todir is absolute: skip over common prefix. */
299 lplen = relatepaths(todir, cwd, linkname);
300 strcpy(linkname + lplen, name);
301 } else {
302 /* todir is named by a relative path: reverse it. */
303 reversepath(todir, name, len, linkname);
304 xchdir(cwd);
305 }
306
307 len = strlen(linkname);
308 }
309 name = linkname;
310 }
311
312 /* Check for a pre-existing symlink with identical content. */
313 if (exists &&
314 (!S_ISLNK(tosb.st_mode)((((tosb.st_mode)) & 0170000) == (0120000)) ||
315 readlink(toname, buf, sizeof buf) != len ||
316 strncmp(buf, name, len) != 0)) {
317 int rmrv;
318 rmrv = (S_ISDIR(tosb.st_mode)((((tosb.st_mode)) & 0170000) == (0040000)) ? rmdir : unlink)(toname);
319 if (rmrv < 0) {
320 fail("destination exists, cannot remove %s", toname);
321 }
322 exists = 0;
323 }
324 if (!exists && symlink(name, toname) < 0) {
325 if (errno(*__errno_location ()) == EEXIST17) {
326 fprintf(stderrstderr, "symlink creation race: %s\n", toname);
327 fail("symlink was attempted in working directory %s "
328 "from %s to %s.\n", cwd, name, toname);
329 goto retry;
330 }
331 diagnosePath(toname);
332 fail("cannot make symbolic link %s", toname);
333 }
334#ifdef HAVE_LCHOWN
335 if ((owner || group) && lchown(toname, uid, gid) < 0)
336 fail("cannot change owner of %s", toname);
337#endif
338
339 if (linkname) {
340 free(linkname);
341 linkname = 0;
342 }
343 } else {
344 /* Copy from name to toname, which might be the same file. */
345 fromfd = open(name, O_RDONLY00);
346 if (fromfd < 0 || fstat(fromfd, &sb) < 0)
347 fail("cannot access %s", name);
348 if (exists &&
349 (!S_ISREG(tosb.st_mode)((((tosb.st_mode)) & 0170000) == (0100000)) || access(toname, W_OK2) < 0)) {
350 int rmrv;
351 rmrv = (S_ISDIR(tosb.st_mode)((((tosb.st_mode)) & 0170000) == (0040000)) ? rmdir : unlink)(toname);
352 if (rmrv < 0) {
353 fail("destination exists, cannot remove %s", toname);
354 }
355 }
356 tofd = open(toname, O_CREAT0100 | O_WRONLY01, 0666);
357 if (tofd < 0)
358 fail("cannot create %s", toname);
359
360 bp = buf;
361 while ((cc = read(fromfd, bp, sizeof buf)) > 0) {
362 while ((wc = write(tofd, bp, cc)) > 0) {
363 if ((cc -= wc) == 0)
364 break;
365 bp += wc;
366 }
367 if (wc < 0)
368 fail("cannot write to %s", toname);
369 }
370 if (cc < 0)
371 fail("cannot read from %s", name);
372
373 if (ftruncate(tofd, sb.st_size) < 0)
374 fail("cannot truncate %s", toname);
375 if (dotimes) {
376 utb.actime = sb.st_atimest_atim.tv_sec;
377 utb.modtime = sb.st_mtimest_mtim.tv_sec;
378 if (utime(toname, &utb) < 0)
379 fail("cannot set times of %s", toname);
380 }
381#ifdef HAVE_FCHMOD
382 if (fchmod(tofd, mode) < 0)
383#else
384 if (chmod(toname, mode) < 0)
385#endif
386 fail("cannot change mode of %s", toname);
387
388 if ((owner || group) && fchown(tofd, uid, gid) < 0)
389 fail("cannot change owner of %s", toname);
390
391 /* Must check for delayed (NFS) write errors on close. */
392 if (close(tofd) < 0)
393 fail("close reports write error on %s", toname);
394 close(fromfd);
395 }
396
397 free(toname);
398 }
399
400 free(cwd);
401 free(todir);
402 return 0;
403}
404