X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/d7e50217d7adf6e52786a38bcaa4cd698cb9a79e..8f6c56a50524aa785f7e596d52dddfb331e18961:/bsd/kern/posix_sem.c?ds=sidebyside diff --git a/bsd/kern/posix_sem.c b/bsd/kern/posix_sem.c index 56b920a4f..1dcc200d2 100644 --- a/bsd/kern/posix_sem.c +++ b/bsd/kern/posix_sem.c @@ -1,16 +1,19 @@ /* - * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ - * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER @@ -20,7 +23,7 @@ * Please see the License for the specific language governing rights and * limitations under the License. * - * @APPLE_LICENSE_HEADER_END@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* * Copyright (c) 1990, 1996-1998 Apple Computer, Inc. @@ -42,11 +45,11 @@ #include #include #include -#include +#include #include #include -#include -#include +#include +#include #include #include #include @@ -54,14 +57,31 @@ #include #include #include +#include + +#include + #include #include #include #include +#include +#include #include #include #include +#if KTRACE +#include +#endif + +#define f_flag f_fglob->fg_flag +#define f_type f_fglob->fg_type +#define f_msgcount f_fglob->fg_msgcount +#define f_cred f_fglob->fg_cred +#define f_ops f_fglob->fg_ops +#define f_offset f_fglob->fg_offset +#define f_data f_fglob->fg_data #define PSEMNAMLEN 31 /* maximum name segment length we bother with */ struct pseminfo { @@ -71,7 +91,7 @@ struct pseminfo { uid_t psem_uid; gid_t psem_gid; char psem_name[PSEMNAMLEN + 1]; /* segment name */ - void * psem_semobject; + semaphore_t psem_semobject; struct proc * sem_proc; }; #define PSEMINFO_NULL (struct pseminfo *)0 @@ -123,23 +143,58 @@ struct psemnode { LIST_HEAD(psemhashhead, psemcache) *psemhashtbl; /* Hash Table */ u_long psemhash; /* size of hash table - 1 */ long psemnument; /* number of cache entries allocated */ +long posix_sem_max = 10000; /* tunable for max POSIX semaphores */ + /* 10000 limits to ~1M of memory */ +SYSCTL_NODE(_kern, KERN_POSIX, posix, CTLFLAG_RW, 0, "Posix"); +SYSCTL_NODE(_kern_posix, OID_AUTO, sem, CTLFLAG_RW, 0, "Semaphores"); +SYSCTL_INT (_kern_posix_sem, OID_AUTO, max, CTLFLAG_RW, &posix_sem_max, 0, "max"); + struct psemstats psemstats; /* cache effectiveness statistics */ -static int psem_cache_search __P((struct pseminfo **, - struct psemname *, struct psemcache **)); +static int psem_access(struct pseminfo *pinfo, int mode, kauth_cred_t cred); +static int psem_cache_search(struct pseminfo **, + struct psemname *, struct psemcache **); +static int psem_delete(struct pseminfo * pinfo); + +static int psem_read (struct fileproc *fp, struct uio *uio, + kauth_cred_t cred, int flags, struct proc *p); +static int psem_write (struct fileproc *fp, struct uio *uio, + kauth_cred_t cred, int flags, struct proc *p); +static int psem_ioctl (struct fileproc *fp, u_long com, + caddr_t data, struct proc *p); +static int psem_select (struct fileproc *fp, int which, void *wql, struct proc *p); +static int psem_closefile (struct fileglob *fp, struct proc *p); -static int psem_read __P((struct file *fp, struct uio *uio, - struct ucred *cred, int flags, struct proc *p)); -static int psem_write __P((struct file *fp, struct uio *uio, - struct ucred *cred, int flags, struct proc *p)); -static int psem_ioctl __P((struct file *fp, u_long com, - caddr_t data, struct proc *p)); -static int psem_select __P((struct file *fp, int which, void *wql, - struct proc *p)); -static int psem_closefile __P((struct file *fp, struct proc *p)); +static int psem_kqfilter (struct fileproc *fp, struct knote *kn, struct proc *p); struct fileops psemops = - { psem_read, psem_write, psem_ioctl, psem_select, psem_closefile }; + { psem_read, psem_write, psem_ioctl, psem_select, psem_closefile, psem_kqfilter, 0 }; + + +static lck_grp_t *psx_sem_subsys_lck_grp; +static lck_grp_attr_t *psx_sem_subsys_lck_grp_attr; +static lck_attr_t *psx_sem_subsys_lck_attr; +static lck_mtx_t psx_sem_subsys_mutex; + +#define PSEM_SUBSYS_LOCK() lck_mtx_lock(& psx_sem_subsys_mutex) +#define PSEM_SUBSYS_UNLOCK() lck_mtx_unlock(& psx_sem_subsys_mutex) + + +static int psem_cache_add(struct pseminfo *psemp, struct psemname *pnp, struct psemcache *pcp); +/* Initialize the mutex governing access to the posix sem subsystem */ +__private_extern__ void +psem_lock_init( void ) +{ + + psx_sem_subsys_lck_grp_attr = lck_grp_attr_alloc_init(); + lck_grp_attr_setstat(psx_sem_subsys_lck_grp_attr); + + psx_sem_subsys_lck_grp = lck_grp_alloc_init("posix shared memory", psx_sem_subsys_lck_grp_attr); + + psx_sem_subsys_lck_attr = lck_attr_alloc_init(); + /* lck_attr_setdebug(psx_sem_subsys_lck_attr); */ + lck_mtx_init(& psx_sem_subsys_mutex, psx_sem_subsys_lck_grp, psx_sem_subsys_lck_attr); +} /* * Lookup an entry in the cache @@ -157,8 +212,8 @@ psem_cache_search(psemp, pnp, pcache) struct psemname *pnp; struct psemcache **pcache; { - register struct psemcache *pcp, *nnp; - register struct psemhashhead *pcpp; + struct psemcache *pcp, *nnp; + struct psemhashhead *pcpp; if (pnp->psem_namelen > PSEMNAMLEN) { psemstats.longnames++; @@ -199,12 +254,9 @@ psem_cache_search(psemp, pnp, pcache) * Add an entry to the cache. */ static int -psem_cache_add(psemp, pnp) - struct pseminfo *psemp; - struct psemname *pnp; +psem_cache_add(struct pseminfo *psemp, struct psemname *pnp, struct psemcache *pcp) { - register struct psemcache *pcp; - register struct psemhashhead *pcpp; + struct psemhashhead *pcpp; struct pseminfo *dpinfo; struct psemcache *dpcp; @@ -213,20 +265,14 @@ psem_cache_add(psemp, pnp) panic("cache_enter: name too long"); #endif - /* - * We allocate a new entry if we are less than the maximum - * allowed and the one at the front of the LRU list is in use. - * Otherwise we use the one at the front of the LRU list. - */ - pcp = (struct psemcache *)_MALLOC(sizeof(struct psemcache), M_SHM, M_WAITOK); + /* if the entry has already been added by some one else return */ if (psem_cache_search(&dpinfo, pnp, &dpcp) == -1) { - _FREE(pcp, M_SHM); return(EEXIST); } + if (psemnument >= posix_sem_max) + return(ENOSPC); psemnument++; - - bzero(pcp, sizeof(struct psemcache)); /* * Fill in cache info, if vp is NULL this is a "negative" cache entry. * For negative entries, we have to record whether it is a whiteout. @@ -239,7 +285,7 @@ psem_cache_add(psemp, pnp) pcpp = PSEMHASH(pnp); #if DIAGNOSTIC { - register struct psemcache *p; + struct psemcache *p; for (p = pcpp->lh_first; p != 0; p = p->psem_hash.le_next) if (p == pcp) @@ -254,14 +300,13 @@ psem_cache_add(psemp, pnp) * Name cache initialization, from vfs_init() when we are booting */ void -psem_cache_init() +psem_cache_init(void) { psemhashtbl = hashinit(desiredvnodes, M_SHM, &psemhash); } static void -psem_cache_delete(pcp) - struct psemcache *pcp; +psem_cache_delete(struct psemcache *pcp) { #if DIAGNOSTIC if (pcp->psem_hash.le_prev == 0) @@ -274,6 +319,7 @@ psem_cache_delete(pcp) psemnument--; } +#if NOT_USED /* * Invalidate a all entries to particular vnode. * @@ -282,40 +328,29 @@ psem_cache_delete(pcp) * need to ditch the entire cache, to avoid confusion. No valid vnode will * ever have (v_id == 0). */ -void +static void psem_cache_purge(void) { struct psemcache *pcp; struct psemhashhead *pcpp; for (pcpp = &psemhashtbl[psemhash]; pcpp >= psemhashtbl; pcpp--) { - while (pcp = pcpp->lh_first) + while ( (pcp = pcpp->lh_first) ) psem_cache_delete(pcp); } } - -struct sem_open_args { - const char *name; - int oflag; - int mode; - int value; -}; +#endif /* NOT_USED */ int -sem_open(p, uap, retval) - struct proc *p; - register struct sem_open_args *uap; - register_t *retval; +sem_open(struct proc *p, struct sem_open_args *uap, user_addr_t *retval) { - register struct filedesc *fdp = p->p_fd; - register struct file *fp; - register struct vnode *vp; - int flags, i; - struct file *nfp; - int type, indx, error; + struct fileproc *fp; + size_t i; + struct fileproc *nfp; + int indx, error; struct psemname nd; struct pseminfo *pinfo; - extern struct fileops psemops; + struct psemcache *pcp; char * pnbuf; char * nameptr; char * cp; @@ -329,17 +364,23 @@ sem_open(p, uap, retval) kern_return_t kret = KERN_SUCCESS; int pinfo_alloc = 0; + AUDIT_ARG(fflags, uap->oflag); + AUDIT_ARG(mode, uap->mode); + AUDIT_ARG(value, uap->value); + pinfo = PSEMINFO_NULL; - MALLOC_ZONE(pnbuf, caddr_t, - MAXPATHLEN, M_NAMEI, M_WAITOK); + MALLOC_ZONE(pnbuf, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK); + if (pnbuf == NULL) + return(ENOSPC); + pathlen = MAXPATHLEN; - error = copyinstr(uap->name, pnbuf, - MAXPATHLEN, &pathlen); + error = copyinstr(uap->name, pnbuf, MAXPATHLEN, &pathlen); if (error) { goto bad; } - if (pathlen > PSEMNAMLEN) { + AUDIT_ARG(text, pnbuf); + if ( (pathlen > PSEMNAMLEN) ) { error = ENAMETOOLONG; goto bad; } @@ -368,9 +409,16 @@ sem_open(p, uap, retval) nd.psem_hash += (unsigned char)*cp * i; } +#if KTRACE + if (KTRPOINT(p, KTR_NAMEI)) + ktrnamei(p->p_tracep, nameptr); +#endif + + PSEM_SUBSYS_LOCK(); error = psem_cache_search(&pinfo, &nd, &pcache); if (error == ENOENT) { + PSEM_SUBSYS_UNLOCK(); error = EINVAL; goto bad; @@ -381,10 +429,12 @@ sem_open(p, uap, retval) incache = 1; fmode = FFLAGS(uap->oflag); - if (error = falloc(p, &nfp, &indx)) { + PSEM_SUBSYS_UNLOCK(); + error = falloc(p, &nfp, &indx); + if (error) goto bad; - } + PSEM_SUBSYS_LOCK(); fp = nfp; cmode &= ALLPERMS; @@ -394,6 +444,9 @@ sem_open(p, uap, retval) if (pinfo->psem_flags & PSEM_INDELETE) { } #endif + AUDIT_ARG(posix_ipc_perm, pinfo->psem_uid, + pinfo->psem_gid, pinfo->psem_mode); + PSEM_SUBSYS_UNLOCK(); error = EEXIST; goto bad1; } @@ -402,57 +455,97 @@ sem_open(p, uap, retval) fmode &= ~O_CREAT; } - if (fmode & O_CREAT) { + if ( (fmode & O_CREAT) ) { if((value < 0) && (value > SEM_VALUE_MAX)) { + PSEM_SUBSYS_UNLOCK(); error = EINVAL; goto bad1; } - pinfo = (struct pseminfo *)_MALLOC(sizeof(struct pseminfo), M_SHM, M_WAITOK); - bzero(pinfo, sizeof(struct pseminfo)); + PSEM_SUBSYS_UNLOCK(); + MALLOC(pinfo, struct pseminfo *, sizeof(struct pseminfo), M_SHM, M_WAITOK|M_ZERO); + if (pinfo == NULL) { + error = ENOSPC; + goto bad1; + } + PSEM_SUBSYS_LOCK(); + pinfo_alloc = 1; pinfo->psem_flags = PSEM_DEFINED | PSEM_INCREATE; pinfo->psem_usecount = 1; pinfo->psem_mode = cmode; - pinfo->psem_uid = p->p_ucred->cr_uid; - pinfo->psem_gid = p->p_ucred->cr_gid; + pinfo->psem_uid = kauth_cred_getuid(kauth_cred_get()); + pinfo->psem_gid = kauth_cred_get()->cr_gid; + PSEM_SUBSYS_UNLOCK(); kret = semaphore_create(kernel_task, &pinfo->psem_semobject, SYNC_POLICY_FIFO, value); if(kret != KERN_SUCCESS) goto bad3; + PSEM_SUBSYS_LOCK(); pinfo->psem_flags &= ~PSEM_DEFINED; pinfo->psem_flags |= PSEM_ALLOCATED; pinfo->sem_proc = p; } else { /* semaphore should exist as it is without O_CREAT */ if (!incache) { + PSEM_SUBSYS_UNLOCK(); error = ENOENT; goto bad1; } if( pinfo->psem_flags & PSEM_INDELETE) { + PSEM_SUBSYS_UNLOCK(); error = ENOENT; goto bad1; } - if (error = psem_access(pinfo, fmode, p->p_ucred, p)) + AUDIT_ARG(posix_ipc_perm, pinfo->psem_uid, + pinfo->psem_gid, pinfo->psem_mode); + if ( (error = psem_access(pinfo, fmode, kauth_cred_get())) ) { + PSEM_SUBSYS_UNLOCK(); goto bad1; + } } - pnode = (struct psemnode *)_MALLOC(sizeof(struct psemnode), M_SHM, M_WAITOK); - bzero(pnode, sizeof(struct psemnode)); + PSEM_SUBSYS_UNLOCK(); + MALLOC(pnode, struct psemnode *, sizeof(struct psemnode), M_SHM, M_WAITOK|M_ZERO); + if (pnode == NULL) { + error = ENOSPC; + goto bad1; + } + if (!incache) { + /* + * We allocate a new entry if we are less than the maximum + * allowed and the one at the front of the LRU list is in use. + * Otherwise we use the one at the front of the LRU list. + */ + MALLOC(pcp, struct psemcache *, sizeof(struct psemcache), M_SHM, M_WAITOK|M_ZERO); + if (pcp == NULL) { + error = ENOMEM; + goto bad2; + } + } + PSEM_SUBSYS_LOCK(); if (!incache) { - if (error = psem_cache_add(pinfo, &nd)) { - goto bad2; + if ( (error = psem_cache_add(pinfo, &nd, pcp)) ) { + PSEM_SUBSYS_UNLOCK(); + FREE(pcp, M_SHM); + goto bad2; } } pinfo->psem_flags &= ~PSEM_INCREATE; pinfo->psem_usecount++; pnode->pinfo = pinfo; - fp->f_flag = flags & FMASK; + PSEM_SUBSYS_UNLOCK(); + + proc_fdlock(p); + fp->f_flag = fmode & FMASK; fp->f_type = DTYPE_PSXSEM; fp->f_ops = &psemops; fp->f_data = (caddr_t)pnode; *fdflags(p, indx) &= ~UF_RESERVED; - *retval = indx; - _FREE_ZONE(pnbuf, MAXPATHLEN, M_NAMEI); + fp_drop(p, indx, fp, 1); + proc_fdunlock(p); + + *retval = CAST_USER_ADDR_T(indx); + FREE_ZONE(pnbuf, MAXPATHLEN, M_NAMEI); return (0); bad3: @@ -466,36 +559,33 @@ bad3: } goto bad1; bad2: - _FREE(pnode, M_SHM); - if (pinfo_alloc) - _FREE(pinfo, M_SHM); + FREE(pnode, M_SHM); bad1: - fdrelse(p, indx); - ffree(nfp); + if (pinfo_alloc) + FREE(pinfo, M_SHM); + fp_free(p, indx, nfp); bad: - _FREE_ZONE(pnbuf, MAXPATHLEN, M_NAMEI); + FREE_ZONE(pnbuf, MAXPATHLEN, M_NAMEI); return (error); } -int -psem_access(pinfo, mode, cred, p) - struct pseminfo *pinfo; - int mode; - struct ucred *cred; - struct proc *p; +/* + * XXX This code is repeated in several places + */ +static int +psem_access(struct pseminfo *pinfo, int mode, kauth_cred_t cred) { mode_t mask; - register gid_t *gp; - int i, error; + int is_member; /* Otherwise, user id 0 always gets access. */ - if (cred->cr_uid == 0) + if (!suser(cred, NULL)) return (0); mask = 0; /* Otherwise, check the owner. */ - if (cred->cr_uid == pinfo->psem_uid) { + if (kauth_cred_getuid(cred) == pinfo->psem_uid) { if (mode & FREAD) mask |= S_IRUSR; if (mode & FWRITE) @@ -504,14 +594,13 @@ psem_access(pinfo, mode, cred, p) } /* Otherwise, check the groups. */ - for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++) - if (pinfo->psem_gid == *gp) { - if (mode & FREAD) - mask |= S_IRGRP; - if (mode & FWRITE) - mask |= S_IWGRP; - return ((pinfo->psem_mode & mask) == mask ? 0 : EACCES); - } + if (kauth_cred_ismember_gid(cred, pinfo->psem_gid, &is_member) == 0 && is_member) { + if (mode & FREAD) + mask |= S_IRGRP; + if (mode & FWRITE) + mask |= S_IWGRP; + return ((pinfo->psem_mode & mask) == mask ? 0 : EACCES); + } /* Otherwise, check everyone else. */ if (mode & FREAD) @@ -521,43 +610,32 @@ psem_access(pinfo, mode, cred, p) return ((pinfo->psem_mode & mask) == mask ? 0 : EACCES); } -struct sem_unlink_args { - const char *name; -}; - int -sem_unlink(p, uap, retval) - struct proc *p; - register struct sem_unlink_args *uap; - register_t *retval; +sem_unlink(__unused struct proc *p, struct sem_unlink_args *uap, __unused register_t *retval) { - register struct filedesc *fdp = p->p_fd; - register struct file *fp; - int flags, i; + size_t i; int error=0; struct psemname nd; struct pseminfo *pinfo; - extern struct fileops psemops; char * pnbuf; char * nameptr; char * cp; size_t pathlen, plen; - int fmode, cmode ; int incache = 0; - struct psemnode * pnode = PSEMNODE_NULL; struct psemcache *pcache = PSEMCACHE_NULL; - kern_return_t kret; pinfo = PSEMINFO_NULL; - MALLOC_ZONE(pnbuf, caddr_t, - MAXPATHLEN, M_NAMEI, M_WAITOK); + MALLOC_ZONE(pnbuf, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK); + if (pnbuf == NULL) { + return(ENOSPC); /* XXX non-standard */ + } pathlen = MAXPATHLEN; - error = copyinstr(uap->name, pnbuf, - MAXPATHLEN, &pathlen); + error = copyinstr(uap->name, pnbuf, MAXPATHLEN, &pathlen); if (error) { goto bad; } + AUDIT_ARG(text, pnbuf); if (pathlen > PSEMNAMLEN) { error = ENAMETOOLONG; goto bad; @@ -588,150 +666,166 @@ sem_unlink(p, uap, retval) nd.psem_hash += (unsigned char)*cp * i; } + PSEM_SUBSYS_LOCK(); error = psem_cache_search(&pinfo, &nd, &pcache); if (error == ENOENT) { + PSEM_SUBSYS_UNLOCK(); error = EINVAL; goto bad; } if (!error) { + PSEM_SUBSYS_UNLOCK(); error = EINVAL; goto bad; } else incache = 1; - if (error = psem_access(pinfo, pinfo->psem_mode, p->p_ucred, p)) + if ( (error = psem_access(pinfo, pinfo->psem_mode, kauth_cred_get())) ) { + PSEM_SUBSYS_UNLOCK(); goto bad; + } if ((pinfo->psem_flags & (PSEM_DEFINED | PSEM_ALLOCATED))==0) { + PSEM_SUBSYS_UNLOCK(); return (EINVAL); } - if (pinfo->psem_flags & PSEM_INDELETE) { + if ( (pinfo->psem_flags & PSEM_INDELETE) ) { + PSEM_SUBSYS_UNLOCK(); error = 0; goto bad; } + + AUDIT_ARG(posix_ipc_perm, pinfo->psem_uid, pinfo->psem_gid, + pinfo->psem_mode); + pinfo->psem_flags |= PSEM_INDELETE; pinfo->psem_usecount--; if (!pinfo->psem_usecount) { psem_delete(pinfo); - _FREE(pinfo,M_SHM); + FREE(pinfo,M_SHM); } else pinfo->psem_flags |= PSEM_REMOVED; psem_cache_delete(pcache); - _FREE(pcache, M_SHM); + PSEM_SUBSYS_UNLOCK(); + FREE(pcache, M_SHM); error = 0; bad: - _FREE_ZONE(pnbuf, MAXPATHLEN, M_NAMEI); + FREE_ZONE(pnbuf, MAXPATHLEN, M_NAMEI); return (error); } -struct sem_close_args { - sem_t *sem; -}; - int -sem_close(p, uap, retval) - struct proc *p; - struct sem_close_args *uap; - register_t *retval; +sem_close(struct proc *p, struct sem_close_args *uap, __unused register_t *retval) { - int fd = (int)uap->sem; - register struct filedesc *fdp = p->p_fd; - register struct file *fp; + int fd = CAST_DOWN(int,uap->sem); + struct fileproc *fp; int error = 0; + AUDIT_ARG(fd, fd); /* XXX This seems wrong; uap->sem is a pointer */ - if ((u_int)fd >= fdp->fd_nfiles || - (fp = fdp->fd_ofiles[fd]) == NULL || - (fdp->fd_ofileflags[fd] & UF_RESERVED)) - return (EBADF); - fdrelse(p, fd); - if( error = closef(fp, p)) + proc_fdlock(p); + error = fp_lookup(p,fd, &fp, 1); + if (error) { + proc_fdunlock(p); return(error); - return(0); + } + fdrelse(p, fd); + error = closef_locked(fp, fp->f_fglob, p); + FREE_ZONE(fp, sizeof *fp, M_FILEPROC); + proc_fdunlock(p); + return(error); } -struct sem_wait_args { - sem_t *sem; -}; - int -sem_wait(p, uap, retval) - struct proc *p; - struct sem_wait_args *uap; - register_t *retval; +sem_wait(struct proc *p, struct sem_wait_args *uap, __unused register_t *retval) { - int fd = (int)uap->sem; - register struct filedesc *fdp = p->p_fd; - struct file *fp; + int fd = CAST_DOWN(int,uap->sem); + struct fileproc *fp; struct pseminfo * pinfo; struct psemnode * pnode ; kern_return_t kret; int error; - if (error = fdgetf(p, (int)uap->sem, &fp)) + error = fp_getfpsem(p, fd, &fp, &pnode); + if (error) return (error); - if (fp->f_type != DTYPE_PSXSEM) - return(EBADF); - if (((pnode = (struct psemnode *)fp->f_data)) == PSEMNODE_NULL ) - return(EINVAL); - if ((pinfo = pnode->pinfo) == PSEMINFO_NULL) - return(EINVAL); + if (((pnode = (struct psemnode *)fp->f_data)) == PSEMNODE_NULL ) { + error = EINVAL; + goto out; + } + PSEM_SUBSYS_LOCK(); + if ((pinfo = pnode->pinfo) == PSEMINFO_NULL) { + PSEM_SUBSYS_UNLOCK(); + error = EINVAL; + goto out; + } if ((pinfo->psem_flags & (PSEM_DEFINED | PSEM_ALLOCATED)) != PSEM_ALLOCATED) { - return(EINVAL); + PSEM_SUBSYS_UNLOCK(); + error = EINVAL; + goto out; } + PSEM_SUBSYS_UNLOCK(); kret = semaphore_wait(pinfo->psem_semobject); switch (kret) { case KERN_INVALID_ADDRESS: case KERN_PROTECTION_FAILURE: - return (EACCES); + error = EACCES; + break; case KERN_ABORTED: case KERN_OPERATION_TIMED_OUT: - return (EINTR); + error = EINTR; + break; case KERN_SUCCESS: - return(0); + error = 0; + break; default: - return (EINVAL); + error = EINVAL; + break; } -} +out: + fp_drop(p, fd, fp, 0); + return(error); -struct sem_trywait_args { - sem_t *sem; -}; +} int -sem_trywait(p, uap, retval) - struct proc *p; - struct sem_trywait_args *uap; - register_t *retval; +sem_trywait(struct proc *p, struct sem_trywait_args *uap, __unused register_t *retval) { - int fd = (int)uap->sem; - register struct filedesc *fdp = p->p_fd; - struct file *fp; + int fd = CAST_DOWN(int,uap->sem); + struct fileproc *fp; struct pseminfo * pinfo; struct psemnode * pnode ; kern_return_t kret; mach_timespec_t wait_time; int error; - if (error = fdgetf(p, (int)uap->sem, &fp)) + error = fp_getfpsem(p, fd, &fp, &pnode); + if (error) return (error); - if (fp->f_type != DTYPE_PSXSEM) - return(EBADF); - if (((pnode = (struct psemnode *)fp->f_data)) == PSEMNODE_NULL ) - return(EINVAL); - if ((pinfo = pnode->pinfo) == PSEMINFO_NULL) - return(EINVAL); + if (((pnode = (struct psemnode *)fp->f_data)) == PSEMNODE_NULL ) { + error = EINVAL; + goto out; + } + PSEM_SUBSYS_LOCK(); + if ((pinfo = pnode->pinfo) == PSEMINFO_NULL) { + PSEM_SUBSYS_UNLOCK(); + error = EINVAL; + goto out; + } if ((pinfo->psem_flags & (PSEM_DEFINED | PSEM_ALLOCATED)) != PSEM_ALLOCATED) { - return(EINVAL); + PSEM_SUBSYS_UNLOCK(); + error = EINVAL; + goto out; } + PSEM_SUBSYS_UNLOCK(); wait_time.tv_sec = 0; wait_time.tv_nsec = 0; @@ -739,121 +833,112 @@ sem_trywait(p, uap, retval) switch (kret) { case KERN_INVALID_ADDRESS: case KERN_PROTECTION_FAILURE: - return (EINVAL); + error = EINVAL; + break; case KERN_ABORTED: - return (EINTR); + error = EINTR; + break; case KERN_OPERATION_TIMED_OUT: - return (EAGAIN); + error = EAGAIN; + break; case KERN_SUCCESS: - return(0); + error = 0; + break; default: - return (EINVAL); + error = EINVAL; + break; } +out: + fp_drop(p, fd, fp, 0); + return(error); } -struct sem_post_args { - sem_t *sem; -}; - int -sem_post(p, uap, retval) - struct proc *p; - struct sem_post_args *uap; - register_t *retval; +sem_post(struct proc *p, struct sem_post_args *uap, __unused register_t *retval) { - int fd = (int)uap->sem; - register struct filedesc *fdp = p->p_fd; - struct file *fp; + int fd = CAST_DOWN(int,uap->sem); + struct fileproc *fp; struct pseminfo * pinfo; struct psemnode * pnode ; kern_return_t kret; int error; - if (error = fdgetf(p, (int)uap->sem, &fp)) + error = fp_getfpsem(p, fd, &fp, &pnode); + if (error) return (error); - if (fp->f_type != DTYPE_PSXSEM) - return(EBADF); - if (((pnode = (struct psemnode *)fp->f_data)) == PSEMNODE_NULL ) - return(EINVAL); - if ((pinfo = pnode->pinfo) == PSEMINFO_NULL) - return(EINVAL); + if (((pnode = (struct psemnode *)fp->f_data)) == PSEMNODE_NULL ) { + error = EINVAL; + goto out; + } + PSEM_SUBSYS_LOCK(); + if ((pinfo = pnode->pinfo) == PSEMINFO_NULL) { + PSEM_SUBSYS_UNLOCK(); + error = EINVAL; + goto out; + } if ((pinfo->psem_flags & (PSEM_DEFINED | PSEM_ALLOCATED)) != PSEM_ALLOCATED) { - return(EINVAL); + PSEM_SUBSYS_UNLOCK(); + error = EINVAL; + goto out; } + PSEM_SUBSYS_UNLOCK(); kret = semaphore_signal(pinfo->psem_semobject); switch (kret) { case KERN_INVALID_ADDRESS: case KERN_PROTECTION_FAILURE: - return (EINVAL); + error = EINVAL; + break; case KERN_ABORTED: case KERN_OPERATION_TIMED_OUT: - return (EINTR); + error = EINTR; + break; case KERN_SUCCESS: - return(0); + error = 0; + break; default: - return (EINVAL); + error = EINVAL; + break; } +out: + fp_drop(p, fd, fp, 0); + return(error); } -struct sem_init_args { - sem_t *sem; - int phsared; - unsigned int value; -}; - int -sem_init(p, uap, retval) - struct proc *p; - struct sem_init_args *uap; - register_t *retval; +sem_init(__unused struct proc *p, __unused struct sem_init_args *uap, __unused register_t *retval) { return(ENOSYS); } -struct sem_destroy_args { - sem_t *sem; -}; - int -sem_destroy(p, uap, retval) - struct proc *p; - struct sem_destroy_args *uap; - register_t *retval; +sem_destroy(__unused struct proc *p, __unused struct sem_destroy_args *uap, __unused register_t *retval) { return(ENOSYS); } -struct sem_getvalue_args { - sem_t *sem; - int * sval; -}; - int -sem_getvalue(p, uap, retval) - struct proc *p; - struct sem_getvalue_args *uap; - register_t *retval; +sem_getvalue(__unused struct proc *p, __unused struct sem_getvalue_args *uap, __unused register_t *retval) { return(ENOSYS); } static int -psem_close(pnode, flags, cred, p) - register struct psemnode *pnode; - int flags; - struct ucred *cred; - struct proc *p; +psem_close(struct psemnode *pnode, __unused int flags, + __unused kauth_cred_t cred, __unused struct proc *p) { int error=0; - kern_return_t kret; register struct pseminfo *pinfo; - if ((pinfo = pnode->pinfo) == PSEMINFO_NULL) + PSEM_SUBSYS_LOCK(); + if ((pinfo = pnode->pinfo) == PSEMINFO_NULL){ + PSEM_SUBSYS_UNLOCK(); return(EINVAL); + } if ((pinfo->psem_flags & PSEM_ALLOCATED) != PSEM_ALLOCATED) { + PSEM_SUBSYS_UNLOCK(); return(EINVAL); } #if DIAGNOSTIC @@ -864,24 +949,33 @@ psem_close(pnode, flags, cred, p) pinfo->psem_usecount--; if ((pinfo->psem_flags & PSEM_REMOVED) && !pinfo->psem_usecount) { + PSEM_SUBSYS_UNLOCK(); + /* lock dropped as only semaphore is destroyed here */ error = psem_delete(pinfo); - _FREE(pinfo,M_SHM); + FREE(pinfo,M_SHM); + } else { + PSEM_SUBSYS_UNLOCK(); } - _FREE(pnode, M_SHM); + /* subsystem lock is dropped when we get here */ + FREE(pnode, M_SHM); return (error); } static int -psem_closefile(fp, p) - struct file *fp; +psem_closefile(fg, p) + struct fileglob *fg; struct proc *p; { + int error; + + /* Not locked as psem_close is called only from here and is locked properly */ + error = psem_close(((struct psemnode *)fg->fg_data), fg->fg_flag, + fg->fg_cred, p); - return (psem_close(((struct psemnode *)fp->f_data), fp->f_flag, - fp->f_cred, p)); + return(error); } -int +static int psem_delete(struct pseminfo * pinfo) { kern_return_t kret; @@ -903,43 +997,39 @@ psem_delete(struct pseminfo * pinfo) } static int -psem_read(fp, uio, cred, flags, p) - struct file *fp; - struct uio *uio; - struct ucred *cred; - int flags; - struct proc *p; +psem_read(__unused struct fileproc *fp, __unused struct uio *uio, + __unused kauth_cred_t cred, __unused int flags, + __unused struct proc *p) { - return(EOPNOTSUPP); + return(ENOTSUP); } static int -psem_write(fp, uio, cred, flags, p) - struct file *fp; - struct uio *uio; - struct ucred *cred; - int flags; - struct proc *p; +psem_write(__unused struct fileproc *fp, __unused struct uio *uio, + __unused kauth_cred_t cred, __unused int flags, + __unused struct proc *p) { - return(EOPNOTSUPP); + return(ENOTSUP); } static int -psem_ioctl(fp, com, data, p) - struct file *fp; - u_long com; - caddr_t data; - struct proc *p; +psem_ioctl(__unused struct fileproc *fp, __unused u_long com, + __unused caddr_t data, __unused struct proc *p) { - return(EOPNOTSUPP); + return(ENOTSUP); } static int -psem_select(fp, which, wql, p) - struct file *fp; - int which; - void *wql; - struct proc *p; +psem_select(__unused struct fileproc *fp, __unused int which, + __unused void *wql, __unused struct proc *p) { - return(EOPNOTSUPP); + return(ENOTSUP); } + +static int +psem_kqfilter(__unused struct fileproc *fp, __unused struct knote *kn, + __unused struct proc *p) +{ + return (ENOTSUP); +} +