X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/cf7d32b81c573a0536dc4da4157f9c26f8d0bed3..c18c124eaa464aaaa5549e99e5a70fc9cbb50944:/bsd/kern/sysv_sem.c?ds=sidebyside diff --git a/bsd/kern/sysv_sem.c b/bsd/kern/sysv_sem.c index 6c90d6485..418a4c6e0 100644 --- a/bsd/kern/sysv_sem.c +++ b/bsd/kern/sysv_sem.c @@ -62,7 +62,7 @@ #include #endif -#include +#include #if SYSV_SEM @@ -173,10 +173,20 @@ sysv_semtime(void) * NOTE: Source and target may *NOT* overlap! (target is smaller) */ static void -semid_ds_64to32(struct user_semid_ds *in, struct semid_ds *out) +semid_ds_kernelto32(struct user_semid_ds *in, struct user32_semid_ds *out) { out->sem_perm = in->sem_perm; - out->sem_base = (__int32_t)in->sem_base; + out->sem_base = CAST_DOWN_EXPLICIT(__int32_t,in->sem_base); + out->sem_nsems = in->sem_nsems; + out->sem_otime = in->sem_otime; /* XXX loses precision */ + out->sem_ctime = in->sem_ctime; /* XXX loses precision */ +} + +static void +semid_ds_kernelto64(struct user_semid_ds *in, struct user64_semid_ds *out) +{ + out->sem_perm = in->sem_perm; + out->sem_base = CAST_DOWN_EXPLICIT(__int32_t,in->sem_base); out->sem_nsems = in->sem_nsems; out->sem_otime = in->sem_otime; /* XXX loses precision */ out->sem_ctime = in->sem_ctime; /* XXX loses precision */ @@ -193,25 +203,50 @@ semid_ds_64to32(struct user_semid_ds *in, struct semid_ds *out) * XXX is the same. */ static void -semid_ds_32to64(struct semid_ds *in, struct user_semid_ds *out) +semid_ds_32tokernel(struct user32_semid_ds *in, struct user_semid_ds *out) { out->sem_ctime = in->sem_ctime; out->sem_otime = in->sem_otime; out->sem_nsems = in->sem_nsems; - out->sem_base = (void *)in->sem_base; + out->sem_base = (void *)(uintptr_t)in->sem_base; + out->sem_perm = in->sem_perm; +} + +static void +semid_ds_64tokernel(struct user64_semid_ds *in, struct user_semid_ds *out) +{ + out->sem_ctime = in->sem_ctime; + out->sem_otime = in->sem_otime; + out->sem_nsems = in->sem_nsems; + out->sem_base = (void *)(uintptr_t)in->sem_base; out->sem_perm = in->sem_perm; } /* - * Entry point for all SEM calls + * semsys + * + * Entry point for all SEM calls: semctl, semget, semop + * + * Parameters: p Process requesting the call + * uap User argument descriptor (see below) + * retval Return value of the selected sem call + * + * Indirect parameters: uap->which sem call to invoke (index in array of sem calls) + * uap->a2 User argument descriptor + * + * Returns: 0 Success + * !0 Not success + * + * Implicit returns: retval Return value of the selected sem call + * + * DEPRECATED: This interface should not be used to call the other SEM + * functions (semctl, semget, semop). The correct usage is + * to call the other SEM functions directly. * - * In Darwin this is no longer the entry point. It will be removed after - * the code has been tested better. */ -/* XXX actually varargs. */ int -semsys(struct proc *p, struct semsys_args *uap, register_t *retval) +semsys(struct proc *p, struct semsys_args *uap, int32_t *retval) { /* The individual calls handling the locking now */ @@ -409,7 +444,8 @@ grow_sem_pool(int new_pool_size) /* Update our id structures to point to the new semaphores */ for(i = 0; i < seminfo.semmni; i++) { if (sema[i].u.sem_perm.mode & SEM_ALLOC) /* ID in use */ - sema[i].u.sem_base += (new_sem_pool - sem_pool); + sema[i].u.sem_base = new_sem_pool + + (sema[i].u.sem_base - sem_pool); } sem_free = sem_pool; @@ -639,7 +675,7 @@ semundo_clear(int semid, int semnum) * because the alignment is the same in user and kernel space. */ int -semctl(struct proc *p, struct semctl_args *uap, register_t *retval) +semctl(struct proc *p, struct semctl_args *uap, int32_t *retval) { int semid = uap->semid; int semnum = uap->semnum; @@ -649,7 +685,6 @@ semctl(struct proc *p, struct semctl_args *uap, register_t *retval) int i, rval, eval; struct user_semid_ds sbuf; struct semid_kernel *semakptr; - struct user_semid_ds uds; AUDIT_ARG(svipc_cmd, cmd); @@ -714,11 +749,13 @@ semctl(struct proc *p, struct semctl_args *uap, register_t *retval) goto semctlout; if (IS_64BIT_PROCESS(p)) { - eval = copyin(user_arg.buf, &sbuf, sizeof(struct user_semid_ds)); + struct user64_semid_ds ds64; + eval = copyin(user_arg.buf, &ds64, sizeof(ds64)); + semid_ds_64tokernel(&ds64, &sbuf); } else { - eval = copyin(user_arg.buf, &sbuf, sizeof(struct semid_ds)); - /* convert in place; ugly, but safe */ - semid_ds_32to64((struct semid_ds *)&sbuf, &sbuf); + struct user32_semid_ds ds32; + eval = copyin(user_arg.buf, &ds32, sizeof(ds32)); + semid_ds_32tokernel(&ds32, &sbuf); } if (eval != 0) { @@ -735,13 +772,17 @@ semctl(struct proc *p, struct semctl_args *uap, register_t *retval) case IPC_STAT: if ((eval = ipcperm(cred, &semakptr->u.sem_perm, IPC_R))) goto semctlout; - bcopy((caddr_t)&semakptr->u, &uds, sizeof(struct user_semid_ds)); + if (IS_64BIT_PROCESS(p)) { - eval = copyout(&uds, user_arg.buf, sizeof(struct user_semid_ds)); + struct user64_semid_ds semid_ds64; + bzero(&semid_ds64, sizeof(semid_ds64)); + semid_ds_kernelto64(&semakptr->u, &semid_ds64); + eval = copyout(&semid_ds64, user_arg.buf, sizeof(semid_ds64)); } else { - struct semid_ds semid_ds32; - semid_ds_64to32(&uds, &semid_ds32); - eval = copyout(&semid_ds32, user_arg.buf, sizeof(struct semid_ds)); + struct user32_semid_ds semid_ds32; + bzero(&semid_ds32, sizeof(semid_ds32)); + semid_ds_kernelto32(&semakptr->u, &semid_ds32); + eval = copyout(&semid_ds32, user_arg.buf, sizeof(semid_ds32)); } break; @@ -815,12 +856,27 @@ semctl(struct proc *p, struct semctl_args *uap, register_t *retval) eval = EINVAL; goto semctlout; } + /* * Cast down a pointer instead of using 'val' member directly * to avoid introducing endieness and a pad field into the * header file. Ugly, but it works. */ - semakptr->u.sem_base[semnum].semval = CAST_DOWN(int,user_arg.buf); + u_int newsemval = CAST_DOWN_EXPLICIT(u_int, user_arg.buf); + + /* + * The check is being performed as unsigned values to match + * eventual destination + */ + if (newsemval > (u_int)seminfo.semvmx) + { +#ifdef SEM_DEBUG + printf("Out of range sem value for set\n"); +#endif + eval = ERANGE; + goto semctlout; + } + semakptr->u.sem_base[semnum].semval = newsemval; semakptr->u.sem_base[semnum].sempid = p->p_pid; /* XXX scottl Should there be a MAC call here? */ semundo_clear(semid, semnum); @@ -858,7 +914,7 @@ semctlout: } int -semget(__unused struct proc *p, struct semget_args *uap, register_t *retval) +semget(__unused struct proc *p, struct semget_args *uap, int32_t *retval) { int semid, eval; int key = uap->key; @@ -961,8 +1017,8 @@ semget(__unused struct proc *p, struct semget_args *uap, register_t *retval) sema[semid].u.sem_perm._key = key; sema[semid].u.sem_perm.cuid = kauth_cred_getuid(cred); sema[semid].u.sem_perm.uid = kauth_cred_getuid(cred); - sema[semid].u.sem_perm.cgid = cred->cr_gid; - sema[semid].u.sem_perm.gid = cred->cr_gid; + sema[semid].u.sem_perm.cgid = kauth_cred_getgid(cred); + sema[semid].u.sem_perm.gid = kauth_cred_getgid(cred); sema[semid].u.sem_perm.mode = (semflg & 0777) | SEM_ALLOC; sema[semid].u.sem_perm._seq = (sema[semid].u.sem_perm._seq + 1) & 0x7fff; @@ -1002,11 +1058,11 @@ semgetout: } int -semop(struct proc *p, struct semop_args *uap, register_t *retval) +semop(struct proc *p, struct semop_args *uap, int32_t *retval) { int semid = uap->semid; int nsops = uap->nsops; - struct sembuf sops[MAX_SOPS]; + struct sembuf sops[seminfo.semopm]; register struct semid_kernel *semakptr; register struct sembuf *sopptr = NULL; /* protected by 'semptr' */ register struct sem *semptr = NULL; /* protected by 'if' */ @@ -1046,13 +1102,23 @@ semop(struct proc *p, struct semop_args *uap, register_t *retval) goto semopout; } - if (nsops < 0 || nsops > MAX_SOPS) { + if (nsops < 0 || nsops > seminfo.semopm) { #ifdef SEM_DEBUG - printf("too many sops (max=%d, nsops=%d)\n", MAX_SOPS, nsops); + printf("too many sops (max=%d, nsops=%d)\n", + seminfo.semopm, nsops); #endif eval = E2BIG; goto semopout; } + + /* OK for LP64, since sizeof(struct sembuf) is currently invariant */ + if ((eval = copyin(uap->sops, &sops, nsops * sizeof(struct sembuf))) != 0) { +#ifdef SEM_DEBUG + printf("eval = %d from copyin(%08x, %08x, %ld)\n", eval, + uap->sops, &sops, nsops * sizeof(struct sembuf)); +#endif + goto semopout; + } #if CONFIG_MACF /* @@ -1072,15 +1138,6 @@ semop(struct proc *p, struct semop_args *uap, register_t *retval) goto semopout; #endif - /* OK for LP64, since sizeof(struct sembuf) is currently invariant */ - if ((eval = copyin(uap->sops, &sops, nsops * sizeof(struct sembuf))) != 0) { -#ifdef SEM_DEBUG - printf("eval = %d from copyin(%08x, %08x, %ld)\n", eval, - uap->sops, &sops, nsops * sizeof(struct sembuf)); -#endif - goto semopout; - } - /* * Loop trying to satisfy the vector of requests. * If we reach a point where we must wait, any requests already @@ -1416,10 +1473,7 @@ semexit(struct proc *p) /* Maybe we should build a list of semakptr's to wake * up, finish all access to data structures, release the * subsystem lock, and wake all the processes. Something - * to think about. It wouldn't buy us anything unless - * wakeup had the potential to block, or the syscall - * funnel state was changed to allow multiple threads - * in the BSD code at once. + * to think about. */ #ifdef SEM_WAKEUP sem_wakeup((caddr_t)semakptr); @@ -1501,19 +1555,19 @@ out: /* SYSCTL_NODE(_kern, KERN_SYSV, sysv, CTLFLAG_RW, 0, "SYSV"); */ extern struct sysctl_oid_list sysctl__kern_sysv_children; -SYSCTL_PROC(_kern_sysv, OID_AUTO, semmni, CTLTYPE_INT | CTLFLAG_RW, +SYSCTL_PROC(_kern_sysv, OID_AUTO, semmni, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED, &limitseminfo.semmni, 0, &sysctl_seminfo ,"I","semmni"); -SYSCTL_PROC(_kern_sysv, OID_AUTO, semmns, CTLTYPE_INT | CTLFLAG_RW, +SYSCTL_PROC(_kern_sysv, OID_AUTO, semmns, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED, &limitseminfo.semmns, 0, &sysctl_seminfo ,"I","semmns"); -SYSCTL_PROC(_kern_sysv, OID_AUTO, semmnu, CTLTYPE_INT | CTLFLAG_RW, +SYSCTL_PROC(_kern_sysv, OID_AUTO, semmnu, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED, &limitseminfo.semmnu, 0, &sysctl_seminfo ,"I","semmnu"); -SYSCTL_PROC(_kern_sysv, OID_AUTO, semmsl, CTLTYPE_INT | CTLFLAG_RW, +SYSCTL_PROC(_kern_sysv, OID_AUTO, semmsl, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED, &limitseminfo.semmsl, 0, &sysctl_seminfo ,"I","semmsl"); -SYSCTL_PROC(_kern_sysv, OID_AUTO, semume, CTLTYPE_INT | CTLFLAG_RW, +SYSCTL_PROC(_kern_sysv, OID_AUTO, semume, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED, &limitseminfo.semume, 0, &sysctl_seminfo ,"I","semume"); @@ -1524,18 +1578,22 @@ IPCS_sem_sysctl(__unused struct sysctl_oid *oidp, __unused void *arg1, int error; int cursor; union { - struct IPCS_command u32; + struct user32_IPCS_command u32; struct user_IPCS_command u64; } ipcs; - struct semid_ds semid_ds32; /* post conversion, 32 bit version */ + struct user32_semid_ds semid_ds32; /* post conversion, 32 bit version */ + struct user64_semid_ds semid_ds64; /* post conversion, 64 bit version */ void *semid_dsp; - size_t ipcs_sz = sizeof(struct user_IPCS_command); - size_t semid_ds_sz = sizeof(struct user_semid_ds); + size_t ipcs_sz; + size_t semid_ds_sz; struct proc *p = current_proc(); - if (!IS_64BIT_PROCESS(p)) { - ipcs_sz = sizeof(struct IPCS_command); - semid_ds_sz = sizeof(struct semid_ds); + if (IS_64BIT_PROCESS(p)) { + ipcs_sz = sizeof(struct user_IPCS_command); + semid_ds_sz = sizeof(struct user64_semid_ds); + } else { + ipcs_sz = sizeof(struct user32_IPCS_command); + semid_ds_sz = sizeof(struct user32_semid_ds); } /* Copy in the command structure */ @@ -1592,13 +1650,23 @@ IPCS_sem_sysctl(__unused struct sysctl_oid *oidp, __unused void *arg1, * descriptor to a 32 bit user one. */ if (!IS_64BIT_PROCESS(p)) { - semid_ds_64to32(semid_dsp, &semid_ds32); + bzero(&semid_ds32, sizeof(semid_ds32)); + semid_ds_kernelto32(semid_dsp, &semid_ds32); semid_dsp = &semid_ds32; + } else { + bzero(&semid_ds64, sizeof(semid_ds64)); + semid_ds_kernelto64(semid_dsp, &semid_ds64); + semid_dsp = &semid_ds64; } + error = copyout(semid_dsp, ipcs.u64.ipcs_data, ipcs.u64.ipcs_datalen); if (!error) { /* update cursor */ ipcs.u64.ipcs_cursor = cursor + 1; + + if (!IS_64BIT_PROCESS(p)) /* convert in place */ + ipcs.u32.ipcs_data = CAST_DOWN_EXPLICIT(user32_addr_t,ipcs.u64.ipcs_data); + error = SYSCTL_OUT(req, &ipcs, ipcs_sz); } break; @@ -1612,7 +1680,7 @@ IPCS_sem_sysctl(__unused struct sysctl_oid *oidp, __unused void *arg1, } SYSCTL_DECL(_kern_sysv_ipcs); -SYSCTL_PROC(_kern_sysv_ipcs, OID_AUTO, sem, CTLFLAG_RW|CTLFLAG_ANYBODY, +SYSCTL_PROC(_kern_sysv_ipcs, OID_AUTO, sem, CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED, 0, 0, IPCS_sem_sysctl, "S,IPCS_sem_command", "ipcs sem command interface");