Bug Summary

File:src/games/sail/sync.c
Warning:line 146, column 2
The return value from the call to 'setegid' is not checked. If an error occurs in 'setegid', the following code may execute with unexpected privileges

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 sync.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/games/sail/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/games/sail/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/games/sail/sync.c
1/* $OpenBSD: sync.c,v 1.16 2019/06/28 13:32:52 deraadt Exp $ */
2/* $NetBSD: sync.c,v 1.9 1998/08/30 09:19:40 veego Exp $ */
3
4/*
5 * Copyright (c) 1983, 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/stat.h>
34
35#include <errno(*__errno()).h>
36#ifdef LOCK_EX
37#include <fcntl.h>
38#endif
39#include <signal.h>
40#include <stdlib.h>
41#include <string.h>
42#include <time.h>
43#include <unistd.h>
44
45#include "extern.h"
46#include "machdep.h"
47#include "pathnames.h"
48#include "player.h"
49
50#define BUFSIZE4096 4096
51
52static const char SF[] = _PATH_SYNC"/tmp/#sailsink.%d";
53static const char LF[] = _PATH_LOCK"/tmp/#saillock.%d";
54static char sync_buf[BUFSIZE4096];
55static char *sync_bp = sync_buf;
56static char sync_lock[sizeof SF];
57static char sync_file[sizeof LF];
58static long sync_seek;
59static FILE *sync_fp;
60
61void
62fmtship(char *buf, size_t len, const char *fmt, struct ship *ship)
63{
64 if (len == 0)
65 abort(); /* XXX */
66
67 while (*fmt && len > 1) {
68 if (*fmt == '$' && fmt[1] == '$') {
69 size_t l;
70 snprintf(buf, len, "%s (%c%c)",
71 ship->shipname, colours(ship), sterncolour(ship)((ship)->file->stern+'0'-((ship)->file->captured?
10:0))
);
72 l = strlen(buf);
73 buf += l;
74 len -= l;
75 fmt += 2;
76 } else {
77 *buf++ = *fmt++;
78 len--;
79 }
80 }
81
82 *buf = '\0';
83}
84
85
86void
87makesignal(struct ship *from, const char *fmt, struct ship *ship, ...)
88{
89 char message[BUFSIZ1024];
90 char format[BUFSIZ1024];
91 va_list ap;
92
93 va_start(ap, ship)__builtin_va_start(ap, ship);
94 fmtship(format, sizeof(format), fmt, ship);
95 (void) vsnprintf(message, sizeof message, format, ap);
96 va_end(ap)__builtin_va_end(ap);
97 Writestr(W_SIGNAL24, from, message);
98}
99
100void
101makemsg(struct ship *from, const char *fmt, ...)
102{
103 char message[BUFSIZ1024];
104 va_list ap;
105
106 va_start(ap, fmt)__builtin_va_start(ap, fmt);
107 (void) vsnprintf(message, sizeof message, fmt, ap);
108 va_end(ap)__builtin_va_end(ap);
109 Writestr(W_SIGNAL24, from, message);
110}
111
112int
113sync_exists(int game)
114{
115 char buf[sizeof sync_file];
116 struct stat s;
117 time_t t;
118
119 (void) snprintf(buf, sizeof buf, SF, game);
120 (void) time(&t);
121 setegid(egid);
122 if (stat(buf, &s) == -1) {
123 setegid(gid);
124 return 0;
125 }
126 if (s.st_mtimest_mtim.tv_sec < t - 60*60*2) { /* 2 hours */
127 (void) unlink(buf);
128 (void) snprintf(buf, sizeof buf, LF, game);
129 (void) unlink(buf);
130 setegid(gid);
131 return 0;
132 }
133 setegid(gid);
134 return 1;
135}
136
137int
138sync_open(void)
139{
140 struct stat tmp;
141
142 if (sync_fp != NULL((void *)0))
143 (void) fclose(sync_fp);
144 (void) snprintf(sync_lock, sizeof sync_lock, LF, game);
145 (void) snprintf(sync_file, sizeof sync_file, SF, game);
146 setegid(egid);
The return value from the call to 'setegid' is not checked. If an error occurs in 'setegid', the following code may execute with unexpected privileges
147 if (stat(sync_file, &tmp) == -1) {
148 mode_t omask = umask(002);
149 sync_fp = fopen(sync_file, "w+");
150 (void) umask(omask);
151 } else
152 sync_fp = fopen(sync_file, "r+");
153 setegid(gid);
154 if (sync_fp == NULL((void *)0))
155 return -1;
156 sync_seek = 0;
157 return 0;
158}
159
160void
161sync_close(int remove)
162{
163 if (sync_fp != 0)
164 (void) fclose(sync_fp);
165 if (remove) {
166 setegid(egid);
167 (void) unlink(sync_file);
168 setegid(gid);
169 }
170}
171
172void
173Write(int type, struct ship *ship, long a, long b, long c, long d)
174{
175 (void) snprintf(sync_bp, sync_buf + sizeof sync_buf - sync_bp,
176 "%d %d 0 %ld %ld %ld %ld\n",
177 type, ship->file->index, a, b, c, d);
178 while (*sync_bp++)
179 ;
180 sync_bp--;
181 if (sync_bp >= &sync_buf[sizeof sync_buf])
182 abort();
183 (void) sync_update(type, ship, NULL((void *)0), a, b, c, d);
184}
185
186void
187Writestr(int type, struct ship *ship, const char *a)
188{
189 (void) snprintf(sync_bp, sync_buf + sizeof sync_buf - sync_bp,
190 "%d %d 1 %s\n",
191 type, ship->file->index, a);
192 while (*sync_bp++)
193 ;
194 sync_bp--;
195 if (sync_bp >= &sync_buf[sizeof sync_buf])
196 abort();
197 (void) sync_update(type, ship, a, 0, 0, 0, 0);
198}
199
200int
201Sync(void)
202{
203 sig_t sighup, sigint;
204 int n;
205 int type, shipnum, isstr;
206 char *astr;
207 long a, b, c, d;
208 char buf[80];
209 char erred = 0;
210
211 sighup = signal(SIGHUP1, SIG_IGN(void (*)(int))1);
212 sigint = signal(SIGINT2, SIG_IGN(void (*)(int))1);
213 for (n = TIMEOUT300; --n >= 0;) {
214#ifdef LOCK_EX
215 if (flock(fileno(sync_fp)(!__isthreaded ? ((sync_fp)->_file) : (fileno)(sync_fp)), LOCK_EX|LOCK_NB) >= 0)
216 break;
217 if (errno(*__errno()) != EWOULDBLOCK35)
218 return -1;
219#else
220 setegid(egid);
221 if (link(sync_file, sync_lock) >= 0) {
222 setegid(gid);
223 break;
224 }
225 setegid(gid);
226 if (errno(*__errno()) != EEXIST17)
227 return -1;
228#endif
229 sleep(1);
230 }
231 if (n <= 0)
232 return -1;
233 (void) fseek(sync_fp, sync_seek, SEEK_SET0);
234 for (;;) {
235 switch (fscanf(sync_fp, "%d%d%d", &type, &shipnum, &isstr)) {
236 case 3:
237 break;
238 case EOF(-1):
239 goto out;
240 default:
241 goto bad;
242 }
243 if (shipnum < 0 || shipnum >= cc->vessels)
244 goto bad;
245 if (isstr != 0 && isstr != 1)
246 goto bad;
247 if (isstr) {
248 int ch;
249 char *p;
250
251 for (p = buf;;) {
252 ch = getc(sync_fp)(!__isthreaded ? (--(sync_fp)->_r < 0 ? __srget(sync_fp
) : (int)(*(sync_fp)->_p++)) : (getc)(sync_fp))
;
253 switch (ch) {
254 case '\n':
255 case EOF(-1):
256 break;
257 default:
258 if (p < buf + sizeof buf)
259 *p++ = ch;
260 continue;
261 }
262 break;
263 }
264 *p = 0;
265 for (p = buf; *p == ' '; p++)
266 ;
267 astr = p;
268 a = b = c = d = 0;
269 } else {
270 if (fscanf(sync_fp, "%ld%ld%ld%ld", &a, &b, &c, &d) != 4)
271 goto bad;
272 astr = NULL((void *)0);
273 }
274 if (sync_update(type, SHIP(shipnum)(&cc->ship[shipnum]), astr, a, b, c, d) < 0)
275 goto bad;
276 }
277bad:
278 erred++;
279out:
280 if (!erred && sync_bp != sync_buf) {
281 (void) fseek(sync_fp, 0L, SEEK_END2);
282 (void) fwrite(sync_buf, sizeof *sync_buf, sync_bp - sync_buf,
283 sync_fp);
284 (void) fflush(sync_fp);
285 sync_bp = sync_buf;
286 }
287 sync_seek = ftell(sync_fp);
288#ifdef LOCK_EX
289 (void) flock(fileno(sync_fp)(!__isthreaded ? ((sync_fp)->_file) : (fileno)(sync_fp)), LOCK_UN);
290#else
291 setegid(egid);
292 (void) unlink(sync_lock);
293 setegid(gid);
294#endif
295 (void) signal(SIGHUP1, sighup);
296 (void) signal(SIGINT2, sigint);
297 return erred ? -1 : 0;
298}
299
300int
301sync_update(int type, struct ship *ship, const char *astr, long a, long b,
302 long c, long d)
303{
304 switch (type) {
305 case W_DBP5: {
306 struct BP *p = &ship->file->DBP[a];
307 p->turnsent = b;
308 p->toship = SHIP(c)(&cc->ship[c]);
309 p->mensent = d;
310 break;
311 }
312 case W_OBP14: {
313 struct BP *p = &ship->file->OBP[a];
314 p->turnsent = b;
315 p->toship = SHIP(c)(&cc->ship[c]);
316 p->mensent = d;
317 break;
318 }
319 case W_FOUL9: {
320 struct snag *p = &ship->file->foul[a];
321 if (SHIP(a)(&cc->ship[a])->file->dir == 0)
322 break;
323 if (p->sn_count++ == 0)
324 p->sn_turn = turn;
325 ship->file->nfoul++;
326 break;
327 }
328 case W_GRAP32: {
329 struct snag *p = &ship->file->grap[a];
330 if (SHIP(a)(&cc->ship[a])->file->dir == 0)
331 break;
332 if (p->sn_count++ == 0)
333 p->sn_turn = turn;
334 ship->file->ngrap++;
335 break;
336 }
337 case W_UNFOUL16: {
338 struct snag *p = &ship->file->foul[a];
339 if (p->sn_count > 0) {
340 if (b) {
341 ship->file->nfoul -= p->sn_count;
342 p->sn_count = 0;
343 } else {
344 ship->file->nfoul--;
345 p->sn_count--;
346 }
347 }
348 break;
349 }
350 case W_UNGRAP19: {
351 struct snag *p = &ship->file->grap[a];
352 if (p->sn_count > 0) {
353 if (b) {
354 ship->file->ngrap -= p->sn_count;
355 p->sn_count = 0;
356 } else {
357 ship->file->ngrap--;
358 p->sn_count--;
359 }
360 }
361 break;
362 }
363 case W_SIGNAL24:
364 if (mode == MODE_PLAYER1) {
365 if (nobells)
366 Signal("$$: %s", ship, astr);
367 else
368 Signal("\7$$: %s", ship, astr);
369 }
370 break;
371 case W_CREW4: {
372 struct shipspecs *s = ship->specs;
373 s->crew1 = a;
374 s->crew2 = b;
375 s->crew3 = c;
376 break;
377 }
378 case W_CAPTAIN1:
379 (void) strlcpy(ship->file->captain, astr,
380 sizeof ship->file->captain);
381 break;
382 case W_CAPTURED2:
383 if (a < 0)
384 ship->file->captured = 0;
385 else
386 ship->file->captured = SHIP(a)(&cc->ship[a]);
387 break;
388 case W_CLASS3:
389 ship->specs->class = a;
390 break;
391 case W_DRIFT6:
392 ship->file->drift = a;
393 break;
394 case W_EXPLODE7:
395 if ((ship->file->explode = a) == 2)
396 ship->file->dir = 0;
397 break;
398 case W_FS31:
399 ship->file->FS = a;
400 break;
401 case W_GUNL10: {
402 struct shipspecs *s = ship->specs;
403 s->gunL = a;
404 s->carL = b;
405 break;
406 }
407 case W_GUNR11: {
408 struct shipspecs *s = ship->specs;
409 s->gunR = a;
410 s->carR = b;
411 break;
412 }
413 case W_HULL12:
414 ship->specs->hull = a;
415 break;
416 case W_MOVE13:
417 (void) strlcpy(ship->file->movebuf, astr,
418 sizeof ship->file->movebuf);
419 break;
420 case W_PCREW15:
421 ship->file->pcrew = a;
422 break;
423 case W_POINTS17:
424 ship->file->points = a;
425 break;
426 case W_QUAL18:
427 ship->specs->qual = a;
428 break;
429 case W_RIGG20: {
430 struct shipspecs *s = ship->specs;
431 s->rig1 = a;
432 s->rig2 = b;
433 s->rig3 = c;
434 s->rig4 = d;
435 break;
436 }
437 case W_RIG133:
438 ship->specs->rig1 = a;
439 break;
440 case W_RIG234:
441 ship->specs->rig2 = a;
442 break;
443 case W_RIG335:
444 ship->specs->rig3 = a;
445 break;
446 case W_RIG436:
447 ship->specs->rig4 = a;
448 break;
449 case W_COL21:
450 ship->file->col = a;
451 break;
452 case W_DIR22:
453 ship->file->dir = a;
454 break;
455 case W_ROW23:
456 ship->file->row = a;
457 break;
458 case W_SINK25:
459 if ((ship->file->sink = a) == 2)
460 ship->file->dir = 0;
461 break;
462 case W_STRUCK26:
463 ship->file->struck = a;
464 break;
465 case W_TA27:
466 ship->specs->ta = a;
467 break;
468 case W_ALIVE28:
469 alive = 1;
470 break;
471 case W_TURN29:
472 turn = a;
473 break;
474 case W_WIND30:
475 winddir = a;
476 windspeed = b;
477 break;
478 case W_BEGIN37:
479 (void) strlcpy(ship->file->captain, "begin",
480 sizeof ship->file->captain);
481 people++;
482 break;
483 case W_END38:
484 *ship->file->captain = 0;
485 ship->file->points = 0;
486 people--;
487 break;
488 case W_DDEAD39:
489 hasdriver = 0;
490 break;
491 default:
492 fprintf(stderr(&__sF[2]), "sync_update: unknown type %d\r\n", type);
493 return -1;
494 }
495 return 0;
496}