2  * Copyright (c) 2000-2004 Apple Computer, 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 #include <sys/param.h> 
  40 #include <sys/systm.h> 
  41 #include <sys/kernel.h> 
  42 #include <sys/proc_internal.h> 
  43 #include <sys/kauth.h> 
  44 #include <sys/sem_internal.h> 
  45 #include <sys/malloc.h> 
  46 #include <mach/mach_types.h> 
  48 #include <sys/filedesc.h> 
  49 #include <sys/file_internal.h> 
  50 #include <sys/sysctl.h> 
  52 #include <sys/sysent.h> 
  53 #include <sys/sysproto.h> 
  55 #include <bsm/audit_kernel.h> 
  58 /* Uncomment this line to see the debugging output */ 
  59 /* #define SEM_DEBUG */ 
  61 #define M_SYSVSEM       M_TEMP 
  64 /* Hard system limits to avoid resource starvation / DOS attacks. 
  65  * These are not needed if we can make the semaphore pages swappable. 
  67 static struct seminfo limitseminfo 
= { 
  68         SEMMAP
,        /* # of entries in semaphore map */ 
  69         SEMMNI
,        /* # of semaphore identifiers */ 
  70         SEMMNS
,        /* # of semaphores in system */ 
  71         SEMMNU
,        /* # of undo structures in system */ 
  72         SEMMSL
,        /* max # of semaphores per id */ 
  73         SEMOPM
,        /* max # of operations per semop call */ 
  74         SEMUME
,        /* max # of undo entries per process */ 
  75         SEMUSZ
,        /* size in bytes of undo structure */ 
  76         SEMVMX
,        /* semaphore maximum value */ 
  77         SEMAEM         
/* adjust on exit max value */ 
  80 /* Current system allocations.  We use this structure to track how many 
  81  * resources we have allocated so far.  This way we can set large hard limits 
  82  * and not allocate the memory for them up front. 
  84 struct seminfo seminfo 
= { 
  85         SEMMAP
, /* Unused, # of entries in semaphore map */ 
  86         0,      /* # of semaphore identifiers */ 
  87         0,      /* # of semaphores in system */ 
  88         0,      /* # of undo entries in system */ 
  89         SEMMSL
, /* max # of semaphores per id */ 
  90         SEMOPM
, /* max # of operations per semop call */ 
  91         SEMUME
, /* max # of undo entries per process */ 
  92         SEMUSZ
, /* size in bytes of undo structure */ 
  93         SEMVMX
, /* semaphore maximum value */ 
  94         SEMAEM  
/* adjust on exit max value */ 
  98 static struct sem_undo 
*semu_alloc(struct proc 
*p
); 
  99 static int semundo_adjust(struct proc 
*p
, struct sem_undo 
**supptr
,  
 100                 int semid
, int semnum
, int adjval
); 
 101 static void semundo_clear(int semid
, int semnum
); 
 103 /* XXX casting to (sy_call_t *) is bogus, as usual. */ 
 104 static sy_call_t 
*semcalls
[] = { 
 105         (sy_call_t 
*)semctl
, (sy_call_t 
*)semget
, 
 109 static int              semtot 
= 0;             /* # of used semaphores */ 
 110 struct user_semid_ds    
*sema 
= NULL
;           /* semaphore id pool */ 
 111 struct sem              
*sem_pool 
=  NULL
;      /* semaphore pool */ 
 112 static struct sem_undo  
*semu_list 
= NULL
;      /* active undo structures */ 
 113 struct sem_undo         
*semu 
= NULL
;           /* semaphore undo pool */ 
 116 void sysv_sem_lock_init(void); 
 117 static lck_grp_t       
*sysv_sem_subsys_lck_grp
; 
 118 static lck_grp_attr_t  
*sysv_sem_subsys_lck_grp_attr
; 
 119 static lck_attr_t      
*sysv_sem_subsys_lck_attr
; 
 120 static lck_mtx_t        sysv_sem_subsys_mutex
; 
 122 #define SYSV_SEM_SUBSYS_LOCK() lck_mtx_lock(&sysv_sem_subsys_mutex) 
 123 #define SYSV_SEM_SUBSYS_UNLOCK() lck_mtx_unlock(&sysv_sem_subsys_mutex) 
 126 __private_extern__ 
void 
 127 sysv_sem_lock_init( void ) 
 130     sysv_sem_subsys_lck_grp_attr 
= lck_grp_attr_alloc_init(); 
 131     lck_grp_attr_setstat(sysv_sem_subsys_lck_grp_attr
); 
 133     sysv_sem_subsys_lck_grp 
= lck_grp_alloc_init("sysv_shm_subsys_lock", sysv_sem_subsys_lck_grp_attr
); 
 135     sysv_sem_subsys_lck_attr 
= lck_attr_alloc_init(); 
 136     lck_attr_setdebug(sysv_sem_subsys_lck_attr
);  
 137     lck_mtx_init(&sysv_sem_subsys_mutex
, sysv_sem_subsys_lck_grp
, sysv_sem_subsys_lck_attr
); 
 140 static __inline__ user_time_t
 
 149  * XXX conversion of internal user_time_t to external tume_t loses 
 150  * XXX precision; not an issue for us now, since we are only ever 
 151  * XXX setting 32 bits worth of time into it. 
 153  * pad field contents are not moved correspondingly; contents will be lost 
 155  * NOTE: Source and target may *NOT* overlap! (target is smaller) 
 158 semid_ds_64to32(struct user_semid_ds 
*in
, struct semid_ds 
*out
) 
 160         out
->sem_perm 
= in
->sem_perm
; 
 161         out
->sem_base 
= (__int32_t
)in
->sem_base
; 
 162         out
->sem_nsems 
= in
->sem_nsems
; 
 163         out
->sem_otime 
= in
->sem_otime
;         /* XXX loses precision */ 
 164         out
->sem_ctime 
= in
->sem_ctime
;         /* XXX loses precision */ 
 168  * pad field contents are not moved correspondingly; contents will be lost 
 170  * NOTE: Source and target may are permitted to overlap! (source is smaller); 
 171  * this works because we copy fields in order from the end of the struct to 
 174  * XXX use CAST_USER_ADDR_T() for lack of a CAST_USER_TIME_T(); net effect 
 178 semid_ds_32to64(struct semid_ds 
*in
, struct user_semid_ds 
*out
) 
 180         out
->sem_ctime 
= in
->sem_ctime
; 
 181         out
->sem_otime 
= in
->sem_otime
; 
 182         out
->sem_nsems 
= in
->sem_nsems
; 
 183         out
->sem_base 
= (void *)in
->sem_base
; 
 184         out
->sem_perm 
= in
->sem_perm
; 
 189  * Entry point for all SEM calls 
 191  * In Darwin this is no longer the entry point.  It will be removed after 
 192  *  the code has been tested better. 
 194 /* XXX actually varargs. */ 
 196 semsys(struct proc 
*p
, struct semsys_args 
*uap
, register_t 
*retval
) 
 199         /* The individual calls handling the locking now */ 
 201         if (uap
->which 
>= sizeof(semcalls
)/sizeof(semcalls
[0])) 
 203         return ((*semcalls
[uap
->which
])(p
, &uap
->a2
, retval
)); 
 207  * Expand the semu array to the given capacity.  If the expansion fails 
 208  * return 0, otherwise return 1. 
 210  * Assumes we already have the subsystem lock. 
 213 grow_semu_array(int newSize
) 
 216         register struct sem_undo 
*newSemu
; 
 218         if (newSize 
<= seminfo
.semmnu
) 
 220         if (newSize 
> limitseminfo
.semmnu
) /* enforce hard limit */ 
 223                 printf("undo structure hard limit of %d reached, requested %d\n", 
 224                         limitseminfo
.semmnu
, newSize
); 
 228         newSize 
= (newSize
/SEMMNU_INC 
+ 1) * SEMMNU_INC
; 
 229         newSize 
= newSize 
> limitseminfo
.semmnu 
? limitseminfo
.semmnu 
: newSize
; 
 232         printf("growing semu[] from %d to %d\n", seminfo
.semmnu
, newSize
); 
 234         MALLOC(newSemu
, struct sem_undo 
*, sizeof (struct sem_undo
) * newSize
, 
 235                M_SYSVSEM
, M_WAITOK 
| M_ZERO
); 
 239                 printf("allocation failed.  no changes made.\n"); 
 244         /* copy the old data to the new array */ 
 245         for (i 
= 0; i 
< seminfo
.semmnu
; i
++) 
 247                 newSemu
[i
] = semu
[i
]; 
 250          * The new elements (from newSemu[i] to newSemu[newSize-1]) have their 
 251          * "un_proc" set to 0 (i.e. NULL) by the M_ZERO flag to MALLOC() above, 
 252          * so they're already marked as "not in use". 
 255         /* Clean up the old array */ 
 257                 FREE(semu
, M_SYSVSEM
); 
 260         seminfo
.semmnu 
= newSize
; 
 262         printf("expansion successful\n"); 
 268  * Expand the sema array to the given capacity.  If the expansion fails 
 269  * we return 0, otherwise we return 1. 
 271  * Assumes we already have the subsystem lock. 
 274 grow_sema_array(int newSize
) 
 276         register struct user_semid_ds 
*newSema
; 
 279         if (newSize 
<= seminfo
.semmni
) 
 281         if (newSize 
> limitseminfo
.semmni
) /* enforce hard limit */ 
 284                 printf("identifier hard limit of %d reached, requested %d\n", 
 285                         limitseminfo
.semmni
, newSize
); 
 289         newSize 
= (newSize
/SEMMNI_INC 
+ 1) * SEMMNI_INC
; 
 290         newSize 
= newSize 
> limitseminfo
.semmni 
? limitseminfo
.semmni 
: newSize
; 
 293         printf("growing sema[] from %d to %d\n", seminfo
.semmni
, newSize
); 
 295         MALLOC(newSema
, struct user_semid_ds 
*, 
 296                sizeof (struct user_semid_ds
) * newSize
, 
 297                M_SYSVSEM
, M_WAITOK 
| M_ZERO
); 
 301                 printf("allocation failed.  no changes made.\n"); 
 306         /* copy over the old ids */ 
 307         for (i 
= 0; i 
< seminfo
.semmni
; i
++) 
 309                 newSema
[i
] = sema
[i
]; 
 310                 /* This is a hack.  What we really want to be able to 
 311                  * do is change the value a process is waiting on 
 312                  * without waking it up, but I don't know how to do 
 313                  * this with the existing code, so we wake up the 
 314                  * process and let it do a lot of work to determine the 
 315                  * semaphore set is really not available yet, and then 
 316                  * sleep on the correct, reallocated user_semid_ds pointer. 
 318                 if (sema
[i
].sem_perm
.mode 
& SEM_ALLOC
) 
 319                         wakeup((caddr_t
)&sema
[i
]); 
 322          * The new elements (from newSema[i] to newSema[newSize-1]) have their 
 323          * "sem_base" and "sem_perm.mode" set to 0 (i.e. NULL) by the M_ZERO 
 324          * flag to MALLOC() above, so they're already marked as "not in use". 
 327         /* Clean up the old array */ 
 329                 FREE(sema
, M_SYSVSEM
); 
 332         seminfo
.semmni 
= newSize
; 
 334         printf("expansion successful\n"); 
 340  * Expand the sem_pool array to the given capacity.  If the expansion fails 
 341  * we return 0 (fail), otherwise we return 1 (success). 
 343  * Assumes we already hold the subsystem lock. 
 346 grow_sem_pool(int new_pool_size
) 
 348         struct sem 
*new_sem_pool 
= NULL
; 
 349         struct sem 
*sem_free
; 
 352         if (new_pool_size 
< semtot
) 
 354         /* enforce hard limit */ 
 355         if (new_pool_size 
> limitseminfo
.semmns
) { 
 357                 printf("semaphore hard limit of %d reached, requested %d\n", 
 358                         limitseminfo
.semmns
, new_pool_size
); 
 363         new_pool_size 
= (new_pool_size
/SEMMNS_INC 
+ 1) * SEMMNS_INC
; 
 364         new_pool_size 
= new_pool_size 
> limitseminfo
.semmns 
? limitseminfo
.semmns 
: new_pool_size
; 
 367         printf("growing sem_pool array from %d to %d\n", seminfo
.semmns
, new_pool_size
); 
 369         MALLOC(new_sem_pool
, struct sem 
*, sizeof (struct sem
) * new_pool_size
, 
 370                M_SYSVSEM
, M_WAITOK 
| M_ZERO
); 
 371         if (NULL 
== new_sem_pool
) { 
 373                 printf("allocation failed.  no changes made.\n"); 
 378         /* We have our new memory, now copy the old contents over */ 
 380                 for(i 
= 0; i 
< seminfo
.semmns
; i
++) 
 381                         new_sem_pool
[i
] = sem_pool
[i
]; 
 383         /* Update our id structures to point to the new semaphores */ 
 384         for(i 
= 0; i 
< seminfo
.semmni
; i
++) { 
 385                 if (sema
[i
].sem_perm
.mode 
& SEM_ALLOC
)  /* ID in use */ 
 386                         sema
[i
].sem_base 
+= (new_sem_pool 
- sem_pool
); 
 390         sem_pool 
= new_sem_pool
; 
 392         /* clean up the old array */ 
 393         if (sem_free 
!= NULL
) 
 394                 FREE(sem_free
, M_SYSVSEM
); 
 396         seminfo
.semmns 
= new_pool_size
; 
 398         printf("expansion complete\n"); 
 404  * Allocate a new sem_undo structure for a process 
 405  * (returns ptr to structure or NULL if no more room) 
 407  * Assumes we already hold the subsystem lock. 
 410 static struct sem_undo 
* 
 411 semu_alloc(struct proc 
*p
) 
 414         register struct sem_undo 
*suptr
; 
 415         register struct sem_undo 
**supptr
; 
 419          * Try twice to allocate something. 
 420          * (we'll purge any empty structures after the first pass so 
 421          * two passes are always enough) 
 424         for (attempt 
= 0; attempt 
< 2; attempt
++) { 
 426                  * Look for a free structure. 
 427                  * Fill it in and return it if we find one. 
 430                 for (i 
= 0; i 
< seminfo
.semmnu
; i
++) { 
 432                         if (suptr
->un_proc 
== NULL
) { 
 433                                 suptr
->un_next 
= semu_list
; 
 436                                 suptr
->un_ent 
= NULL
; 
 443                  * We didn't find a free one, if this is the first attempt 
 444                  * then try to free some structures. 
 448                         /* All the structures are in use - try to free some */ 
 449                         int did_something 
= 0; 
 452                         while ((suptr 
= *supptr
) != NULL
) { 
 453                                 if (suptr
->un_cnt 
== 0)  { 
 454                                         suptr
->un_proc 
= NULL
; 
 455                                         *supptr 
= suptr
->un_next
; 
 458                                         supptr 
= &(suptr
->un_next
); 
 461                         /* If we didn't free anything. Try expanding 
 462                          * the semu[] array.  If that doesn't work 
 463                          * then fail.  We expand last to get the 
 464                          * most reuse out of existing resources. 
 467                                 if (!grow_semu_array(seminfo
.semmnu 
+ 1)) 
 471                          * The second pass failed even though we freed 
 472                          * something after the first pass! 
 473                          * This is IMPOSSIBLE! 
 475                         panic("semu_alloc - second attempt failed"); 
 482  * Adjust a particular entry for a particular proc 
 484  * Assumes we already hold the subsystem lock. 
 487 semundo_adjust(struct proc 
*p
, struct sem_undo 
**supptr
, int semid
, 
 488         int semnum
, int adjval
) 
 490         register struct sem_undo 
*suptr
; 
 491         register struct undo 
*sueptr
, **suepptr
, *new_sueptr
; 
 495          * Look for and remember the sem_undo if the caller doesn't provide it 
 500                 for (suptr 
= semu_list
; suptr 
!= NULL
; 
 501                     suptr 
= suptr
->un_next
) { 
 502                         if (suptr
->un_proc 
== p
) { 
 510                         suptr 
= semu_alloc(p
); 
 518          * Look for the requested entry and adjust it (delete if adjval becomes 
 522         for (i 
= 0, suepptr 
= &suptr
->un_ent
, sueptr 
= suptr
->un_ent
; 
 524              i
++, suepptr 
= &sueptr
->une_next
, sueptr 
= sueptr
->une_next
) { 
 525                 if (sueptr
->une_id 
!= semid 
|| sueptr
->une_num 
!= semnum
) 
 528                         sueptr
->une_adjval 
= 0; 
 530                         sueptr
->une_adjval 
+= adjval
; 
 531                 if (sueptr
->une_adjval 
== 0) { 
 533                         *suepptr 
= sueptr
->une_next
; 
 534                         FREE(sueptr
, M_SYSVSEM
); 
 540         /* Didn't find the right entry - create it */ 
 542                 /* no adjustment: no need for a new entry */ 
 546         if (suptr
->un_cnt 
== limitseminfo
.semume
) { 
 547                 /* reached the limit number of semaphore undo entries */ 
 551         /* allocate a new semaphore undo entry */ 
 552         MALLOC(new_sueptr
, struct undo 
*, sizeof (struct undo
), 
 553                M_SYSVSEM
, M_WAITOK
); 
 554         if (new_sueptr 
== NULL
) { 
 558         /* fill in the new semaphore undo entry */ 
 559         new_sueptr
->une_next 
= suptr
->un_ent
; 
 560         suptr
->un_ent 
= new_sueptr
; 
 562         new_sueptr
->une_adjval 
= adjval
; 
 563         new_sueptr
->une_id 
= semid
; 
 564         new_sueptr
->une_num 
= semnum
; 
 569 /* Assumes we already hold the subsystem lock. 
 572 semundo_clear(int semid
, int semnum
) 
 574         struct sem_undo 
*suptr
; 
 576         for (suptr 
= semu_list
; suptr 
!= NULL
; suptr 
= suptr
->un_next
) { 
 578                 struct undo 
**suepptr
; 
 581                 sueptr 
= suptr
->un_ent
; 
 582                 suepptr 
= &suptr
->un_ent
; 
 583                 while (i 
< suptr
->un_cnt
) { 
 584                         if (sueptr
->une_id 
== semid
) { 
 585                                 if (semnum 
== -1 || sueptr
->une_num 
== semnum
) { 
 587                                         *suepptr 
= sueptr
->une_next
; 
 588                                         FREE(sueptr
, M_SYSVSEM
); 
 596                         suepptr 
= &sueptr
->une_next
; 
 597                         sueptr 
= sueptr
->une_next
; 
 603  * Note that the user-mode half of this passes a union coerced to a 
 604  * user_addr_t.  The union contains either an int or a pointer, and 
 605  * so we have to coerce it back, variant on whether the calling 
 606  * process is 64 bit or not.  The coercion works for the 'val' element 
 607  * because the alignment is the same in user and kernel space. 
 610 semctl(struct proc 
*p
, struct semctl_args 
*uap
, register_t 
*retval
) 
 612         int semid 
= uap
->semid
; 
 613         int semnum 
= uap
->semnum
; 
 615         user_semun_t user_arg 
= (user_semun_t
)uap
->arg
; 
 616         kauth_cred_t cred 
= kauth_cred_get(); 
 618         struct user_semid_ds sbuf
; 
 619         struct user_semid_ds 
*semaptr
; 
 620         struct user_semid_ds uds
; 
 623         AUDIT_ARG(svipc_cmd
, cmd
); 
 624         AUDIT_ARG(svipc_id
, semid
); 
 626         SYSV_SEM_SUBSYS_LOCK(); 
 629         printf("call to semctl(%d, %d, %d, 0x%qx)\n", semid
, semnum
, cmd
, user_arg
); 
 632         semid 
= IPCID_TO_IX(semid
); 
 634         if (semid 
< 0 || semid 
>= seminfo
.semmni
) { 
 636                 printf("Invalid semid\n"); 
 642         semaptr 
= &sema
[semid
]; 
 643         if ((semaptr
->sem_perm
.mode 
& SEM_ALLOC
) == 0 || 
 644             semaptr
->sem_perm
.seq 
!= IPCID_TO_SEQ(uap
->semid
)) { 
 654                 if ((eval 
= ipcperm(cred
, &semaptr
->sem_perm
, IPC_M
)))  
 657                 semaptr
->sem_perm
.cuid 
= kauth_cred_getuid(cred
); 
 658                 semaptr
->sem_perm
.uid 
= kauth_cred_getuid(cred
); 
 659                 semtot 
-= semaptr
->sem_nsems
; 
 660                 for (i 
= semaptr
->sem_base 
- sem_pool
; i 
< semtot
; i
++) 
 661                         sem_pool
[i
] = sem_pool
[i 
+ semaptr
->sem_nsems
]; 
 662                 for (i 
= 0; i 
< seminfo
.semmni
; i
++) { 
 663                         if ((sema
[i
].sem_perm
.mode 
& SEM_ALLOC
) && 
 664                             sema
[i
].sem_base 
> semaptr
->sem_base
) 
 665                                 sema
[i
].sem_base 
-= semaptr
->sem_nsems
; 
 667                 semaptr
->sem_perm
.mode 
= 0; 
 668                 semundo_clear(semid
, -1); 
 669                 wakeup((caddr_t
)semaptr
); 
 673                 if ((eval 
= ipcperm(cred
, &semaptr
->sem_perm
, IPC_M
))) 
 676                 if (IS_64BIT_PROCESS(p
)) { 
 677                         eval 
= copyin(user_arg
.buf
, &sbuf
, sizeof(struct user_semid_ds
)); 
 679                         eval 
= copyin(user_arg
.buf
, &sbuf
, sizeof(struct semid_ds
)); 
 680                         /* convert in place; ugly, but safe */ 
 681                         semid_ds_32to64((struct semid_ds 
*)&sbuf
, &sbuf
); 
 688                 semaptr
->sem_perm
.uid 
= sbuf
.sem_perm
.uid
; 
 689                 semaptr
->sem_perm
.gid 
= sbuf
.sem_perm
.gid
; 
 690                 semaptr
->sem_perm
.mode 
= (semaptr
->sem_perm
.mode 
& ~0777) | 
 691                     (sbuf
.sem_perm
.mode 
& 0777); 
 692                 semaptr
->sem_ctime 
= sysv_semtime(); 
 696                 if ((eval 
= ipcperm(cred
, &semaptr
->sem_perm
, IPC_R
))) 
 698                 bcopy(semaptr
, &uds
, sizeof(struct user_semid_ds
)); 
 699                 if (IS_64BIT_PROCESS(p
)) { 
 700                         eval 
= copyout(&uds
, user_arg
.buf
, sizeof(struct user_semid_ds
)); 
 702                         struct semid_ds semid_ds32
; 
 703                         semid_ds_64to32(&uds
, &semid_ds32
); 
 704                         eval 
= copyout(&semid_ds32
, user_arg
.buf
, sizeof(struct semid_ds
)); 
 709                 if ((eval 
= ipcperm(cred
, &semaptr
->sem_perm
, IPC_R
))) 
 711                 if (semnum 
< 0 || semnum 
>= semaptr
->sem_nsems
) { 
 715                 rval 
= semaptr
->sem_base
[semnum
].semncnt
; 
 719                 if ((eval 
= ipcperm(cred
, &semaptr
->sem_perm
, IPC_R
))) 
 721                 if (semnum 
< 0 || semnum 
>= semaptr
->sem_nsems
) { 
 725                 rval 
= semaptr
->sem_base
[semnum
].sempid
; 
 729                 if ((eval 
= ipcperm(cred
, &semaptr
->sem_perm
, IPC_R
))) 
 731                 if (semnum 
< 0 || semnum 
>= semaptr
->sem_nsems
) { 
 735                 rval 
= semaptr
->sem_base
[semnum
].semval
; 
 739                 if ((eval 
= ipcperm(cred
, &semaptr
->sem_perm
, IPC_R
))) 
 741 /* XXXXXXXXXXXXXXXX TBD XXXXXXXXXXXXXXXX */ 
 742                 for (i 
= 0; i 
< semaptr
->sem_nsems
; i
++) { 
 743                         /* XXX could be done in one go... */ 
 744                         eval 
= copyout((caddr_t
)&semaptr
->sem_base
[i
].semval
, 
 745                             user_arg
.array 
+ (i 
* sizeof(unsigned short)), 
 746                             sizeof(unsigned short)); 
 753                 if ((eval 
= ipcperm(cred
, &semaptr
->sem_perm
, IPC_R
))) 
 755                 if (semnum 
< 0 || semnum 
>= semaptr
->sem_nsems
) { 
 759                 rval 
= semaptr
->sem_base
[semnum
].semzcnt
; 
 763                 if ((eval 
= ipcperm(cred
, &semaptr
->sem_perm
, IPC_W
))) 
 766                         printf("Invalid credentials for write\n"); 
 770                 if (semnum 
< 0 || semnum 
>= semaptr
->sem_nsems
) 
 773                         printf("Invalid number out of range for set\n"); 
 779                  * Cast down a pointer instead of using 'val' member directly 
 780                  * to avoid introducing endieness and a pad field into the 
 781                  * header file.  Ugly, but it works. 
 783                 semaptr
->sem_base
[semnum
].semval 
= CAST_DOWN(int,user_arg
.buf
); 
 784                 semundo_clear(semid
, semnum
); 
 785                 wakeup((caddr_t
)semaptr
); 
 789                 if ((eval 
= ipcperm(cred
, &semaptr
->sem_perm
, IPC_W
))) 
 791 /*** XXXXXXXXXXXX TBD ********/ 
 792                 for (i 
= 0; i 
< semaptr
->sem_nsems
; i
++) { 
 793                         /* XXX could be done in one go... */ 
 794                         eval 
= copyin(user_arg
.array 
+ (i 
* sizeof(unsigned short)), 
 795                             (caddr_t
)&semaptr
->sem_base
[i
].semval
, 
 796                             sizeof(unsigned short)); 
 800                 semundo_clear(semid
, -1); 
 801                 wakeup((caddr_t
)semaptr
); 
 812         SYSV_SEM_SUBSYS_UNLOCK(); 
 817 semget(__unused 
struct proc 
*p
, struct semget_args 
*uap
, register_t 
*retval
) 
 821         int nsems 
= uap
->nsems
; 
 822         int semflg 
= uap
->semflg
; 
 823         kauth_cred_t cred 
= kauth_cred_get(); 
 826         if (key 
!= IPC_PRIVATE
) 
 827                 printf("semget(0x%x, %d, 0%o)\n", key
, nsems
, semflg
); 
 829                 printf("semget(IPC_PRIVATE, %d, 0%o)\n", nsems
, semflg
); 
 833         SYSV_SEM_SUBSYS_LOCK(); 
 836         if (key 
!= IPC_PRIVATE
) { 
 837                 for (semid 
= 0; semid 
< seminfo
.semmni
; semid
++) { 
 838                         if ((sema
[semid
].sem_perm
.mode 
& SEM_ALLOC
) && 
 839                             sema
[semid
].sem_perm
.key 
== key
) 
 842                 if (semid 
< seminfo
.semmni
) { 
 844                         printf("found public key\n"); 
 846                         if ((eval 
= ipcperm(cred
, &sema
[semid
].sem_perm
, 
 849                         if (nsems 
< 0 || sema
[semid
].sem_nsems 
< nsems
) { 
 851                                 printf("too small\n"); 
 856                         if ((semflg 
& IPC_CREAT
) && (semflg 
& IPC_EXCL
)) { 
 858                                 printf("not exclusive\n"); 
 868         printf("need to allocate an id for the request\n"); 
 870         if (key 
== IPC_PRIVATE 
|| (semflg 
& IPC_CREAT
)) { 
 871                 if (nsems 
<= 0 || nsems 
> limitseminfo
.semmsl
) { 
 873                         printf("nsems out of range (0<%d<=%d)\n", nsems
, 
 879                 if (nsems 
> seminfo
.semmns 
- semtot
) { 
 881                         printf("not enough semaphores left (need %d, got %d)\n", 
 882                             nsems
, seminfo
.semmns 
- semtot
); 
 884                         if (!grow_sem_pool(semtot 
+ nsems
)) { 
 886                                 printf("failed to grow the sem array\n"); 
 892                 for (semid 
= 0; semid 
< seminfo
.semmni
; semid
++) { 
 893                         if ((sema
[semid
].sem_perm
.mode 
& SEM_ALLOC
) == 0) 
 896                 if (semid 
== seminfo
.semmni
) { 
 898                         printf("no more id's available\n"); 
 900                         if (!grow_sema_array(seminfo
.semmni 
+ 1)) 
 903                                 printf("failed to grow sema array\n"); 
 910                 printf("semid %d is available\n", semid
); 
 912                 sema
[semid
].sem_perm
.key 
= key
; 
 913                 sema
[semid
].sem_perm
.cuid 
= kauth_cred_getuid(cred
); 
 914                 sema
[semid
].sem_perm
.uid 
= kauth_cred_getuid(cred
); 
 915                 sema
[semid
].sem_perm
.cgid 
= cred
->cr_gid
; 
 916                 sema
[semid
].sem_perm
.gid 
= cred
->cr_gid
; 
 917                 sema
[semid
].sem_perm
.mode 
= (semflg 
& 0777) | SEM_ALLOC
; 
 918                 sema
[semid
].sem_perm
.seq 
= 
 919                     (sema
[semid
].sem_perm
.seq 
+ 1) & 0x7fff; 
 920                 sema
[semid
].sem_nsems 
= nsems
; 
 921                 sema
[semid
].sem_otime 
= 0; 
 922                 sema
[semid
].sem_ctime 
= sysv_semtime(); 
 923                 sema
[semid
].sem_base 
= &sem_pool
[semtot
]; 
 925                 bzero(sema
[semid
].sem_base
, 
 926                     sizeof(sema
[semid
].sem_base
[0])*nsems
); 
 928                 printf("sembase = 0x%x, next = 0x%x\n", sema
[semid
].sem_base
, 
 933                 printf("didn't find it and wasn't asked to create it\n"); 
 940         *retval 
= IXSEQ_TO_IPCID(semid
, sema
[semid
].sem_perm
); 
 941         AUDIT_ARG(svipc_id
, *retval
); 
 943         printf("semget is done, returning %d\n", *retval
); 
 948         SYSV_SEM_SUBSYS_UNLOCK(); 
 953 semop(struct proc 
*p
, struct semop_args 
*uap
, register_t 
*retval
) 
 955         int semid 
= uap
->semid
; 
 956         int nsops 
= uap
->nsops
; 
 957         struct sembuf sops
[MAX_SOPS
]; 
 958         register struct user_semid_ds 
*semaptr
; 
 959         register struct sembuf 
*sopptr 
= NULL
;  /* protected by 'semptr' */ 
 960         register struct sem 
*semptr 
= NULL
;     /* protected by 'if' */ 
 961         struct sem_undo 
*suptr 
= NULL
; 
 963         int do_wakeup
, do_undos
; 
 965         AUDIT_ARG(svipc_id
, uap
->semid
); 
 967         SYSV_SEM_SUBSYS_LOCK(); 
 970         printf("call to semop(%d, 0x%x, %d)\n", semid
, sops
, nsops
); 
 973         semid 
= IPCID_TO_IX(semid
);     /* Convert back to zero origin */ 
 975         if (semid 
< 0 || semid 
>= seminfo
.semmni
) { 
 980         semaptr 
= &sema
[semid
]; 
 981         if ((semaptr
->sem_perm
.mode 
& SEM_ALLOC
) == 0) { 
 985         if (semaptr
->sem_perm
.seq 
!= IPCID_TO_SEQ(uap
->semid
)) { 
 990         if ((eval 
= ipcperm(kauth_cred_get(), &semaptr
->sem_perm
, IPC_W
))) { 
 992                 printf("eval = %d from ipaccess\n", eval
); 
 997         if (nsops 
< 0 || nsops 
> MAX_SOPS
) { 
 999                 printf("too many sops (max=%d, nsops=%d)\n", MAX_SOPS
, nsops
); 
1005         /*  OK for LP64, since sizeof(struct sembuf) is currently invariant */ 
1006         if ((eval 
= copyin(uap
->sops
, &sops
, nsops 
* sizeof(struct sembuf
))) != 0) { 
1008                 printf("eval = %d from copyin(%08x, %08x, %ld)\n", eval
, 
1009                     uap
->sops
, &sops
, nsops 
* sizeof(struct sembuf
)); 
1015          * Loop trying to satisfy the vector of requests. 
1016          * If we reach a point where we must wait, any requests already 
1017          * performed are rolled back and we go to sleep until some other 
1018          * process wakes us up.  At this point, we start all over again. 
1020          * This ensures that from the perspective of other tasks, a set 
1021          * of requests is atomic (never partially satisfied). 
1028                 for (i 
= 0; i 
< nsops
; i
++) { 
1031                         if (sopptr
->sem_num 
>= semaptr
->sem_nsems
) { 
1036                         semptr 
= &semaptr
->sem_base
[sopptr
->sem_num
]; 
1039                         printf("semop:  semaptr=%x, sem_base=%x, semptr=%x, sem[%d]=%d : op=%d, flag=%s\n", 
1040                             semaptr
, semaptr
->sem_base
, semptr
, 
1041                             sopptr
->sem_num
, semptr
->semval
, sopptr
->sem_op
, 
1042                             (sopptr
->sem_flg 
& IPC_NOWAIT
) ? "nowait" : "wait"); 
1045                         if (sopptr
->sem_op 
< 0) { 
1046                                 if (semptr
->semval 
+ sopptr
->sem_op 
< 0) { 
1048                                         printf("semop:  can't do it now\n"); 
1052                                         semptr
->semval 
+= sopptr
->sem_op
; 
1053                                         if (semptr
->semval 
== 0 && 
1054                                             semptr
->semzcnt 
> 0) 
1057                                 if (sopptr
->sem_flg 
& SEM_UNDO
) 
1059                         } else if (sopptr
->sem_op 
== 0) { 
1060                                 if (semptr
->semval 
> 0) { 
1062                                         printf("semop:  not zero now\n"); 
1067                                 if (semptr
->semncnt 
> 0) 
1069                                 semptr
->semval 
+= sopptr
->sem_op
; 
1070                                 if (sopptr
->sem_flg 
& SEM_UNDO
) 
1076                  * Did we get through the entire vector? 
1082                  * No ... rollback anything that we've already done 
1085                 printf("semop:  rollback 0 through %d\n", i
-1); 
1087                 for (j 
= 0; j 
< i
; j
++) 
1088                         semaptr
->sem_base
[sops
[j
].sem_num
].semval 
-= 
1092                  * If the request that we couldn't satisfy has the 
1093                  * NOWAIT flag set then return with EAGAIN. 
1095                 if (sopptr
->sem_flg 
& IPC_NOWAIT
) { 
1100                 if (sopptr
->sem_op 
== 0) 
1106                 printf("semop:  good night!\n"); 
1108                 /* Release our lock on the semaphore subsystem so 
1109                  * another thread can get at the semaphore we are 
1110                  * waiting for. We will get the lock back after we 
1113                 eval 
= msleep((caddr_t
)semaptr
, &sysv_sem_subsys_mutex 
, (PZERO 
- 4) | PCATCH
, 
1117                 printf("semop:  good morning (eval=%d)!\n", eval
); 
1124                  * IMPORTANT: while we were asleep, the semaphore array might 
1125                  * have been reallocated somewhere else (see grow_sema_array()). 
1126                  * When we wake up, we have to re-lookup the semaphore  
1127                  * structures and re-validate them. 
1130                 suptr 
= NULL
;   /* sem_undo may have been reallocated */ 
1131                 semaptr 
= &sema
[semid
];    /* sema may have been reallocated */ 
1134                  * Make sure that the semaphore still exists 
1136                 if ((semaptr
->sem_perm
.mode 
& SEM_ALLOC
) == 0 || 
1137                     semaptr
->sem_perm
.seq 
!= IPCID_TO_SEQ(uap
->semid
) || 
1138                     sopptr
->sem_num 
>= semaptr
->sem_nsems
) { 
1139                         if (eval 
== EINTR
) { 
1141                                  * EINTR takes precedence over the fact that 
1142                                  * the semaphore disappeared while we were 
1147                                  * The man page says to return EIDRM. 
1148                                  * Unfortunately, BSD doesn't define that code! 
1160                  * The semaphore is still alive.  Readjust the count of 
1161                  * waiting processes. semptr needs to be recomputed 
1162                  * because the sem[] may have been reallocated while 
1163                  * we were sleeping, updating our sem_base pointer. 
1165                 semptr 
= &semaptr
->sem_base
[sopptr
->sem_num
]; 
1166                 if (sopptr
->sem_op 
== 0) 
1171                 if (eval 
!= 0) { /* EINTR */ 
1178          * Process any SEM_UNDO requests. 
1181                 for (i 
= 0; i 
< nsops
; i
++) { 
1183                          * We only need to deal with SEM_UNDO's for non-zero 
1188                         if ((sops
[i
].sem_flg 
& SEM_UNDO
) == 0) 
1190                         adjval 
= sops
[i
].sem_op
; 
1193                         eval 
= semundo_adjust(p
, &suptr
, semid
, 
1194                             sops
[i
].sem_num
, -adjval
); 
1199                          * Oh-Oh!  We ran out of either sem_undo's or undo's. 
1200                          * Rollback the adjustments to this point and then 
1201                          * rollback the semaphore ups and down so we can return 
1202                          * with an error with all structures restored.  We 
1203                          * rollback the undo's in the exact reverse order that 
1204                          * we applied them.  This guarantees that we won't run 
1205                          * out of space as we roll things back out. 
1207                         for (j 
= i 
- 1; j 
>= 0; j
--) { 
1208                                 if ((sops
[j
].sem_flg 
& SEM_UNDO
) == 0) 
1210                                 adjval 
= sops
[j
].sem_op
; 
1213                                 if (semundo_adjust(p
, &suptr
, semid
, 
1214                                     sops
[j
].sem_num
, adjval
) != 0) 
1215                                         panic("semop - can't undo undos"); 
1218                         for (j 
= 0; j 
< nsops
; j
++) 
1219                                 semaptr
->sem_base
[sops
[j
].sem_num
].semval 
-= 
1223                         printf("eval = %d from semundo_adjust\n", eval
); 
1226                 } /* loop through the sops */ 
1227         } /* if (do_undos) */ 
1229         /* We're definitely done - set the sempid's */ 
1230         for (i 
= 0; i 
< nsops
; i
++) { 
1232                 semptr 
= &semaptr
->sem_base
[sopptr
->sem_num
]; 
1233                 semptr
->sempid 
= p
->p_pid
; 
1238                 printf("semop:  doing wakeup\n"); 
1240                 sem_wakeup((caddr_t
)semaptr
); 
1242                 wakeup((caddr_t
)semaptr
); 
1244                 printf("semop:  back from wakeup\n"); 
1246                 wakeup((caddr_t
)semaptr
); 
1250         printf("semop:  done\n"); 
1255         SYSV_SEM_SUBSYS_UNLOCK(); 
1260  * Go through the undo structures for this process and apply the adjustments to 
1264 semexit(struct proc 
*p
) 
1266         register struct sem_undo 
*suptr
; 
1267         register struct sem_undo 
**supptr
; 
1270         /* If we have not allocated our semaphores yet there can't be 
1271          * anything to undo, but we need the lock to prevent 
1272          * dynamic memory race conditions. 
1274         SYSV_SEM_SUBSYS_LOCK(); 
1278                 SYSV_SEM_SUBSYS_UNLOCK(); 
1284          * Go through the chain of undo vectors looking for one 
1285          * associated with this process. 
1288         for (supptr 
= &semu_list
; (suptr 
= *supptr
) != NULL
; 
1289             supptr 
= &suptr
->un_next
) { 
1290                 if (suptr
->un_proc 
== p
) 
1298         printf("proc @%08x has undo structure with %d entries\n", p
, 
1303          * If there are any active undo elements then process them. 
1305         if (suptr
->un_cnt 
> 0) { 
1306                 while (suptr
->un_ent 
!= NULL
) { 
1307                         struct undo 
*sueptr
; 
1311                         struct user_semid_ds 
*semaptr
; 
1313                         sueptr 
= suptr
->un_ent
; 
1314                         semid 
= sueptr
->une_id
; 
1315                         semnum 
= sueptr
->une_num
; 
1316                         adjval 
= sueptr
->une_adjval
; 
1318                         semaptr 
= &sema
[semid
]; 
1319                         if ((semaptr
->sem_perm
.mode 
& SEM_ALLOC
) == 0) 
1320                                 panic("semexit - semid not allocated"); 
1321                         if (semnum 
>= semaptr
->sem_nsems
) 
1322                                 panic("semexit - semnum out of range"); 
1325                         printf("semexit:  %08x id=%d num=%d(adj=%d) ; sem=%d\n", 
1330                                semaptr
->sem_base
[semnum
].semval
); 
1334                                 if (semaptr
->sem_base
[semnum
].semval 
< -adjval
) 
1335                                         semaptr
->sem_base
[semnum
].semval 
= 0; 
1337                                         semaptr
->sem_base
[semnum
].semval 
+= 
1340                                 semaptr
->sem_base
[semnum
].semval 
+= adjval
; 
1342                 /* Maybe we should build a list of semaptr's to wake 
1343                  * up, finish all access to data structures, release the 
1344                  * subsystem lock, and wake all the processes.  Something 
1345                  * to think about.  It wouldn't buy us anything unless 
1346                  * wakeup had the potential to block, or the syscall 
1347                  * funnel state was changed to allow multiple threads 
1348                  * in the BSD code at once. 
1351                         sem_wakeup((caddr_t
)semaptr
); 
1353                         wakeup((caddr_t
)semaptr
); 
1356                         printf("semexit:  back from wakeup\n"); 
1359                         suptr
->un_ent 
= sueptr
->une_next
; 
1360                         FREE(sueptr
, M_SYSVSEM
); 
1366          * Deallocate the undo vector. 
1369         printf("removing vector\n"); 
1371         suptr
->un_proc 
= NULL
; 
1372         *supptr 
= suptr
->un_next
; 
1376          * There is a semaphore leak (i.e. memory leak) in this code. 
1377          * We should be deleting the IPC_PRIVATE semaphores when they are 
1378          * no longer needed, and we dont. We would have to track which processes 
1379          * know about which IPC_PRIVATE semaphores, updating the list after 
1380          * every fork.  We can't just delete them semaphore when the process 
1381          * that created it dies, because that process may well have forked 
1382          * some children.  So we need to wait until all of it's children have 
1383          * died, and so on.  Maybe we should tag each IPC_PRIVATE sempahore 
1384          * with the creating group ID, count the number of processes left in 
1385          * that group, and delete the semaphore when the group is gone. 
1386          * Until that code gets implemented we will leak IPC_PRIVATE semaphores. 
1387          * There is an upper bound on the size of our semaphore array, so    
1388          * leaking the semaphores should not work as a DOS attack. 
1390          * Please note that the original BSD code this file is based on had the 
1391          * same leaky semaphore problem. 
1394         SYSV_SEM_SUBSYS_UNLOCK(); 
1398 /* (struct sysctl_oid *oidp, void *arg1, int arg2, \ 
1399         struct sysctl_req *req) */ 
1401 sysctl_seminfo(__unused 
struct sysctl_oid 
*oidp
, void *arg1
, 
1402         __unused 
int arg2
, struct sysctl_req 
*req
) 
1406         error 
= SYSCTL_OUT(req
, arg1
, sizeof(int)); 
1407         if (error 
|| req
->newptr 
== USER_ADDR_NULL
) 
1410         SYSV_SEM_SUBSYS_LOCK(); 
1412         /* Set the values only if shared memory is not initialised */ 
1413         if ((sem_pool 
== NULL
) &&  
1416                 (semu_list 
== NULL
)) { 
1417                         if ((error 
= SYSCTL_IN(req
, arg1
, sizeof(int)))) { 
1423         SYSV_SEM_SUBSYS_UNLOCK(); 
1428 /* SYSCTL_NODE(_kern, KERN_SYSV, sysv, CTLFLAG_RW, 0, "SYSV"); */ 
1429 extern struct sysctl_oid_list sysctl__kern_sysv_children
; 
1430 SYSCTL_PROC(_kern_sysv
, KSYSV_SEMMNI
, semmni
, CTLTYPE_INT 
| CTLFLAG_RW
, 
1431     &limitseminfo
.semmni
, 0, &sysctl_seminfo 
,"I","semmni"); 
1433 SYSCTL_PROC(_kern_sysv
, KSYSV_SEMMNS
, semmns
, CTLTYPE_INT 
| CTLFLAG_RW
, 
1434     &limitseminfo
.semmns
, 0, &sysctl_seminfo 
,"I","semmns"); 
1436 SYSCTL_PROC(_kern_sysv
, KSYSV_SEMMNU
, semmnu
, CTLTYPE_INT 
| CTLFLAG_RW
, 
1437     &limitseminfo
.semmnu
, 0, &sysctl_seminfo 
,"I","semmnu"); 
1439 SYSCTL_PROC(_kern_sysv
, KSYSV_SEMMSL
, semmsl
, CTLTYPE_INT 
| CTLFLAG_RW
, 
1440     &limitseminfo
.semmsl
, 0, &sysctl_seminfo 
,"I","semmsl"); 
1442 SYSCTL_PROC(_kern_sysv
, KSYSV_SEMUNE
, semume
, CTLTYPE_INT 
| CTLFLAG_RW
, 
1443     &limitseminfo
.semume
, 0, &sysctl_seminfo 
,"I","semume"); 
1447 IPCS_sem_sysctl(__unused 
struct sysctl_oid 
*oidp
, __unused 
void *arg1
, 
1448         __unused 
int arg2
, struct sysctl_req 
*req
) 
1453                 struct IPCS_command u32
; 
1454                 struct user_IPCS_command u64
; 
1456         struct semid_ds semid_ds32
;     /* post conversion, 32 bit version */ 
1458         size_t ipcs_sz 
= sizeof(struct user_IPCS_command
); 
1459         size_t semid_ds_sz 
= sizeof(struct user_semid_ds
); 
1460         struct proc 
*p 
= current_proc(); 
1462         /* Copy in the command structure */ 
1463         if ((error 
= SYSCTL_IN(req
, &ipcs
, ipcs_sz
)) != 0) { 
1467         if (!IS_64BIT_PROCESS(p
)) { 
1468                 ipcs_sz 
= sizeof(struct IPCS_command
); 
1469                 semid_ds_sz 
= sizeof(struct semid_ds
); 
1472         /* Let us version this interface... */ 
1473         if (ipcs
.u64
.ipcs_magic 
!= IPCS_MAGIC
) { 
1477         SYSV_SEM_SUBSYS_LOCK(); 
1478         switch(ipcs
.u64
.ipcs_op
) { 
1479         case IPCS_SEM_CONF
:     /* Obtain global configuration data */ 
1480                 if (ipcs
.u64
.ipcs_datalen 
!= sizeof(struct seminfo
)) { 
1484                 if (ipcs
.u64
.ipcs_cursor 
!= 0) {        /* fwd. compat. */ 
1488                 error 
= copyout(&seminfo
, ipcs
.u64
.ipcs_data
, ipcs
.u64
.ipcs_datalen
); 
1491         case IPCS_SEM_ITER
:     /* Iterate over existing segments */ 
1492                 cursor 
= ipcs
.u64
.ipcs_cursor
; 
1493                 if (cursor 
< 0 || cursor 
>= seminfo
.semmni
) { 
1497                 if (ipcs
.u64
.ipcs_datalen 
!= (int)semid_ds_sz 
) { 
1501                 for( ; cursor 
< seminfo
.semmni
; cursor
++) { 
1502                         if (sema
[cursor
].sem_perm
.mode 
& SEM_ALLOC
) 
1506                 if (cursor 
== seminfo
.semmni
) { 
1511                 semid_dsp 
= &sema
[cursor
];      /* default: 64 bit */ 
1514                  * If necessary, convert the 64 bit kernel segment 
1515                  * descriptor to a 32 bit user one. 
1517                 if (!IS_64BIT_PROCESS(p
)) { 
1518                         semid_ds_64to32(semid_dsp
, &semid_ds32
); 
1519                         semid_dsp 
= &semid_ds32
; 
1521                 error 
= copyout(semid_dsp
, ipcs
.u64
.ipcs_data
, ipcs
.u64
.ipcs_datalen
); 
1524                         ipcs
.u64
.ipcs_cursor 
= cursor 
+ 1; 
1525                         error 
= SYSCTL_OUT(req
, &ipcs
, ipcs_sz
); 
1533         SYSV_SEM_SUBSYS_UNLOCK(); 
1537 SYSCTL_DECL(_kern_sysv_ipcs
); 
1538 SYSCTL_PROC(_kern_sysv_ipcs
, OID_AUTO
, sem
, CTLFLAG_RW
|CTLFLAG_ANYBODY
, 
1539         0, 0, IPCS_sem_sysctl
, 
1540         "S,IPCS_sem_command", 
1541         "ipcs sem command interface");