]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/sysv_sem.c
xnu-6153.41.3.tar.gz
[apple/xnu.git] / bsd / kern / sysv_sem.c
CommitLineData
1c79356b 1/*
cb323159 2 * Copyright (c) 2000-2019 Apple Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
0a7de745 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
0a7de745 17 *
2d21ac55
A
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
0a7de745 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/*
29 * Implementation of SVID semaphores
30 *
31 * Author: Daniel Boulet
32 *
33 * This software is provided ``AS IS'' without any warranties of any kind.
34 */
9bccf70c
A
35/*
36 * John Bellardo modified the implementation for Darwin. 12/2000
37 */
2d21ac55
A
38/*
39 * NOTICE: This file was modified by McAfee Research in 2004 to introduce
40 * support for mandatory and extensible security protections. This notice
41 * is included in support of clause 2.2 (b) of the Apple Public License,
42 * Version 2.0.
43 * Copyright (c) 2005-2006 SPARTA, Inc.
44 */
1c79356b
A
45
46#include <sys/param.h>
47#include <sys/systm.h>
1c79356b 48#include <sys/kernel.h>
91447636
A
49#include <sys/proc_internal.h>
50#include <sys/kauth.h>
51#include <sys/sem_internal.h>
9bccf70c 52#include <sys/malloc.h>
91447636
A
53#include <mach/mach_types.h>
54
9bccf70c 55#include <sys/filedesc.h>
91447636 56#include <sys/file_internal.h>
55e303ae 57#include <sys/sysctl.h>
91447636
A
58#include <sys/ipcs.h>
59#include <sys/sysent.h>
60#include <sys/sysproto.h>
2d21ac55
A
61#if CONFIG_MACF
62#include <security/mac_framework.h>
63#endif
9bccf70c 64
b0d623f7 65#include <security/audit/audit.h>
e5568f75 66
2d21ac55
A
67#if SYSV_SEM
68
9bccf70c
A
69
70/* Uncomment this line to see the debugging output */
71/* #define SEM_DEBUG */
72
2d21ac55
A
73/* Uncomment this line to see MAC debugging output. */
74/* #define MAC_DEBUG */
75#if CONFIG_MACF_DEBUG
0a7de745 76#define MPRINTF(a) printf(a)
2d21ac55 77#else
0a7de745 78#define MPRINTF(a)
2d21ac55
A
79#endif
80
0a7de745 81#define M_SYSVSEM M_TEMP
9bccf70c 82
1c79356b 83
9bccf70c
A
84/* Hard system limits to avoid resource starvation / DOS attacks.
85 * These are not needed if we can make the semaphore pages swappable.
86 */
87static struct seminfo limitseminfo = {
cb323159
A
88 .semmap = SEMMAP, /* # of entries in semaphore map */
89 .semmni = SEMMNI, /* # of semaphore identifiers */
90 .semmns = SEMMNS, /* # of semaphores in system */
91 .semmnu = SEMMNU, /* # of undo structures in system */
92 .semmsl = SEMMSL, /* max # of semaphores per id */
93 .semopm = SEMOPM, /* max # of operations per semop call */
94 .semume = SEMUME, /* max # of undo entries per process */
95 .semusz = SEMUSZ, /* size in bytes of undo structure */
96 .semvmx = SEMVMX, /* semaphore maximum value */
97 .semaem = SEMAEM /* adjust on exit max value */
9bccf70c
A
98};
99
100/* Current system allocations. We use this structure to track how many
101 * resources we have allocated so far. This way we can set large hard limits
102 * and not allocate the memory for them up front.
103 */
104struct seminfo seminfo = {
cb323159
A
105 .semmap = SEMMAP, /* Unused, # of entries in semaphore map */
106 .semmni = 0, /* # of semaphore identifiers */
107 .semmns = 0, /* # of semaphores in system */
108 .semmnu = 0, /* # of undo entries in system */
109 .semmsl = SEMMSL, /* max # of semaphores per id */
110 .semopm = SEMOPM, /* max # of operations per semop call */
111 .semume = SEMUME, /* max # of undo entries per process */
112 .semusz = SEMUSZ, /* size in bytes of undo structure */
113 .semvmx = SEMVMX, /* semaphore maximum value */
114 .semaem = SEMAEM /* adjust on exit max value */
9bccf70c
A
115};
116
1c79356b 117
2d21ac55 118static int semu_alloc(struct proc *p);
0a7de745
A
119static int semundo_adjust(struct proc *p, int *supidx,
120 int semid, int semnum, int adjval);
91447636 121static void semundo_clear(int semid, int semnum);
9bccf70c 122
1c79356b 123/* XXX casting to (sy_call_t *) is bogus, as usual. */
cb323159 124static sy_call_t* const semcalls[] = {
9bccf70c 125 (sy_call_t *)semctl, (sy_call_t *)semget,
37839358 126 (sy_call_t *)semop
1c79356b
A
127};
128
0a7de745
A
129static int semtot = 0; /* # of used semaphores */
130struct semid_kernel *sema = NULL; /* semaphore id pool */
131struct sem *sem_pool = NULL; /* semaphore pool */
132static int semu_list_idx = -1; /* active undo structures */
133struct sem_undo *semu = NULL; /* semaphore undo pool */
1c79356b 134
1c79356b 135
91447636
A
136void sysv_sem_lock_init(void);
137static lck_grp_t *sysv_sem_subsys_lck_grp;
138static lck_grp_attr_t *sysv_sem_subsys_lck_grp_attr;
139static lck_attr_t *sysv_sem_subsys_lck_attr;
140static lck_mtx_t sysv_sem_subsys_mutex;
141
142#define SYSV_SEM_SUBSYS_LOCK() lck_mtx_lock(&sysv_sem_subsys_mutex)
143#define SYSV_SEM_SUBSYS_UNLOCK() lck_mtx_unlock(&sysv_sem_subsys_mutex)
144
145
146__private_extern__ void
147sysv_sem_lock_init( void )
148{
0a7de745 149 sysv_sem_subsys_lck_grp_attr = lck_grp_attr_alloc_init();
91447636 150
0a7de745 151 sysv_sem_subsys_lck_grp = lck_grp_alloc_init("sysv_sem_subsys_lock", sysv_sem_subsys_lck_grp_attr);
91447636 152
0a7de745
A
153 sysv_sem_subsys_lck_attr = lck_attr_alloc_init();
154 lck_mtx_init(&sysv_sem_subsys_mutex, sysv_sem_subsys_lck_grp, sysv_sem_subsys_lck_attr);
91447636
A
155}
156
157static __inline__ user_time_t
158sysv_semtime(void)
159{
0a7de745 160 struct timeval tv;
91447636 161 microtime(&tv);
0a7de745 162 return tv.tv_sec;
91447636
A
163}
164
165/*
166 * XXX conversion of internal user_time_t to external tume_t loses
167 * XXX precision; not an issue for us now, since we are only ever
168 * XXX setting 32 bits worth of time into it.
169 *
170 * pad field contents are not moved correspondingly; contents will be lost
171 *
172 * NOTE: Source and target may *NOT* overlap! (target is smaller)
173 */
174static void
b0d623f7 175semid_ds_kernelto32(struct user_semid_ds *in, struct user32_semid_ds *out)
1c79356b 176{
91447636 177 out->sem_perm = in->sem_perm;
0a7de745 178 out->sem_base = CAST_DOWN_EXPLICIT(__int32_t, in->sem_base);
b0d623f7 179 out->sem_nsems = in->sem_nsems;
0a7de745
A
180 out->sem_otime = in->sem_otime; /* XXX loses precision */
181 out->sem_ctime = in->sem_ctime; /* XXX loses precision */
b0d623f7
A
182}
183
184static void
185semid_ds_kernelto64(struct user_semid_ds *in, struct user64_semid_ds *out)
186{
187 out->sem_perm = in->sem_perm;
0a7de745 188 out->sem_base = CAST_DOWN_EXPLICIT(__int32_t, in->sem_base);
91447636 189 out->sem_nsems = in->sem_nsems;
0a7de745
A
190 out->sem_otime = in->sem_otime; /* XXX loses precision */
191 out->sem_ctime = in->sem_ctime; /* XXX loses precision */
1c79356b
A
192}
193
91447636
A
194/*
195 * pad field contents are not moved correspondingly; contents will be lost
196 *
197 * NOTE: Source and target may are permitted to overlap! (source is smaller);
198 * this works because we copy fields in order from the end of the struct to
199 * the beginning.
200 *
201 * XXX use CAST_USER_ADDR_T() for lack of a CAST_USER_TIME_T(); net effect
202 * XXX is the same.
203 */
204static void
b0d623f7 205semid_ds_32tokernel(struct user32_semid_ds *in, struct user_semid_ds *out)
91447636
A
206{
207 out->sem_ctime = in->sem_ctime;
208 out->sem_otime = in->sem_otime;
209 out->sem_nsems = in->sem_nsems;
b0d623f7
A
210 out->sem_base = (void *)(uintptr_t)in->sem_base;
211 out->sem_perm = in->sem_perm;
212}
213
214static void
215semid_ds_64tokernel(struct user64_semid_ds *in, struct user_semid_ds *out)
216{
217 out->sem_ctime = in->sem_ctime;
218 out->sem_otime = in->sem_otime;
219 out->sem_nsems = in->sem_nsems;
220 out->sem_base = (void *)(uintptr_t)in->sem_base;
91447636
A
221 out->sem_perm = in->sem_perm;
222}
223
224
1c79356b 225/*
b0d623f7
A
226 * semsys
227 *
228 * Entry point for all SEM calls: semctl, semget, semop
229 *
230 * Parameters: p Process requesting the call
0a7de745
A
231 * uap User argument descriptor (see below)
232 * retval Return value of the selected sem call
b0d623f7
A
233 *
234 * Indirect parameters: uap->which sem call to invoke (index in array of sem calls)
0a7de745
A
235 * uap->a2 User argument descriptor
236 *
b0d623f7
A
237 * Returns: 0 Success
238 * !0 Not success
239 *
240 * Implicit returns: retval Return value of the selected sem call
241 *
242 * DEPRECATED: This interface should not be used to call the other SEM
0a7de745
A
243 * functions (semctl, semget, semop). The correct usage is
244 * to call the other SEM functions directly.
9bccf70c 245 *
1c79356b
A
246 */
247int
b0d623f7 248semsys(struct proc *p, struct semsys_args *uap, int32_t *retval)
1c79356b 249{
9bccf70c 250 /* The individual calls handling the locking now */
1c79356b 251
0a7de745
A
252 if (uap->which >= sizeof(semcalls) / sizeof(semcalls[0])) {
253 return EINVAL;
254 }
255 return (*semcalls[uap->which])(p, &uap->a2, retval);
1c79356b
A
256}
257
91447636
A
258/*
259 * Expand the semu array to the given capacity. If the expansion fails
9bccf70c
A
260 * return 0, otherwise return 1.
261 *
262 * Assumes we already have the subsystem lock.
263 */
264static int
91447636 265grow_semu_array(int newSize)
9bccf70c 266{
39037602
A
267 int i;
268 struct sem_undo *newSemu;
91447636 269
0a7de745 270 if (newSize <= seminfo.semmnu) {
91447636 271 return 1;
0a7de745
A
272 }
273 if (newSize > limitseminfo.semmnu) { /* enforce hard limit */
9bccf70c
A
274#ifdef SEM_DEBUG
275 printf("undo structure hard limit of %d reached, requested %d\n",
0a7de745 276 limitseminfo.semmnu, newSize);
9bccf70c
A
277#endif
278 return 0;
279 }
0a7de745 280 newSize = (newSize / SEMMNU_INC + 1) * SEMMNU_INC;
9bccf70c
A
281 newSize = newSize > limitseminfo.semmnu ? limitseminfo.semmnu : newSize;
282
283#ifdef SEM_DEBUG
284 printf("growing semu[] from %d to %d\n", seminfo.semmnu, newSize);
285#endif
0a7de745
A
286 MALLOC(newSemu, struct sem_undo *, sizeof(struct sem_undo) * newSize,
287 M_SYSVSEM, M_WAITOK | M_ZERO);
288 if (NULL == newSemu) {
9bccf70c
A
289#ifdef SEM_DEBUG
290 printf("allocation failed. no changes made.\n");
291#endif
292 return 0;
293 }
294
0a7de745
A
295 /* copy the old data to the new array */
296 for (i = 0; i < seminfo.semmnu; i++) {
9bccf70c 297 newSemu[i] = semu[i];
9bccf70c 298 }
3a60a9f5
A
299 /*
300 * The new elements (from newSemu[i] to newSemu[newSize-1]) have their
301 * "un_proc" set to 0 (i.e. NULL) by the M_ZERO flag to MALLOC() above,
302 * so they're already marked as "not in use".
303 */
9bccf70c
A
304
305 /* Clean up the old array */
0a7de745 306 if (semu) {
9bccf70c 307 FREE(semu, M_SYSVSEM);
0a7de745 308 }
9bccf70c
A
309
310 semu = newSemu;
311 seminfo.semmnu = newSize;
312#ifdef SEM_DEBUG
313 printf("expansion successful\n");
314#endif
315 return 1;
316}
317
318/*
319 * Expand the sema array to the given capacity. If the expansion fails
320 * we return 0, otherwise we return 1.
321 *
322 * Assumes we already have the subsystem lock.
323 */
324static int
91447636 325grow_sema_array(int newSize)
9bccf70c 326{
39037602
A
327 struct semid_kernel *newSema;
328 int i;
9bccf70c 329
0a7de745 330 if (newSize <= seminfo.semmni) {
9bccf70c 331 return 0;
0a7de745
A
332 }
333 if (newSize > limitseminfo.semmni) { /* enforce hard limit */
9bccf70c
A
334#ifdef SEM_DEBUG
335 printf("identifier hard limit of %d reached, requested %d\n",
0a7de745 336 limitseminfo.semmni, newSize);
9bccf70c
A
337#endif
338 return 0;
339 }
0a7de745 340 newSize = (newSize / SEMMNI_INC + 1) * SEMMNI_INC;
9bccf70c
A
341 newSize = newSize > limitseminfo.semmni ? limitseminfo.semmni : newSize;
342
343#ifdef SEM_DEBUG
344 printf("growing sema[] from %d to %d\n", seminfo.semmni, newSize);
345#endif
2d21ac55 346 MALLOC(newSema, struct semid_kernel *,
0a7de745
A
347 sizeof(struct semid_kernel) * newSize,
348 M_SYSVSEM, M_WAITOK | M_ZERO);
349 if (NULL == newSema) {
9bccf70c
A
350#ifdef SEM_DEBUG
351 printf("allocation failed. no changes made.\n");
352#endif
353 return 0;
354 }
355
3a60a9f5 356 /* copy over the old ids */
0a7de745 357 for (i = 0; i < seminfo.semmni; i++) {
9bccf70c
A
358 newSema[i] = sema[i];
359 /* This is a hack. What we really want to be able to
360 * do is change the value a process is waiting on
361 * without waking it up, but I don't know how to do
362 * this with the existing code, so we wake up the
363 * process and let it do a lot of work to determine the
364 * semaphore set is really not available yet, and then
2d21ac55 365 * sleep on the correct, reallocated semid_kernel pointer.
9bccf70c 366 */
0a7de745 367 if (sema[i].u.sem_perm.mode & SEM_ALLOC) {
9bccf70c 368 wakeup((caddr_t)&sema[i]);
0a7de745 369 }
9bccf70c 370 }
2d21ac55
A
371
372#if CONFIG_MACF
0a7de745 373 for (i = seminfo.semmni; i < newSize; i++) {
2d21ac55
A
374 mac_sysvsem_label_init(&newSema[i]);
375 }
376#endif
0a7de745 377
3a60a9f5
A
378 /*
379 * The new elements (from newSema[i] to newSema[newSize-1]) have their
380 * "sem_base" and "sem_perm.mode" set to 0 (i.e. NULL) by the M_ZERO
381 * flag to MALLOC() above, so they're already marked as "not in use".
382 */
9bccf70c
A
383
384 /* Clean up the old array */
0a7de745 385 if (sema) {
9bccf70c 386 FREE(sema, M_SYSVSEM);
0a7de745 387 }
9bccf70c
A
388
389 sema = newSema;
390 seminfo.semmni = newSize;
391#ifdef SEM_DEBUG
392 printf("expansion successful\n");
393#endif
394 return 1;
395}
396
397/*
91447636 398 * Expand the sem_pool array to the given capacity. If the expansion fails
9bccf70c
A
399 * we return 0 (fail), otherwise we return 1 (success).
400 *
401 * Assumes we already hold the subsystem lock.
402 */
403static int
91447636 404grow_sem_pool(int new_pool_size)
9bccf70c 405{
91447636
A
406 struct sem *new_sem_pool = NULL;
407 struct sem *sem_free;
408 int i;
9bccf70c 409
0a7de745 410 if (new_pool_size < semtot) {
9bccf70c 411 return 0;
0a7de745 412 }
91447636
A
413 /* enforce hard limit */
414 if (new_pool_size > limitseminfo.semmns) {
9bccf70c
A
415#ifdef SEM_DEBUG
416 printf("semaphore hard limit of %d reached, requested %d\n",
0a7de745 417 limitseminfo.semmns, new_pool_size);
9bccf70c
A
418#endif
419 return 0;
420 }
91447636 421
0a7de745 422 new_pool_size = (new_pool_size / SEMMNS_INC + 1) * SEMMNS_INC;
91447636 423 new_pool_size = new_pool_size > limitseminfo.semmns ? limitseminfo.semmns : new_pool_size;
9bccf70c
A
424
425#ifdef SEM_DEBUG
91447636 426 printf("growing sem_pool array from %d to %d\n", seminfo.semmns, new_pool_size);
9bccf70c 427#endif
0a7de745
A
428 MALLOC(new_sem_pool, struct sem *, sizeof(struct sem) * new_pool_size,
429 M_SYSVSEM, M_WAITOK | M_ZERO | M_NULL);
91447636 430 if (NULL == new_sem_pool) {
9bccf70c
A
431#ifdef SEM_DEBUG
432 printf("allocation failed. no changes made.\n");
433#endif
434 return 0;
435 }
436
437 /* We have our new memory, now copy the old contents over */
0a7de745
A
438 if (sem_pool) {
439 for (i = 0; i < seminfo.semmns; i++) {
91447636 440 new_sem_pool[i] = sem_pool[i];
0a7de745
A
441 }
442 }
9bccf70c
A
443
444 /* Update our id structures to point to the new semaphores */
0a7de745
A
445 for (i = 0; i < seminfo.semmni; i++) {
446 if (sema[i].u.sem_perm.mode & SEM_ALLOC) { /* ID in use */
447 sema[i].u.sem_base = new_sem_pool +
448 (sema[i].u.sem_base - sem_pool);
449 }
91447636
A
450 }
451
452 sem_free = sem_pool;
453 sem_pool = new_sem_pool;
9bccf70c
A
454
455 /* clean up the old array */
0a7de745 456 if (sem_free != NULL) {
91447636 457 FREE(sem_free, M_SYSVSEM);
0a7de745 458 }
9bccf70c 459
91447636 460 seminfo.semmns = new_pool_size;
9bccf70c
A
461#ifdef SEM_DEBUG
462 printf("expansion complete\n");
463#endif
464 return 1;
465}
466
1c79356b
A
467/*
468 * Allocate a new sem_undo structure for a process
469 * (returns ptr to structure or NULL if no more room)
9bccf70c
A
470 *
471 * Assumes we already hold the subsystem lock.
1c79356b
A
472 */
473
2d21ac55 474static int
91447636 475semu_alloc(struct proc *p)
1c79356b 476{
39037602
A
477 int i;
478 struct sem_undo *suptr;
2d21ac55 479 int *supidx;
1c79356b
A
480 int attempt;
481
482 /*
483 * Try twice to allocate something.
484 * (we'll purge any empty structures after the first pass so
485 * two passes are always enough)
486 */
487
488 for (attempt = 0; attempt < 2; attempt++) {
489 /*
490 * Look for a free structure.
491 * Fill it in and return it if we find one.
492 */
493
494 for (i = 0; i < seminfo.semmnu; i++) {
495 suptr = SEMU(i);
496 if (suptr->un_proc == NULL) {
2d21ac55
A
497 suptr->un_next_idx = semu_list_idx;
498 semu_list_idx = i;
1c79356b 499 suptr->un_cnt = 0;
91447636 500 suptr->un_ent = NULL;
1c79356b 501 suptr->un_proc = p;
2d21ac55 502 return i;
1c79356b
A
503 }
504 }
505
506 /*
507 * We didn't find a free one, if this is the first attempt
508 * then try to free some structures.
509 */
510
511 if (attempt == 0) {
512 /* All the structures are in use - try to free some */
513 int did_something = 0;
514
2d21ac55
A
515 supidx = &semu_list_idx;
516 while (*supidx != -1) {
517 suptr = SEMU(*supidx);
0a7de745 518 if (suptr->un_cnt == 0) {
1c79356b 519 suptr->un_proc = NULL;
2d21ac55 520 *supidx = suptr->un_next_idx;
1c79356b 521 did_something = 1;
0a7de745 522 } else {
2d21ac55 523 supidx = &(suptr->un_next_idx);
0a7de745 524 }
1c79356b
A
525 }
526
9bccf70c
A
527 /* If we didn't free anything. Try expanding
528 * the semu[] array. If that doesn't work
529 * then fail. We expand last to get the
530 * most reuse out of existing resources.
531 */
0a7de745
A
532 if (!did_something) {
533 if (!grow_semu_array(seminfo.semmnu + 1)) {
2d21ac55 534 return -1;
0a7de745
A
535 }
536 }
1c79356b
A
537 } else {
538 /*
539 * The second pass failed even though we freed
540 * something after the first pass!
541 * This is IMPOSSIBLE!
542 */
543 panic("semu_alloc - second attempt failed");
544 }
545 }
2d21ac55 546 return -1;
1c79356b
A
547}
548
549/*
550 * Adjust a particular entry for a particular proc
9bccf70c
A
551 *
552 * Assumes we already hold the subsystem lock.
1c79356b 553 */
1c79356b 554static int
2d21ac55 555semundo_adjust(struct proc *p, int *supidx, int semid,
0a7de745 556 int semnum, int adjval)
1c79356b 557{
39037602 558 struct sem_undo *suptr;
2d21ac55 559 int suidx;
39037602 560 struct undo *sueptr, **suepptr, *new_sueptr;
1c79356b
A
561 int i;
562
3a60a9f5
A
563 /*
564 * Look for and remember the sem_undo if the caller doesn't provide it
565 */
1c79356b 566
2d21ac55
A
567 suidx = *supidx;
568 if (suidx == -1) {
569 for (suidx = semu_list_idx; suidx != -1;
570 suidx = suptr->un_next_idx) {
571 suptr = SEMU(suidx);
1c79356b 572 if (suptr->un_proc == p) {
2d21ac55 573 *supidx = suidx;
1c79356b
A
574 break;
575 }
576 }
2d21ac55 577 if (suidx == -1) {
0a7de745
A
578 if (adjval == 0) {
579 return 0;
580 }
2d21ac55 581 suidx = semu_alloc(p);
0a7de745
A
582 if (suidx == -1) {
583 return ENOSPC;
584 }
2d21ac55 585 *supidx = suidx;
1c79356b
A
586 }
587 }
588
589 /*
590 * Look for the requested entry and adjust it (delete if adjval becomes
591 * 0).
592 */
2d21ac55 593 suptr = SEMU(suidx);
91447636 594 new_sueptr = NULL;
91447636 595 for (i = 0, suepptr = &suptr->un_ent, sueptr = suptr->un_ent;
0a7de745
A
596 i < suptr->un_cnt;
597 i++, suepptr = &sueptr->une_next, sueptr = sueptr->une_next) {
598 if (sueptr->une_id != semid || sueptr->une_num != semnum) {
1c79356b 599 continue;
0a7de745
A
600 }
601 if (adjval == 0) {
91447636 602 sueptr->une_adjval = 0;
0a7de745 603 } else {
91447636 604 sueptr->une_adjval += adjval;
0a7de745 605 }
91447636 606 if (sueptr->une_adjval == 0) {
1c79356b 607 suptr->un_cnt--;
91447636
A
608 *suepptr = sueptr->une_next;
609 FREE(sueptr, M_SYSVSEM);
610 sueptr = NULL;
611 }
3a60a9f5 612 return 0;
1c79356b
A
613 }
614
615 /* Didn't find the right entry - create it */
91447636 616 if (adjval == 0) {
3a60a9f5
A
617 /* no adjustment: no need for a new entry */
618 return 0;
91447636
A
619 }
620
3a60a9f5
A
621 if (suptr->un_cnt == limitseminfo.semume) {
622 /* reached the limit number of semaphore undo entries */
623 return EINVAL;
91447636
A
624 }
625
3a60a9f5 626 /* allocate a new semaphore undo entry */
0a7de745
A
627 MALLOC(new_sueptr, struct undo *, sizeof(struct undo),
628 M_SYSVSEM, M_WAITOK);
3a60a9f5
A
629 if (new_sueptr == NULL) {
630 return ENOMEM;
631 }
632
633 /* fill in the new semaphore undo entry */
634 new_sueptr->une_next = suptr->un_ent;
635 suptr->un_ent = new_sueptr;
636 suptr->un_cnt++;
637 new_sueptr->une_adjval = adjval;
638 new_sueptr->une_id = semid;
639 new_sueptr->une_num = semnum;
640
641 return 0;
1c79356b
A
642}
643
9bccf70c
A
644/* Assumes we already hold the subsystem lock.
645 */
1c79356b 646static void
91447636 647semundo_clear(int semid, int semnum)
1c79356b 648{
91447636 649 struct sem_undo *suptr;
2d21ac55 650 int suidx;
1c79356b 651
2d21ac55 652 for (suidx = semu_list_idx; suidx != -1; suidx = suptr->un_next_idx) {
91447636
A
653 struct undo *sueptr;
654 struct undo **suepptr;
655 int i = 0;
1c79356b 656
2d21ac55 657 suptr = SEMU(suidx);
91447636
A
658 sueptr = suptr->un_ent;
659 suepptr = &suptr->un_ent;
1c79356b 660 while (i < suptr->un_cnt) {
91447636
A
661 if (sueptr->une_id == semid) {
662 if (semnum == -1 || sueptr->une_num == semnum) {
1c79356b 663 suptr->un_cnt--;
91447636
A
664 *suepptr = sueptr->une_next;
665 FREE(sueptr, M_SYSVSEM);
666 sueptr = *suepptr;
667 continue;
1c79356b 668 }
0a7de745 669 if (semnum != -1) {
1c79356b 670 break;
0a7de745 671 }
1c79356b 672 }
91447636
A
673 i++;
674 suepptr = &sueptr->une_next;
675 sueptr = sueptr->une_next;
1c79356b
A
676 }
677 }
678}
679
680/*
91447636
A
681 * Note that the user-mode half of this passes a union coerced to a
682 * user_addr_t. The union contains either an int or a pointer, and
683 * so we have to coerce it back, variant on whether the calling
684 * process is 64 bit or not. The coercion works for the 'val' element
685 * because the alignment is the same in user and kernel space.
1c79356b 686 */
1c79356b 687int
b0d623f7 688semctl(struct proc *p, struct semctl_args *uap, int32_t *retval)
1c79356b
A
689{
690 int semid = uap->semid;
691 int semnum = uap->semnum;
692 int cmd = uap->cmd;
91447636
A
693 user_semun_t user_arg = (user_semun_t)uap->arg;
694 kauth_cred_t cred = kauth_cred_get();
1c79356b 695 int i, rval, eval;
91447636 696 struct user_semid_ds sbuf;
2d21ac55 697 struct semid_kernel *semakptr;
0a7de745 698
1c79356b 699
55e303ae
A
700 AUDIT_ARG(svipc_cmd, cmd);
701 AUDIT_ARG(svipc_id, semid);
91447636
A
702
703 SYSV_SEM_SUBSYS_LOCK();
704
1c79356b 705#ifdef SEM_DEBUG
91447636 706 printf("call to semctl(%d, %d, %d, 0x%qx)\n", semid, semnum, cmd, user_arg);
1c79356b
A
707#endif
708
709 semid = IPCID_TO_IX(semid);
91447636
A
710
711 if (semid < 0 || semid >= seminfo.semmni) {
9bccf70c
A
712#ifdef SEM_DEBUG
713 printf("Invalid semid\n");
714#endif
91447636
A
715 eval = EINVAL;
716 goto semctlout;
717 }
1c79356b 718
2d21ac55
A
719 semakptr = &sema[semid];
720 if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 ||
721 semakptr->u.sem_perm._seq != IPCID_TO_SEQ(uap->semid)) {
91447636
A
722 eval = EINVAL;
723 goto semctlout;
724 }
2d21ac55
A
725#if CONFIG_MACF
726 eval = mac_sysvsem_check_semctl(cred, semakptr, cmd);
0a7de745 727 if (eval) {
2d21ac55 728 goto semctlout;
0a7de745 729 }
2d21ac55 730#endif
1c79356b
A
731
732 eval = 0;
733 rval = 0;
734
735 switch (cmd) {
736 case IPC_RMID:
0a7de745 737 if ((eval = ipcperm(cred, &semakptr->u.sem_perm, IPC_M))) {
91447636 738 goto semctlout;
0a7de745 739 }
91447636 740
2d21ac55
A
741 semakptr->u.sem_perm.cuid = kauth_cred_getuid(cred);
742 semakptr->u.sem_perm.uid = kauth_cred_getuid(cred);
743 semtot -= semakptr->u.sem_nsems;
0a7de745 744 for (i = semakptr->u.sem_base - sem_pool; i < semtot; i++) {
2d21ac55 745 sem_pool[i] = sem_pool[i + semakptr->u.sem_nsems];
0a7de745 746 }
1c79356b 747 for (i = 0; i < seminfo.semmni; i++) {
2d21ac55 748 if ((sema[i].u.sem_perm.mode & SEM_ALLOC) &&
0a7de745 749 sema[i].u.sem_base > semakptr->u.sem_base) {
2d21ac55 750 sema[i].u.sem_base -= semakptr->u.sem_nsems;
0a7de745 751 }
1c79356b 752 }
2d21ac55
A
753 semakptr->u.sem_perm.mode = 0;
754#if CONFIG_MACF
755 mac_sysvsem_label_recycle(semakptr);
756#endif
1c79356b 757 semundo_clear(semid, -1);
2d21ac55 758 wakeup((caddr_t)semakptr);
1c79356b
A
759 break;
760
761 case IPC_SET:
0a7de745
A
762 if ((eval = ipcperm(cred, &semakptr->u.sem_perm, IPC_M))) {
763 goto semctlout;
764 }
91447636 765
91447636 766 if (IS_64BIT_PROCESS(p)) {
b0d623f7
A
767 struct user64_semid_ds ds64;
768 eval = copyin(user_arg.buf, &ds64, sizeof(ds64));
769 semid_ds_64tokernel(&ds64, &sbuf);
91447636 770 } else {
b0d623f7
A
771 struct user32_semid_ds ds32;
772 eval = copyin(user_arg.buf, &ds32, sizeof(ds32));
773 semid_ds_32tokernel(&ds32, &sbuf);
91447636 774 }
0a7de745 775
3a60a9f5
A
776 if (eval != 0) {
777 goto semctlout;
778 }
91447636 779
2d21ac55
A
780 semakptr->u.sem_perm.uid = sbuf.sem_perm.uid;
781 semakptr->u.sem_perm.gid = sbuf.sem_perm.gid;
782 semakptr->u.sem_perm.mode = (semakptr->u.sem_perm.mode &
783 ~0777) | (sbuf.sem_perm.mode & 0777);
784 semakptr->u.sem_ctime = sysv_semtime();
1c79356b
A
785 break;
786
787 case IPC_STAT:
0a7de745
A
788 if ((eval = ipcperm(cred, &semakptr->u.sem_perm, IPC_R))) {
789 goto semctlout;
790 }
b0d623f7 791
91447636 792 if (IS_64BIT_PROCESS(p)) {
b0d623f7 793 struct user64_semid_ds semid_ds64;
39236c6e 794 bzero(&semid_ds64, sizeof(semid_ds64));
b0d623f7
A
795 semid_ds_kernelto64(&semakptr->u, &semid_ds64);
796 eval = copyout(&semid_ds64, user_arg.buf, sizeof(semid_ds64));
91447636 797 } else {
b0d623f7 798 struct user32_semid_ds semid_ds32;
39236c6e 799 bzero(&semid_ds32, sizeof(semid_ds32));
b0d623f7
A
800 semid_ds_kernelto32(&semakptr->u, &semid_ds32);
801 eval = copyout(&semid_ds32, user_arg.buf, sizeof(semid_ds32));
91447636 802 }
1c79356b
A
803 break;
804
805 case GETNCNT:
0a7de745
A
806 if ((eval = ipcperm(cred, &semakptr->u.sem_perm, IPC_R))) {
807 goto semctlout;
808 }
2d21ac55 809 if (semnum < 0 || semnum >= semakptr->u.sem_nsems) {
91447636
A
810 eval = EINVAL;
811 goto semctlout;
812 }
2d21ac55 813 rval = semakptr->u.sem_base[semnum].semncnt;
1c79356b
A
814 break;
815
816 case GETPID:
0a7de745
A
817 if ((eval = ipcperm(cred, &semakptr->u.sem_perm, IPC_R))) {
818 goto semctlout;
819 }
2d21ac55 820 if (semnum < 0 || semnum >= semakptr->u.sem_nsems) {
91447636
A
821 eval = EINVAL;
822 goto semctlout;
823 }
2d21ac55 824 rval = semakptr->u.sem_base[semnum].sempid;
1c79356b
A
825 break;
826
827 case GETVAL:
0a7de745
A
828 if ((eval = ipcperm(cred, &semakptr->u.sem_perm, IPC_R))) {
829 goto semctlout;
830 }
2d21ac55 831 if (semnum < 0 || semnum >= semakptr->u.sem_nsems) {
91447636
A
832 eval = EINVAL;
833 goto semctlout;
834 }
2d21ac55 835 rval = semakptr->u.sem_base[semnum].semval;
1c79356b
A
836 break;
837
838 case GETALL:
0a7de745
A
839 if ((eval = ipcperm(cred, &semakptr->u.sem_perm, IPC_R))) {
840 goto semctlout;
841 }
91447636 842/* XXXXXXXXXXXXXXXX TBD XXXXXXXXXXXXXXXX */
2d21ac55 843 for (i = 0; i < semakptr->u.sem_nsems; i++) {
91447636 844 /* XXX could be done in one go... */
2d21ac55 845 eval = copyout((caddr_t)&semakptr->u.sem_base[i].semval,
91447636
A
846 user_arg.array + (i * sizeof(unsigned short)),
847 sizeof(unsigned short));
0a7de745 848 if (eval != 0) {
1c79356b 849 break;
0a7de745 850 }
1c79356b
A
851 }
852 break;
853
854 case GETZCNT:
0a7de745
A
855 if ((eval = ipcperm(cred, &semakptr->u.sem_perm, IPC_R))) {
856 goto semctlout;
857 }
2d21ac55 858 if (semnum < 0 || semnum >= semakptr->u.sem_nsems) {
91447636
A
859 eval = EINVAL;
860 goto semctlout;
861 }
2d21ac55 862 rval = semakptr->u.sem_base[semnum].semzcnt;
1c79356b
A
863 break;
864
865 case SETVAL:
0a7de745 866 if ((eval = ipcperm(cred, &semakptr->u.sem_perm, IPC_W))) {
9bccf70c
A
867#ifdef SEM_DEBUG
868 printf("Invalid credentials for write\n");
869#endif
0a7de745 870 goto semctlout;
9bccf70c 871 }
0a7de745 872 if (semnum < 0 || semnum >= semakptr->u.sem_nsems) {
9bccf70c
A
873#ifdef SEM_DEBUG
874 printf("Invalid number out of range for set\n");
875#endif
91447636
A
876 eval = EINVAL;
877 goto semctlout;
9bccf70c 878 }
0a7de745 879
91447636
A
880 /*
881 * Cast down a pointer instead of using 'val' member directly
882 * to avoid introducing endieness and a pad field into the
883 * header file. Ugly, but it works.
884 */
39236c6e 885 u_int newsemval = CAST_DOWN_EXPLICIT(u_int, user_arg.buf);
0a7de745 886
39236c6e 887 /*
0a7de745 888 * The check is being performed as unsigned values to match
39236c6e 889 * eventual destination
0a7de745
A
890 */
891 if (newsemval > (u_int)seminfo.semvmx) {
39236c6e
A
892#ifdef SEM_DEBUG
893 printf("Out of range sem value for set\n");
894#endif
895 eval = ERANGE;
896 goto semctlout;
897 }
898 semakptr->u.sem_base[semnum].semval = newsemval;
2d21ac55
A
899 semakptr->u.sem_base[semnum].sempid = p->p_pid;
900 /* XXX scottl Should there be a MAC call here? */
1c79356b 901 semundo_clear(semid, semnum);
2d21ac55 902 wakeup((caddr_t)semakptr);
1c79356b
A
903 break;
904
905 case SETALL:
0a7de745
A
906 if ((eval = ipcperm(cred, &semakptr->u.sem_perm, IPC_W))) {
907 goto semctlout;
908 }
91447636 909/*** XXXXXXXXXXXX TBD ********/
2d21ac55 910 for (i = 0; i < semakptr->u.sem_nsems; i++) {
91447636
A
911 /* XXX could be done in one go... */
912 eval = copyin(user_arg.array + (i * sizeof(unsigned short)),
2d21ac55 913 (caddr_t)&semakptr->u.sem_base[i].semval,
91447636 914 sizeof(unsigned short));
0a7de745 915 if (eval != 0) {
1c79356b 916 break;
0a7de745 917 }
2d21ac55 918 semakptr->u.sem_base[i].sempid = p->p_pid;
1c79356b 919 }
2d21ac55 920 /* XXX scottl Should there be a MAC call here? */
1c79356b 921 semundo_clear(semid, -1);
2d21ac55 922 wakeup((caddr_t)semakptr);
1c79356b
A
923 break;
924
925 default:
0a7de745
A
926 eval = EINVAL;
927 goto semctlout;
1c79356b
A
928 }
929
0a7de745 930 if (eval == 0) {
9bccf70c 931 *retval = rval;
0a7de745 932 }
91447636
A
933semctlout:
934 SYSV_SEM_SUBSYS_UNLOCK();
0a7de745 935 return eval;
1c79356b
A
936}
937
1c79356b 938int
b0d623f7 939semget(__unused struct proc *p, struct semget_args *uap, int32_t *retval)
1c79356b
A
940{
941 int semid, eval;
942 int key = uap->key;
943 int nsems = uap->nsems;
944 int semflg = uap->semflg;
91447636 945 kauth_cred_t cred = kauth_cred_get();
1c79356b
A
946
947#ifdef SEM_DEBUG
0a7de745 948 if (key != IPC_PRIVATE) {
9bccf70c 949 printf("semget(0x%x, %d, 0%o)\n", key, nsems, semflg);
0a7de745 950 } else {
9bccf70c 951 printf("semget(IPC_PRIVATE, %d, 0%o)\n", nsems, semflg);
0a7de745 952 }
1c79356b 953#endif
91447636
A
954
955
3a60a9f5 956 SYSV_SEM_SUBSYS_LOCK();
91447636 957
0a7de745 958
1c79356b
A
959 if (key != IPC_PRIVATE) {
960 for (semid = 0; semid < seminfo.semmni; semid++) {
2d21ac55 961 if ((sema[semid].u.sem_perm.mode & SEM_ALLOC) &&
0a7de745 962 sema[semid].u.sem_perm._key == key) {
1c79356b 963 break;
0a7de745 964 }
1c79356b
A
965 }
966 if (semid < seminfo.semmni) {
967#ifdef SEM_DEBUG
968 printf("found public key\n");
969#endif
2d21ac55 970 if ((eval = ipcperm(cred, &sema[semid].u.sem_perm,
0a7de745 971 semflg & 0700))) {
91447636 972 goto semgetout;
0a7de745 973 }
2d21ac55 974 if (nsems < 0 || sema[semid].u.sem_nsems < nsems) {
1c79356b
A
975#ifdef SEM_DEBUG
976 printf("too small\n");
977#endif
91447636
A
978 eval = EINVAL;
979 goto semgetout;
1c79356b
A
980 }
981 if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) {
982#ifdef SEM_DEBUG
983 printf("not exclusive\n");
984#endif
91447636
A
985 eval = EEXIST;
986 goto semgetout;
1c79356b 987 }
2d21ac55
A
988#if CONFIG_MACF
989 eval = mac_sysvsem_check_semget(cred, &sema[semid]);
0a7de745 990 if (eval) {
2d21ac55 991 goto semgetout;
0a7de745 992 }
2d21ac55 993#endif
1c79356b
A
994 goto found;
995 }
996 }
997
998#ifdef SEM_DEBUG
9bccf70c 999 printf("need to allocate an id for the request\n");
1c79356b
A
1000#endif
1001 if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) {
55e303ae 1002 if (nsems <= 0 || nsems > limitseminfo.semmsl) {
1c79356b
A
1003#ifdef SEM_DEBUG
1004 printf("nsems out of range (0<%d<=%d)\n", nsems,
1005 seminfo.semmsl);
1006#endif
91447636
A
1007 eval = EINVAL;
1008 goto semgetout;
1c79356b
A
1009 }
1010 if (nsems > seminfo.semmns - semtot) {
1011#ifdef SEM_DEBUG
1012 printf("not enough semaphores left (need %d, got %d)\n",
1013 nsems, seminfo.semmns - semtot);
1014#endif
91447636 1015 if (!grow_sem_pool(semtot + nsems)) {
9bccf70c
A
1016#ifdef SEM_DEBUG
1017 printf("failed to grow the sem array\n");
1018#endif
91447636
A
1019 eval = ENOSPC;
1020 goto semgetout;
9bccf70c 1021 }
1c79356b
A
1022 }
1023 for (semid = 0; semid < seminfo.semmni; semid++) {
0a7de745 1024 if ((sema[semid].u.sem_perm.mode & SEM_ALLOC) == 0) {
1c79356b 1025 break;
0a7de745 1026 }
1c79356b
A
1027 }
1028 if (semid == seminfo.semmni) {
1029#ifdef SEM_DEBUG
9bccf70c 1030 printf("no more id's available\n");
1c79356b 1031#endif
0a7de745 1032 if (!grow_sema_array(seminfo.semmni + 1)) {
9bccf70c
A
1033#ifdef SEM_DEBUG
1034 printf("failed to grow sema array\n");
1035#endif
91447636
A
1036 eval = ENOSPC;
1037 goto semgetout;
9bccf70c 1038 }
1c79356b
A
1039 }
1040#ifdef SEM_DEBUG
1041 printf("semid %d is available\n", semid);
1042#endif
2d21ac55
A
1043 sema[semid].u.sem_perm._key = key;
1044 sema[semid].u.sem_perm.cuid = kauth_cred_getuid(cred);
1045 sema[semid].u.sem_perm.uid = kauth_cred_getuid(cred);
6d2010ae
A
1046 sema[semid].u.sem_perm.cgid = kauth_cred_getgid(cred);
1047 sema[semid].u.sem_perm.gid = kauth_cred_getgid(cred);
2d21ac55
A
1048 sema[semid].u.sem_perm.mode = (semflg & 0777) | SEM_ALLOC;
1049 sema[semid].u.sem_perm._seq =
1050 (sema[semid].u.sem_perm._seq + 1) & 0x7fff;
1051 sema[semid].u.sem_nsems = nsems;
1052 sema[semid].u.sem_otime = 0;
1053 sema[semid].u.sem_ctime = sysv_semtime();
1054 sema[semid].u.sem_base = &sem_pool[semtot];
1c79356b 1055 semtot += nsems;
2d21ac55 1056 bzero(sema[semid].u.sem_base,
0a7de745 1057 sizeof(sema[semid].u.sem_base[0]) * nsems);
2d21ac55
A
1058#if CONFIG_MACF
1059 mac_sysvsem_label_associate(cred, &sema[semid]);
1060#endif
1c79356b 1061#ifdef SEM_DEBUG
2d21ac55 1062 printf("sembase = 0x%x, next = 0x%x\n", sema[semid].u.sem_base,
91447636 1063 &sem_pool[semtot]);
1c79356b
A
1064#endif
1065 } else {
1066#ifdef SEM_DEBUG
1067 printf("didn't find it and wasn't asked to create it\n");
1068#endif
91447636
A
1069 eval = ENOENT;
1070 goto semgetout;
1c79356b
A
1071 }
1072
1073found:
2d21ac55 1074 *retval = IXSEQ_TO_IPCID(semid, sema[semid].u.sem_perm);
55e303ae 1075 AUDIT_ARG(svipc_id, *retval);
9bccf70c
A
1076#ifdef SEM_DEBUG
1077 printf("semget is done, returning %d\n", *retval);
1078#endif
91447636 1079 eval = 0;
1c79356b 1080
91447636
A
1081semgetout:
1082 SYSV_SEM_SUBSYS_UNLOCK();
0a7de745 1083 return eval;
91447636 1084}
1c79356b
A
1085
1086int
b0d623f7 1087semop(struct proc *p, struct semop_args *uap, int32_t *retval)
1c79356b
A
1088{
1089 int semid = uap->semid;
1090 int nsops = uap->nsops;
316670eb 1091 struct sembuf sops[seminfo.semopm];
39037602 1092 struct semid_kernel *semakptr;
0a7de745
A
1093 struct sembuf *sopptr = NULL; /* protected by 'semptr' */
1094 struct sem *semptr = NULL; /* protected by 'if' */
2d21ac55 1095 int supidx = -1;
1c79356b
A
1096 int i, j, eval;
1097 int do_wakeup, do_undos;
1098
55e303ae 1099 AUDIT_ARG(svipc_id, uap->semid);
91447636
A
1100
1101 SYSV_SEM_SUBSYS_LOCK();
1102
1c79356b
A
1103#ifdef SEM_DEBUG
1104 printf("call to semop(%d, 0x%x, %d)\n", semid, sops, nsops);
1105#endif
1106
0a7de745 1107 semid = IPCID_TO_IX(semid); /* Convert back to zero origin */
1c79356b 1108
91447636
A
1109 if (semid < 0 || semid >= seminfo.semmni) {
1110 eval = EINVAL;
1111 goto semopout;
1112 }
1c79356b 1113
2d21ac55
A
1114 semakptr = &sema[semid];
1115 if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0) {
91447636
A
1116 eval = EINVAL;
1117 goto semopout;
1118 }
2d21ac55 1119 if (semakptr->u.sem_perm._seq != IPCID_TO_SEQ(uap->semid)) {
91447636
A
1120 eval = EINVAL;
1121 goto semopout;
1122 }
1c79356b 1123
2d21ac55 1124 if ((eval = ipcperm(kauth_cred_get(), &semakptr->u.sem_perm, IPC_W))) {
1c79356b
A
1125#ifdef SEM_DEBUG
1126 printf("eval = %d from ipaccess\n", eval);
1127#endif
91447636 1128 goto semopout;
1c79356b
A
1129 }
1130
316670eb 1131 if (nsops < 0 || nsops > seminfo.semopm) {
cf7d32b8 1132#ifdef SEM_DEBUG
316670eb
A
1133 printf("too many sops (max=%d, nsops=%d)\n",
1134 seminfo.semopm, nsops);
cf7d32b8
A
1135#endif
1136 eval = E2BIG;
1137 goto semopout;
1138 }
0a7de745 1139
6d2010ae
A
1140 /* OK for LP64, since sizeof(struct sembuf) is currently invariant */
1141 if ((eval = copyin(uap->sops, &sops, nsops * sizeof(struct sembuf))) != 0) {
1142#ifdef SEM_DEBUG
1143 printf("eval = %d from copyin(%08x, %08x, %ld)\n", eval,
1144 uap->sops, &sops, nsops * sizeof(struct sembuf));
1145#endif
1146 goto semopout;
1147 }
1148
2d21ac55
A
1149#if CONFIG_MACF
1150 /*
1151 * Initial pass thru sops to see what permissions are needed.
1152 */
0a7de745
A
1153 j = 0; /* permission needed */
1154 for (i = 0; i < nsops; i++) {
2d21ac55 1155 j |= (sops[i].sem_op == 0) ? SEM_R : SEM_A;
0a7de745 1156 }
2d21ac55
A
1157
1158 /*
1159 * The MAC hook checks whether the thread has read (and possibly
1160 * write) permissions to the semaphore array based on the
1161 * sopptr->sem_op value.
1162 */
1163 eval = mac_sysvsem_check_semop(kauth_cred_get(), semakptr, j);
0a7de745 1164 if (eval) {
2d21ac55 1165 goto semopout;
0a7de745 1166 }
2d21ac55
A
1167#endif
1168
1c79356b
A
1169 /*
1170 * Loop trying to satisfy the vector of requests.
1171 * If we reach a point where we must wait, any requests already
1172 * performed are rolled back and we go to sleep until some other
1173 * process wakes us up. At this point, we start all over again.
1174 *
1175 * This ensures that from the perspective of other tasks, a set
1176 * of requests is atomic (never partially satisfied).
1177 */
1178 do_undos = 0;
1179
1180 for (;;) {
1181 do_wakeup = 0;
1182
1183 for (i = 0; i < nsops; i++) {
1184 sopptr = &sops[i];
1185
2d21ac55 1186 if (sopptr->sem_num >= semakptr->u.sem_nsems) {
91447636
A
1187 eval = EFBIG;
1188 goto semopout;
1189 }
1c79356b 1190
2d21ac55 1191 semptr = &semakptr->u.sem_base[sopptr->sem_num];
1c79356b
A
1192
1193#ifdef SEM_DEBUG
2d21ac55
A
1194 printf("semop: semakptr=%x, sem_base=%x, semptr=%x, sem[%d]=%d : op=%d, flag=%s\n",
1195 semakptr, semakptr->u.sem_base, semptr,
1c79356b
A
1196 sopptr->sem_num, semptr->semval, sopptr->sem_op,
1197 (sopptr->sem_flg & IPC_NOWAIT) ? "nowait" : "wait");
1198#endif
1199
1200 if (sopptr->sem_op < 0) {
1201 if (semptr->semval + sopptr->sem_op < 0) {
1202#ifdef SEM_DEBUG
1203 printf("semop: can't do it now\n");
1204#endif
1205 break;
1206 } else {
1207 semptr->semval += sopptr->sem_op;
1208 if (semptr->semval == 0 &&
0a7de745 1209 semptr->semzcnt > 0) {
1c79356b 1210 do_wakeup = 1;
0a7de745 1211 }
1c79356b 1212 }
0a7de745 1213 if (sopptr->sem_flg & SEM_UNDO) {
1c79356b 1214 do_undos = 1;
0a7de745 1215 }
1c79356b
A
1216 } else if (sopptr->sem_op == 0) {
1217 if (semptr->semval > 0) {
1218#ifdef SEM_DEBUG
1219 printf("semop: not zero now\n");
1220#endif
1221 break;
1222 }
1223 } else {
0a7de745 1224 if (semptr->semncnt > 0) {
1c79356b 1225 do_wakeup = 1;
0a7de745 1226 }
1c79356b 1227 semptr->semval += sopptr->sem_op;
0a7de745 1228 if (sopptr->sem_flg & SEM_UNDO) {
1c79356b 1229 do_undos = 1;
0a7de745 1230 }
1c79356b
A
1231 }
1232 }
1233
1234 /*
1235 * Did we get through the entire vector?
1236 */
0a7de745 1237 if (i >= nsops) {
1c79356b 1238 goto done;
0a7de745 1239 }
1c79356b
A
1240
1241 /*
1242 * No ... rollback anything that we've already done
1243 */
1244#ifdef SEM_DEBUG
0a7de745 1245 printf("semop: rollback 0 through %d\n", i - 1);
1c79356b 1246#endif
0a7de745 1247 for (j = 0; j < i; j++) {
2d21ac55 1248 semakptr->u.sem_base[sops[j].sem_num].semval -=
1c79356b 1249 sops[j].sem_op;
0a7de745 1250 }
1c79356b
A
1251
1252 /*
1253 * If the request that we couldn't satisfy has the
1254 * NOWAIT flag set then return with EAGAIN.
1255 */
91447636
A
1256 if (sopptr->sem_flg & IPC_NOWAIT) {
1257 eval = EAGAIN;
1258 goto semopout;
1259 }
1c79356b 1260
0a7de745 1261 if (sopptr->sem_op == 0) {
1c79356b 1262 semptr->semzcnt++;
0a7de745 1263 } else {
1c79356b 1264 semptr->semncnt++;
0a7de745 1265 }
1c79356b
A
1266
1267#ifdef SEM_DEBUG
1268 printf("semop: good night!\n");
1269#endif
9bccf70c
A
1270 /* Release our lock on the semaphore subsystem so
1271 * another thread can get at the semaphore we are
1272 * waiting for. We will get the lock back after we
1273 * wake up.
1274 */
0a7de745 1275 eval = msleep((caddr_t)semakptr, &sysv_sem_subsys_mutex, (PZERO - 4) | PCATCH,
1c79356b 1276 "semwait", 0);
0a7de745 1277
1c79356b
A
1278#ifdef SEM_DEBUG
1279 printf("semop: good morning (eval=%d)!\n", eval);
1280#endif
91447636 1281 if (eval != 0) {
91447636 1282 eval = EINTR;
91447636 1283 }
1c79356b 1284
3a60a9f5
A
1285 /*
1286 * IMPORTANT: while we were asleep, the semaphore array might
1287 * have been reallocated somewhere else (see grow_sema_array()).
0a7de745 1288 * When we wake up, we have to re-lookup the semaphore
3a60a9f5
A
1289 * structures and re-validate them.
1290 */
1291
2d21ac55 1292 semptr = NULL;
9bccf70c 1293
1c79356b
A
1294 /*
1295 * Make sure that the semaphore still exists
2d21ac55
A
1296 *
1297 * XXX POSIX: Third test this 'if' and 'EINTR' precedence may
1298 * fail testing; if so, we will need to revert this code.
1c79356b 1299 */
0a7de745 1300 semakptr = &sema[semid]; /* sema may have been reallocated */
2d21ac55
A
1301 if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 ||
1302 semakptr->u.sem_perm._seq != IPCID_TO_SEQ(uap->semid) ||
1303 sopptr->sem_num >= semakptr->u.sem_nsems) {
1304 /* The man page says to return EIDRM. */
1305 /* Unfortunately, BSD doesn't define that code! */
3a60a9f5
A
1306 if (eval == EINTR) {
1307 /*
1308 * EINTR takes precedence over the fact that
1309 * the semaphore disappeared while we were
1310 * sleeping...
1311 */
1312 } else {
1c79356b 1313#ifdef EIDRM
3a60a9f5 1314 eval = EIDRM;
1c79356b 1315#else
0a7de745 1316 eval = EINVAL; /* Ancient past */
1c79356b 1317#endif
3a60a9f5
A
1318 }
1319 goto semopout;
1c79356b
A
1320 }
1321
1322 /*
1323 * The semaphore is still alive. Readjust the count of
9bccf70c
A
1324 * waiting processes. semptr needs to be recomputed
1325 * because the sem[] may have been reallocated while
1326 * we were sleeping, updating our sem_base pointer.
1c79356b 1327 */
2d21ac55 1328 semptr = &semakptr->u.sem_base[sopptr->sem_num];
0a7de745 1329 if (sopptr->sem_op == 0) {
1c79356b 1330 semptr->semzcnt--;
0a7de745 1331 } else {
1c79356b 1332 semptr->semncnt--;
0a7de745 1333 }
3a60a9f5
A
1334
1335 if (eval != 0) { /* EINTR */
1336 goto semopout;
1337 }
1c79356b
A
1338 }
1339
1340done:
1341 /*
1342 * Process any SEM_UNDO requests.
1343 */
1344 if (do_undos) {
1345 for (i = 0; i < nsops; i++) {
1346 /*
1347 * We only need to deal with SEM_UNDO's for non-zero
1348 * op's.
1349 */
1350 int adjval;
1351
0a7de745 1352 if ((sops[i].sem_flg & SEM_UNDO) == 0) {
1c79356b 1353 continue;
0a7de745 1354 }
1c79356b 1355 adjval = sops[i].sem_op;
0a7de745 1356 if (adjval == 0) {
1c79356b 1357 continue;
0a7de745 1358 }
2d21ac55 1359 eval = semundo_adjust(p, &supidx, semid,
1c79356b 1360 sops[i].sem_num, -adjval);
0a7de745 1361 if (eval == 0) {
1c79356b 1362 continue;
0a7de745 1363 }
1c79356b
A
1364
1365 /*
1366 * Oh-Oh! We ran out of either sem_undo's or undo's.
1367 * Rollback the adjustments to this point and then
1368 * rollback the semaphore ups and down so we can return
1369 * with an error with all structures restored. We
1370 * rollback the undo's in the exact reverse order that
1371 * we applied them. This guarantees that we won't run
1372 * out of space as we roll things back out.
1373 */
1374 for (j = i - 1; j >= 0; j--) {
0a7de745 1375 if ((sops[j].sem_flg & SEM_UNDO) == 0) {
1c79356b 1376 continue;
0a7de745 1377 }
1c79356b 1378 adjval = sops[j].sem_op;
0a7de745 1379 if (adjval == 0) {
1c79356b 1380 continue;
0a7de745 1381 }
2d21ac55 1382 if (semundo_adjust(p, &supidx, semid,
0a7de745 1383 sops[j].sem_num, adjval) != 0) {
1c79356b 1384 panic("semop - can't undo undos");
0a7de745 1385 }
1c79356b
A
1386 }
1387
0a7de745 1388 for (j = 0; j < nsops; j++) {
2d21ac55 1389 semakptr->u.sem_base[sops[j].sem_num].semval -=
1c79356b 1390 sops[j].sem_op;
0a7de745 1391 }
1c79356b
A
1392
1393#ifdef SEM_DEBUG
1394 printf("eval = %d from semundo_adjust\n", eval);
1395#endif
91447636 1396 goto semopout;
1c79356b
A
1397 } /* loop through the sops */
1398 } /* if (do_undos) */
1399
1400 /* We're definitely done - set the sempid's */
1401 for (i = 0; i < nsops; i++) {
1402 sopptr = &sops[i];
2d21ac55 1403 semptr = &semakptr->u.sem_base[sopptr->sem_num];
1c79356b
A
1404 semptr->sempid = p->p_pid;
1405 }
2d21ac55 1406 semakptr->u.sem_otime = sysv_semtime();
1c79356b 1407
1c79356b
A
1408 if (do_wakeup) {
1409#ifdef SEM_DEBUG
1410 printf("semop: doing wakeup\n");
1411#ifdef SEM_WAKEUP
2d21ac55 1412 sem_wakeup((caddr_t)semakptr);
1c79356b 1413#else
2d21ac55 1414 wakeup((caddr_t)semakptr);
1c79356b
A
1415#endif
1416 printf("semop: back from wakeup\n");
1417#else
2d21ac55 1418 wakeup((caddr_t)semakptr);
1c79356b
A
1419#endif
1420 }
1421#ifdef SEM_DEBUG
1422 printf("semop: done\n");
1423#endif
9bccf70c 1424 *retval = 0;
91447636
A
1425 eval = 0;
1426semopout:
1427 SYSV_SEM_SUBSYS_UNLOCK();
0a7de745 1428 return eval;
1c79356b
A
1429}
1430
1431/*
1432 * Go through the undo structures for this process and apply the adjustments to
1433 * semaphores.
1434 */
1435void
91447636 1436semexit(struct proc *p)
1c79356b 1437{
39037602 1438 struct sem_undo *suptr = NULL;
2d21ac55
A
1439 int suidx;
1440 int *supidx;
1c79356b
A
1441 int did_something;
1442
9bccf70c
A
1443 /* If we have not allocated our semaphores yet there can't be
1444 * anything to undo, but we need the lock to prevent
1445 * dynamic memory race conditions.
1c79356b 1446 */
91447636
A
1447 SYSV_SEM_SUBSYS_LOCK();
1448
0a7de745 1449 if (!sem_pool) {
91447636 1450 SYSV_SEM_SUBSYS_UNLOCK();
9bccf70c 1451 return;
1c79356b 1452 }
1c79356b
A
1453 did_something = 0;
1454
1455 /*
1456 * Go through the chain of undo vectors looking for one
1457 * associated with this process.
1458 */
1459
2d21ac55
A
1460 for (supidx = &semu_list_idx; (suidx = *supidx) != -1;
1461 supidx = &suptr->un_next_idx) {
1462 suptr = SEMU(suidx);
0a7de745 1463 if (suptr->un_proc == p) {
1c79356b 1464 break;
0a7de745 1465 }
1c79356b
A
1466 }
1467
0a7de745 1468 if (suidx == -1) {
1c79356b 1469 goto unlock;
0a7de745 1470 }
1c79356b
A
1471
1472#ifdef SEM_DEBUG
1473 printf("proc @%08x has undo structure with %d entries\n", p,
1474 suptr->un_cnt);
1475#endif
1476
1477 /*
1478 * If there are any active undo elements then process them.
1479 */
1480 if (suptr->un_cnt > 0) {
91447636
A
1481 while (suptr->un_ent != NULL) {
1482 struct undo *sueptr;
1483 int semid;
1484 int semnum;
1485 int adjval;
2d21ac55 1486 struct semid_kernel *semakptr;
1c79356b 1487
91447636
A
1488 sueptr = suptr->un_ent;
1489 semid = sueptr->une_id;
1490 semnum = sueptr->une_num;
1491 adjval = sueptr->une_adjval;
1c79356b 1492
2d21ac55 1493 semakptr = &sema[semid];
0a7de745 1494 if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0) {
1c79356b 1495 panic("semexit - semid not allocated");
0a7de745
A
1496 }
1497 if (semnum >= semakptr->u.sem_nsems) {
1c79356b 1498 panic("semexit - semnum out of range");
0a7de745 1499 }
1c79356b
A
1500
1501#ifdef SEM_DEBUG
1502 printf("semexit: %08x id=%d num=%d(adj=%d) ; sem=%d\n",
0a7de745
A
1503 suptr->un_proc,
1504 semid,
1505 semnum,
1506 adjval,
1507 semakptr->u.sem_base[semnum].semval);
1c79356b
A
1508#endif
1509
1510 if (adjval < 0) {
0a7de745 1511 if (semakptr->u.sem_base[semnum].semval < -adjval) {
2d21ac55 1512 semakptr->u.sem_base[semnum].semval = 0;
0a7de745 1513 } else {
2d21ac55 1514 semakptr->u.sem_base[semnum].semval +=
1c79356b 1515 adjval;
0a7de745
A
1516 }
1517 } else {
2d21ac55 1518 semakptr->u.sem_base[semnum].semval += adjval;
0a7de745 1519 }
1c79356b 1520
0a7de745
A
1521 /* Maybe we should build a list of semakptr's to wake
1522 * up, finish all access to data structures, release the
1523 * subsystem lock, and wake all the processes. Something
1524 * to think about.
1525 */
1c79356b 1526#ifdef SEM_WAKEUP
2d21ac55 1527 sem_wakeup((caddr_t)semakptr);
1c79356b 1528#else
2d21ac55 1529 wakeup((caddr_t)semakptr);
1c79356b
A
1530#endif
1531#ifdef SEM_DEBUG
1532 printf("semexit: back from wakeup\n");
1533#endif
91447636
A
1534 suptr->un_cnt--;
1535 suptr->un_ent = sueptr->une_next;
1536 FREE(sueptr, M_SYSVSEM);
1537 sueptr = NULL;
1c79356b
A
1538 }
1539 }
1540
1541 /*
1542 * Deallocate the undo vector.
1543 */
1544#ifdef SEM_DEBUG
1545 printf("removing vector\n");
1546#endif
1547 suptr->un_proc = NULL;
2d21ac55 1548 *supidx = suptr->un_next_idx;
1c79356b
A
1549
1550unlock:
1551 /*
0a7de745
A
1552 * There is a semaphore leak (i.e. memory leak) in this code.
1553 * We should be deleting the IPC_PRIVATE semaphores when they are
1554 * no longer needed, and we dont. We would have to track which processes
1555 * know about which IPC_PRIVATE semaphores, updating the list after
1556 * every fork. We can't just delete them semaphore when the process
1557 * that created it dies, because that process may well have forked
1558 * some children. So we need to wait until all of it's children have
1559 * died, and so on. Maybe we should tag each IPC_PRIVATE sempahore
1560 * with the creating group ID, count the number of processes left in
1561 * that group, and delete the semaphore when the group is gone.
1562 * Until that code gets implemented we will leak IPC_PRIVATE semaphores.
1563 * There is an upper bound on the size of our semaphore array, so
1564 * leaking the semaphores should not work as a DOS attack.
1565 *
1566 * Please note that the original BSD code this file is based on had the
1567 * same leaky semaphore problem.
1568 */
9bccf70c 1569
91447636 1570 SYSV_SEM_SUBSYS_UNLOCK();
1c79356b 1571}
91447636
A
1572
1573
55e303ae 1574/* (struct sysctl_oid *oidp, void *arg1, int arg2, \
0a7de745 1575 * struct sysctl_req *req) */
55e303ae 1576static int
91447636 1577sysctl_seminfo(__unused struct sysctl_oid *oidp, void *arg1,
0a7de745 1578 __unused int arg2, struct sysctl_req *req)
55e303ae
A
1579{
1580 int error = 0;
1581
1582 error = SYSCTL_OUT(req, arg1, sizeof(int));
0a7de745
A
1583 if (error || req->newptr == USER_ADDR_NULL) {
1584 return error;
1585 }
55e303ae 1586
91447636
A
1587 SYSV_SEM_SUBSYS_LOCK();
1588
55e303ae 1589 /* Set the values only if shared memory is not initialised */
0a7de745
A
1590 if ((sem_pool == NULL) &&
1591 (sema == NULL) &&
1592 (semu == NULL) &&
1593 (semu_list_idx == -1)) {
1594 if ((error = SYSCTL_IN(req, arg1, sizeof(int)))) {
1595 goto out;
1596 }
1597 } else {
55e303ae 1598 error = EINVAL;
0a7de745 1599 }
55e303ae 1600out:
91447636 1601 SYSV_SEM_SUBSYS_UNLOCK();
0a7de745 1602 return error;
55e303ae
A
1603}
1604
1605/* SYSCTL_NODE(_kern, KERN_SYSV, sysv, CTLFLAG_RW, 0, "SYSV"); */
1606extern struct sysctl_oid_list sysctl__kern_sysv_children;
6d2010ae 1607SYSCTL_PROC(_kern_sysv, OID_AUTO, semmni, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
0a7de745 1608 &limitseminfo.semmni, 0, &sysctl_seminfo, "I", "semmni");
55e303ae 1609
6d2010ae 1610SYSCTL_PROC(_kern_sysv, OID_AUTO, semmns, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
0a7de745 1611 &limitseminfo.semmns, 0, &sysctl_seminfo, "I", "semmns");
55e303ae 1612
6d2010ae 1613SYSCTL_PROC(_kern_sysv, OID_AUTO, semmnu, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
0a7de745 1614 &limitseminfo.semmnu, 0, &sysctl_seminfo, "I", "semmnu");
55e303ae 1615
6d2010ae 1616SYSCTL_PROC(_kern_sysv, OID_AUTO, semmsl, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
0a7de745
A
1617 &limitseminfo.semmsl, 0, &sysctl_seminfo, "I", "semmsl");
1618
6d2010ae 1619SYSCTL_PROC(_kern_sysv, OID_AUTO, semume, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
0a7de745 1620 &limitseminfo.semume, 0, &sysctl_seminfo, "I", "semume");
55e303ae 1621
9bccf70c 1622
91447636
A
1623static int
1624IPCS_sem_sysctl(__unused struct sysctl_oid *oidp, __unused void *arg1,
0a7de745 1625 __unused int arg2, struct sysctl_req *req)
91447636
A
1626{
1627 int error;
1628 int cursor;
1629 union {
b0d623f7 1630 struct user32_IPCS_command u32;
91447636
A
1631 struct user_IPCS_command u64;
1632 } ipcs;
0a7de745
A
1633 struct user32_semid_ds semid_ds32; /* post conversion, 32 bit version */
1634 struct user64_semid_ds semid_ds64; /* post conversion, 64 bit version */
91447636 1635 void *semid_dsp;
b0d623f7
A
1636 size_t ipcs_sz;
1637 size_t semid_ds_sz;
91447636
A
1638 struct proc *p = current_proc();
1639
b0d623f7
A
1640 if (IS_64BIT_PROCESS(p)) {
1641 ipcs_sz = sizeof(struct user_IPCS_command);
1642 semid_ds_sz = sizeof(struct user64_semid_ds);
1643 } else {
1644 ipcs_sz = sizeof(struct user32_IPCS_command);
1645 semid_ds_sz = sizeof(struct user32_semid_ds);
2d21ac55
A
1646 }
1647
91447636
A
1648 /* Copy in the command structure */
1649 if ((error = SYSCTL_IN(req, &ipcs, ipcs_sz)) != 0) {
0a7de745 1650 return error;
91447636
A
1651 }
1652
0a7de745 1653 if (!IS_64BIT_PROCESS(p)) { /* convert in place */
2d21ac55 1654 ipcs.u64.ipcs_data = CAST_USER_ADDR_T(ipcs.u32.ipcs_data);
0a7de745 1655 }
91447636
A
1656
1657 /* Let us version this interface... */
1658 if (ipcs.u64.ipcs_magic != IPCS_MAGIC) {
0a7de745 1659 return EINVAL;
91447636
A
1660 }
1661
1662 SYSV_SEM_SUBSYS_LOCK();
0a7de745
A
1663 switch (ipcs.u64.ipcs_op) {
1664 case IPCS_SEM_CONF: /* Obtain global configuration data */
91447636
A
1665 if (ipcs.u64.ipcs_datalen != sizeof(struct seminfo)) {
1666 error = ERANGE;
1667 break;
1668 }
0a7de745 1669 if (ipcs.u64.ipcs_cursor != 0) { /* fwd. compat. */
91447636
A
1670 error = EINVAL;
1671 break;
1672 }
91447636 1673 error = copyout(&seminfo, ipcs.u64.ipcs_data, ipcs.u64.ipcs_datalen);
91447636
A
1674 break;
1675
0a7de745 1676 case IPCS_SEM_ITER: /* Iterate over existing segments */
91447636
A
1677 cursor = ipcs.u64.ipcs_cursor;
1678 if (cursor < 0 || cursor >= seminfo.semmni) {
1679 error = ERANGE;
1680 break;
1681 }
0a7de745 1682 if (ipcs.u64.ipcs_datalen != (int)semid_ds_sz) {
91447636
A
1683 error = EINVAL;
1684 break;
1685 }
0a7de745
A
1686 for (; cursor < seminfo.semmni; cursor++) {
1687 if (sema[cursor].u.sem_perm.mode & SEM_ALLOC) {
91447636 1688 break;
0a7de745 1689 }
91447636
A
1690 continue;
1691 }
1692 if (cursor == seminfo.semmni) {
1693 error = ENOENT;
1694 break;
1695 }
1696
0a7de745 1697 semid_dsp = &sema[cursor].u; /* default: 64 bit */
91447636
A
1698
1699 /*
1700 * If necessary, convert the 64 bit kernel segment
1701 * descriptor to a 32 bit user one.
1702 */
1703 if (!IS_64BIT_PROCESS(p)) {
39236c6e 1704 bzero(&semid_ds32, sizeof(semid_ds32));
b0d623f7 1705 semid_ds_kernelto32(semid_dsp, &semid_ds32);
91447636 1706 semid_dsp = &semid_ds32;
b0d623f7 1707 } else {
39236c6e 1708 bzero(&semid_ds64, sizeof(semid_ds64));
b0d623f7
A
1709 semid_ds_kernelto64(semid_dsp, &semid_ds64);
1710 semid_dsp = &semid_ds64;
91447636 1711 }
b0d623f7 1712
91447636
A
1713 error = copyout(semid_dsp, ipcs.u64.ipcs_data, ipcs.u64.ipcs_datalen);
1714 if (!error) {
1715 /* update cursor */
1716 ipcs.u64.ipcs_cursor = cursor + 1;
b0d623f7 1717
0a7de745
A
1718 if (!IS_64BIT_PROCESS(p)) { /* convert in place */
1719 ipcs.u32.ipcs_data = CAST_DOWN_EXPLICIT(user32_addr_t, ipcs.u64.ipcs_data);
1720 }
b0d623f7 1721
91447636
A
1722 error = SYSCTL_OUT(req, &ipcs, ipcs_sz);
1723 }
91447636
A
1724 break;
1725
1726 default:
1727 error = EINVAL;
1728 break;
1729 }
1730 SYSV_SEM_SUBSYS_UNLOCK();
0a7de745 1731 return error;
91447636
A
1732}
1733
1734SYSCTL_DECL(_kern_sysv_ipcs);
6d2010ae 1735SYSCTL_PROC(_kern_sysv_ipcs, OID_AUTO, sem, CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED,
0a7de745
A
1736 0, 0, IPCS_sem_sysctl,
1737 "S,IPCS_sem_command",
1738 "ipcs sem command interface");
2d21ac55
A
1739
1740#endif /* SYSV_SEM */