Bug Summary

File:kern/sysv_sem.c
Warning:line 476, 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.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name sysv_sem.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 -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -ffp-contract=on -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 -target-feature +retpoline-external-thunk -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/llvm16/lib/clang/16 -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/legacy-dpm -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/inc -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/swsmu/smu13 -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/inc -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/pm/swsmu/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/inc/pmfw_if -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 SUSPEND -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 -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 -fcf-protection=branch -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 /home/ben/Projects/scan/2024-01-11-110808-61670-1 -x c /usr/src/sys/kern/sysv_sem.c
1/* $OpenBSD: sysv_sem.c,v 1.63 2022/09/28 13:21:13 mbuhl 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 struct ucred *cred = p->p_ucred;
233 int semid = SCARG(uap, semid)((uap)->semid.le.datum);
234 int semnum = SCARG(uap, semnum)((uap)->semnum.le.datum);
235 int cmd = SCARG(uap, cmd)((uap)->cmd.le.datum);
236 union semun arg, *uarg = SCARG(uap, arg)((uap)->arg.le.datum);
237 struct semid_ds sbuf;
238 struct semid_ds *semaptr;
239 unsigned short *semval = NULL((void *)0), nsems;
240 int i, ix, error;
241
242 switch (cmd) {
243 case IPC_SET1:
244 case IPC_STAT2:
245 case GETALL6:
246 case SETVAL8:
247 case SETALL9:
248 if ((error = copyin(uarg, &arg, sizeof(union semun))))
249 return (error);
250 }
251 if (cmd == IPC_SET1)
252 if ((error = copyin(arg.buf, &sbuf, sizeof(sbuf))))
253 return (error);
254
255 DPRINTF(("call to semctl(%d, %d, %d, %p)\n", semid, semnum, cmd, uarg));
256
257 ix = IPCID_TO_IX(semid)((semid) & 0xffff);
258 if (ix < 0 || ix >= seminfo.semmni)
259 return (EINVAL22);
260
261again:
262 if ((semaptr = sema[ix]) == NULL((void *)0) ||
263 semaptr->sem_perm.seq != IPCID_TO_SEQ(semid)(((semid) >> 16) & 0xffff))
264 return (EINVAL22);
265
266 switch (cmd) {
267 case IPC_RMID0:
268 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_M010000)) != 0)
269 return (error);
270 semaptr->sem_perm.cuid = cred->cr_uid;
271 semaptr->sem_perm.uid = cred->cr_uid;
272 semtot -= semaptr->sem_nsems;
273 free(semaptr->sem_base, M_SEM31,
274 semaptr->sem_nsems * sizeof(struct sem));
275 pool_put(&sema_pool, semaptr);
276 sema[ix] = NULL((void *)0);
277 semundo_clear(ix, -1);
278 wakeup(&sema[ix]);
279 break;
280
281 case IPC_SET1:
282 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_M010000)))
283 return (error);
284 semaptr->sem_perm.uid = sbuf.sem_perm.uid;
285 semaptr->sem_perm.gid = sbuf.sem_perm.gid;
286 semaptr->sem_perm.mode = (semaptr->sem_perm.mode & ~0777) |
287 (sbuf.sem_perm.mode & 0777);
288 semaptr->sem_ctime = gettime();
289 break;
290
291 case IPC_STAT2:
292 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R000400)))
293 return (error);
294 memcpy(&sbuf, semaptr, sizeof sbuf)__builtin_memcpy((&sbuf), (semaptr), (sizeof sbuf));
295 sbuf.sem_base = NULL((void *)0);
296 error = copyout(&sbuf, arg.buf, sizeof(struct semid_ds));
297 break;
298
299 case GETNCNT3:
300 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R000400)))
301 return (error);
302 if (semnum < 0 || semnum >= semaptr->sem_nsems)
303 return (EINVAL22);
304 *retval = semaptr->sem_base[semnum].semncnt;
305 break;
306
307 case GETPID4:
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].sempid;
313 break;
314
315 case GETVAL5:
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].semval;
321 break;
322
323 case GETALL6:
324 nsems = semaptr->sem_nsems;
325 semval = mallocarray(nsems, sizeof(arg.array[0]),
326 M_TEMP127, M_WAITOK0x0001);
327 if (semaptr != sema[ix] ||
328 semaptr->sem_perm.seq != IPCID_TO_SEQ(semid)(((semid) >> 16) & 0xffff) ||
329 semaptr->sem_nsems != nsems) {
330 free(semval, M_TEMP127, nsems * sizeof(arg.array[0]));
331 goto again;
332 }
333 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R000400)))
334 goto error;
335 for (i = 0; i < nsems; i++)
336 semval[i] = semaptr->sem_base[i].semval;
337 for (i = 0; i < nsems; i++) {
338 error = copyout(&semval[i], &arg.array[i],
339 sizeof(arg.array[0]));
340 if (error != 0)
341 break;
342 }
343 break;
344
345 case GETZCNT7:
346 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R000400)))
347 return (error);
348 if (semnum < 0 || semnum >= semaptr->sem_nsems)
349 return (EINVAL22);
350 *retval = semaptr->sem_base[semnum].semzcnt;
351 break;
352
353 case SETVAL8:
354 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_W000200)))
355 return (error);
356 if (semnum < 0 || semnum >= semaptr->sem_nsems)
357 return (EINVAL22);
358 if (arg.val > seminfo.semvmx)
359 return (ERANGE34);
360 semaptr->sem_base[semnum].semval = arg.val;
361 semundo_clear(ix, semnum);
362 wakeup(&sema[ix]);
363 break;
364
365 case SETALL9:
366 nsems = semaptr->sem_nsems;
367 semval = mallocarray(nsems, sizeof(arg.array[0]),
368 M_TEMP127, M_WAITOK0x0001);
369 for (i = 0; i < nsems; i++) {
370 error = copyin(&arg.array[i], &semval[i],
371 sizeof(arg.array[0]));
372 if (error != 0)
373 goto error;
374 if (semval[i] > seminfo.semvmx) {
375 error = ERANGE34;
376 goto error;
377 }
378 }
379 if (semaptr != sema[ix] ||
380 semaptr->sem_perm.seq != IPCID_TO_SEQ(semid)(((semid) >> 16) & 0xffff) ||
381 semaptr->sem_nsems != nsems) {
382 free(semval, M_TEMP127, nsems * sizeof(arg.array[0]));
383 goto again;
384 }
385 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_W000200)))
386 goto error;
387 for (i = 0; i < nsems; i++)
388 semaptr->sem_base[i].semval = semval[i];
389 semundo_clear(ix, -1);
390 wakeup(&sema[ix]);
391 break;
392
393 default:
394 return (EINVAL22);
395 }
396
397error:
398 free(semval, M_TEMP127, nsems * sizeof(arg.array[0]));
399
400 return (error);
401}
402
403int
404sys_semget(struct proc *p, void *v, register_t *retval)
405{
406 struct sys_semget_args /* {
407 syscallarg(key_t) key;
408 syscallarg(int) nsems;
409 syscallarg(int) semflg;
410 } */ *uap = v;
411 int semid, error;
412 int key = SCARG(uap, key)((uap)->key.le.datum);
413 int nsems = SCARG(uap, nsems)((uap)->nsems.le.datum);
414 int semflg = SCARG(uap, semflg)((uap)->semflg.le.datum);
415 struct semid_ds *semaptr, *semaptr_new = NULL((void *)0);
416 struct ucred *cred = p->p_ucred;
417
418 DPRINTF(("semget(0x%x, %d, 0%o)\n", key, nsems, semflg));
419
420 /*
421 * Preallocate space for the new semaphore. If we are going
422 * to sleep, we want to sleep now to eliminate any race
423 * condition in allocating a semaphore with a specific key.
424 */
425 if (key == IPC_PRIVATE(key_t)0 || (semflg & IPC_CREAT001000)) {
426 if (nsems <= 0 || nsems > seminfo.semmsl) {
427 DPRINTF(("nsems out of range (0<%d<=%d)\n", nsems,
428 seminfo.semmsl));
429 return (EINVAL22);
430 }
431 if (nsems > seminfo.semmns - semtot) {
432 DPRINTF(("not enough semaphores left (need %d, got %d)\n",
433 nsems, seminfo.semmns - semtot));
434 return (ENOSPC28);
435 }
436 semaptr_new = pool_get(&sema_pool, PR_WAITOK0x0001 | PR_ZERO0x0008);
437 semaptr_new->sem_base = mallocarray(nsems, sizeof(struct sem),
438 M_SEM31, M_WAITOK0x0001|M_ZERO0x0008);
439 if (nsems > seminfo.semmns - semtot) {
440 error = ENOSPC28;
441 goto error;
442 }
443 }
444
445 if (key != IPC_PRIVATE(key_t)0) {
446 for (semid = 0, semaptr = NULL((void *)0); semid < seminfo.semmni; semid++) {
447 if ((semaptr = sema[semid]) != NULL((void *)0) &&
448 semaptr->sem_perm.key == key) {
449 DPRINTF(("found public key\n"));
450 if ((error = ipcperm(cred, &semaptr->sem_perm,
451 semflg & 0700)))
452 goto error;
453 if (nsems > 0 && semaptr->sem_nsems < nsems) {
454 DPRINTF(("too small\n"));
455 error = EINVAL22;
456 goto error;
457 }
458 if ((semflg & IPC_CREAT001000) && (semflg & IPC_EXCL002000)) {
459 DPRINTF(("not exclusive\n"));
460 error = EEXIST17;
461 goto error;
462 }
463 if (semaptr_new != NULL((void *)0)) {
464 free(semaptr_new->sem_base, M_SEM31,
465 nsems * sizeof(struct sem));
466 pool_put(&sema_pool, semaptr_new);
467 }
468 goto found;
469 }
470 }
471 }
472
473 DPRINTF(("need to allocate the semid_ds\n"));
474 if (key == IPC_PRIVATE(key_t)0 || (semflg & IPC_CREAT001000)) {
475 for (semid = 0; semid < seminfo.semmni; semid++) {
476 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'
477 break;
478 }
479 if (semid == seminfo.semmni) {
480 DPRINTF(("no more semid_ds's available\n"));
481 error = ENOSPC28;
482 goto error;
483 }
484 DPRINTF(("semid %d is available\n", semid));
485 semaptr_new->sem_perm.key = key;
486 semaptr_new->sem_perm.cuid = cred->cr_uid;
487 semaptr_new->sem_perm.uid = cred->cr_uid;
488 semaptr_new->sem_perm.cgid = cred->cr_gid;
489 semaptr_new->sem_perm.gid = cred->cr_gid;
490 semaptr_new->sem_perm.mode = (semflg & 0777);
491 semaptr_new->sem_perm.seq = semseqs[semid] =
492 (semseqs[semid] + 1) & 0x7fff;
493 semaptr_new->sem_nsems = nsems;
494 semaptr_new->sem_otime = 0;
495 semaptr_new->sem_ctime = gettime();
496 sema[semid] = semaptr_new;
497 semtot += nsems;
498 } else {
499 DPRINTF(("didn't find it and wasn't asked to create it\n"));
500 return (ENOENT2);
501 }
502
503found:
504 *retval = IXSEQ_TO_IPCID(semid, sema[semid]->sem_perm)(((sema[semid]->sem_perm.seq) << 16) | (semid & 0xffff
))
;
505 return (0);
506error:
507 if (semaptr_new != NULL((void *)0)) {
508 free(semaptr_new->sem_base, M_SEM31, nsems * sizeof(struct sem));
509 pool_put(&sema_pool, semaptr_new);
510 }
511 return (error);
512}
513
514int
515sys_semop(struct proc *p, void *v, register_t *retval)
516{
517 struct sys_semop_args /* {
518 syscallarg(int) semid;
519 syscallarg(struct sembuf *) sops;
520 syscallarg(size_t) nsops;
521 } */ *uap = v;
522#define NSOPS8 8
523 struct sembuf sopbuf[NSOPS8];
524 int semid = SCARG(uap, semid)((uap)->semid.le.datum);
525 size_t nsops = SCARG(uap, nsops)((uap)->nsops.le.datum);
526 struct sembuf *sops;
527 struct semid_ds *semaptr;
528 struct sembuf *sopptr = NULL((void *)0);
529 struct sem *semptr = NULL((void *)0);
530 struct sem_undo *suptr = NULL((void *)0);
531 struct ucred *cred = p->p_ucred;
532 size_t i, j;
533 int do_wakeup, do_undos, error;
534
535 DPRINTF(("call to semop(%d, %p, %lu)\n", semid, SCARG(uap, sops),
536 (u_long)nsops));
537
538 semid = IPCID_TO_IX(semid)((semid) & 0xffff); /* Convert back to zero origin */
539
540 if (semid < 0 || semid >= seminfo.semmni)
541 return (EINVAL22);
542
543 if ((semaptr = sema[semid]) == NULL((void *)0) ||
544 semaptr->sem_perm.seq != IPCID_TO_SEQ(SCARG(uap, semid))(((((uap)->semid.le.datum)) >> 16) & 0xffff))
545 return (EINVAL22);
546
547 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_W000200))) {
548 DPRINTF(("error = %d from ipaccess\n", error));
549 return (error);
550 }
551
552 if (nsops == 0) {
553 *retval = 0;
554 return (0);
555 } else if (nsops > (size_t)seminfo.semopm) {
556 DPRINTF(("too many sops (max=%d, nsops=%lu)\n", seminfo.semopm,
557 (u_long)nsops));
558 return (E2BIG7);
559 }
560
561 if (nsops <= NSOPS8)
562 sops = sopbuf;
563 else
564 sops = mallocarray(nsops, sizeof(struct sembuf), M_SEM31, M_WAITOK0x0001);
565 error = copyin(SCARG(uap, sops)((uap)->sops.le.datum), sops, nsops * sizeof(struct sembuf));
566 if (error != 0) {
567 DPRINTF(("error = %d from copyin(%p, %p, %u)\n", error,
568 SCARG(uap, sops), &sops, nsops * sizeof(struct sembuf)));
569 goto done2;
570 }
571
572 /*
573 * Loop trying to satisfy the vector of requests.
574 * If we reach a point where we must wait, any requests already
575 * performed are rolled back and we go to sleep until some other
576 * process wakes us up. At this point, we start all over again.
577 *
578 * This ensures that from the perspective of other tasks, a set
579 * of requests is atomic (never partially satisfied).
580 */
581 do_undos = 0;
582
583 for (;;) {
584 do_wakeup = 0;
585
586 for (i = 0; i < nsops; i++) {
587 sopptr = &sops[i];
588
589 if (sopptr->sem_num >= semaptr->sem_nsems) {
590 error = EFBIG27;
591 goto done2;
592 }
593
594 semptr = &semaptr->sem_base[sopptr->sem_num];
595
596 DPRINTF(("semop: semaptr=%x, sem_base=%x, semptr=%x, sem[%d]=%d : op=%d, flag=%s\n",
597 semaptr, semaptr->sem_base, semptr,
598 sopptr->sem_num, semptr->semval, sopptr->sem_op,
599 (sopptr->sem_flg & IPC_NOWAIT) ? "nowait" : "wait"));
600
601 if (sopptr->sem_op < 0) {
602 if ((int)(semptr->semval +
603 sopptr->sem_op) < 0) {
604 DPRINTF(("semop: can't do it now\n"));
605 break;
606 } else {
607 semptr->semval += sopptr->sem_op;
608 if (semptr->semval == 0 &&
609 semptr->semzcnt > 0)
610 do_wakeup = 1;
611 }
612 if (sopptr->sem_flg & SEM_UNDO010000)
613 do_undos++;
614 } else if (sopptr->sem_op == 0) {
615 if (semptr->semval > 0) {
616 DPRINTF(("semop: not zero now\n"));
617 break;
618 }
619 } else {
620 if (semptr->semncnt > 0)
621 do_wakeup = 1;
622 semptr->semval += sopptr->sem_op;
623 if (sopptr->sem_flg & SEM_UNDO010000)
624 do_undos++;
625 }
626 }
627
628 /*
629 * Did we get through the entire vector and can we undo it?
630 */
631 if (i >= nsops && do_undos <= SEMUME10)
632 goto done;
633
634 /*
635 * No ... rollback anything that we've already done
636 */
637 DPRINTF(("semop: rollback 0 through %d\n", i - 1));
638 for (j = 0; j < i; j++)
639 semaptr->sem_base[sops[j].sem_num].semval -=
640 sops[j].sem_op;
641
642 /*
643 * Did we have too many SEM_UNDO's
644 */
645 if (do_undos > SEMUME10) {
646 error = ENOSPC28;
647 goto done2;
648 }
649
650 /*
651 * If the request that we couldn't satisfy has the
652 * NOWAIT flag set then return with EAGAIN.
653 */
654 if (sopptr->sem_flg & IPC_NOWAIT004000) {
655 error = EAGAIN35;
656 goto done2;
657 }
658
659 if (sopptr->sem_op == 0)
660 semptr->semzcnt++;
661 else
662 semptr->semncnt++;
663
664 DPRINTF(("semop: good night!\n"));
665 error = tsleep_nsec(&sema[semid], PLOCK36 | PCATCH0x100,
666 "semwait", INFSLP0xffffffffffffffffULL);
667 DPRINTF(("semop: good morning (error=%d)!\n", error));
668
669 suptr = NULL((void *)0); /* sem_undo may have been reallocated */
670
671 /*
672 * Make sure that the semaphore still exists
673 */
674 if (sema[semid] == NULL((void *)0) ||
675 semaptr->sem_perm.seq != IPCID_TO_SEQ(SCARG(uap, semid))(((((uap)->semid.le.datum)) >> 16) & 0xffff)) {
676 error = EIDRM89;
677 goto done2;
678 }
679
680 /*
681 * The semaphore is still alive. Readjust the count of
682 * waiting processes.
683 */
684 if (sopptr->sem_op == 0)
685 semptr->semzcnt--;
686 else
687 semptr->semncnt--;
688
689 /*
690 * Is it really morning, or was our sleep interrupted?
691 * (Delayed check of tsleep() return code because we
692 * need to decrement sem[nz]cnt either way.)
693 */
694 if (error != 0) {
695 error = EINTR4;
696 goto done2;
697 }
698 DPRINTF(("semop: good morning!\n"));
699 }
700
701done:
702 /*
703 * Process any SEM_UNDO requests.
704 */
705 if (do_undos) {
706 for (i = 0; i < nsops; i++) {
707 /*
708 * We only need to deal with SEM_UNDO's for non-zero
709 * op's.
710 */
711 int adjval;
712
713 if ((sops[i].sem_flg & SEM_UNDO010000) == 0)
714 continue;
715 adjval = sops[i].sem_op;
716 if (adjval == 0)
717 continue;
718 error = semundo_adjust(p, &suptr, semid,
719 sops[i].sem_num, -adjval);
720 if (error == 0)
721 continue;
722
723 /*
724 * Uh-Oh! We ran out of either sem_undo's or undo's.
725 * Rollback the adjustments to this point and then
726 * rollback the semaphore ups and down so we can return
727 * with an error with all structures restored. We
728 * rollback the undo's in the exact reverse order that
729 * we applied them. This guarantees that we won't run
730 * out of space as we roll things back out.
731 */
732 for (j = i; j > 0;) {
733 j--;
734 if ((sops[j].sem_flg & SEM_UNDO010000) == 0)
735 continue;
736 adjval = sops[j].sem_op;
737 if (adjval == 0)
738 continue;
739 if (semundo_adjust(p, &suptr, semid,
740 sops[j].sem_num, adjval) != 0)
741 panic("semop - can't undo undos");
742 }
743
744 for (j = 0; j < nsops; j++)
745 semaptr->sem_base[sops[j].sem_num].semval -=
746 sops[j].sem_op;
747
748 DPRINTF(("error = %d from semundo_adjust\n", error));
749 goto done2;
750 } /* loop through the sops */
751 } /* if (do_undos) */
752
753 /* We're definitely done - set the sempid's */
754 for (i = 0; i < nsops; i++) {
755 sopptr = &sops[i];
756 semptr = &semaptr->sem_base[sopptr->sem_num];
757 semptr->sempid = p->p_p->ps_pid;
758 }
759
760 semaptr->sem_otime = gettime();
761
762 /* Do a wakeup if any semaphore was up'd. */
763 if (do_wakeup) {
764 DPRINTF(("semop: doing wakeup\n"));
765 wakeup(&sema[semid]);
766 DPRINTF(("semop: back from wakeup\n"));
767 }
768 DPRINTF(("semop: done\n"));
769 *retval = 0;
770done2:
771 if (sops != sopbuf)
772 free(sops, M_SEM31, nsops * sizeof(struct sembuf));
773 return (error);
774}
775
776/*
777 * Go through the undo structures for this process and apply the adjustments to
778 * semaphores.
779 */
780void
781semexit(struct process *pr)
782{
783 struct sem_undo *suptr;
784 struct sem_undo **supptr;
785
786 /*
787 * Go through the chain of undo vectors looking for one associated with
788 * this process. Remember the pointer to the pointer to the element
789 * to dequeue it later.
790 */
791 supptr = &SLIST_FIRST(&semu_list)((&semu_list)->slh_first);
792 SLIST_FOREACH(suptr, &semu_list, un_next)for((suptr) = ((&semu_list)->slh_first); (suptr) != ((
void *)0); (suptr) = ((suptr)->un_next.sle_next))
{
793 if (suptr->un_proc == pr)
794 break;
795 supptr = &SLIST_NEXT(suptr, un_next)((suptr)->un_next.sle_next);
796 }
797
798 /*
799 * If there is no undo vector, skip to the end.
800 */
801 if (suptr == NULL((void *)0))
802 return;
803
804 /*
805 * We now have an undo vector for this process.
806 */
807 DPRINTF(("process @%p has undo structure with %d entries\n", pr,
808 suptr->un_cnt));
809
810 /*
811 * If there are any active undo elements then process them.
812 */
813 if (suptr->un_cnt > 0) {
814 int ix;
815
816 for (ix = 0; ix < suptr->un_cnt; ix++) {
817 int semid = suptr->un_ent[ix].un_id;
818 int semnum = suptr->un_ent[ix].un_num;
819 int adjval = suptr->un_ent[ix].un_adjval;
820 struct semid_ds *semaptr;
821
822 if ((semaptr = sema[semid]) == NULL((void *)0))
823 panic("semexit - semid not allocated");
824 if (semnum >= semaptr->sem_nsems)
825 panic("semexit - semnum out of range");
826
827 DPRINTF(("semexit: %p id=%d num=%d(adj=%d) ; sem=%d\n",
828 suptr->un_proc, suptr->un_ent[ix].un_id,
829 suptr->un_ent[ix].un_num,
830 suptr->un_ent[ix].un_adjval,
831 semaptr->sem_base[semnum].semval));
832
833 if (adjval < 0 &&
834 semaptr->sem_base[semnum].semval < -adjval)
835 semaptr->sem_base[semnum].semval = 0;
836 else
837 semaptr->sem_base[semnum].semval += adjval;
838
839 wakeup(&sema[semid]);
840 DPRINTF(("semexit: back from wakeup\n"));
841 }
842 }
843
844 /*
845 * Deallocate the undo vector.
846 */
847 DPRINTF(("removing vector\n"));
848 *supptr = SLIST_NEXT(suptr, un_next)((suptr)->un_next.sle_next);
849 pool_put(&semu_pool, suptr);
850 semutot--;
851}
852
853/* Expand semsegs and semseqs arrays */
854void
855sema_reallocate(int val)
856{
857 struct semid_ds **sema_new;
858 unsigned short *newseqs;
859 sema_new = mallocarray(val, sizeof(struct semid_ds *),
860 M_SEM31, M_WAITOK0x0001|M_ZERO0x0008);
861 memcpy(sema_new, sema,__builtin_memcpy((sema_new), (sema), (seminfo.semmni * sizeof
(struct semid_ds *)))
862 seminfo.semmni * sizeof(struct semid_ds *))__builtin_memcpy((sema_new), (sema), (seminfo.semmni * sizeof
(struct semid_ds *)))
;
863 newseqs = mallocarray(val, sizeof(unsigned short), M_SEM31,
864 M_WAITOK0x0001|M_ZERO0x0008);
865 memcpy(newseqs, semseqs,__builtin_memcpy((newseqs), (semseqs), (seminfo.semmni * sizeof
(unsigned short)))
866 seminfo.semmni * sizeof(unsigned short))__builtin_memcpy((newseqs), (semseqs), (seminfo.semmni * sizeof
(unsigned short)))
;
867 free(sema, M_SEM31, seminfo.semmni * sizeof(struct semid_ds *));
868 free(semseqs, M_SEM31, seminfo.semmni * sizeof(unsigned short));
869 sema = sema_new;
870 semseqs = newseqs;
871 seminfo.semmni = val;
872}
873
874const struct sysctl_bounded_args sysvsem_vars[] = {
875 { KERN_SEMINFO_SEMUME6, &seminfo.semume, SYSCTL_INT_READONLY1,0 },
876 { KERN_SEMINFO_SEMUSZ7, &seminfo.semusz, SYSCTL_INT_READONLY1,0 },
877 { KERN_SEMINFO_SEMVMX8, &seminfo.semvmx, SYSCTL_INT_READONLY1,0 },
878 { KERN_SEMINFO_SEMAEM9, &seminfo.semaem, SYSCTL_INT_READONLY1,0 },
879 { KERN_SEMINFO_SEMOPM5, &seminfo.semopm, 1, INT_MAX0x7fffffff },
880};
881
882/*
883 * Userland access to struct seminfo.
884 */
885int
886sysctl_sysvsem(int *name, u_int namelen, void *oldp, size_t *oldlenp,
887 void *newp, size_t newlen)
888{
889 int error, val;
890
891 if (namelen != 1)
892 return (ENOTDIR20); /* leaf-only */
893
894 switch (name[0]) {
895 case KERN_SEMINFO_SEMMNI1:
896 val = seminfo.semmni;
897 error = sysctl_int_bounded(oldp, oldlenp, newp, newlen,
898 &val, val, 0xffff);
899 /* returns success and skips reallocation if val is unchanged */
900 if (error || val == seminfo.semmni)
901 return (error);
902 sema_reallocate(val);
903 return (0);
904 case KERN_SEMINFO_SEMMNS2:
905 /* can't decrease semmns or go over 2^16 */
906 return (sysctl_int_bounded(oldp, oldlenp, newp, newlen,
907 &seminfo.semmns, seminfo.semmns, 0xffff));
908 case KERN_SEMINFO_SEMMNU3:
909 /* can't decrease semmnu or go over 2^16 */
910 return (sysctl_int_bounded(oldp, oldlenp, newp, newlen,
911 &seminfo.semmnu, seminfo.semmnu, 0xffff));
912 case KERN_SEMINFO_SEMMSL4:
913 /* can't decrease semmsl or go over 2^16 */
914 return (sysctl_int_bounded(oldp, oldlenp, newp, newlen,
915 &seminfo.semmsl, seminfo.semmsl, 0xffff));
916 default:
917 return (sysctl_bounded_arr(sysvsem_vars, nitems(sysvsem_vars)(sizeof((sysvsem_vars)) / sizeof((sysvsem_vars)[0])),
918 name, namelen, oldp, oldlenp, newp, newlen));
919 }
920 /* NOTREACHED */
921}