2  * Copyright (c) 2000-2007 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  *      Copyright (c) 1990, 1996-1998 Apple Computer, Inc. 
  30  *      All Rights Reserved. 
  33  * posix_sem.c : Support for POSIX semaphore APIs 
  36  *      Author: Ananthakrishna Ramesh 
  44  * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce 
  45  * support for mandatory and extensible security protections.  This notice 
  46  * is included in support of clause 2.2 (b) of the Apple Public License, 
  50 #include <sys/cdefs.h> 
  51 #include <sys/param.h> 
  52 #include <sys/systm.h> 
  53 #include <sys/kernel.h> 
  54 #include <sys/file_internal.h> 
  55 #include <sys/filedesc.h> 
  57 #include <sys/proc_internal.h> 
  58 #include <sys/kauth.h> 
  59 #include <sys/mount.h> 
  60 #include <sys/namei.h> 
  61 #include <sys/vnode.h> 
  62 #include <sys/ioctl.h> 
  64 #include <sys/malloc.h> 
  65 #include <sys/semaphore.h> 
  66 #include <sys/sysproto.h> 
  67 #include <sys/proc_info.h> 
  70 #include <sys/vnode_internal.h> 
  71 #include <security/mac_framework.h> 
  74 #include <security/audit/audit.h> 
  76 #include <mach/mach_types.h> 
  77 #include <mach/vm_prot.h> 
  78 #include <mach/semaphore.h> 
  79 #include <mach/sync_policy.h> 
  80 #include <mach/task.h> 
  81 #include <kern/kern_types.h> 
  82 #include <kern/task.h> 
  83 #include <kern/clock.h> 
  84 #include <mach/kern_return.h> 
  87 #define f_flag f_fglob->fg_flag 
  88 #define f_type f_fglob->fg_ops->fo_type 
  89 #define f_msgcount f_fglob->fg_msgcount 
  90 #define f_cred f_fglob->fg_cred 
  91 #define f_ops f_fglob->fg_ops 
  92 #define f_offset f_fglob->fg_offset 
  93 #define f_data f_fglob->fg_data 
  94 #define PSEMNAMLEN      31      /* maximum name segment length we bother with */ 
  97         unsigned int    psem_flags
; 
  98         unsigned int    psem_usecount
; 
 102         char            psem_name
[PSEMNAMLEN 
+ 1];      /* segment name */ 
 103         semaphore_t     psem_semobject
; 
 104         struct label 
*  psem_label
; 
 105         pid_t           psem_creator_pid
; 
 106         uint64_t        psem_creator_uniqueid
; 
 108 #define PSEMINFO_NULL (struct pseminfo *)0 
 111 #define PSEM_DEFINED    2 
 112 #define PSEM_ALLOCATED  4 
 113 #define PSEM_MAPPED     8 
 114 #define PSEM_INUSE      0x10 
 115 #define PSEM_REMOVED    0x20 
 116 #define PSEM_INCREATE   0x40 
 117 #define PSEM_INDELETE   0x80 
 120         LIST_ENTRY(psemcache
) psem_hash
;        /* hash chain */ 
 121         struct  pseminfo 
*pseminfo
;             /* vnode the name refers to */ 
 122         int     psem_nlen
;              /* length of name */ 
 123         char    psem_name
[PSEMNAMLEN 
+ 1];      /* segment name */ 
 125 #define PSEMCACHE_NULL (struct psemcache *)0 
 127 #define PSEMCACHE_NOTFOUND (0) 
 128 #define PSEMCACHE_FOUND    (-1) 
 129 #define PSEMCACHE_NEGATIVE (ENOENT) 
 132         long    goodhits
;               /* hits that we can really use */ 
 133         long    neghits
;                /* negative hits that we can use */ 
 134         long    badhits
;                /* hits we must drop */ 
 135         long    falsehits
;              /* hits with id mismatch */ 
 136         long    miss
;           /* misses */ 
 137         long    longnames
;              /* long names that ignore cache */ 
 141         char    *psem_nameptr
;  /* pointer to looked up name */ 
 142         long    psem_namelen
;   /* length of looked up component */ 
 143         u_int32_t       psem_hash
;      /* hash value of looked up name */ 
 147         struct pseminfo 
*pinfo
; 
 149         unsigned int readcnt
; 
 150         unsigned int writecnt
; 
 153 #define PSEMNODE_NULL (struct psemnode *)0 
 156 #define PSEMHASH(pnp) \ 
 157         (&psemhashtbl[(pnp)->psem_hash & psemhash]) 
 158 LIST_HEAD(psemhashhead
, psemcache
) *psemhashtbl
;        /* Hash Table */ 
 159 u_long  psemhash
;                               /* size of hash table - 1 */ 
 160 long    psemnument
;                     /* number of cache entries allocated */ 
 161 long    posix_sem_max 
= 10000;          /* tunable for max POSIX semaphores */ 
 162                                         /* 10000 limits to ~1M of memory */ 
 163 SYSCTL_NODE(_kern
, KERN_POSIX
, posix
, CTLFLAG_RW 
| CTLFLAG_LOCKED
, 0, "Posix"); 
 164 SYSCTL_NODE(_kern_posix
, OID_AUTO
, sem
, CTLFLAG_RW 
| CTLFLAG_LOCKED
, 0, "Semaphores"); 
 165 SYSCTL_LONG (_kern_posix_sem
, OID_AUTO
, max
, CTLFLAG_RW 
| CTLFLAG_LOCKED
, &posix_sem_max
, "max"); 
 167 struct psemstats psemstats
;             /* cache effectiveness statistics */ 
 169 static int psem_access(struct pseminfo 
*pinfo
, int mode
, kauth_cred_t cred
); 
 170 static int psem_cache_search(struct pseminfo 
**, 
 171                                 struct psemname 
*, struct psemcache 
**); 
 172 static int psem_delete(struct pseminfo 
* pinfo
); 
 174 static int psem_read (struct fileproc 
*fp
, struct uio 
*uio
, 
 175                             int flags
, vfs_context_t ctx
); 
 176 static int psem_write (struct fileproc 
*fp
, struct uio 
*uio
, 
 177                             int flags
, vfs_context_t ctx
); 
 178 static int psem_ioctl (struct fileproc 
*fp
, u_long com
, 
 179                             caddr_t data
, vfs_context_t ctx
); 
 180 static int psem_select (struct fileproc 
*fp
, int which
, void *wql
, vfs_context_t ctx
); 
 181 static int psem_closefile (struct fileglob 
*fp
, vfs_context_t ctx
); 
 182 static int psem_unlink_internal(struct pseminfo 
*pinfo
, struct psemcache 
*pcache
); 
 184 static int psem_kqfilter (struct fileproc 
*fp
, struct knote 
*kn
, vfs_context_t ctx
); 
 186 static const struct fileops psemops 
= { 
 187         .fo_type 
= DTYPE_PSXSEM
, 
 188         .fo_read 
= psem_read
, 
 189         .fo_write 
= psem_write
, 
 190         .fo_ioctl 
= psem_ioctl
, 
 191         .fo_select 
= psem_select
, 
 192         .fo_close 
= psem_closefile
, 
 193         .fo_kqfilter 
= psem_kqfilter
, 
 197 static lck_grp_t       
*psx_sem_subsys_lck_grp
; 
 198 static lck_grp_attr_t  
*psx_sem_subsys_lck_grp_attr
; 
 199 static lck_attr_t      
*psx_sem_subsys_lck_attr
; 
 200 static lck_mtx_t        psx_sem_subsys_mutex
; 
 202 #define PSEM_SUBSYS_LOCK() lck_mtx_lock(& psx_sem_subsys_mutex) 
 203 #define PSEM_SUBSYS_UNLOCK() lck_mtx_unlock(& psx_sem_subsys_mutex) 
 204 #define PSEM_SUBSYS_ASSERT_HELD() LCK_MTX_ASSERT(&psx_sem_subsys_mutex, LCK_MTX_ASSERT_OWNED) 
 207 static int psem_cache_add(struct pseminfo 
*psemp
, struct psemname 
*pnp
, struct psemcache 
*pcp
); 
 208 static void psem_cache_delete(struct psemcache 
*pcp
); 
 209 int psem_cache_purge_all(proc_t
); 
 212 /* Initialize the mutex governing access to the posix sem subsystem */ 
 213 __private_extern__ 
void 
 214 psem_lock_init( void ) 
 217     psx_sem_subsys_lck_grp_attr 
= lck_grp_attr_alloc_init(); 
 219     psx_sem_subsys_lck_grp 
= lck_grp_alloc_init("posix shared memory", psx_sem_subsys_lck_grp_attr
); 
 221     psx_sem_subsys_lck_attr 
= lck_attr_alloc_init(); 
 222     lck_mtx_init(& psx_sem_subsys_mutex
, psx_sem_subsys_lck_grp
, psx_sem_subsys_lck_attr
); 
 226  * Lookup an entry in the cache  
 229  * status of -1 is returned if matches 
 230  * If the lookup determines that the name does not exist 
 231  * (negative cacheing), a status of ENOENT is returned. If the lookup 
 232  * fails, a status of zero is returned. 
 236 psem_cache_search(struct pseminfo 
**psemp
, struct psemname 
*pnp
, 
 237                   struct psemcache 
**pcache
) 
 239         struct psemcache 
*pcp
, *nnp
; 
 240         struct psemhashhead 
*pcpp
; 
 242         if (pnp
->psem_namelen 
> PSEMNAMLEN
) { 
 243                 psemstats
.longnames
++; 
 244                 return PSEMCACHE_NOTFOUND
; 
 247         pcpp 
= PSEMHASH(pnp
); 
 248         for (pcp 
= pcpp
->lh_first
; pcp 
!= 0; pcp 
= nnp
) { 
 249                 nnp 
= pcp
->psem_hash
.le_next
; 
 250                 if (pcp
->psem_nlen 
== pnp
->psem_namelen 
&& 
 251                     !bcmp(pcp
->psem_name
, pnp
->psem_nameptr
,                                            (u_int
)pcp
-> psem_nlen
)) 
 257                 return PSEMCACHE_NOTFOUND
; 
 260         /* We found a "positive" match, return the vnode */ 
 262                 psemstats
.goodhits
++; 
 264                 *psemp 
= pcp
->pseminfo
; 
 266                 return PSEMCACHE_FOUND
; 
 270          * We found a "negative" match, ENOENT notifies client of this match. 
 271          * The nc_vpid field records whether this is a whiteout. 
 274         return PSEMCACHE_NEGATIVE
; 
 278  * Add an entry to the cache. 
 281 psem_cache_add(struct pseminfo 
*psemp
, struct psemname 
*pnp
, struct psemcache 
*pcp
) 
 283         struct psemhashhead 
*pcpp
; 
 284         struct pseminfo 
*dpinfo
; 
 285         struct psemcache 
*dpcp
; 
 288         if (pnp
->psem_namelen 
> PSEMNAMLEN
) 
 289                 panic("cache_enter: name too long"); 
 293         /*  if the entry has already been added by some one else return */ 
 294         if (psem_cache_search(&dpinfo
, pnp
, &dpcp
) == PSEMCACHE_FOUND
) { 
 297         if (psemnument 
>= posix_sem_max
) 
 301          * Fill in cache info, if vp is NULL this is a "negative" cache entry. 
 302          * For negative entries, we have to record whether it is a whiteout. 
 303          * the whiteout flag is stored in the nc_vpid field which is 
 306         pcp
->pseminfo 
= psemp
; 
 307         pcp
->psem_nlen 
= pnp
->psem_namelen
; 
 308         bcopy(pnp
->psem_nameptr
, pcp
->psem_name
, (unsigned)pcp
->psem_nlen
); 
 309         pcpp 
= PSEMHASH(pnp
); 
 314                 for (p 
= pcpp
->lh_first
; p 
!= 0; p 
= p
->psem_hash
.le_next
) 
 316                                 panic("psem:cache_enter duplicate"); 
 319         LIST_INSERT_HEAD(pcpp
, pcp
, psem_hash
); 
 324  * Name cache initialization, from vfs_init() when we are booting 
 327 psem_cache_init(void) 
 329         psemhashtbl 
= hashinit(posix_sem_max 
/ 2, M_SHM
, &psemhash
); 
 333 psem_cache_delete(struct psemcache 
*pcp
) 
 336         if (pcp
->psem_hash
.le_prev 
== 0) 
 337                 panic("psem namecache purge le_prev"); 
 338         if (pcp
->psem_hash
.le_next 
== pcp
) 
 339                 panic("namecache purge le_next"); 
 340 #endif /* DIAGNOSTIC */ 
 341         LIST_REMOVE(pcp
, psem_hash
); 
 342         pcp
->psem_hash
.le_prev 
= NULL
;   
 347  * Remove all cached psem entries. Open semaphores (with a positive refcount) 
 348  * will continue to exist, but their cache entries tying them to a particular 
 349  * name/path will be removed making all future lookups on the name fail. 
 352 psem_cache_purge_all(__unused proc_t p
) 
 354         struct psemcache 
*pcp
, *tmppcp
; 
 355         struct psemhashhead 
*pcpp
; 
 358         if (kauth_cred_issuser(kauth_cred_get()) == 0) 
 362         for (pcpp 
= &psemhashtbl
[psemhash
]; pcpp 
>= psemhashtbl
; pcpp
--) { 
 363                 LIST_FOREACH_SAFE(pcp
, pcpp
, psem_hash
, tmppcp
) { 
 364                         assert(pcp
->psem_nlen
); 
 366                          * unconditionally unlink the cache entry 
 368                         error 
= psem_unlink_internal(pcp
->pseminfo
, pcp
); 
 373         assert(psemnument 
== 0); 
 376         PSEM_SUBSYS_UNLOCK(); 
 379                 printf("%s: Error %d removing all semaphores: %ld remain!\n", 
 380                        __func__
, error
, psemnument
); 
 385 sem_open(proc_t p
, struct sem_open_args 
*uap
, user_addr_t 
*retval
) 
 390         struct pseminfo 
*pinfo
; 
 391         struct fileproc 
*fp 
= NULL
; 
 393         struct pseminfo 
*new_pinfo 
= PSEMINFO_NULL
; 
 394         struct psemnode 
*new_pnode 
= PSEMNODE_NULL
; 
 395         struct psemcache 
*pcache 
= PSEMCACHE_NULL
; 
 398         size_t pathlen
, plen
; 
 400         int cmode 
= uap
->mode
; 
 401         int value 
= uap
->value
; 
 403         struct psemcache 
*pcp 
= PSEMCACHE_NULL
; 
 404         kern_return_t kret 
= KERN_INVALID_ADDRESS
;      /* default fail */ 
 406         AUDIT_ARG(fflags
, uap
->oflag
); 
 407         AUDIT_ARG(mode
, uap
->mode
); 
 408         AUDIT_ARG(value32
, uap
->value
); 
 410         pinfo 
= PSEMINFO_NULL
; 
 413          * Preallocate everything we might need up front to avoid taking 
 414          * and dropping the lock, opening us up to race conditions. 
 416         MALLOC_ZONE(pnbuf
, caddr_t
, MAXPATHLEN
, M_NAMEI
, M_WAITOK
); 
 422         pathlen 
= MAXPATHLEN
; 
 423         error 
= copyinstr(uap
->name
, pnbuf
, MAXPATHLEN
, &pathlen
); 
 427         AUDIT_ARG(text
, pnbuf
); 
 428         if ( (pathlen 
> PSEMNAMLEN
) ) { 
 429                 error 
= ENAMETOOLONG
; 
 433 #ifdef PSXSEM_NAME_RESTRICT 
 435         if (*nameptr 
== '/') { 
 436                 while (*(nameptr
++) == '/') { 
 445 #endif /* PSXSEM_NAME_RESTRICT */ 
 449         nd
.psem_nameptr 
= nameptr
; 
 450         nd
.psem_namelen 
= plen
; 
 453         for (cp 
= nameptr
, i
=1; *cp 
!= 0 && i 
<= plen
; i
++, cp
++) { 
 454                nd
.psem_hash 
+= (unsigned char)*cp 
* i
; 
 458          * attempt to allocate a new fp; if unsuccessful, the fp will be 
 459          * left unmodified (NULL). 
 461         error 
= falloc(p
, &fp
, &indx
, vfs_context_current()); 
 466          * We allocate a new entry if we are less than the maximum 
 467          * allowed and the one at the front of the LRU list is in use. 
 468          * Otherwise we use the one at the front of the LRU list. 
 470         MALLOC(pcp
, struct psemcache 
*, sizeof(struct psemcache
), M_SHM
, M_WAITOK
|M_ZERO
); 
 471         if (pcp 
== PSEMCACHE_NULL
) { 
 476         MALLOC(new_pinfo
, struct pseminfo 
*, sizeof(struct pseminfo
), M_SHM
, M_WAITOK
|M_ZERO
); 
 477         if (new_pinfo 
== NULL
) { 
 482         mac_posixsem_label_init(new_pinfo
); 
 486          * Provisionally create the semaphore in the new_pinfo; we have to do 
 487          * this here to prevent locking later.  We use the value of kret to 
 488          * signal success or failure, which is why we set its default value 
 489          * to KERN_INVALID_ADDRESS, above. 
 492         fmode 
= FFLAGS(uap
->oflag
); 
 494         if((fmode 
& O_CREAT
)) { 
 496                 if((value 
< 0) || (value 
> SEM_VALUE_MAX
)) { 
 501                 kret 
= semaphore_create(kernel_task
, &new_pinfo
->psem_semobject
, SYNC_POLICY_FIFO
, value
); 
 503                 if (kret 
!= KERN_SUCCESS
) { 
 505                                 case KERN_RESOURCE_SHORTAGE
: 
 508                                 case KERN_PROTECTION_FAILURE
: 
 518         MALLOC(new_pnode
, struct psemnode 
*, sizeof(struct psemnode
), M_SHM
, M_WAITOK
|M_ZERO
); 
 519         if (new_pnode 
== NULL
) { 
 525         error 
= psem_cache_search(&pinfo
, &nd
, &pcache
); 
 527         if (error 
== PSEMCACHE_NEGATIVE
) { 
 532         if (error 
== PSEMCACHE_FOUND
) 
 539         if (((fmode 
& (O_CREAT 
| O_EXCL
))==(O_CREAT 
| O_EXCL
)) &&  incache
) { 
 540                 /* sem exists and opened O_EXCL */ 
 542                 if (pinfo
->psem_flags 
& PSEM_INDELETE
) { 
 545                 AUDIT_ARG(posix_ipc_perm
, pinfo
->psem_uid
, 
 546                         pinfo
->psem_gid
, pinfo
->psem_mode
); 
 550         if (((fmode 
& (O_CREAT 
| O_EXCL
))== O_CREAT
) &&  incache
) { 
 551                 /* As per POSIX, O_CREAT has no effect */ 
 555         if ( (fmode 
& O_CREAT
) ) { 
 556                 /* create a new one (commit the allocation) */ 
 558                 pinfo
->psem_flags 
= PSEM_DEFINED 
| PSEM_INCREATE
; 
 559                 pinfo
->psem_usecount 
= 1; 
 560                 pinfo
->psem_mode 
= cmode
; 
 561                 pinfo
->psem_uid 
= kauth_getuid(); 
 562                 pinfo
->psem_gid 
= kauth_getgid(); 
 563                 bcopy(pnbuf
, &pinfo
->psem_name
[0], PSEMNAMLEN
); 
 564                 pinfo
->psem_name
[PSEMNAMLEN
]= 0; 
 565                 pinfo
->psem_flags 
&= ~PSEM_DEFINED
; 
 566                 pinfo
->psem_flags 
|= PSEM_ALLOCATED
; 
 567                 pinfo
->psem_creator_pid 
= p
->p_pid
; 
 568                 pinfo
->psem_creator_uniqueid 
= p
->p_uniqueid
; 
 571                 error 
= mac_posixsem_check_create(kauth_cred_get(), nameptr
); 
 575                 mac_posixsem_label_associate(kauth_cred_get(), pinfo
, nameptr
); 
 578                 /* semaphore should exist as it is without  O_CREAT */ 
 583                 if( pinfo
->psem_flags 
& PSEM_INDELETE
) { 
 587                 AUDIT_ARG(posix_ipc_perm
, pinfo
->psem_uid
, 
 588                         pinfo
->psem_gid
, pinfo
->psem_mode
); 
 590                 error 
= mac_posixsem_check_open(kauth_cred_get(), pinfo
); 
 595                 if ( (error 
= psem_access(pinfo
, fmode
, kauth_cred_get())) ) { 
 601                 /* if successful, this will consume the pcp */ 
 602                 if ( (error 
= psem_cache_add(pinfo
, &nd
, pcp
)) ) { 
 606         pinfo
->psem_flags 
&= ~PSEM_INCREATE
; 
 607         pinfo
->psem_usecount
++; 
 608         new_pnode
->pinfo 
= pinfo
; 
 609         PSEM_SUBSYS_UNLOCK(); 
 612          * if incache, we did not use the new pcp or the new pcp or the 
 613          * new . and we must free them. 
 617                 pcp 
= PSEMCACHE_NULL
; 
 618                 if (new_pinfo 
!= PSEMINFO_NULL
) { 
 619                         /* return value ignored - we can't _not_ do this */ 
 620                         (void)semaphore_destroy(kernel_task
, new_pinfo
->psem_semobject
); 
 622                         mac_posixsem_label_destroy(new_pinfo
); 
 624                         FREE(new_pinfo
, M_SHM
); 
 625                         new_pinfo 
= PSEMINFO_NULL
; 
 630         fp
->f_flag 
= fmode 
& FMASK
; 
 631         fp
->f_ops 
= &psemops
; 
 632         fp
->f_data 
= (caddr_t
)new_pnode
; 
 633         procfdtbl_releasefd(p
, indx
, NULL
); 
 634         fp_drop(p
, indx
, fp
, 1); 
 637         *retval 
= CAST_USER_ADDR_T(indx
); 
 638         FREE_ZONE(pnbuf
, MAXPATHLEN
, M_NAMEI
); 
 642         PSEM_SUBSYS_UNLOCK(); 
 644         if (pcp 
!= PSEMCACHE_NULL
) 
 647         if (new_pnode 
!= PSEMNODE_NULL
) 
 648                 FREE(new_pnode
, M_SHM
); 
 651                 fp_free(p
, indx
, fp
); 
 653         if (new_pinfo 
!= PSEMINFO_NULL
) { 
 655                  * kret signals whether or not we successfully created a 
 656                  * Mach semaphore for this semaphore; if so, we need to 
 659                 if (kret 
== KERN_SUCCESS
) { 
 660                         /* return value ignored - we can't _not_ do this */ 
 661                         (void)semaphore_destroy(kernel_task
, new_pinfo
->psem_semobject
); 
 664                 mac_posixsem_label_destroy(new_pinfo
); 
 666                 FREE(new_pinfo
, M_SHM
); 
 670                 FREE_ZONE(pnbuf
, MAXPATHLEN
, M_NAMEI
); 
 675  * XXX This code is repeated in several places 
 678 psem_access(struct pseminfo 
*pinfo
, int mode
, kauth_cred_t cred
) 
 680         int mode_req 
= ((mode 
& FREAD
) ? S_IRUSR 
: 0) | 
 681                        ((mode 
& FWRITE
) ? S_IWUSR 
: 0); 
 683         /* Otherwise, user id 0 always gets access. */ 
 684         if (!suser(cred
, NULL
)) 
 687         return(posix_cred_access(cred
, pinfo
->psem_uid
, pinfo
->psem_gid
, pinfo
->psem_mode
, mode_req
)); 
 691 psem_unlink_internal(struct pseminfo 
*pinfo
, struct psemcache 
*pcache
) 
 693         PSEM_SUBSYS_ASSERT_HELD(); 
 695         if (!pinfo 
|| !pcache
) 
 698         if ((pinfo
->psem_flags 
& (PSEM_DEFINED 
| PSEM_ALLOCATED
)) == 0) 
 701         if (pinfo
->psem_flags 
& PSEM_INDELETE
) 
 704         AUDIT_ARG(posix_ipc_perm
, pinfo
->psem_uid
, pinfo
->psem_gid
, 
 707         pinfo
->psem_flags 
|= PSEM_INDELETE
; 
 708         pinfo
->psem_usecount
--; 
 710         if (!pinfo
->psem_usecount
) { 
 714                 pinfo
->psem_flags 
|= PSEM_REMOVED
; 
 717         psem_cache_delete(pcache
); 
 724 sem_unlink(__unused proc_t p
, struct sem_unlink_args 
*uap
, __unused 
int32_t *retval
) 
 729         struct pseminfo 
*pinfo
; 
 734         struct psemcache 
*pcache 
= PSEMCACHE_NULL
; 
 736         pinfo 
= PSEMINFO_NULL
; 
 738         MALLOC_ZONE(pnbuf
, caddr_t
, MAXPATHLEN
, M_NAMEI
, M_WAITOK
); 
 740                 return(ENOSPC
);         /* XXX non-standard */ 
 742         pathlen 
= MAXPATHLEN
; 
 743         error 
= copyinstr(uap
->name
, pnbuf
, MAXPATHLEN
, &pathlen
); 
 747         AUDIT_ARG(text
, pnbuf
); 
 748         if (pathlen 
> PSEMNAMLEN
) { 
 749                 error 
= ENAMETOOLONG
; 
 755 #ifdef PSXSEM_NAME_RESTRICT 
 756         if (*nameptr 
== '/') { 
 757                 while (*(nameptr
++) == '/') { 
 766 #endif /* PSXSEM_NAME_RESTRICT */ 
 768         nd
.psem_nameptr 
= nameptr
; 
 769         nd
.psem_namelen 
= pathlen
; 
 772         for (cp 
= nameptr
, i
=1; *cp 
!= 0 && i 
<= pathlen
; i
++, cp
++) { 
 773                nd
.psem_hash 
+= (unsigned char)*cp 
* i
; 
 777         error 
= psem_cache_search(&pinfo
, &nd
, &pcache
); 
 779         if (error 
!= PSEMCACHE_FOUND
) { 
 780                 PSEM_SUBSYS_UNLOCK(); 
 787         error 
= mac_posixsem_check_unlink(kauth_cred_get(), pinfo
, nameptr
); 
 789                 PSEM_SUBSYS_UNLOCK(); 
 793         if ( (error 
= psem_access(pinfo
, pinfo
->psem_mode
, kauth_cred_get())) ) { 
 794                 PSEM_SUBSYS_UNLOCK(); 
 798         error 
= psem_unlink_internal(pinfo
, pcache
); 
 799         PSEM_SUBSYS_UNLOCK(); 
 802         FREE_ZONE(pnbuf
, MAXPATHLEN
, M_NAMEI
); 
 807 sem_close(proc_t p
, struct sem_close_args 
*uap
, __unused 
int32_t *retval
) 
 809         int fd 
= CAST_DOWN_EXPLICIT(int,uap
->sem
); 
 813         AUDIT_ARG(fd
, fd
); /* XXX This seems wrong; uap->sem is a pointer */ 
 816         error 
= fp_lookup(p
,fd
, &fp
, 1); 
 821         procfdtbl_markclosefd(p
, fd
); 
 822         fileproc_drain(p
, fp
); 
 824         error 
= closef_locked(fp
, fp
->f_fglob
, p
); 
 831 sem_wait(proc_t p
, struct sem_wait_args 
*uap
, int32_t *retval
) 
 833         __pthread_testcancel(1); 
 834         return(sem_wait_nocancel(p
, (struct sem_wait_nocancel_args 
*)uap
, retval
)); 
 838 sem_wait_nocancel(proc_t p
, struct sem_wait_nocancel_args 
*uap
, __unused 
int32_t *retval
) 
 840         int fd 
= CAST_DOWN_EXPLICIT(int,uap
->sem
); 
 842         struct pseminfo 
* pinfo
; 
 843         struct psemnode 
* pnode 
; 
 847         error 
= fp_getfpsem(p
, fd
, &fp
, &pnode
); 
 850         if (((pnode 
= (struct psemnode 
*)fp
->f_data
)) == PSEMNODE_NULL 
)  { 
 855         if ((pinfo 
= pnode
->pinfo
) == PSEMINFO_NULL
) { 
 856                 PSEM_SUBSYS_UNLOCK(); 
 860         if ((pinfo
->psem_flags 
& (PSEM_DEFINED 
| PSEM_ALLOCATED
))  
 862                 PSEM_SUBSYS_UNLOCK(); 
 867         error 
= mac_posixsem_check_wait(kauth_cred_get(), pinfo
); 
 869                 PSEM_SUBSYS_UNLOCK(); 
 873         PSEM_SUBSYS_UNLOCK(); 
 874         kret 
= semaphore_wait(pinfo
->psem_semobject
); 
 876         case KERN_INVALID_ADDRESS
: 
 877         case KERN_PROTECTION_FAILURE
: 
 881         case KERN_OPERATION_TIMED_OUT
: 
 892         fp_drop(p
, fd
, fp
, 0); 
 898 sem_trywait(proc_t p
, struct sem_trywait_args 
*uap
, __unused 
int32_t *retval
) 
 900         int fd 
= CAST_DOWN_EXPLICIT(int,uap
->sem
); 
 902         struct pseminfo 
* pinfo
; 
 903         struct psemnode 
* pnode 
; 
 905         mach_timespec_t wait_time
; 
 908         error 
= fp_getfpsem(p
, fd
, &fp
, &pnode
); 
 911         if (((pnode 
= (struct psemnode 
*)fp
->f_data
)) == PSEMNODE_NULL 
)  { 
 916         if ((pinfo 
= pnode
->pinfo
) == PSEMINFO_NULL
) { 
 917                 PSEM_SUBSYS_UNLOCK(); 
 921         if ((pinfo
->psem_flags 
& (PSEM_DEFINED 
| PSEM_ALLOCATED
))  
 923                 PSEM_SUBSYS_UNLOCK(); 
 928         error 
= mac_posixsem_check_wait(kauth_cred_get(), pinfo
); 
 930                 PSEM_SUBSYS_UNLOCK(); 
 934         PSEM_SUBSYS_UNLOCK(); 
 935         wait_time
.tv_sec 
= 0; 
 936         wait_time
.tv_nsec 
= 0; 
 938         kret 
= semaphore_timedwait(pinfo
->psem_semobject
, MACH_TIMESPEC_ZERO
); 
 940         case KERN_INVALID_ADDRESS
: 
 941         case KERN_PROTECTION_FAILURE
: 
 947         case KERN_OPERATION_TIMED_OUT
: 
 958         fp_drop(p
, fd
, fp
, 0); 
 963 sem_post(proc_t p
, struct sem_post_args 
*uap
, __unused 
int32_t *retval
) 
 965         int fd 
= CAST_DOWN_EXPLICIT(int,uap
->sem
); 
 967         struct pseminfo 
* pinfo
; 
 968         struct psemnode 
* pnode 
; 
 972         error 
= fp_getfpsem(p
, fd
, &fp
, &pnode
); 
 975         if (((pnode 
= (struct psemnode 
*)fp
->f_data
)) == PSEMNODE_NULL 
)  { 
 980         if ((pinfo 
= pnode
->pinfo
) == PSEMINFO_NULL
) { 
 981                 PSEM_SUBSYS_UNLOCK(); 
 985         if ((pinfo
->psem_flags 
& (PSEM_DEFINED 
| PSEM_ALLOCATED
))  
 987                 PSEM_SUBSYS_UNLOCK(); 
 992         error 
= mac_posixsem_check_post(kauth_cred_get(), pinfo
); 
 994                 PSEM_SUBSYS_UNLOCK(); 
 998         PSEM_SUBSYS_UNLOCK(); 
 999         kret 
= semaphore_signal(pinfo
->psem_semobject
); 
1001         case KERN_INVALID_ADDRESS
: 
1002         case KERN_PROTECTION_FAILURE
: 
1006         case KERN_OPERATION_TIMED_OUT
: 
1017         fp_drop(p
, fd
, fp
, 0); 
1022 psem_close(struct psemnode 
*pnode
, __unused 
int flags
) 
1025         struct pseminfo 
*pinfo
; 
1028         if ((pinfo 
= pnode
->pinfo
) == PSEMINFO_NULL
){ 
1029                 PSEM_SUBSYS_UNLOCK(); 
1033         if ((pinfo
->psem_flags 
& PSEM_ALLOCATED
) != PSEM_ALLOCATED
) { 
1034                 PSEM_SUBSYS_UNLOCK(); 
1038         if(!pinfo
->psem_usecount
) { 
1039                 kprintf("negative usecount in psem_close\n"); 
1041 #endif /* DIAGNOSTIC */ 
1042         pinfo
->psem_usecount
--; 
1044         if ((pinfo
->psem_flags 
& PSEM_REMOVED
) && !pinfo
->psem_usecount
) { 
1045                 PSEM_SUBSYS_UNLOCK(); 
1046                 /* lock dropped as only semaphore is destroyed here */ 
1047                 error 
= psem_delete(pinfo
); 
1050                 PSEM_SUBSYS_UNLOCK(); 
1052         /* subsystem lock is dropped when we get here */ 
1058 psem_closefile(struct fileglob 
*fg
, __unused vfs_context_t ctx
) 
1063          * Not locked as psem_close is called only from here and is locked 
1066         error 
=  psem_close(((struct psemnode 
*)fg
->fg_data
), fg
->fg_flag
); 
1072 psem_delete(struct pseminfo 
* pinfo
) 
1076         kret 
= semaphore_destroy(kernel_task
, pinfo
->psem_semobject
); 
1078         mac_posixsem_label_destroy(pinfo
); 
1082         case KERN_INVALID_ADDRESS
: 
1083         case KERN_PROTECTION_FAILURE
: 
1086         case KERN_OPERATION_TIMED_OUT
: 
1096 psem_read(__unused 
struct fileproc 
*fp
, __unused 
struct uio 
*uio
,  
1097                   __unused 
int flags
, __unused vfs_context_t ctx
) 
1103 psem_write(__unused 
struct fileproc 
*fp
, __unused 
struct uio 
*uio
,  
1104                    __unused 
int flags
, __unused vfs_context_t ctx
) 
1110 psem_ioctl(__unused 
struct fileproc 
*fp
, __unused u_long com
,  
1111                         __unused caddr_t data
, __unused vfs_context_t ctx
) 
1117 psem_select(__unused 
struct fileproc 
*fp
, __unused 
int which
,  
1118                         __unused 
void *wql
, __unused vfs_context_t ctx
) 
1124 psem_kqfilter(__unused 
struct fileproc 
*fp
, struct knote 
*kn
,  
1125                                 __unused vfs_context_t ctx
) 
1127         kn
->kn_flags 
= EV_ERROR
; 
1128         kn
->kn_data 
= ENOTSUP
; 
1133 fill_pseminfo(struct psemnode 
*pnode
, struct psem_info 
* info
) 
1135         struct pseminfo 
*pinfo
; 
1136         struct vinfo_stat  
*sb
; 
1139         if ((pinfo 
= pnode
->pinfo
) == PSEMINFO_NULL
){ 
1140                 PSEM_SUBSYS_UNLOCK(); 
1145         if ((pinfo
->psem_flags 
& PSEM_ALLOCATED
) != PSEM_ALLOCATED
) { 
1146                 PSEM_SUBSYS_UNLOCK(); 
1151         sb 
= &info
->psem_stat
; 
1152         bzero(sb
, sizeof(struct vinfo_stat
)); 
1154         sb
->vst_mode 
= pinfo
->psem_mode
; 
1155         sb
->vst_uid 
= pinfo
->psem_uid
; 
1156         sb
->vst_gid 
= pinfo
->psem_gid
; 
1157         sb
->vst_size 
= pinfo
->psem_usecount
; 
1158         bcopy(&pinfo
->psem_name
[0], &info
->psem_name
[0], PSEMNAMLEN
+1); 
1160         PSEM_SUBSYS_UNLOCK(); 
1166 psem_label_associate(struct fileproc 
*fp
, struct vnode 
*vp
, vfs_context_t ctx
) 
1168         struct psemnode 
*pnode
; 
1169         struct pseminfo 
*psem
; 
1172         pnode 
= (struct psemnode 
*)fp
->f_fglob
->fg_data
; 
1173         if (pnode 
!= NULL
) { 
1174                 psem 
= pnode
->pinfo
; 
1176                         mac_posixsem_vnode_label_associate( 
1177                                 vfs_context_ucred(ctx
), psem
, psem
->psem_label
, 
1180         PSEM_SUBSYS_UNLOCK();