Bug Summary

File:kern/sysv_sem.c
Warning:line 464, column 9
Although the value stored to 'semaptr' is used in the enclosing expression, the value is never actually read from 'semaptr'

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 sysv_sem.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 static -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -ffreestanding -mcmodel=kernel -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -target-feature -sse2 -target-feature -sse -target-feature -3dnow -target-feature -mmx -target-feature +save-args -disable-red-zone -no-implicit-float -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -nostdsysteminc -nobuiltininc -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/sys -I /usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -I /usr/src/sys/arch -I /usr/src/sys/dev/pci/drm/include -I /usr/src/sys/dev/pci/drm/include/uapi -I /usr/src/sys/dev/pci/drm/amd/include/asic_reg -I /usr/src/sys/dev/pci/drm/amd/include -I /usr/src/sys/dev/pci/drm/amd/amdgpu -I /usr/src/sys/dev/pci/drm/amd/display -I /usr/src/sys/dev/pci/drm/amd/display/include -I /usr/src/sys/dev/pci/drm/amd/display/dc -I /usr/src/sys/dev/pci/drm/amd/display/amdgpu_dm -I /usr/src/sys/dev/pci/drm/amd/pm/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu11 -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu12 -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/hwmgr -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/smumgr -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc/hw -I /usr/src/sys/dev/pci/drm/amd/display/dc/clk_mgr -I /usr/src/sys/dev/pci/drm/amd/display/modules/inc -I /usr/src/sys/dev/pci/drm/amd/display/modules/hdcp -I /usr/src/sys/dev/pci/drm/amd/display/dmub/inc -I /usr/src/sys/dev/pci/drm/i915 -D DDB -D DIAGNOSTIC -D KTRACE -D ACCOUNTING -D KMEMSTATS -D PTRACE -D POOL_DEBUG -D CRYPTO -D SYSVMSG -D SYSVSEM -D SYSVSHM -D UVM_SWAP_ENCRYPT -D FFS -D FFS2 -D FFS_SOFTUPDATES -D UFS_DIRHASH -D QUOTA -D EXT2FS -D MFS -D NFSCLIENT -D NFSSERVER -D CD9660 -D UDF -D MSDOSFS -D FIFO -D FUSE -D SOCKET_SPLICE -D TCP_ECN -D TCP_SIGNATURE -D INET6 -D IPSEC -D PPP_BSDCOMP -D PPP_DEFLATE -D PIPEX -D MROUTING -D MPLS -D BOOT_CONFIG -D USER_PCICONF -D APERTURE -D MTRR -D NTFS -D HIBERNATE -D PCIVERBOSE -D USBVERBOSE -D WSDISPLAY_COMPAT_USL -D WSDISPLAY_COMPAT_RAWKBD -D WSDISPLAY_DEFAULTSCREENS=6 -D X86EMU -D ONEWIREVERBOSE -D MULTIPROCESSOR -D MAXUSERS=80 -D _KERNEL -D CONFIG_DRM_AMD_DC_DCN3_0 -O2 -Wno-pointer-sign -Wno-address-of-packed-member -Wno-constant-conversion -Wno-unused-but-set-variable -Wno-gnu-folding-constant -fdebug-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/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 -o /usr/obj/sys/arch/amd64/compile/GENERIC.MP/scan-build/2022-01-12-131800-47421-1 -x c /usr/src/sys/kern/sysv_sem.c
1/* $OpenBSD: sysv_sem.c,v 1.61 2021/04/30 13:52:48 bluhm Exp $ */
2/* $NetBSD: sysv_sem.c,v 1.26 1996/02/09 19:00:25 christos Exp $ */
3
4/*
5 * Copyright (c) 2002,2003 Todd C. Miller <millert@openbsd.org>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 *
19 * Sponsored in part by the Defense Advanced Research Projects
20 * Agency (DARPA) and Air Force Research Laboratory, Air Force
21 * Materiel Command, USAF, under agreement number F39502-99-1-0512.
22 */
23/*
24 * Implementation of SVID semaphores
25 *
26 * Author: Daniel Boulet
27 *
28 * This software is provided ``AS IS'' without any warranties of any kind.
29 */
30
31#include <sys/param.h>
32#include <sys/systm.h>
33#include <sys/proc.h>
34#include <sys/sem.h>
35#include <sys/sysctl.h>
36#include <sys/malloc.h>
37#include <sys/pool.h>
38
39#include <sys/mount.h>
40#include <sys/syscallargs.h>
41
42#ifdef SEM_DEBUG
43#define DPRINTF(x) printf x
44#else
45#define DPRINTF(x)
46#endif
47
48int semtot = 0;
49int semutot = 0;
50struct semid_ds **sema; /* semaphore id list */
51SLIST_HEAD(, sem_undo)struct { struct sem_undo *slh_first; } semu_list; /* list of undo structures */
52struct pool sema_pool; /* pool for struct semid_ds */
53struct pool semu_pool; /* pool for struct sem_undo (SEMUSZ) */
54unsigned short *semseqs; /* array of sem sequence numbers */
55
56struct sem_undo *semu_alloc(struct process *);
57int semundo_adjust(struct proc *, struct sem_undo **, int, int, int);
58void semundo_clear(int, int);
59
60void
61seminit(void)
62{
63
64 pool_init(&sema_pool, sizeof(struct semid_ds), 0, 0, PR_WAITOK0x0001,
65 "semapl", NULL((void *)0));
66 pool_init(&semu_pool, SEMUSZ(sizeof(struct sem_undo)+sizeof(struct undo)*10), 0, 0, PR_WAITOK0x0001, "semupl", NULL((void *)0));
67 sema = mallocarray(seminfo.semmni, sizeof(struct semid_ds *),
68 M_SEM31, M_WAITOK0x0001|M_ZERO0x0008);
69 semseqs = mallocarray(seminfo.semmni, sizeof(unsigned short),
70 M_SEM31, M_WAITOK0x0001|M_ZERO0x0008);
71 SLIST_INIT(&semu_list){ ((&semu_list)->slh_first) = ((void *)0); };
72}
73
74/*
75 * Allocate a new sem_undo structure for a process
76 * (returns ptr to structure or NULL if no more room)
77 */
78struct sem_undo *
79semu_alloc(struct process *pr)
80{
81 struct sem_undo *suptr, *sutmp;
82
83 if (semutot == seminfo.semmnu)
84 return (NULL((void *)0)); /* no space */
85
86 /*
87 * Allocate a semu w/o waiting if possible.
88 * If we do have to wait, we must check to verify that a semu
89 * with un_proc == pr has not been allocated in the meantime.
90 */
91 semutot++;
92 if ((suptr = pool_get(&semu_pool, PR_NOWAIT0x0002)) == NULL((void *)0)) {
93 sutmp = pool_get(&semu_pool, PR_WAITOK0x0001);
94 SLIST_FOREACH(suptr, &semu_list, un_next)for((suptr) = ((&semu_list)->slh_first); (suptr) != ((
void *)0); (suptr) = ((suptr)->un_next.sle_next))
{
95 if (suptr->un_proc == pr) {
96 pool_put(&semu_pool, sutmp);
97 semutot--;
98 return (suptr);
99 }
100 }
101 suptr = sutmp;
102 }
103 suptr->un_cnt = 0;
104 suptr->un_proc = pr;
105 SLIST_INSERT_HEAD(&semu_list, suptr, un_next)do { (suptr)->un_next.sle_next = (&semu_list)->slh_first
; (&semu_list)->slh_first = (suptr); } while (0)
;
106 return (suptr);
107}
108
109/*
110 * Adjust a particular entry for a particular proc
111 */
112int
113semundo_adjust(struct proc *p, struct sem_undo **supptr, int semid, int semnum,
114 int adjval)
115{
116 struct process *pr = p->p_p;
117 struct sem_undo *suptr;
118 struct undo *sunptr;
119 int i;
120
121 /*
122 * Look for and remember the sem_undo if the caller doesn't provide it.
123 */
124 suptr = *supptr;
125 if (suptr == NULL((void *)0)) {
126 SLIST_FOREACH(suptr, &semu_list, un_next)for((suptr) = ((&semu_list)->slh_first); (suptr) != ((
void *)0); (suptr) = ((suptr)->un_next.sle_next))
{
127 if (suptr->un_proc == pr) {
128 *supptr = suptr;
129 break;
130 }
131 }
132 if (suptr == NULL((void *)0)) {
133 if (adjval == 0)
134 return (0);
135 suptr = semu_alloc(p->p_p);
136 if (suptr == NULL((void *)0))
137 return (ENOSPC28);
138 *supptr = suptr;
139 }
140 }
141
142 /*
143 * Look for the requested entry and adjust it
144 * (delete if adjval becomes 0).
145 */
146 sunptr = &suptr->un_ent[0];
147 for (i = 0; i < suptr->un_cnt; i++, sunptr++) {
148 if (sunptr->un_id != semid || sunptr->un_num != semnum)
149 continue;
150 if (adjval == 0)
151 sunptr->un_adjval = 0;
152 else
153 sunptr->un_adjval += adjval;
154 if (sunptr->un_adjval != 0)
155 return (0);
156
157 if (--suptr->un_cnt == 0) {
158 *supptr = NULL((void *)0);
159 SLIST_REMOVE(&semu_list, suptr, sem_undo, un_next)do { if ((&semu_list)->slh_first == (suptr)) { do { ((
&semu_list))->slh_first = ((&semu_list))->slh_first
->un_next.sle_next; } while (0); } else { struct sem_undo *
curelm = (&semu_list)->slh_first; while (curelm->un_next
.sle_next != (suptr)) curelm = curelm->un_next.sle_next; curelm
->un_next.sle_next = curelm->un_next.sle_next->un_next
.sle_next; } ((suptr)->un_next.sle_next) = ((void *)-1); }
while (0)
;
160 pool_put(&semu_pool, suptr);
161 semutot--;
162 } else if (i < suptr->un_cnt)
163 suptr->un_ent[i] =
164 suptr->un_ent[suptr->un_cnt];
165 return (0);
166 }
167
168 /* Didn't find the right entry - create it */
169 if (adjval == 0)
170 return (0);
171 if (suptr->un_cnt == SEMUME10)
172 return (EINVAL22);
173
174 sunptr = &suptr->un_ent[suptr->un_cnt];
175 suptr->un_cnt++;
176 sunptr->un_adjval = adjval;
177 sunptr->un_id = semid;
178 sunptr->un_num = semnum;
179 return (0);
180}
181
182void
183semundo_clear(int semid, int semnum)
184{
185 struct sem_undo *suptr = SLIST_FIRST(&semu_list)((&semu_list)->slh_first);
186 struct sem_undo *suprev = NULL((void *)0);
187 struct undo *sunptr;
188 int i;
189
190 while (suptr != NULL((void *)0)) {
191 sunptr = &suptr->un_ent[0];
192 for (i = 0; i < suptr->un_cnt; i++, sunptr++) {
193 if (sunptr->un_id == semid) {
194 if (semnum == -1 || sunptr->un_num == semnum) {
195 suptr->un_cnt--;
196 if (i < suptr->un_cnt) {
197 suptr->un_ent[i] =
198 suptr->un_ent[suptr->un_cnt];
199 i--, sunptr--;
200 }
201 }
202 if (semnum != -1)
203 break;
204 }
205 }
206 if (suptr->un_cnt == 0) {
207 struct sem_undo *sutmp = suptr;
208
209 if (suptr == SLIST_FIRST(&semu_list)((&semu_list)->slh_first))
210 SLIST_REMOVE_HEAD(&semu_list, un_next)do { (&semu_list)->slh_first = (&semu_list)->slh_first
->un_next.sle_next; } while (0)
;
211 else
212 SLIST_REMOVE_AFTER(suprev, un_next)do { (suprev)->un_next.sle_next = (suprev)->un_next.sle_next
->un_next.sle_next; } while (0)
;
213 suptr = SLIST_NEXT(suptr, un_next)((suptr)->un_next.sle_next);
214 pool_put(&semu_pool, sutmp);
215 semutot--;
216 } else {
217 suprev = suptr;
218 suptr = SLIST_NEXT(suptr, un_next)((suptr)->un_next.sle_next);
219 }
220 }
221}
222
223int
224sys___semctl(struct proc *p, void *v, register_t *retval)
225{
226 struct sys___semctl_args /* {
227 syscallarg(int) semid;
228 syscallarg(int) semnum;
229 syscallarg(int) cmd;
230 syscallarg(union semun *) arg;
231 } */ *uap = v;
232 union semun arg;
233 int error = 0, cmd = SCARG(uap, cmd)((uap)->cmd.le.datum);
234
235 switch (cmd) {
236 case IPC_SET1:
237 case IPC_STAT2:
238 case GETALL6:
239 case SETVAL8:
240 case SETALL9:
241 error = copyin(SCARG(uap, arg)((uap)->arg.le.datum), &arg, sizeof(arg));
242 break;
243 }
244 if (error == 0) {
245 error = semctl1(p, SCARG(uap, semid)((uap)->semid.le.datum), SCARG(uap, semnum)((uap)->semnum.le.datum),
246 cmd, &arg, retval, copyin, copyout);
247 }
248 return (error);
249}
250
251int
252semctl1(struct proc *p, int semid, int semnum, int cmd, union semun *arg,
253 register_t *retval, int (*ds_copyin)(const void *, void *, size_t),
254 int (*ds_copyout)(const void *, void *, size_t))
255{
256 struct ucred *cred = p->p_ucred;
257 int i, ix, error = 0;
258 struct semid_ds sbuf;
259 struct semid_ds *semaptr;
260 unsigned short *semval = NULL((void *)0);
261
262 DPRINTF(("call to semctl(%d, %d, %d, %p)\n", semid, semnum, cmd, arg));
263
264 ix = IPCID_TO_IX(semid)((semid) & 0xffff);
265 if (ix < 0 || ix >= seminfo.semmni)
266 return (EINVAL22);
267
268 if ((semaptr = sema[ix]) == NULL((void *)0) ||
269 semaptr->sem_perm.seq != IPCID_TO_SEQ(semid)(((semid) >> 16) & 0xffff))
270 return (EINVAL22);
271
272 switch (cmd) {
273 case IPC_RMID0:
274 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_M010000)) != 0)
275 return (error);
276 semaptr->sem_perm.cuid = cred->cr_uid;
277 semaptr->sem_perm.uid = cred->cr_uid;
278 semtot -= semaptr->sem_nsems;
279 free(semaptr->sem_base, M_SEM31,
280 semaptr->sem_nsems * sizeof(struct sem));
281 pool_put(&sema_pool, semaptr);
282 sema[ix] = NULL((void *)0);
283 semundo_clear(ix, -1);
284 wakeup(&sema[ix]);
285 break;
286
287 case IPC_SET1:
288 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_M010000)))
289 return (error);
290 if ((error = ds_copyin(arg->buf, &sbuf, sizeof(sbuf))) != 0)
291 return (error);
292 semaptr->sem_perm.uid = sbuf.sem_perm.uid;
293 semaptr->sem_perm.gid = sbuf.sem_perm.gid;
294 semaptr->sem_perm.mode = (semaptr->sem_perm.mode & ~0777) |
295 (sbuf.sem_perm.mode & 0777);
296 semaptr->sem_ctime = gettime();
297 break;
298
299 case IPC_STAT2:
300 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R000400)))
301 return (error);
302 memcpy(&sbuf, semaptr, sizeof sbuf)__builtin_memcpy((&sbuf), (semaptr), (sizeof sbuf));
303 sbuf.sem_base = NULL((void *)0);
304 error = ds_copyout(&sbuf, arg->buf, sizeof(struct semid_ds));
305 break;
306
307 case GETNCNT3:
308 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R000400)))
309 return (error);
310 if (semnum < 0 || semnum >= semaptr->sem_nsems)
311 return (EINVAL22);
312 *retval = semaptr->sem_base[semnum].semncnt;
313 break;
314
315 case GETPID4:
316 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R000400)))
317 return (error);
318 if (semnum < 0 || semnum >= semaptr->sem_nsems)
319 return (EINVAL22);
320 *retval = semaptr->sem_base[semnum].sempid;
321 break;
322
323 case GETVAL5:
324 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R000400)))
325 return (error);
326 if (semnum < 0 || semnum >= semaptr->sem_nsems)
327 return (EINVAL22);
328 *retval = semaptr->sem_base[semnum].semval;
329 break;
330
331 case GETALL6:
332 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R000400)))
333 return (error);
334 for (i = 0; i < semaptr->sem_nsems; i++) {
335 error = ds_copyout(&semaptr->sem_base[i].semval,
336 &arg->array[i], sizeof(arg->array[0]));
337 if (error != 0)
338 break;
339 }
340 break;
341
342 case GETZCNT7:
343 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R000400)))
344 return (error);
345 if (semnum < 0 || semnum >= semaptr->sem_nsems)
346 return (EINVAL22);
347 *retval = semaptr->sem_base[semnum].semzcnt;
348 break;
349
350 case SETVAL8:
351 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_W000200)))
352 return (error);
353 if (semnum < 0 || semnum >= semaptr->sem_nsems)
354 return (EINVAL22);
355 if (arg->val > seminfo.semvmx)
356 return (ERANGE34);
357 semaptr->sem_base[semnum].semval = arg->val;
358 semundo_clear(ix, semnum);
359 wakeup(&sema[ix]);
360 break;
361
362 case SETALL9:
363 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_W000200)))
364 return (error);
365 semval = mallocarray(semaptr->sem_nsems, sizeof(arg->array[0]),
366 M_TEMP127, M_WAITOK0x0001);
367 for (i = 0; i < semaptr->sem_nsems; i++) {
368 error = ds_copyin(&arg->array[i], &semval[i],
369 sizeof(arg->array[0]));
370 if (error != 0)
371 goto error;
372 if (semval[i] > seminfo.semvmx) {
373 error = ERANGE34;
374 goto error;
375 }
376 }
377 for (i = 0; i < semaptr->sem_nsems; i++)
378 semaptr->sem_base[i].semval = semval[i];
379 semundo_clear(ix, -1);
380 wakeup(&sema[ix]);
381 break;
382
383 default:
384 return (EINVAL22);
385 }
386
387error:
388 if (semval)
389 free(semval, M_TEMP127,
390 semaptr->sem_nsems * sizeof(arg->array[0]));
391
392 return (error);
393}
394
395int
396sys_semget(struct proc *p, void *v, register_t *retval)
397{
398 struct sys_semget_args /* {
399 syscallarg(key_t) key;
400 syscallarg(int) nsems;
401 syscallarg(int) semflg;
402 } */ *uap = v;
403 int semid, error;
404 int key = SCARG(uap, key)((uap)->key.le.datum);
405 int nsems = SCARG(uap, nsems)((uap)->nsems.le.datum);
406 int semflg = SCARG(uap, semflg)((uap)->semflg.le.datum);
407 struct semid_ds *semaptr, *semaptr_new = NULL((void *)0);
408 struct ucred *cred = p->p_ucred;
409
410 DPRINTF(("semget(0x%x, %d, 0%o)\n", key, nsems, semflg));
411
412 /*
413 * Preallocate space for the new semaphore. If we are going
414 * to sleep, we want to sleep now to eliminate any race
415 * condition in allocating a semaphore with a specific key.
416 */
417 if (key == IPC_PRIVATE(key_t)0 || (semflg & IPC_CREAT001000)) {
418 if (nsems <= 0 || nsems > seminfo.semmsl) {
419 DPRINTF(("nsems out of range (0<%d<=%d)\n", nsems,
420 seminfo.semmsl));
421 return (EINVAL22);
422 }
423 if (nsems > seminfo.semmns - semtot) {
424 DPRINTF(("not enough semaphores left (need %d, got %d)\n",
425 nsems, seminfo.semmns - semtot));
426 return (ENOSPC28);
427 }
428 semaptr_new = pool_get(&sema_pool, PR_WAITOK0x0001 | PR_ZERO0x0008);
429 semaptr_new->sem_base = mallocarray(nsems, sizeof(struct sem),
430 M_SEM31, M_WAITOK0x0001|M_ZERO0x0008);
431 }
432
433 if (key != IPC_PRIVATE(key_t)0) {
434 for (semid = 0, semaptr = NULL((void *)0); semid < seminfo.semmni; semid++) {
435 if ((semaptr = sema[semid]) != NULL((void *)0) &&
436 semaptr->sem_perm.key == key) {
437 DPRINTF(("found public key\n"));
438 if ((error = ipcperm(cred, &semaptr->sem_perm,
439 semflg & 0700)))
440 goto error;
441 if (nsems > 0 && semaptr->sem_nsems < nsems) {
442 DPRINTF(("too small\n"));
443 error = EINVAL22;
444 goto error;
445 }
446 if ((semflg & IPC_CREAT001000) && (semflg & IPC_EXCL002000)) {
447 DPRINTF(("not exclusive\n"));
448 error = EEXIST17;
449 goto error;
450 }
451 if (semaptr_new != NULL((void *)0)) {
452 free(semaptr_new->sem_base, M_SEM31,
453 nsems * sizeof(struct sem));
454 pool_put(&sema_pool, semaptr_new);
455 }
456 goto found;
457 }
458 }
459 }
460
461 DPRINTF(("need to allocate the semid_ds\n"));
462 if (key == IPC_PRIVATE(key_t)0 || (semflg & IPC_CREAT001000)) {
463 for (semid = 0; semid < seminfo.semmni; semid++) {
464 if ((semaptr = sema[semid]) == NULL((void *)0))
Although the value stored to 'semaptr' is used in the enclosing expression, the value is never actually read from 'semaptr'
465 break;
466 }
467 if (semid == seminfo.semmni) {
468 DPRINTF(("no more semid_ds's available\n"));
469 error = ENOSPC28;
470 goto error;
471 }
472 DPRINTF(("semid %d is available\n", semid));
473 semaptr_new->sem_perm.key = key;
474 semaptr_new->sem_perm.cuid = cred->cr_uid;
475 semaptr_new->sem_perm.uid = cred->cr_uid;
476 semaptr_new->sem_perm.cgid = cred->cr_gid;
477 semaptr_new->sem_perm.gid = cred->cr_gid;
478 semaptr_new->sem_perm.mode = (semflg & 0777);
479 semaptr_new->sem_perm.seq = semseqs[semid] =
480 (semseqs[semid] + 1) & 0x7fff;
481 semaptr_new->sem_nsems = nsems;
482 semaptr_new->sem_otime = 0;
483 semaptr_new->sem_ctime = gettime();
484 sema[semid] = semaptr_new;
485 semtot += nsems;
486 } else {
487 DPRINTF(("didn't find it and wasn't asked to create it\n"));
488 return (ENOENT2);
489 }
490
491found:
492 *retval = IXSEQ_TO_IPCID(semid, sema[semid]->sem_perm)(((sema[semid]->sem_perm.seq) << 16) | (semid & 0xffff
))
;
493 return (0);
494error:
495 if (semaptr_new != NULL((void *)0)) {
496 free(semaptr_new->sem_base, M_SEM31, nsems * sizeof(struct sem));
497 pool_put(&sema_pool, semaptr_new);
498 }
499 return (error);
500}
501
502int
503sys_semop(struct proc *p, void *v, register_t *retval)
504{
505 struct sys_semop_args /* {
506 syscallarg(int) semid;
507 syscallarg(struct sembuf *) sops;
508 syscallarg(size_t) nsops;
509 } */ *uap = v;
510#define NSOPS8 8
511 struct sembuf sopbuf[NSOPS8];
512 int semid = SCARG(uap, semid)((uap)->semid.le.datum);
513 size_t nsops = SCARG(uap, nsops)((uap)->nsops.le.datum);
514 struct sembuf *sops;
515 struct semid_ds *semaptr;
516 struct sembuf *sopptr = NULL((void *)0);
517 struct sem *semptr = NULL((void *)0);
518 struct sem_undo *suptr = NULL((void *)0);
519 struct ucred *cred = p->p_ucred;
520 size_t i, j;
521 int do_wakeup, do_undos, error;
522
523 DPRINTF(("call to semop(%d, %p, %lu)\n", semid, SCARG(uap, sops),
524 (u_long)nsops));
525
526 semid = IPCID_TO_IX(semid)((semid) & 0xffff); /* Convert back to zero origin */
527
528 if (semid < 0 || semid >= seminfo.semmni)
529 return (EINVAL22);
530
531 if ((semaptr = sema[semid]) == NULL((void *)0) ||
532 semaptr->sem_perm.seq != IPCID_TO_SEQ(SCARG(uap, semid))(((((uap)->semid.le.datum)) >> 16) & 0xffff))
533 return (EINVAL22);
534
535 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_W000200))) {
536 DPRINTF(("error = %d from ipaccess\n", error));
537 return (error);
538 }
539
540 if (nsops == 0) {
541 *retval = 0;
542 return (0);
543 } else if (nsops > (size_t)seminfo.semopm) {
544 DPRINTF(("too many sops (max=%d, nsops=%lu)\n", seminfo.semopm,
545 (u_long)nsops));
546 return (E2BIG7);
547 }
548
549 if (nsops <= NSOPS8)
550 sops = sopbuf;
551 else
552 sops = mallocarray(nsops, sizeof(struct sembuf), M_SEM31, M_WAITOK0x0001);
553 error = copyin(SCARG(uap, sops)((uap)->sops.le.datum), sops, nsops * sizeof(struct sembuf));
554 if (error != 0) {
555 DPRINTF(("error = %d from copyin(%p, %p, %u)\n", error,
556 SCARG(uap, sops), &sops, nsops * sizeof(struct sembuf)));
557 goto done2;
558 }
559
560 /*
561 * Loop trying to satisfy the vector of requests.
562 * If we reach a point where we must wait, any requests already
563 * performed are rolled back and we go to sleep until some other
564 * process wakes us up. At this point, we start all over again.
565 *
566 * This ensures that from the perspective of other tasks, a set
567 * of requests is atomic (never partially satisfied).
568 */
569 do_undos = 0;
570
571 for (;;) {
572 do_wakeup = 0;
573
574 for (i = 0; i < nsops; i++) {
575 sopptr = &sops[i];
576
577 if (sopptr->sem_num >= semaptr->sem_nsems) {
578 error = EFBIG27;
579 goto done2;
580 }
581
582 semptr = &semaptr->sem_base[sopptr->sem_num];
583
584 DPRINTF(("semop: semaptr=%x, sem_base=%x, semptr=%x, sem[%d]=%d : op=%d, flag=%s\n",
585 semaptr, semaptr->sem_base, semptr,
586 sopptr->sem_num, semptr->semval, sopptr->sem_op,
587 (sopptr->sem_flg & IPC_NOWAIT) ? "nowait" : "wait"));
588
589 if (sopptr->sem_op < 0) {
590 if ((int)(semptr->semval +
591 sopptr->sem_op) < 0) {
592 DPRINTF(("semop: can't do it now\n"));
593 break;
594 } else {
595 semptr->semval += sopptr->sem_op;
596 if (semptr->semval == 0 &&
597 semptr->semzcnt > 0)
598 do_wakeup = 1;
599 }
600 if (sopptr->sem_flg & SEM_UNDO010000)
601 do_undos++;
602 } else if (sopptr->sem_op == 0) {
603 if (semptr->semval > 0) {
604 DPRINTF(("semop: not zero now\n"));
605 break;
606 }
607 } else {
608 if (semptr->semncnt > 0)
609 do_wakeup = 1;
610 semptr->semval += sopptr->sem_op;
611 if (sopptr->sem_flg & SEM_UNDO010000)
612 do_undos++;
613 }
614 }
615
616 /*
617 * Did we get through the entire vector and can we undo it?
618 */
619 if (i >= nsops && do_undos <= SEMUME10)
620 goto done;
621
622 /*
623 * No ... rollback anything that we've already done
624 */
625 DPRINTF(("semop: rollback 0 through %d\n", i - 1));
626 for (j = 0; j < i; j++)
627 semaptr->sem_base[sops[j].sem_num].semval -=
628 sops[j].sem_op;
629
630 /*
631 * Did we have too many SEM_UNDO's
632 */
633 if (do_undos > SEMUME10) {
634 error = ENOSPC28;
635 goto done2;
636 }
637
638 /*
639 * If the request that we couldn't satisfy has the
640 * NOWAIT flag set then return with EAGAIN.
641 */
642 if (sopptr->sem_flg & IPC_NOWAIT004000) {
643 error = EAGAIN35;
644 goto done2;
645 }
646
647 if (sopptr->sem_op == 0)
648 semptr->semzcnt++;
649 else
650 semptr->semncnt++;
651
652 DPRINTF(("semop: good night!\n"));
653 error = tsleep_nsec(&sema[semid], PLOCK36 | PCATCH0x100,
654 "semwait", INFSLP0xffffffffffffffffULL);
655 DPRINTF(("semop: good morning (error=%d)!\n", error));
656
657 suptr = NULL((void *)0); /* sem_undo may have been reallocated */
658
659 /*
660 * Make sure that the semaphore still exists
661 */
662 if (sema[semid] == NULL((void *)0) ||
663 semaptr->sem_perm.seq != IPCID_TO_SEQ(SCARG(uap, semid))(((((uap)->semid.le.datum)) >> 16) & 0xffff)) {
664 error = EIDRM89;
665 goto done2;
666 }
667
668 /*
669 * The semaphore is still alive. Readjust the count of
670 * waiting processes.
671 */
672 if (sopptr->sem_op == 0)
673 semptr->semzcnt--;
674 else
675 semptr->semncnt--;
676
677 /*
678 * Is it really morning, or was our sleep interrupted?
679 * (Delayed check of tsleep() return code because we
680 * need to decrement sem[nz]cnt either way.)
681 */
682 if (error != 0) {
683 error = EINTR4;
684 goto done2;
685 }
686 DPRINTF(("semop: good morning!\n"));
687 }
688
689done:
690 /*
691 * Process any SEM_UNDO requests.
692 */
693 if (do_undos) {
694 for (i = 0; i < nsops; i++) {
695 /*
696 * We only need to deal with SEM_UNDO's for non-zero
697 * op's.
698 */
699 int adjval;
700
701 if ((sops[i].sem_flg & SEM_UNDO010000) == 0)
702 continue;
703 adjval = sops[i].sem_op;
704 if (adjval == 0)
705 continue;
706 error = semundo_adjust(p, &suptr, semid,
707 sops[i].sem_num, -adjval);
708 if (error == 0)
709 continue;
710
711 /*
712 * Uh-Oh! We ran out of either sem_undo's or undo's.
713 * Rollback the adjustments to this point and then
714 * rollback the semaphore ups and down so we can return
715 * with an error with all structures restored. We
716 * rollback the undo's in the exact reverse order that
717 * we applied them. This guarantees that we won't run
718 * out of space as we roll things back out.
719 */
720 for (j = i; j > 0;) {
721 j--;
722 if ((sops[j].sem_flg & SEM_UNDO010000) == 0)
723 continue;
724 adjval = sops[j].sem_op;
725 if (adjval == 0)
726 continue;
727 if (semundo_adjust(p, &suptr, semid,
728 sops[j].sem_num, adjval) != 0)
729 panic("semop - can't undo undos");
730 }
731
732 for (j = 0; j < nsops; j++)
733 semaptr->sem_base[sops[j].sem_num].semval -=
734 sops[j].sem_op;
735
736 DPRINTF(("error = %d from semundo_adjust\n", error));
737 goto done2;
738 } /* loop through the sops */
739 } /* if (do_undos) */
740
741 /* We're definitely done - set the sempid's */
742 for (i = 0; i < nsops; i++) {
743 sopptr = &sops[i];
744 semptr = &semaptr->sem_base[sopptr->sem_num];
745 semptr->sempid = p->p_p->ps_pid;
746 }
747
748 semaptr->sem_otime = gettime();
749
750 /* Do a wakeup if any semaphore was up'd. */
751 if (do_wakeup) {
752 DPRINTF(("semop: doing wakeup\n"));
753 wakeup(&sema[semid]);
754 DPRINTF(("semop: back from wakeup\n"));
755 }
756 DPRINTF(("semop: done\n"));
757 *retval = 0;
758done2:
759 if (sops != sopbuf)
760 free(sops, M_SEM31, nsops * sizeof(struct sembuf));
761 return (error);
762}
763
764/*
765 * Go through the undo structures for this process and apply the adjustments to
766 * semaphores.
767 */
768void
769semexit(struct process *pr)
770{
771 struct sem_undo *suptr;
772 struct sem_undo **supptr;
773
774 /*
775 * Go through the chain of undo vectors looking for one associated with
776 * this process. Remember the pointer to the pointer to the element
777 * to dequeue it later.
778 */
779 supptr = &SLIST_FIRST(&semu_list)((&semu_list)->slh_first);
780 SLIST_FOREACH(suptr, &semu_list, un_next)for((suptr) = ((&semu_list)->slh_first); (suptr) != ((
void *)0); (suptr) = ((suptr)->un_next.sle_next))
{
781 if (suptr->un_proc == pr)
782 break;
783 supptr = &SLIST_NEXT(suptr, un_next)((suptr)->un_next.sle_next);
784 }
785
786 /*
787 * If there is no undo vector, skip to the end.
788 */
789 if (suptr == NULL((void *)0))
790 return;
791
792 /*
793 * We now have an undo vector for this process.
794 */
795 DPRINTF(("process @%p has undo structure with %d entries\n", pr,
796 suptr->un_cnt));
797
798 /*
799 * If there are any active undo elements then process them.
800 */
801 if (suptr->un_cnt > 0) {
802 int ix;
803
804 for (ix = 0; ix < suptr->un_cnt; ix++) {
805 int semid = suptr->un_ent[ix].un_id;
806 int semnum = suptr->un_ent[ix].un_num;
807 int adjval = suptr->un_ent[ix].un_adjval;
808 struct semid_ds *semaptr;
809
810 if ((semaptr = sema[semid]) == NULL((void *)0))
811 panic("semexit - semid not allocated");
812 if (semnum >= semaptr->sem_nsems)
813 panic("semexit - semnum out of range");
814
815 DPRINTF(("semexit: %p id=%d num=%d(adj=%d) ; sem=%d\n",
816 suptr->un_proc, suptr->un_ent[ix].un_id,
817 suptr->un_ent[ix].un_num,
818 suptr->un_ent[ix].un_adjval,
819 semaptr->sem_base[semnum].semval));
820
821 if (adjval < 0 &&
822 semaptr->sem_base[semnum].semval < -adjval)
823 semaptr->sem_base[semnum].semval = 0;
824 else
825 semaptr->sem_base[semnum].semval += adjval;
826
827 wakeup(&sema[semid]);
828 DPRINTF(("semexit: back from wakeup\n"));
829 }
830 }
831
832 /*
833 * Deallocate the undo vector.
834 */
835 DPRINTF(("removing vector\n"));
836 *supptr = SLIST_NEXT(suptr, un_next)((suptr)->un_next.sle_next);
837 pool_put(&semu_pool, suptr);
838 semutot--;
839}
840
841/* Expand semsegs and semseqs arrays */
842void
843sema_reallocate(int val)
844{
845 struct semid_ds **sema_new;
846 unsigned short *newseqs;
847 sema_new = mallocarray(val, sizeof(struct semid_ds *),
848 M_SEM31, M_WAITOK0x0001|M_ZERO0x0008);
849 memcpy(sema_new, sema,__builtin_memcpy((sema_new), (sema), (seminfo.semmni * sizeof
(struct semid_ds *)))
850 seminfo.semmni * sizeof(struct semid_ds *))__builtin_memcpy((sema_new), (sema), (seminfo.semmni * sizeof
(struct semid_ds *)))
;
851 newseqs = mallocarray(val, sizeof(unsigned short), M_SEM31,
852 M_WAITOK0x0001|M_ZERO0x0008);
853 memcpy(newseqs, semseqs,__builtin_memcpy((newseqs), (semseqs), (seminfo.semmni * sizeof
(unsigned short)))
854 seminfo.semmni * sizeof(unsigned short))__builtin_memcpy((newseqs), (semseqs), (seminfo.semmni * sizeof
(unsigned short)))
;
855 free(sema, M_SEM31, seminfo.semmni * sizeof(struct semid_ds *));
856 free(semseqs, M_SEM31, seminfo.semmni * sizeof(unsigned short));
857 sema = sema_new;
858 semseqs = newseqs;
859 seminfo.semmni = val;
860}
861
862const struct sysctl_bounded_args sysvsem_vars[] = {
863 { KERN_SEMINFO_SEMUME6, &seminfo.semume, SYSCTL_INT_READONLY1,0 },
864 { KERN_SEMINFO_SEMUSZ7, &seminfo.semusz, SYSCTL_INT_READONLY1,0 },
865 { KERN_SEMINFO_SEMVMX8, &seminfo.semvmx, SYSCTL_INT_READONLY1,0 },
866 { KERN_SEMINFO_SEMAEM9, &seminfo.semaem, SYSCTL_INT_READONLY1,0 },
867 { KERN_SEMINFO_SEMOPM5, &seminfo.semopm, 1, INT_MAX0x7fffffff },
868};
869
870/*
871 * Userland access to struct seminfo.
872 */
873int
874sysctl_sysvsem(int *name, u_int namelen, void *oldp, size_t *oldlenp,
875 void *newp, size_t newlen)
876{
877 int error, val;
878
879 if (namelen != 1)
880 return (ENOTDIR20); /* leaf-only */
881
882 switch (name[0]) {
883 case KERN_SEMINFO_SEMMNI1:
884 val = seminfo.semmni;
885 error = sysctl_int_bounded(oldp, oldlenp, newp, newlen,
886 &val, val, 0xffff);
887 /* returns success and skips reallocation if val is unchanged */
888 if (error || val == seminfo.semmni)
889 return (error);
890 sema_reallocate(val);
891 return (0);
892 case KERN_SEMINFO_SEMMNS2:
893 /* can't decrease semmns or go over 2^16 */
894 return (sysctl_int_bounded(oldp, oldlenp, newp, newlen,
895 &seminfo.semmns, seminfo.semmns, 0xffff));
896 case KERN_SEMINFO_SEMMNU3:
897 /* can't decrease semmnu or go over 2^16 */
898 return (sysctl_int_bounded(oldp, oldlenp, newp, newlen,
899 &seminfo.semmnu, seminfo.semmnu, 0xffff));
900 case KERN_SEMINFO_SEMMSL4:
901 /* can't decrease semmsl or go over 2^16 */
902 return (sysctl_int_bounded(oldp, oldlenp, newp, newlen,
903 &seminfo.semmsl, seminfo.semmsl, 0xffff));
904 default:
905 return (sysctl_bounded_arr(sysvsem_vars, nitems(sysvsem_vars)(sizeof((sysvsem_vars)) / sizeof((sysvsem_vars)[0])),
906 name, namelen, oldp, oldlenp, newp, newlen));
907 }
908 /* NOTREACHED */
909}