2 * Copyright (c) 2000-2019 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 * Implementation of SVID semaphores
31 * Author: Daniel Boulet
33 * This software is provided ``AS IS'' without any warranties of any kind.
36 * John Bellardo modified the implementation for Darwin. 12/2000
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,
43 * Copyright (c) 2005-2006 SPARTA, Inc.
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/kernel.h>
49 #include <sys/proc_internal.h>
50 #include <sys/kauth.h>
51 #include <sys/sem_internal.h>
52 #include <sys/malloc.h>
53 #include <mach/mach_types.h>
55 #include <sys/filedesc.h>
56 #include <sys/file_internal.h>
57 #include <sys/sysctl.h>
59 #include <sys/sysent.h>
60 #include <sys/sysproto.h>
62 #include <security/mac_framework.h>
65 #include <security/audit/audit.h>
70 /* Uncomment this line to see the debugging output */
71 /* #define SEM_DEBUG */
73 /* Uncomment this line to see MAC debugging output. */
74 /* #define MAC_DEBUG */
76 #define MPRINTF(a) printf(a)
81 #define M_SYSVSEM M_TEMP
84 /* Hard system limits to avoid resource starvation / DOS attacks.
85 * These are not needed if we can make the semaphore pages swappable.
87 static struct seminfo limitseminfo
= {
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 */
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.
104 struct seminfo seminfo
= {
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 */
118 static int semu_alloc(struct proc
*p
);
119 static int semundo_adjust(struct proc
*p
, int *supidx
,
120 int semid
, int semnum
, int adjval
);
121 static void semundo_clear(int semid
, int semnum
);
123 /* XXX casting to (sy_call_t *) is bogus, as usual. */
124 static sy_call_t
* const semcalls
[] = {
125 (sy_call_t
*)semctl
, (sy_call_t
*)semget
,
129 static int semtot
= 0; /* # of used semaphores */
130 struct semid_kernel
*sema
= NULL
; /* semaphore id pool */
131 struct sem
*sem_pool
= NULL
; /* semaphore pool */
132 static int semu_list_idx
= -1; /* active undo structures */
133 struct sem_undo
*semu
= NULL
; /* semaphore undo pool */
136 void sysv_sem_lock_init(void);
137 static lck_grp_t
*sysv_sem_subsys_lck_grp
;
138 static lck_grp_attr_t
*sysv_sem_subsys_lck_grp_attr
;
139 static lck_attr_t
*sysv_sem_subsys_lck_attr
;
140 static lck_mtx_t sysv_sem_subsys_mutex
;
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)
146 __private_extern__
void
147 sysv_sem_lock_init( void )
149 sysv_sem_subsys_lck_grp_attr
= lck_grp_attr_alloc_init();
151 sysv_sem_subsys_lck_grp
= lck_grp_alloc_init("sysv_sem_subsys_lock", sysv_sem_subsys_lck_grp_attr
);
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
);
157 static __inline__ user_time_t
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.
170 * pad field contents are not moved correspondingly; contents will be lost
172 * NOTE: Source and target may *NOT* overlap! (target is smaller)
175 semid_ds_kernelto32(struct user_semid_ds
*in
, struct user32_semid_ds
*out
)
177 out
->sem_perm
= in
->sem_perm
;
178 out
->sem_base
= CAST_DOWN_EXPLICIT(__int32_t
, in
->sem_base
);
179 out
->sem_nsems
= in
->sem_nsems
;
180 out
->sem_otime
= in
->sem_otime
; /* XXX loses precision */
181 out
->sem_ctime
= in
->sem_ctime
; /* XXX loses precision */
185 semid_ds_kernelto64(struct user_semid_ds
*in
, struct user64_semid_ds
*out
)
187 out
->sem_perm
= in
->sem_perm
;
188 out
->sem_base
= CAST_DOWN_EXPLICIT(__int32_t
, in
->sem_base
);
189 out
->sem_nsems
= in
->sem_nsems
;
190 out
->sem_otime
= in
->sem_otime
; /* XXX loses precision */
191 out
->sem_ctime
= in
->sem_ctime
; /* XXX loses precision */
195 * pad field contents are not moved correspondingly; contents will be lost
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
201 * XXX use CAST_USER_ADDR_T() for lack of a CAST_USER_TIME_T(); net effect
205 semid_ds_32tokernel(struct user32_semid_ds
*in
, struct user_semid_ds
*out
)
207 out
->sem_ctime
= in
->sem_ctime
;
208 out
->sem_otime
= in
->sem_otime
;
209 out
->sem_nsems
= in
->sem_nsems
;
210 out
->sem_base
= (void *)(uintptr_t)in
->sem_base
;
211 out
->sem_perm
= in
->sem_perm
;
215 semid_ds_64tokernel(struct user64_semid_ds
*in
, struct user_semid_ds
*out
)
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
;
221 out
->sem_perm
= in
->sem_perm
;
228 * Entry point for all SEM calls: semctl, semget, semop
230 * Parameters: p Process requesting the call
231 * uap User argument descriptor (see below)
232 * retval Return value of the selected sem call
234 * Indirect parameters: uap->which sem call to invoke (index in array of sem calls)
235 * uap->a2 User argument descriptor
240 * Implicit returns: retval Return value of the selected sem call
242 * DEPRECATED: This interface should not be used to call the other SEM
243 * functions (semctl, semget, semop). The correct usage is
244 * to call the other SEM functions directly.
248 semsys(struct proc
*p
, struct semsys_args
*uap
, int32_t *retval
)
250 /* The individual calls handling the locking now */
252 if (uap
->which
>= sizeof(semcalls
) / sizeof(semcalls
[0])) {
255 return (*semcalls
[uap
->which
])(p
, &uap
->a2
, retval
);
259 * Expand the semu array to the given capacity. If the expansion fails
260 * return 0, otherwise return 1.
262 * Assumes we already have the subsystem lock.
265 grow_semu_array(int newSize
)
268 struct sem_undo
*newSemu
;
270 if (newSize
<= seminfo
.semmnu
) {
273 if (newSize
> limitseminfo
.semmnu
) { /* enforce hard limit */
275 printf("undo structure hard limit of %d reached, requested %d\n",
276 limitseminfo
.semmnu
, newSize
);
280 newSize
= (newSize
/ SEMMNU_INC
+ 1) * SEMMNU_INC
;
281 newSize
= newSize
> limitseminfo
.semmnu
? limitseminfo
.semmnu
: newSize
;
284 printf("growing semu[] from %d to %d\n", seminfo
.semmnu
, newSize
);
286 MALLOC(newSemu
, struct sem_undo
*, sizeof(struct sem_undo
) * newSize
,
287 M_SYSVSEM
, M_WAITOK
| M_ZERO
);
288 if (NULL
== newSemu
) {
290 printf("allocation failed. no changes made.\n");
295 /* copy the old data to the new array */
296 for (i
= 0; i
< seminfo
.semmnu
; i
++) {
297 newSemu
[i
] = semu
[i
];
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".
305 /* Clean up the old array */
307 FREE(semu
, M_SYSVSEM
);
311 seminfo
.semmnu
= newSize
;
313 printf("expansion successful\n");
319 * Expand the sema array to the given capacity. If the expansion fails
320 * we return 0, otherwise we return 1.
322 * Assumes we already have the subsystem lock.
325 grow_sema_array(int newSize
)
327 struct semid_kernel
*newSema
;
330 if (newSize
<= seminfo
.semmni
) {
333 if (newSize
> limitseminfo
.semmni
) { /* enforce hard limit */
335 printf("identifier hard limit of %d reached, requested %d\n",
336 limitseminfo
.semmni
, newSize
);
340 newSize
= (newSize
/ SEMMNI_INC
+ 1) * SEMMNI_INC
;
341 newSize
= newSize
> limitseminfo
.semmni
? limitseminfo
.semmni
: newSize
;
344 printf("growing sema[] from %d to %d\n", seminfo
.semmni
, newSize
);
346 MALLOC(newSema
, struct semid_kernel
*,
347 sizeof(struct semid_kernel
) * newSize
,
348 M_SYSVSEM
, M_WAITOK
| M_ZERO
);
349 if (NULL
== newSema
) {
351 printf("allocation failed. no changes made.\n");
356 /* copy over the old ids */
357 for (i
= 0; i
< seminfo
.semmni
; i
++) {
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
365 * sleep on the correct, reallocated semid_kernel pointer.
367 if (sema
[i
].u
.sem_perm
.mode
& SEM_ALLOC
) {
368 wakeup((caddr_t
)&sema
[i
]);
373 for (i
= seminfo
.semmni
; i
< newSize
; i
++) {
374 mac_sysvsem_label_init(&newSema
[i
]);
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".
384 /* Clean up the old array */
386 FREE(sema
, M_SYSVSEM
);
390 seminfo
.semmni
= newSize
;
392 printf("expansion successful\n");
398 * Expand the sem_pool array to the given capacity. If the expansion fails
399 * we return 0 (fail), otherwise we return 1 (success).
401 * Assumes we already hold the subsystem lock.
404 grow_sem_pool(int new_pool_size
)
406 struct sem
*new_sem_pool
= NULL
;
407 struct sem
*sem_free
;
410 if (new_pool_size
< semtot
) {
413 /* enforce hard limit */
414 if (new_pool_size
> limitseminfo
.semmns
) {
416 printf("semaphore hard limit of %d reached, requested %d\n",
417 limitseminfo
.semmns
, new_pool_size
);
422 new_pool_size
= (new_pool_size
/ SEMMNS_INC
+ 1) * SEMMNS_INC
;
423 new_pool_size
= new_pool_size
> limitseminfo
.semmns
? limitseminfo
.semmns
: new_pool_size
;
426 printf("growing sem_pool array from %d to %d\n", seminfo
.semmns
, new_pool_size
);
428 MALLOC(new_sem_pool
, struct sem
*, sizeof(struct sem
) * new_pool_size
,
429 M_SYSVSEM
, M_WAITOK
| M_ZERO
| M_NULL
);
430 if (NULL
== new_sem_pool
) {
432 printf("allocation failed. no changes made.\n");
437 /* We have our new memory, now copy the old contents over */
439 for (i
= 0; i
< seminfo
.semmns
; i
++) {
440 new_sem_pool
[i
] = sem_pool
[i
];
444 /* Update our id structures to point to the new semaphores */
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
);
453 sem_pool
= new_sem_pool
;
455 /* clean up the old array */
456 if (sem_free
!= NULL
) {
457 FREE(sem_free
, M_SYSVSEM
);
460 seminfo
.semmns
= new_pool_size
;
462 printf("expansion complete\n");
468 * Allocate a new sem_undo structure for a process
469 * (returns ptr to structure or NULL if no more room)
471 * Assumes we already hold the subsystem lock.
475 semu_alloc(struct proc
*p
)
478 struct sem_undo
*suptr
;
483 * Try twice to allocate something.
484 * (we'll purge any empty structures after the first pass so
485 * two passes are always enough)
488 for (attempt
= 0; attempt
< 2; attempt
++) {
490 * Look for a free structure.
491 * Fill it in and return it if we find one.
494 for (i
= 0; i
< seminfo
.semmnu
; i
++) {
496 if (suptr
->un_proc
== NULL
) {
497 suptr
->un_next_idx
= semu_list_idx
;
500 suptr
->un_ent
= NULL
;
507 * We didn't find a free one, if this is the first attempt
508 * then try to free some structures.
512 /* All the structures are in use - try to free some */
513 int did_something
= 0;
515 supidx
= &semu_list_idx
;
516 while (*supidx
!= -1) {
517 suptr
= SEMU(*supidx
);
518 if (suptr
->un_cnt
== 0) {
519 suptr
->un_proc
= NULL
;
520 *supidx
= suptr
->un_next_idx
;
523 supidx
= &(suptr
->un_next_idx
);
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.
532 if (!did_something
) {
533 if (!grow_semu_array(seminfo
.semmnu
+ 1)) {
539 * The second pass failed even though we freed
540 * something after the first pass!
541 * This is IMPOSSIBLE!
543 panic("semu_alloc - second attempt failed");
550 * Adjust a particular entry for a particular proc
552 * Assumes we already hold the subsystem lock.
555 semundo_adjust(struct proc
*p
, int *supidx
, int semid
,
556 int semnum
, int adjval
)
558 struct sem_undo
*suptr
;
560 struct undo
*sueptr
, **suepptr
, *new_sueptr
;
564 * Look for and remember the sem_undo if the caller doesn't provide it
569 for (suidx
= semu_list_idx
; suidx
!= -1;
570 suidx
= suptr
->un_next_idx
) {
572 if (suptr
->un_proc
== p
) {
581 suidx
= semu_alloc(p
);
590 * Look for the requested entry and adjust it (delete if adjval becomes
595 for (i
= 0, suepptr
= &suptr
->un_ent
, sueptr
= suptr
->un_ent
;
597 i
++, suepptr
= &sueptr
->une_next
, sueptr
= sueptr
->une_next
) {
598 if (sueptr
->une_id
!= semid
|| sueptr
->une_num
!= semnum
) {
602 sueptr
->une_adjval
= 0;
604 sueptr
->une_adjval
+= adjval
;
606 if (sueptr
->une_adjval
== 0) {
608 *suepptr
= sueptr
->une_next
;
609 FREE(sueptr
, M_SYSVSEM
);
615 /* Didn't find the right entry - create it */
617 /* no adjustment: no need for a new entry */
621 if (suptr
->un_cnt
== limitseminfo
.semume
) {
622 /* reached the limit number of semaphore undo entries */
626 /* allocate a new semaphore undo entry */
627 MALLOC(new_sueptr
, struct undo
*, sizeof(struct undo
),
628 M_SYSVSEM
, M_WAITOK
);
629 if (new_sueptr
== NULL
) {
633 /* fill in the new semaphore undo entry */
634 new_sueptr
->une_next
= suptr
->un_ent
;
635 suptr
->un_ent
= new_sueptr
;
637 new_sueptr
->une_adjval
= adjval
;
638 new_sueptr
->une_id
= semid
;
639 new_sueptr
->une_num
= semnum
;
644 /* Assumes we already hold the subsystem lock.
647 semundo_clear(int semid
, int semnum
)
649 struct sem_undo
*suptr
;
652 for (suidx
= semu_list_idx
; suidx
!= -1; suidx
= suptr
->un_next_idx
) {
654 struct undo
**suepptr
;
658 sueptr
= suptr
->un_ent
;
659 suepptr
= &suptr
->un_ent
;
660 while (i
< suptr
->un_cnt
) {
661 if (sueptr
->une_id
== semid
) {
662 if (semnum
== -1 || sueptr
->une_num
== semnum
) {
664 *suepptr
= sueptr
->une_next
;
665 FREE(sueptr
, M_SYSVSEM
);
674 suepptr
= &sueptr
->une_next
;
675 sueptr
= sueptr
->une_next
;
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.
688 semctl(struct proc
*p
, struct semctl_args
*uap
, int32_t *retval
)
690 int semid
= uap
->semid
;
691 int semnum
= uap
->semnum
;
693 user_semun_t user_arg
= (user_semun_t
)uap
->arg
;
694 kauth_cred_t cred
= kauth_cred_get();
696 struct user_semid_ds sbuf
;
697 struct semid_kernel
*semakptr
;
700 AUDIT_ARG(svipc_cmd
, cmd
);
701 AUDIT_ARG(svipc_id
, semid
);
703 SYSV_SEM_SUBSYS_LOCK();
706 printf("call to semctl(%d, %d, %d, 0x%qx)\n", semid
, semnum
, cmd
, user_arg
);
709 semid
= IPCID_TO_IX(semid
);
711 if (semid
< 0 || semid
>= seminfo
.semmni
) {
713 printf("Invalid semid\n");
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
)) {
726 eval
= mac_sysvsem_check_semctl(cred
, semakptr
, cmd
);
737 if ((eval
= ipcperm(cred
, &semakptr
->u
.sem_perm
, IPC_M
))) {
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
;
744 for (i
= semakptr
->u
.sem_base
- sem_pool
; i
< semtot
; i
++) {
745 sem_pool
[i
] = sem_pool
[i
+ semakptr
->u
.sem_nsems
];
747 for (i
= 0; i
< seminfo
.semmni
; i
++) {
748 if ((sema
[i
].u
.sem_perm
.mode
& SEM_ALLOC
) &&
749 sema
[i
].u
.sem_base
> semakptr
->u
.sem_base
) {
750 sema
[i
].u
.sem_base
-= semakptr
->u
.sem_nsems
;
753 semakptr
->u
.sem_perm
.mode
= 0;
755 mac_sysvsem_label_recycle(semakptr
);
757 semundo_clear(semid
, -1);
758 wakeup((caddr_t
)semakptr
);
762 if ((eval
= ipcperm(cred
, &semakptr
->u
.sem_perm
, IPC_M
))) {
766 if (IS_64BIT_PROCESS(p
)) {
767 struct user64_semid_ds ds64
;
768 eval
= copyin(user_arg
.buf
, &ds64
, sizeof(ds64
));
769 semid_ds_64tokernel(&ds64
, &sbuf
);
771 struct user32_semid_ds ds32
;
772 eval
= copyin(user_arg
.buf
, &ds32
, sizeof(ds32
));
773 semid_ds_32tokernel(&ds32
, &sbuf
);
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();
788 if ((eval
= ipcperm(cred
, &semakptr
->u
.sem_perm
, IPC_R
))) {
792 if (IS_64BIT_PROCESS(p
)) {
793 struct user64_semid_ds semid_ds64
;
794 bzero(&semid_ds64
, sizeof(semid_ds64
));
795 semid_ds_kernelto64(&semakptr
->u
, &semid_ds64
);
796 eval
= copyout(&semid_ds64
, user_arg
.buf
, sizeof(semid_ds64
));
798 struct user32_semid_ds semid_ds32
;
799 bzero(&semid_ds32
, sizeof(semid_ds32
));
800 semid_ds_kernelto32(&semakptr
->u
, &semid_ds32
);
801 eval
= copyout(&semid_ds32
, user_arg
.buf
, sizeof(semid_ds32
));
806 if ((eval
= ipcperm(cred
, &semakptr
->u
.sem_perm
, IPC_R
))) {
809 if (semnum
< 0 || semnum
>= semakptr
->u
.sem_nsems
) {
813 rval
= semakptr
->u
.sem_base
[semnum
].semncnt
;
817 if ((eval
= ipcperm(cred
, &semakptr
->u
.sem_perm
, IPC_R
))) {
820 if (semnum
< 0 || semnum
>= semakptr
->u
.sem_nsems
) {
824 rval
= semakptr
->u
.sem_base
[semnum
].sempid
;
828 if ((eval
= ipcperm(cred
, &semakptr
->u
.sem_perm
, IPC_R
))) {
831 if (semnum
< 0 || semnum
>= semakptr
->u
.sem_nsems
) {
835 rval
= semakptr
->u
.sem_base
[semnum
].semval
;
839 if ((eval
= ipcperm(cred
, &semakptr
->u
.sem_perm
, IPC_R
))) {
842 /* XXXXXXXXXXXXXXXX TBD XXXXXXXXXXXXXXXX */
843 for (i
= 0; i
< semakptr
->u
.sem_nsems
; i
++) {
844 /* XXX could be done in one go... */
845 eval
= copyout((caddr_t
)&semakptr
->u
.sem_base
[i
].semval
,
846 user_arg
.array
+ (i
* sizeof(unsigned short)),
847 sizeof(unsigned short));
855 if ((eval
= ipcperm(cred
, &semakptr
->u
.sem_perm
, IPC_R
))) {
858 if (semnum
< 0 || semnum
>= semakptr
->u
.sem_nsems
) {
862 rval
= semakptr
->u
.sem_base
[semnum
].semzcnt
;
866 if ((eval
= ipcperm(cred
, &semakptr
->u
.sem_perm
, IPC_W
))) {
868 printf("Invalid credentials for write\n");
872 if (semnum
< 0 || semnum
>= semakptr
->u
.sem_nsems
) {
874 printf("Invalid number out of range for set\n");
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.
885 u_int newsemval
= CAST_DOWN_EXPLICIT(u_int
, user_arg
.buf
);
888 * The check is being performed as unsigned values to match
889 * eventual destination
891 if (newsemval
> (u_int
)seminfo
.semvmx
) {
893 printf("Out of range sem value for set\n");
898 semakptr
->u
.sem_base
[semnum
].semval
= newsemval
;
899 semakptr
->u
.sem_base
[semnum
].sempid
= p
->p_pid
;
900 /* XXX scottl Should there be a MAC call here? */
901 semundo_clear(semid
, semnum
);
902 wakeup((caddr_t
)semakptr
);
906 if ((eval
= ipcperm(cred
, &semakptr
->u
.sem_perm
, IPC_W
))) {
909 /*** XXXXXXXXXXXX TBD ********/
910 for (i
= 0; i
< semakptr
->u
.sem_nsems
; i
++) {
911 /* XXX could be done in one go... */
912 eval
= copyin(user_arg
.array
+ (i
* sizeof(unsigned short)),
913 (caddr_t
)&semakptr
->u
.sem_base
[i
].semval
,
914 sizeof(unsigned short));
918 semakptr
->u
.sem_base
[i
].sempid
= p
->p_pid
;
920 /* XXX scottl Should there be a MAC call here? */
921 semundo_clear(semid
, -1);
922 wakeup((caddr_t
)semakptr
);
934 SYSV_SEM_SUBSYS_UNLOCK();
939 semget(__unused
struct proc
*p
, struct semget_args
*uap
, int32_t *retval
)
943 int nsems
= uap
->nsems
;
944 int semflg
= uap
->semflg
;
945 kauth_cred_t cred
= kauth_cred_get();
948 if (key
!= IPC_PRIVATE
) {
949 printf("semget(0x%x, %d, 0%o)\n", key
, nsems
, semflg
);
951 printf("semget(IPC_PRIVATE, %d, 0%o)\n", nsems
, semflg
);
956 SYSV_SEM_SUBSYS_LOCK();
959 if (key
!= IPC_PRIVATE
) {
960 for (semid
= 0; semid
< seminfo
.semmni
; semid
++) {
961 if ((sema
[semid
].u
.sem_perm
.mode
& SEM_ALLOC
) &&
962 sema
[semid
].u
.sem_perm
._key
== key
) {
966 if (semid
< seminfo
.semmni
) {
968 printf("found public key\n");
970 if ((eval
= ipcperm(cred
, &sema
[semid
].u
.sem_perm
,
974 if (nsems
< 0 || sema
[semid
].u
.sem_nsems
< nsems
) {
976 printf("too small\n");
981 if ((semflg
& IPC_CREAT
) && (semflg
& IPC_EXCL
)) {
983 printf("not exclusive\n");
989 eval
= mac_sysvsem_check_semget(cred
, &sema
[semid
]);
999 printf("need to allocate an id for the request\n");
1001 if (key
== IPC_PRIVATE
|| (semflg
& IPC_CREAT
)) {
1002 if (nsems
<= 0 || nsems
> limitseminfo
.semmsl
) {
1004 printf("nsems out of range (0<%d<=%d)\n", nsems
,
1010 if (nsems
> seminfo
.semmns
- semtot
) {
1012 printf("not enough semaphores left (need %d, got %d)\n",
1013 nsems
, seminfo
.semmns
- semtot
);
1015 if (!grow_sem_pool(semtot
+ nsems
)) {
1017 printf("failed to grow the sem array\n");
1023 for (semid
= 0; semid
< seminfo
.semmni
; semid
++) {
1024 if ((sema
[semid
].u
.sem_perm
.mode
& SEM_ALLOC
) == 0) {
1028 if (semid
== seminfo
.semmni
) {
1030 printf("no more id's available\n");
1032 if (!grow_sema_array(seminfo
.semmni
+ 1)) {
1034 printf("failed to grow sema array\n");
1041 printf("semid %d is available\n", semid
);
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
);
1046 sema
[semid
].u
.sem_perm
.cgid
= kauth_cred_getgid(cred
);
1047 sema
[semid
].u
.sem_perm
.gid
= kauth_cred_getgid(cred
);
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
];
1056 bzero(sema
[semid
].u
.sem_base
,
1057 sizeof(sema
[semid
].u
.sem_base
[0]) * nsems
);
1059 mac_sysvsem_label_associate(cred
, &sema
[semid
]);
1062 printf("sembase = 0x%x, next = 0x%x\n", sema
[semid
].u
.sem_base
,
1067 printf("didn't find it and wasn't asked to create it\n");
1074 *retval
= IXSEQ_TO_IPCID(semid
, sema
[semid
].u
.sem_perm
);
1075 AUDIT_ARG(svipc_id
, *retval
);
1077 printf("semget is done, returning %d\n", *retval
);
1082 SYSV_SEM_SUBSYS_UNLOCK();
1087 semop(struct proc
*p
, struct semop_args
*uap
, int32_t *retval
)
1089 int semid
= uap
->semid
;
1090 int nsops
= uap
->nsops
;
1091 struct sembuf sops
[seminfo
.semopm
];
1092 struct semid_kernel
*semakptr
;
1093 struct sembuf
*sopptr
= NULL
; /* protected by 'semptr' */
1094 struct sem
*semptr
= NULL
; /* protected by 'if' */
1097 int do_wakeup
, do_undos
;
1099 AUDIT_ARG(svipc_id
, uap
->semid
);
1101 SYSV_SEM_SUBSYS_LOCK();
1104 printf("call to semop(%d, 0x%x, %d)\n", semid
, sops
, nsops
);
1107 semid
= IPCID_TO_IX(semid
); /* Convert back to zero origin */
1109 if (semid
< 0 || semid
>= seminfo
.semmni
) {
1114 semakptr
= &sema
[semid
];
1115 if ((semakptr
->u
.sem_perm
.mode
& SEM_ALLOC
) == 0) {
1119 if (semakptr
->u
.sem_perm
._seq
!= IPCID_TO_SEQ(uap
->semid
)) {
1124 if ((eval
= ipcperm(kauth_cred_get(), &semakptr
->u
.sem_perm
, IPC_W
))) {
1126 printf("eval = %d from ipaccess\n", eval
);
1131 if (nsops
< 0 || nsops
> seminfo
.semopm
) {
1133 printf("too many sops (max=%d, nsops=%d)\n",
1134 seminfo
.semopm
, nsops
);
1140 /* OK for LP64, since sizeof(struct sembuf) is currently invariant */
1141 if ((eval
= copyin(uap
->sops
, &sops
, nsops
* sizeof(struct sembuf
))) != 0) {
1143 printf("eval = %d from copyin(%08x, %08x, %ld)\n", eval
,
1144 uap
->sops
, &sops
, nsops
* sizeof(struct sembuf
));
1151 * Initial pass thru sops to see what permissions are needed.
1153 j
= 0; /* permission needed */
1154 for (i
= 0; i
< nsops
; i
++) {
1155 j
|= (sops
[i
].sem_op
== 0) ? SEM_R
: SEM_A
;
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.
1163 eval
= mac_sysvsem_check_semop(kauth_cred_get(), semakptr
, j
);
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.
1175 * This ensures that from the perspective of other tasks, a set
1176 * of requests is atomic (never partially satisfied).
1183 for (i
= 0; i
< nsops
; i
++) {
1186 if (sopptr
->sem_num
>= semakptr
->u
.sem_nsems
) {
1191 semptr
= &semakptr
->u
.sem_base
[sopptr
->sem_num
];
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
,
1196 sopptr
->sem_num
, semptr
->semval
, sopptr
->sem_op
,
1197 (sopptr
->sem_flg
& IPC_NOWAIT
) ? "nowait" : "wait");
1200 if (sopptr
->sem_op
< 0) {
1201 if (semptr
->semval
+ sopptr
->sem_op
< 0) {
1203 printf("semop: can't do it now\n");
1207 semptr
->semval
+= sopptr
->sem_op
;
1208 if (semptr
->semval
== 0 &&
1209 semptr
->semzcnt
> 0) {
1213 if (sopptr
->sem_flg
& SEM_UNDO
) {
1216 } else if (sopptr
->sem_op
== 0) {
1217 if (semptr
->semval
> 0) {
1219 printf("semop: not zero now\n");
1224 if (semptr
->semncnt
> 0) {
1227 semptr
->semval
+= sopptr
->sem_op
;
1228 if (sopptr
->sem_flg
& SEM_UNDO
) {
1235 * Did we get through the entire vector?
1242 * No ... rollback anything that we've already done
1245 printf("semop: rollback 0 through %d\n", i
- 1);
1247 for (j
= 0; j
< i
; j
++) {
1248 semakptr
->u
.sem_base
[sops
[j
].sem_num
].semval
-=
1253 * If the request that we couldn't satisfy has the
1254 * NOWAIT flag set then return with EAGAIN.
1256 if (sopptr
->sem_flg
& IPC_NOWAIT
) {
1261 if (sopptr
->sem_op
== 0) {
1268 printf("semop: good night!\n");
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
1275 eval
= msleep((caddr_t
)semakptr
, &sysv_sem_subsys_mutex
, (PZERO
- 4) | PCATCH
,
1279 printf("semop: good morning (eval=%d)!\n", eval
);
1286 * IMPORTANT: while we were asleep, the semaphore array might
1287 * have been reallocated somewhere else (see grow_sema_array()).
1288 * When we wake up, we have to re-lookup the semaphore
1289 * structures and re-validate them.
1295 * Make sure that the semaphore still exists
1297 * XXX POSIX: Third test this 'if' and 'EINTR' precedence may
1298 * fail testing; if so, we will need to revert this code.
1300 semakptr
= &sema
[semid
]; /* sema may have been reallocated */
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! */
1306 if (eval
== EINTR
) {
1308 * EINTR takes precedence over the fact that
1309 * the semaphore disappeared while we were
1316 eval
= EINVAL
; /* Ancient past */
1323 * The semaphore is still alive. Readjust the count of
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.
1328 semptr
= &semakptr
->u
.sem_base
[sopptr
->sem_num
];
1329 if (sopptr
->sem_op
== 0) {
1335 if (eval
!= 0) { /* EINTR */
1342 * Process any SEM_UNDO requests.
1345 for (i
= 0; i
< nsops
; i
++) {
1347 * We only need to deal with SEM_UNDO's for non-zero
1352 if ((sops
[i
].sem_flg
& SEM_UNDO
) == 0) {
1355 adjval
= sops
[i
].sem_op
;
1359 eval
= semundo_adjust(p
, &supidx
, semid
,
1360 sops
[i
].sem_num
, -adjval
);
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.
1374 for (j
= i
- 1; j
>= 0; j
--) {
1375 if ((sops
[j
].sem_flg
& SEM_UNDO
) == 0) {
1378 adjval
= sops
[j
].sem_op
;
1382 if (semundo_adjust(p
, &supidx
, semid
,
1383 sops
[j
].sem_num
, adjval
) != 0) {
1384 panic("semop - can't undo undos");
1388 for (j
= 0; j
< nsops
; j
++) {
1389 semakptr
->u
.sem_base
[sops
[j
].sem_num
].semval
-=
1394 printf("eval = %d from semundo_adjust\n", eval
);
1397 } /* loop through the sops */
1398 } /* if (do_undos) */
1400 /* We're definitely done - set the sempid's */
1401 for (i
= 0; i
< nsops
; i
++) {
1403 semptr
= &semakptr
->u
.sem_base
[sopptr
->sem_num
];
1404 semptr
->sempid
= p
->p_pid
;
1406 semakptr
->u
.sem_otime
= sysv_semtime();
1410 printf("semop: doing wakeup\n");
1412 sem_wakeup((caddr_t
)semakptr
);
1414 wakeup((caddr_t
)semakptr
);
1416 printf("semop: back from wakeup\n");
1418 wakeup((caddr_t
)semakptr
);
1422 printf("semop: done\n");
1427 SYSV_SEM_SUBSYS_UNLOCK();
1432 * Go through the undo structures for this process and apply the adjustments to
1436 semexit(struct proc
*p
)
1438 struct sem_undo
*suptr
= NULL
;
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.
1447 SYSV_SEM_SUBSYS_LOCK();
1450 SYSV_SEM_SUBSYS_UNLOCK();
1456 * Go through the chain of undo vectors looking for one
1457 * associated with this process.
1460 for (supidx
= &semu_list_idx
; (suidx
= *supidx
) != -1;
1461 supidx
= &suptr
->un_next_idx
) {
1462 suptr
= SEMU(suidx
);
1463 if (suptr
->un_proc
== p
) {
1473 printf("proc @%08x has undo structure with %d entries\n", p
,
1478 * If there are any active undo elements then process them.
1480 if (suptr
->un_cnt
> 0) {
1481 while (suptr
->un_ent
!= NULL
) {
1482 struct undo
*sueptr
;
1486 struct semid_kernel
*semakptr
;
1488 sueptr
= suptr
->un_ent
;
1489 semid
= sueptr
->une_id
;
1490 semnum
= sueptr
->une_num
;
1491 adjval
= sueptr
->une_adjval
;
1493 semakptr
= &sema
[semid
];
1494 if ((semakptr
->u
.sem_perm
.mode
& SEM_ALLOC
) == 0) {
1495 panic("semexit - semid not allocated");
1497 if (semnum
>= semakptr
->u
.sem_nsems
) {
1498 panic("semexit - semnum out of range");
1502 printf("semexit: %08x id=%d num=%d(adj=%d) ; sem=%d\n",
1507 semakptr
->u
.sem_base
[semnum
].semval
);
1511 if (semakptr
->u
.sem_base
[semnum
].semval
< -adjval
) {
1512 semakptr
->u
.sem_base
[semnum
].semval
= 0;
1514 semakptr
->u
.sem_base
[semnum
].semval
+=
1518 semakptr
->u
.sem_base
[semnum
].semval
+= adjval
;
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
1527 sem_wakeup((caddr_t
)semakptr
);
1529 wakeup((caddr_t
)semakptr
);
1532 printf("semexit: back from wakeup\n");
1535 suptr
->un_ent
= sueptr
->une_next
;
1536 FREE(sueptr
, M_SYSVSEM
);
1542 * Deallocate the undo vector.
1545 printf("removing vector\n");
1547 suptr
->un_proc
= NULL
;
1548 *supidx
= suptr
->un_next_idx
;
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.
1566 * Please note that the original BSD code this file is based on had the
1567 * same leaky semaphore problem.
1570 SYSV_SEM_SUBSYS_UNLOCK();
1574 /* (struct sysctl_oid *oidp, void *arg1, int arg2, \
1575 * struct sysctl_req *req) */
1577 sysctl_seminfo(__unused
struct sysctl_oid
*oidp
, void *arg1
,
1578 __unused
int arg2
, struct sysctl_req
*req
)
1582 error
= SYSCTL_OUT(req
, arg1
, sizeof(int));
1583 if (error
|| req
->newptr
== USER_ADDR_NULL
) {
1587 SYSV_SEM_SUBSYS_LOCK();
1589 /* Set the values only if shared memory is not initialised */
1590 if ((sem_pool
== NULL
) &&
1593 (semu_list_idx
== -1)) {
1594 if ((error
= SYSCTL_IN(req
, arg1
, sizeof(int)))) {
1601 SYSV_SEM_SUBSYS_UNLOCK();
1605 /* SYSCTL_NODE(_kern, KERN_SYSV, sysv, CTLFLAG_RW, 0, "SYSV"); */
1606 extern struct sysctl_oid_list sysctl__kern_sysv_children
;
1607 SYSCTL_PROC(_kern_sysv
, OID_AUTO
, semmni
, CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_LOCKED
,
1608 &limitseminfo
.semmni
, 0, &sysctl_seminfo
, "I", "semmni");
1610 SYSCTL_PROC(_kern_sysv
, OID_AUTO
, semmns
, CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_LOCKED
,
1611 &limitseminfo
.semmns
, 0, &sysctl_seminfo
, "I", "semmns");
1613 SYSCTL_PROC(_kern_sysv
, OID_AUTO
, semmnu
, CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_LOCKED
,
1614 &limitseminfo
.semmnu
, 0, &sysctl_seminfo
, "I", "semmnu");
1616 SYSCTL_PROC(_kern_sysv
, OID_AUTO
, semmsl
, CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_LOCKED
,
1617 &limitseminfo
.semmsl
, 0, &sysctl_seminfo
, "I", "semmsl");
1619 SYSCTL_PROC(_kern_sysv
, OID_AUTO
, semume
, CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_LOCKED
,
1620 &limitseminfo
.semume
, 0, &sysctl_seminfo
, "I", "semume");
1624 IPCS_sem_sysctl(__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
,
1625 __unused
int arg2
, struct sysctl_req
*req
)
1630 struct user32_IPCS_command u32
;
1631 struct user_IPCS_command u64
;
1633 struct user32_semid_ds semid_ds32
= { }; /* post conversion, 32 bit version */
1634 struct user64_semid_ds semid_ds64
= { }; /* post conversion, 64 bit version */
1638 struct proc
*p
= current_proc();
1640 if (IS_64BIT_PROCESS(p
)) {
1641 ipcs_sz
= sizeof(struct user_IPCS_command
);
1642 semid_ds_sz
= sizeof(struct user64_semid_ds
);
1644 ipcs_sz
= sizeof(struct user32_IPCS_command
);
1645 semid_ds_sz
= sizeof(struct user32_semid_ds
);
1648 /* Copy in the command structure */
1649 if ((error
= SYSCTL_IN(req
, &ipcs
, ipcs_sz
)) != 0) {
1653 if (!IS_64BIT_PROCESS(p
)) { /* convert in place */
1654 ipcs
.u64
.ipcs_data
= CAST_USER_ADDR_T(ipcs
.u32
.ipcs_data
);
1657 /* Let us version this interface... */
1658 if (ipcs
.u64
.ipcs_magic
!= IPCS_MAGIC
) {
1662 SYSV_SEM_SUBSYS_LOCK();
1663 switch (ipcs
.u64
.ipcs_op
) {
1664 case IPCS_SEM_CONF
: /* Obtain global configuration data */
1665 if (ipcs
.u64
.ipcs_datalen
!= sizeof(struct seminfo
)) {
1669 if (ipcs
.u64
.ipcs_cursor
!= 0) { /* fwd. compat. */
1673 error
= copyout(&seminfo
, ipcs
.u64
.ipcs_data
, ipcs
.u64
.ipcs_datalen
);
1676 case IPCS_SEM_ITER
: /* Iterate over existing segments */
1677 cursor
= ipcs
.u64
.ipcs_cursor
;
1678 if (cursor
< 0 || cursor
>= seminfo
.semmni
) {
1682 if (ipcs
.u64
.ipcs_datalen
!= (int)semid_ds_sz
) {
1686 for (; cursor
< seminfo
.semmni
; cursor
++) {
1687 if (sema
[cursor
].u
.sem_perm
.mode
& SEM_ALLOC
) {
1692 if (cursor
== seminfo
.semmni
) {
1697 semid_dsp
= &sema
[cursor
].u
; /* default: 64 bit */
1700 * If necessary, convert the 64 bit kernel segment
1701 * descriptor to a 32 bit user one.
1703 if (!IS_64BIT_PROCESS(p
)) {
1704 bzero(&semid_ds32
, sizeof(semid_ds32
));
1705 semid_ds_kernelto32(semid_dsp
, &semid_ds32
);
1706 semid_dsp
= &semid_ds32
;
1708 bzero(&semid_ds64
, sizeof(semid_ds64
));
1709 semid_ds_kernelto64(semid_dsp
, &semid_ds64
);
1710 semid_dsp
= &semid_ds64
;
1713 error
= copyout(semid_dsp
, ipcs
.u64
.ipcs_data
, ipcs
.u64
.ipcs_datalen
);
1716 ipcs
.u64
.ipcs_cursor
= cursor
+ 1;
1718 if (!IS_64BIT_PROCESS(p
)) { /* convert in place */
1719 ipcs
.u32
.ipcs_data
= CAST_DOWN_EXPLICIT(user32_addr_t
, ipcs
.u64
.ipcs_data
);
1722 error
= SYSCTL_OUT(req
, &ipcs
, ipcs_sz
);
1730 SYSV_SEM_SUBSYS_UNLOCK();
1734 SYSCTL_DECL(_kern_sysv_ipcs
);
1735 SYSCTL_PROC(_kern_sysv_ipcs
, OID_AUTO
, sem
, CTLFLAG_RW
| CTLFLAG_ANYBODY
| CTLFLAG_LOCKED
,
1736 0, 0, IPCS_sem_sysctl
,
1737 "S,IPCS_sem_command",
1738 "ipcs sem command interface");
1740 #endif /* SYSV_SEM */