--- compat/linux/linux_ipc.c.orig Tue Oct 10 16:15:10 2006 +++ compat/linux/linux_ipc.c Thu Oct 12 21:56:52 2006 @@ -492,58 +492,70 @@ { struct l_semid_ds linux_semid; struct l_seminfo linux_seminfo; - struct semid_ds semid; - union semun semun; - register_t rval; - int cmd, error; + struct __semctl_args /* { + int semid; + int semnum; + int cmd; + union semun *arg; + } */ bsd_args; + int error; + union semun *unptr; + caddr_t sg; + + sg = stackgap_init(); + + /* Make sure the arg parameter can be copied in. */ + unptr = stackgap_alloc(&sg, sizeof(union semun)); + bcopy(&args->arg, unptr, sizeof(union semun)); + + bsd_args.semid = args->semid; + bsd_args.semnum = args->semnum; + bsd_args.arg = unptr; switch (args->cmd & ~LINUX_IPC_64) { case LINUX_IPC_RMID: - cmd = IPC_RMID; + bsd_args.cmd = IPC_RMID; break; case LINUX_GETNCNT: - cmd = GETNCNT; + bsd_args.cmd = GETNCNT; break; case LINUX_GETPID: - cmd = GETPID; + bsd_args.cmd = GETPID; break; case LINUX_GETVAL: - cmd = GETVAL; + bsd_args.cmd = GETVAL; break; case LINUX_GETZCNT: - cmd = GETZCNT; + bsd_args.cmd = GETZCNT; break; case LINUX_SETVAL: - cmd = SETVAL; - semun.val = args->arg.val; + bsd_args.cmd = SETVAL; break; case LINUX_IPC_SET: - cmd = IPC_SET; + bsd_args.cmd = IPC_SET; error = linux_semid_pullup(args->cmd & LINUX_IPC_64, &linux_semid, PTRIN(args->arg.buf)); if (error) return (error); - linux_to_bsd_semid_ds(&linux_semid, &semid); - semun.buf = &semid; - return (kern_semctl(td, args->semid, args->semnum, cmd, &semun, - td->td_retval)); + unptr->buf = stackgap_alloc(&sg, sizeof(struct semid_ds)); + linux_to_bsd_semid_ds(&linux_semid, unptr->buf); + return __semctl(td, &bsd_args); case LINUX_IPC_STAT: case LINUX_SEM_STAT: if ((args->cmd & ~LINUX_IPC_64) == LINUX_IPC_STAT) - cmd = IPC_STAT; + bsd_args.cmd = IPC_STAT; else - cmd = SEM_STAT; - semun.buf = &semid; - error = kern_semctl(td, args->semid, args->semnum, cmd, &semun, - &rval); + bsd_args.cmd = SEM_STAT; + unptr->buf = stackgap_alloc(&sg, sizeof(struct semid_ds)); + error = __semctl(td, &bsd_args); if (error) return (error); - bsd_to_linux_semid_ds(&semid, &linux_semid); - error = linux_semid_pushdown(args->cmd & LINUX_IPC_64, - &linux_semid, PTRIN(args->arg.buf)); - if (error == 0) - td->td_retval[0] = (cmd == SEM_STAT) ? rval : 0; - return (error); + td->td_retval[0] = (bsd_args.cmd == SEM_STAT) ? + IXSEQ_TO_IPCID(bsd_args.semid, unptr->buf->sem_perm) : + 0; + bsd_to_linux_semid_ds(unptr->buf, &linux_semid); + return (linux_semid_pushdown(args->cmd & LINUX_IPC_64, + &linux_semid, PTRIN(args->arg.buf))); case LINUX_IPC_INFO: case LINUX_SEM_INFO: bcopy(&seminfo, &linux_seminfo, sizeof(linux_seminfo) ); @@ -568,8 +580,7 @@ args->cmd & ~LINUX_IPC_64); return EINVAL; } - return (kern_semctl(td, args->semid, args->semnum, cmd, &semun, - td->td_retval)); + return __semctl(td, &bsd_args); } int --- compat/linux/linux_util.h.orig Tue Jun 27 14:30:49 2006 +++ compat/linux/linux_util.h Thu Oct 12 22:25:49 2006 @@ -49,6 +49,32 @@ #include #include +static __inline caddr_t stackgap_init(void); +static __inline void *stackgap_alloc(caddr_t *, size_t); + +#define szsigcode (*(curthread->td_proc->p_sysent->sv_szsigcode)) +#define psstrings (curthread->td_proc->p_sysent->sv_psstrings) + +static __inline caddr_t +stackgap_init() +{ + return (caddr_t)(psstrings - szsigcode - SPARE_USRSPACE); +} + +static __inline void * +stackgap_alloc(sgp, sz) + caddr_t *sgp; + size_t sz; +{ + void *p = (void *) *sgp; + + sz = ALIGN(sz); + if (*sgp + sz > (caddr_t)(psstrings - szsigcode)) + return NULL; + *sgp += sz; + return p; +} + extern const char linux_emul_path[]; int linux_emul_convpath(struct thread *, char *, enum uio_seg, char **, int); --- compat/svr4/svr4_ipc.c.orig Sat Jul 8 15:51:37 2006 +++ compat/svr4/svr4_ipc.c Thu Oct 12 22:09:21 2006 @@ -105,6 +105,8 @@ struct svr4_semid_ds *); static void svr4_to_bsd_semid_ds(const struct svr4_semid_ds *, struct semid_ds *); +static int svr4_setsemun(caddr_t *sgp, union semun **argp, + union semun *usp); static int svr4_semop(struct thread *, void *); static int svr4_semget(struct thread *, void *); static int svr4_semctl(struct thread *, void *); @@ -192,6 +194,16 @@ bds->sem_pad2 = sds->sem_pad2; } +static int +svr4_setsemun(sgp, argp, usp) + caddr_t *sgp; + union semun **argp; + union semun *usp; +{ + *argp = stackgap_alloc(sgp, sizeof(union semun)); + return copyout((caddr_t)usp, *argp, sizeof(union semun)); +} + struct svr4_sys_semctl_args { int what; int semid; @@ -205,68 +217,100 @@ struct thread *td; void *v; { + int error; struct svr4_sys_semctl_args *uap = v; + struct __semctl_args ap; struct svr4_semid_ds ss; - struct semid_ds bs; - union semun semun; - register_t rval; - int cmd, error; + struct semid_ds bs, *bsp; + caddr_t sg = stackgap_init(); + + ap.semid = uap->semid; + ap.semnum = uap->semnum; switch (uap->cmd) { case SVR4_SEM_GETZCNT: - cmd = GETZCNT; - break; - case SVR4_SEM_GETNCNT: - cmd = GETNCNT; - break; - case SVR4_SEM_GETPID: - cmd = GETPID; - break; - case SVR4_SEM_GETVAL: - cmd = GETVAL; - break; + switch (uap->cmd) { + case SVR4_SEM_GETZCNT: + ap.cmd = GETZCNT; + break; + case SVR4_SEM_GETNCNT: + ap.cmd = GETNCNT; + break; + case SVR4_SEM_GETPID: + ap.cmd = GETPID; + break; + case SVR4_SEM_GETVAL: + ap.cmd = GETVAL; + break; + } + return __semctl(td, &ap); case SVR4_SEM_SETVAL: - cmd = SETVAL; - break; + error = svr4_setsemun(&sg, &ap.arg, &uap->arg); + if (error) + return (error); + ap.cmd = SETVAL; + return __semctl(td, &ap); case SVR4_SEM_GETALL: - cmd = GETVAL; - break; + error = svr4_setsemun(&sg, &ap.arg, &uap->arg); + if (error) + return (error); + ap.cmd = GETVAL; + return __semctl(td, &ap); case SVR4_SEM_SETALL: - cmd = SETVAL; - break; + error = svr4_setsemun(&sg, &ap.arg, &uap->arg); + if (error) + return (error); + ap.cmd = SETVAL; + return __semctl(td, &ap); case SVR4_IPC_STAT: - cmd = IPC_STAT; - semun.buf = &bs; - error = kern_semctl(td, uap->semid, uap->semnum, cmd, &semun, - &rval); + ap.cmd = IPC_STAT; + bsp = stackgap_alloc(&sg, sizeof(bs)); + error = svr4_setsemun(&sg, &ap.arg, + (union semun *)&bsp); if (error) return (error); - bsd_to_svr4_semid_ds(&bs, &ss); - error = copyout(&ss, uap->arg.buf, sizeof(ss)); - if (error == 0) - td->td_retval[0] = rval; - return (error); + if ((error = __semctl(td, &ap)) != 0) + return (error); + error = copyin((caddr_t)bsp, (caddr_t)&bs, sizeof(bs)); + if (error) + return (error); + bsd_to_svr4_semid_ds(&bs, &ss); + return copyout(&ss, uap->arg.buf, sizeof(ss)); case SVR4_IPC_SET: - cmd = IPC_SET; - error = copyin(uap->arg.buf, (caddr_t) &ss, sizeof ss); - if (error) - return (error); - svr4_to_bsd_semid_ds(&ss, &bs); - semun.buf = &bs; - return (kern_semctl(td, uap->semid, uap->semnum, cmd, &semun, - td->td_retval)); + ap.cmd = IPC_SET; + bsp = stackgap_alloc(&sg, sizeof(bs)); + error = svr4_setsemun(&sg, &ap.arg, + (union semun *)&bsp); + if (error) + return (error); + error = copyout(&bs, bsp, sizeof(bs)); + if (error) + return (error); + return __semctl(td, &ap); case SVR4_IPC_RMID: - cmd = IPC_RMID; - break; + ap.cmd = IPC_RMID; + bsp = stackgap_alloc(&sg, sizeof(bs)); + error = svr4_setsemun(&sg, &ap.arg, + (union semun *)&bsp); + if (error) + return (error); + error = copyin(uap->arg.buf, &ss, sizeof ss); + if (error) + return (error); + svr4_to_bsd_semid_ds(&ss, &bs); + error = copyout(&bs, bsp, sizeof(bs)); + if (error) + return (error); + return __semctl(td, &ap); default: return EINVAL; @@ -492,14 +536,14 @@ case SVR4_IPC_STAT: error = kern_msgctl(td, uap->msqid, IPC_STAT, &bs); if (error) - return error; + return (error); bsd_to_svr4_msqid_ds(&bs, &ss); return copyout(&ss, uap->buf, sizeof ss); case SVR4_IPC_SET: error = copyin(uap->buf, &ss, sizeof ss); if (error) - return error; + return (error); svr4_to_bsd_msqid_ds(&ss, &bs); return (kern_msgctl(td, uap->msqid, IPC_SET, &bs)); --- compat/svr4/svr4_ipc.c.orig Sat Jul 8 15:51:37 2006 +++ compat/svr4/svr4_ipc.c Thu Oct 12 22:09:21 2006 @@ -105,6 +105,8 @@ struct svr4_semid_ds *); static void svr4_to_bsd_semid_ds(const struct svr4_semid_ds *, struct semid_ds *); +static int svr4_setsemun(caddr_t *sgp, union semun **argp, + union semun *usp); static int svr4_semop(struct thread *, void *); static int svr4_semget(struct thread *, void *); static int svr4_semctl(struct thread *, void *); @@ -192,6 +194,16 @@ bds->sem_pad2 = sds->sem_pad2; } +static int +svr4_setsemun(sgp, argp, usp) + caddr_t *sgp; + union semun **argp; + union semun *usp; +{ + *argp = stackgap_alloc(sgp, sizeof(union semun)); + return copyout((caddr_t)usp, *argp, sizeof(union semun)); +} + struct svr4_sys_semctl_args { int what; int semid; @@ -205,68 +217,100 @@ struct thread *td; void *v; { + int error; struct svr4_sys_semctl_args *uap = v; + struct __semctl_args ap; struct svr4_semid_ds ss; - struct semid_ds bs; - union semun semun; - register_t rval; - int cmd, error; + struct semid_ds bs, *bsp; + caddr_t sg = stackgap_init(); + + ap.semid = uap->semid; + ap.semnum = uap->semnum; switch (uap->cmd) { case SVR4_SEM_GETZCNT: - cmd = GETZCNT; - break; - case SVR4_SEM_GETNCNT: - cmd = GETNCNT; - break; - case SVR4_SEM_GETPID: - cmd = GETPID; - break; - case SVR4_SEM_GETVAL: - cmd = GETVAL; - break; + switch (uap->cmd) { + case SVR4_SEM_GETZCNT: + ap.cmd = GETZCNT; + break; + case SVR4_SEM_GETNCNT: + ap.cmd = GETNCNT; + break; + case SVR4_SEM_GETPID: + ap.cmd = GETPID; + break; + case SVR4_SEM_GETVAL: + ap.cmd = GETVAL; + break; + } + return __semctl(td, &ap); case SVR4_SEM_SETVAL: - cmd = SETVAL; - break; + error = svr4_setsemun(&sg, &ap.arg, &uap->arg); + if (error) + return (error); + ap.cmd = SETVAL; + return __semctl(td, &ap); case SVR4_SEM_GETALL: - cmd = GETVAL; - break; + error = svr4_setsemun(&sg, &ap.arg, &uap->arg); + if (error) + return (error); + ap.cmd = GETVAL; + return __semctl(td, &ap); case SVR4_SEM_SETALL: - cmd = SETVAL; - break; + error = svr4_setsemun(&sg, &ap.arg, &uap->arg); + if (error) + return (error); + ap.cmd = SETVAL; + return __semctl(td, &ap); case SVR4_IPC_STAT: - cmd = IPC_STAT; - semun.buf = &bs; - error = kern_semctl(td, uap->semid, uap->semnum, cmd, &semun, - &rval); + ap.cmd = IPC_STAT; + bsp = stackgap_alloc(&sg, sizeof(bs)); + error = svr4_setsemun(&sg, &ap.arg, + (union semun *)&bsp); if (error) return (error); - bsd_to_svr4_semid_ds(&bs, &ss); - error = copyout(&ss, uap->arg.buf, sizeof(ss)); - if (error == 0) - td->td_retval[0] = rval; - return (error); + if ((error = __semctl(td, &ap)) != 0) + return (error); + error = copyin((caddr_t)bsp, (caddr_t)&bs, sizeof(bs)); + if (error) + return (error); + bsd_to_svr4_semid_ds(&bs, &ss); + return copyout(&ss, uap->arg.buf, sizeof(ss)); case SVR4_IPC_SET: - cmd = IPC_SET; - error = copyin(uap->arg.buf, (caddr_t) &ss, sizeof ss); - if (error) - return (error); - svr4_to_bsd_semid_ds(&ss, &bs); - semun.buf = &bs; - return (kern_semctl(td, uap->semid, uap->semnum, cmd, &semun, - td->td_retval)); + ap.cmd = IPC_SET; + bsp = stackgap_alloc(&sg, sizeof(bs)); + error = svr4_setsemun(&sg, &ap.arg, + (union semun *)&bsp); + if (error) + return (error); + error = copyout(&bs, bsp, sizeof(bs)); + if (error) + return (error); + return __semctl(td, &ap); case SVR4_IPC_RMID: - cmd = IPC_RMID; - break; + ap.cmd = IPC_RMID; + bsp = stackgap_alloc(&sg, sizeof(bs)); + error = svr4_setsemun(&sg, &ap.arg, + (union semun *)&bsp); + if (error) + return (error); + error = copyin(uap->arg.buf, &ss, sizeof ss); + if (error) + return (error); + svr4_to_bsd_semid_ds(&ss, &bs); + error = copyout(&bs, bsp, sizeof(bs)); + if (error) + return (error); + return __semctl(td, &ap); default: return EINVAL; @@ -492,14 +536,14 @@ case SVR4_IPC_STAT: error = kern_msgctl(td, uap->msqid, IPC_STAT, &bs); if (error) - return error; + return (error); bsd_to_svr4_msqid_ds(&bs, &ss); return copyout(&ss, uap->buf, sizeof ss); case SVR4_IPC_SET: error = copyin(uap->buf, &ss, sizeof ss); if (error) - return error; + return (error); svr4_to_bsd_msqid_ds(&ss, &bs); return (kern_msgctl(td, uap->msqid, IPC_SET, &bs)); --- kern/sysv_sem.c.orig Thu Oct 12 22:46:56 2006 +++ kern/sysv_sem.c Thu Oct 12 22:45:01 2006 @@ -53,10 +53,8 @@ #include #include #include -#include #include #include -#include #include #include #include @@ -551,73 +549,18 @@ struct thread *td; struct __semctl_args *uap; { - struct semid_ds dsbuf; - union semun arg, semun; - register_t rval; - int error; - - switch (uap->cmd) { - case SEM_STAT: - case IPC_SET: - case IPC_STAT: - case GETALL: - case SETVAL: - case SETALL: - error = copyin(uap->arg, &arg, sizeof(arg)); - if (error) - return (error); - break; - } - - switch (uap->cmd) { - case SEM_STAT: - case IPC_STAT: - semun.buf = &dsbuf; - break; - case IPC_SET: - error = copyin(arg.buf, &dsbuf, sizeof(dsbuf)); - if (error) - return (error); - semun.buf = &dsbuf; - break; - case GETALL: - case SETALL: - semun.array = arg.array; - break; - case SETVAL: - semun.val = arg.val; - break; - } - - error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, - &rval); - if (error) - return (error); - - switch (uap->cmd) { - case SEM_STAT: - case IPC_STAT: - error = copyout(&dsbuf, arg.buf, sizeof(dsbuf)); - break; - } - - if (error == 0) - td->td_retval[0] = rval; - return (error); -} - -int -kern_semctl(struct thread *td, int semid, int semnum, int cmd, - union semun *arg, register_t *rval) -{ + int semid = uap->semid; + int semnum = uap->semnum; + int cmd = uap->cmd; u_short *array; + union semun *arg = uap->arg; + union semun real_arg; struct ucred *cred = td->td_ucred; - int i, error; - struct semid_ds *sbuf; + int i, rval, error; + struct semid_ds sbuf; struct semid_kernel *semakptr; struct mtx *sema_mtxp; u_short usval, count; - int semidx; DPRINTF(("call to semctl(%d, %d, %d, 0x%p)\n", semid, semnum, cmd, arg)); @@ -628,12 +571,10 @@ switch(cmd) { case SEM_STAT: - /* - * For this command we assume semid is an array index - * rather than an IPC id. - */ if (semid < 0 || semid >= seminfo.semmni) return (EINVAL); + if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0) + return (error); semakptr = &sema[semid]; sema_mtxp = &sema_mtx[semid]; mtx_lock(sema_mtxp); @@ -648,31 +589,38 @@ if (error != 0) goto done2; #endif - bcopy(&semakptr->u, arg->buf, sizeof(struct semid_ds)); - *rval = IXSEQ_TO_IPCID(semid, semakptr->u.sem_perm); mtx_unlock(sema_mtxp); - return (0); + error = copyout(&semakptr->u, real_arg.buf, + sizeof(struct semid_ds)); + rval = IXSEQ_TO_IPCID(semid, semakptr->u.sem_perm); + if (error == 0) + td->td_retval[0] = rval; + return (error); } - semidx = IPCID_TO_IX(semid); - if (semidx < 0 || semidx >= seminfo.semmni) + semid = IPCID_TO_IX(semid); + if (semid < 0 || semid >= seminfo.semmni) return (EINVAL); - semakptr = &sema[semidx]; - sema_mtxp = &sema_mtx[semidx]; - mtx_lock(sema_mtxp); + semakptr = &sema[semid]; + sema_mtxp = &sema_mtx[semid]; #ifdef MAC + mtx_lock(sema_mtxp); error = mac_check_sysv_semctl(cred, semakptr, cmd); - if (error != 0) - goto done2; + if (error != 0) { + mtx_unlock(sema_mtxp); + return (error); + } + mtx_unlock(sema_mtxp); #endif error = 0; - *rval = 0; + rval = 0; switch (cmd) { case IPC_RMID: - if ((error = semvalid(semid, semakptr)) != 0) + mtx_lock(sema_mtxp); + if ((error = semvalid(uap->semid, semakptr)) != 0) goto done2; if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_M))) goto done2; @@ -691,34 +639,45 @@ mac_cleanup_sysv_sem(semakptr); #endif SEMUNDO_LOCK(); - semundo_clear(semidx, -1); + semundo_clear(semid, -1); SEMUNDO_UNLOCK(); wakeup(semakptr); break; case IPC_SET: - if ((error = semvalid(semid, semakptr)) != 0) + if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0) + goto done2; + if ((error = copyin(real_arg.buf, &sbuf, sizeof(sbuf))) != 0) + goto done2; + mtx_lock(sema_mtxp); + if ((error = semvalid(uap->semid, semakptr)) != 0) goto done2; if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_M))) goto done2; - sbuf = arg->buf; - semakptr->u.sem_perm.uid = sbuf->sem_perm.uid; - semakptr->u.sem_perm.gid = sbuf->sem_perm.gid; + semakptr->u.sem_perm.uid = sbuf.sem_perm.uid; + semakptr->u.sem_perm.gid = sbuf.sem_perm.gid; semakptr->u.sem_perm.mode = (semakptr->u.sem_perm.mode & - ~0777) | (sbuf->sem_perm.mode & 0777); + ~0777) | (sbuf.sem_perm.mode & 0777); semakptr->u.sem_ctime = time_second; break; case IPC_STAT: - if ((error = semvalid(semid, semakptr)) != 0) + if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0) + goto done2; + mtx_lock(sema_mtxp); + if ((error = semvalid(uap->semid, semakptr)) != 0) goto done2; if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) goto done2; - bcopy(&semakptr->u, arg->buf, sizeof(struct semid_ds)); + sbuf = semakptr->u; + mtx_unlock(sema_mtxp); + error = copyout(&semakptr->u, real_arg.buf, + sizeof(struct semid_ds)); break; case GETNCNT: - if ((error = semvalid(semid, semakptr)) != 0) + mtx_lock(sema_mtxp); + if ((error = semvalid(uap->semid, semakptr)) != 0) goto done2; if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) goto done2; @@ -726,11 +685,12 @@ error = EINVAL; goto done2; } - *rval = semakptr->u.sem_base[semnum].semncnt; + rval = semakptr->u.sem_base[semnum].semncnt; break; case GETPID: - if ((error = semvalid(semid, semakptr)) != 0) + mtx_lock(sema_mtxp); + if ((error = semvalid(uap->semid, semakptr)) != 0) goto done2; if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) goto done2; @@ -738,11 +698,12 @@ error = EINVAL; goto done2; } - *rval = semakptr->u.sem_base[semnum].sempid; + rval = semakptr->u.sem_base[semnum].sempid; break; case GETVAL: - if ((error = semvalid(semid, semakptr)) != 0) + mtx_lock(sema_mtxp); + if ((error = semvalid(uap->semid, semakptr)) != 0) goto done2; if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) goto done2; @@ -750,48 +711,29 @@ error = EINVAL; goto done2; } - *rval = semakptr->u.sem_base[semnum].semval; + rval = semakptr->u.sem_base[semnum].semval; break; case GETALL: - /* - * Unfortunately, callers of this function don't know - * in advance how many semaphores are in this set. - * While we could just allocate the maximum size array - * and pass the actual size back to the caller, that - * won't work for SETALL since we can't copyin() more - * data than the user specified as we may return a - * spurious EFAULT. - * - * Note that the number of semaphores in a set is - * fixed for the life of that set. The only way that - * the 'count' could change while are blocked in - * malloc() is if this semaphore set were destroyed - * and a new one created with the same index. - * However, semvalid() will catch that due to the - * sequence number unless exactly 0x8000 (or a - * multiple thereof) semaphore sets for the same index - * are created and destroyed while we are in malloc! - * - */ - count = semakptr->u.sem_nsems; - mtx_unlock(sema_mtxp); - array = malloc(sizeof(*array) * count, M_TEMP, M_WAITOK); + if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0) + goto done2; + array = malloc(sizeof(*array) * semakptr->u.sem_nsems, M_TEMP, + M_WAITOK); mtx_lock(sema_mtxp); - if ((error = semvalid(semid, semakptr)) != 0) + if ((error = semvalid(uap->semid, semakptr)) != 0) goto done2; - KASSERT(count == semakptr->u.sem_nsems, ("nsems changed")); if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) goto done2; for (i = 0; i < semakptr->u.sem_nsems; i++) array[i] = semakptr->u.sem_base[i].semval; mtx_unlock(sema_mtxp); - error = copyout(array, arg->array, count * sizeof(*array)); - mtx_lock(sema_mtxp); + error = copyout(array, real_arg.array, + i * sizeof(real_arg.array[0])); break; case GETZCNT: - if ((error = semvalid(semid, semakptr)) != 0) + mtx_lock(sema_mtxp); + if ((error = semvalid(uap->semid, semakptr)) != 0) goto done2; if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) goto done2; @@ -799,11 +741,14 @@ error = EINVAL; goto done2; } - *rval = semakptr->u.sem_base[semnum].semzcnt; + rval = semakptr->u.sem_base[semnum].semzcnt; break; case SETVAL: - if ((error = semvalid(semid, semakptr)) != 0) + if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0) + goto done2; + mtx_lock(sema_mtxp); + if ((error = semvalid(uap->semid, semakptr)) != 0) goto done2; if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_W))) goto done2; @@ -811,32 +756,39 @@ error = EINVAL; goto done2; } - if (arg->val < 0 || arg->val > seminfo.semvmx) { + if (real_arg.val < 0 || real_arg.val > seminfo.semvmx) { error = ERANGE; goto done2; } - semakptr->u.sem_base[semnum].semval = arg->val; + semakptr->u.sem_base[semnum].semval = real_arg.val; SEMUNDO_LOCK(); - semundo_clear(semidx, semnum); + semundo_clear(semid, semnum); SEMUNDO_UNLOCK(); wakeup(semakptr); break; case SETALL: - /* - * See comment on GETALL for why 'count' shouldn't change - * and why we require a userland buffer. - */ + mtx_lock(sema_mtxp); +raced: + if ((error = semvalid(uap->semid, semakptr)) != 0) + goto done2; count = semakptr->u.sem_nsems; - mtx_unlock(sema_mtxp); + mtx_unlock(sema_mtxp); + if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0) + goto done2; array = malloc(sizeof(*array) * count, M_TEMP, M_WAITOK); - error = copyin(arg->array, array, count * sizeof(*array)); + error = copyin(real_arg.array, array, count * sizeof(*array)); if (error) break; mtx_lock(sema_mtxp); - if ((error = semvalid(semid, semakptr)) != 0) + if ((error = semvalid(uap->semid, semakptr)) != 0) goto done2; - KASSERT(count == semakptr->u.sem_nsems, ("nsems changed")); + /* we could have raced? */ + if (count != semakptr->u.sem_nsems) { + free(array, M_TEMP); + array = NULL; + goto raced; + } if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_W))) goto done2; for (i = 0; i < semakptr->u.sem_nsems; i++) { @@ -848,7 +800,7 @@ semakptr->u.sem_base[i].semval = usval; } SEMUNDO_LOCK(); - semundo_clear(semidx, -1); + semundo_clear(semid, -1); SEMUNDO_UNLOCK(); wakeup(semakptr); break; @@ -858,8 +810,11 @@ break; } + if (error == 0) + td->td_retval[0] = rval; done2: - mtx_unlock(sema_mtxp); + if (mtx_owned(sema_mtxp)) + mtx_unlock(sema_mtxp); if (array != NULL) free(array, M_TEMP); return(error); --- sys/syscallsubr.h.orig Tue Aug 1 14:56:09 2006 +++ sys/syscallsubr.h Thu Oct 12 22:11:42 2006 @@ -42,7 +42,6 @@ struct msqid_ds; struct rlimit; struct rusage; -union semun; struct sockaddr; struct stat; struct kevent; @@ -134,8 +133,6 @@ int kern_rmdir(struct thread *td, char *path, enum uio_seg pathseg); int kern_sched_rr_get_interval(struct thread *td, pid_t pid, struct timespec *ts); -int kern_semctl(struct thread *td, int semid, int semnum, int cmd, - union semun *arg, register_t *rval); int kern_select(struct thread *td, int nd, fd_set *fd_in, fd_set *fd_ou, fd_set *fd_ex, struct timeval *tvp); int kern_sendfile(struct thread *td, struct sendfile_args *uap,