diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-01 07:21:43 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-01 07:21:43 -0700 |
commit | 08d76760832993050ad8c25e63b56773ef2ca303 (patch) | |
tree | abdcf148dfe43cd49f30f204f1dac6978107a508 /ipc | |
parent | 5f56886521d6ddd3648777fae44d82382dd8c87f (diff) | |
parent | 99e621f796d7f0341a51e8cdf32b81663b10b448 (diff) | |
download | lwn-08d76760832993050ad8c25e63b56773ef2ca303.tar.gz lwn-08d76760832993050ad8c25e63b56773ef2ca303.zip |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal
Pull compat cleanup from Al Viro:
"Mostly about syscall wrappers this time; there will be another pile
with patches in the same general area from various people, but I'd
rather push those after both that and vfs.git pile are in."
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal:
syscalls.h: slightly reduce the jungles of macros
get rid of union semop in sys_semctl(2) arguments
make do_mremap() static
sparc: no need to sign-extend in sync_file_range() wrapper
ppc compat wrappers for add_key(2) and request_key(2) are pointless
x86: trim sys_ia32.h
x86: sys32_kill and sys32_mprotect are pointless
get rid of compat_sys_semctl() and friends in case of ARCH_WANT_OLD_COMPAT_IPC
merge compat sys_ipc instances
consolidate compat lookup_dcookie()
convert vmsplice to COMPAT_SYSCALL_DEFINE
switch getrusage() to COMPAT_SYSCALL_DEFINE
switch epoll_pwait to COMPAT_SYSCALL_DEFINE
convert sendfile{,64} to COMPAT_SYSCALL_DEFINE
switch signalfd{,4}() to COMPAT_SYSCALL_DEFINE
make SYSCALL_DEFINE<n>-generated wrappers do asmlinkage_protect
make HAVE_SYSCALL_WRAPPERS unconditional
consolidate cond_syscall and SYSCALL_ALIAS declarations
teach SYSCALL_DEFINE<n> how to deal with long long/unsigned long long
get rid of duplicate logics in __SC_....[1-6] definitions
Diffstat (limited to 'ipc')
-rw-r--r-- | ipc/compat.c | 174 | ||||
-rw-r--r-- | ipc/sem.c | 123 | ||||
-rw-r--r-- | ipc/syscall.c | 6 |
3 files changed, 177 insertions, 126 deletions
diff --git a/ipc/compat.c b/ipc/compat.c index 2547f29dcd1b..892f6585dd60 100644 --- a/ipc/compat.c +++ b/ipc/compat.c @@ -240,7 +240,7 @@ static inline int put_compat_semid_ds(struct semid64_ds *s, static long do_compat_semctl(int first, int second, int third, u32 pad) { - union semun fourth; + unsigned long fourth; int err, err2; struct semid64_ds s64; struct semid64_ds __user *up64; @@ -249,9 +249,13 @@ static long do_compat_semctl(int first, int second, int third, u32 pad) memset(&s64, 0, sizeof(s64)); if ((third & (~IPC_64)) == SETVAL) - fourth.val = (int) pad; +#ifdef __BIG_ENDIAN + fourth = (unsigned long)pad << 32; +#else + fourth = pad; +#endif else - fourth.__pad = compat_ptr(pad); + fourth = (unsigned long)compat_ptr(pad); switch (third & (~IPC_64)) { case IPC_INFO: case IPC_RMID: @@ -269,7 +273,7 @@ static long do_compat_semctl(int first, int second, int third, u32 pad) case IPC_STAT: case SEM_STAT: up64 = compat_alloc_user_space(sizeof(s64)); - fourth.__pad = up64; + fourth = (unsigned long)up64; err = sys_semctl(first, second, third, fourth); if (err < 0) break; @@ -295,7 +299,7 @@ static long do_compat_semctl(int first, int second, int third, u32 pad) if (err) break; - fourth.__pad = up64; + fourth = (unsigned long)up64; err = sys_semctl(first, second, third, fourth); break; @@ -306,7 +310,7 @@ static long do_compat_semctl(int first, int second, int third, u32 pad) return err; } -long compat_do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz) +static long compat_do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz) { struct compat_msgbuf __user *msgp = dest; size_t msgsz; @@ -320,77 +324,117 @@ long compat_do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz) return msgsz; } +#ifndef COMPAT_SHMLBA +#define COMPAT_SHMLBA SHMLBA +#endif + #ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC -long compat_sys_semctl(int first, int second, int third, void __user *uptr) +COMPAT_SYSCALL_DEFINE6(ipc, u32, call, int, first, int, second, + u32, third, compat_uptr_t, ptr, u32, fifth) { + int version; u32 pad; - if (!uptr) - return -EINVAL; - if (get_user(pad, (u32 __user *) uptr)) - return -EFAULT; - return do_compat_semctl(first, second, third, pad); -} + version = call >> 16; /* hack for backward compatibility */ + call &= 0xffff; + + switch (call) { + case SEMOP: + /* struct sembuf is the same on 32 and 64bit :)) */ + return sys_semtimedop(first, compat_ptr(ptr), second, NULL); + case SEMTIMEDOP: + return compat_sys_semtimedop(first, compat_ptr(ptr), second, + compat_ptr(fifth)); + case SEMGET: + return sys_semget(first, second, third); + case SEMCTL: + if (!ptr) + return -EINVAL; + if (get_user(pad, (u32 __user *) compat_ptr(ptr))) + return -EFAULT; + return do_compat_semctl(first, second, third, pad); -long compat_sys_msgsnd(int first, int second, int third, void __user *uptr) -{ - struct compat_msgbuf __user *up = uptr; - long type; + case MSGSND: { + struct compat_msgbuf __user *up = compat_ptr(ptr); + compat_long_t type; - if (first < 0) - return -EINVAL; - if (second < 0) - return -EINVAL; + if (first < 0 || second < 0) + return -EINVAL; - if (get_user(type, &up->mtype)) - return -EFAULT; + if (get_user(type, &up->mtype)) + return -EFAULT; - return do_msgsnd(first, type, up->mtext, second, third); -} + return do_msgsnd(first, type, up->mtext, second, third); + } + case MSGRCV: { + void __user *uptr = compat_ptr(ptr); -long compat_sys_msgrcv(int first, int second, int msgtyp, int third, - int version, void __user *uptr) -{ - if (first < 0) - return -EINVAL; - if (second < 0) - return -EINVAL; - - if (!version) { - struct compat_ipc_kludge ipck; - if (!uptr) + if (first < 0 || second < 0) return -EINVAL; - if (copy_from_user (&ipck, uptr, sizeof(ipck))) - return -EFAULT; - uptr = compat_ptr(ipck.msgp); - msgtyp = ipck.msgtyp; + + if (!version) { + struct compat_ipc_kludge ipck; + if (!uptr) + return -EINVAL; + if (copy_from_user (&ipck, uptr, sizeof(ipck))) + return -EFAULT; + uptr = compat_ptr(ipck.msgp); + fifth = ipck.msgtyp; + } + return do_msgrcv(first, uptr, second, fifth, third, + compat_do_msg_fill); } - return do_msgrcv(first, uptr, second, msgtyp, third, - compat_do_msg_fill); + case MSGGET: + return sys_msgget(first, second); + case MSGCTL: + return compat_sys_msgctl(first, second, compat_ptr(ptr)); + + case SHMAT: { + int err; + unsigned long raddr; + + if (version == 1) + return -EINVAL; + err = do_shmat(first, compat_ptr(ptr), second, &raddr, + COMPAT_SHMLBA); + if (err < 0) + return err; + return put_user(raddr, (compat_ulong_t *)compat_ptr(third)); + } + case SHMDT: + return sys_shmdt(compat_ptr(ptr)); + case SHMGET: + return sys_shmget(first, (unsigned)second, third); + case SHMCTL: + return compat_sys_shmctl(first, second, compat_ptr(ptr)); + } + + return -ENOSYS; } -#else -long compat_sys_semctl(int semid, int semnum, int cmd, int arg) +#endif + +COMPAT_SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, int, arg) { return do_compat_semctl(semid, semnum, cmd, arg); } -long compat_sys_msgsnd(int msqid, struct compat_msgbuf __user *msgp, - compat_ssize_t msgsz, int msgflg) +COMPAT_SYSCALL_DEFINE4(msgsnd, int, msqid, compat_uptr_t, msgp, + compat_ssize_t, msgsz, int, msgflg) { + struct compat_msgbuf __user *up = compat_ptr(msgp); compat_long_t mtype; - if (get_user(mtype, &msgp->mtype)) + if (get_user(mtype, &up->mtype)) return -EFAULT; - return do_msgsnd(msqid, mtype, msgp->mtext, (ssize_t)msgsz, msgflg); + return do_msgsnd(msqid, mtype, up->mtext, (ssize_t)msgsz, msgflg); } -long compat_sys_msgrcv(int msqid, struct compat_msgbuf __user *msgp, - compat_ssize_t msgsz, long msgtyp, int msgflg) +COMPAT_SYSCALL_DEFINE5(msgrcv, int, msqid, compat_uptr_t, msgp, + compat_ssize_t, msgsz, long, msgtyp, int, msgflg) { - return do_msgrcv(msqid, msgp, (ssize_t)msgsz, msgtyp, msgflg, - compat_do_msg_fill); + return do_msgrcv(msqid, compat_ptr(msgp), (ssize_t)msgsz, msgtyp, + msgflg, compat_do_msg_fill); } -#endif static inline int get_compat_msqid64(struct msqid64_ds *m64, struct compat_msqid64_ds __user *up64) @@ -508,28 +552,7 @@ long compat_sys_msgctl(int first, int second, void __user *uptr) return err; } -#ifndef COMPAT_SHMLBA -#define COMPAT_SHMLBA SHMLBA -#endif - -#ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC -long compat_sys_shmat(int first, int second, compat_uptr_t third, int version, - void __user *uptr) -{ - int err; - unsigned long raddr; - compat_ulong_t __user *uaddr; - - if (version == 1) - return -EINVAL; - err = do_shmat(first, uptr, second, &raddr, COMPAT_SHMLBA); - if (err < 0) - return err; - uaddr = compat_ptr(third); - return put_user(raddr, uaddr); -} -#else -long compat_sys_shmat(int shmid, compat_uptr_t shmaddr, int shmflg) +COMPAT_SYSCALL_DEFINE3(shmat, int, shmid, compat_uptr_t, shmaddr, int, shmflg) { unsigned long ret; long err; @@ -540,7 +563,6 @@ long compat_sys_shmat(int shmid, compat_uptr_t shmaddr, int shmflg) force_successful_syscall_return(); return (long)ret; } -#endif static inline int get_compat_shmid64_ds(struct shmid64_ds *s64, struct compat_shmid64_ds __user *up64) diff --git a/ipc/sem.c b/ipc/sem.c index 58d31f1c1eb5..5b167d00efa6 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -799,7 +799,7 @@ static unsigned long copy_semid_to_user(void __user *buf, struct semid64_ds *in, } static int semctl_nolock(struct ipc_namespace *ns, int semid, - int cmd, int version, union semun arg) + int cmd, int version, void __user *p) { int err; struct sem_array *sma; @@ -834,7 +834,7 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid, } max_id = ipc_get_maxid(&sem_ids(ns)); up_read(&sem_ids(ns).rw_mutex); - if (copy_to_user (arg.__buf, &seminfo, sizeof(struct seminfo))) + if (copy_to_user(p, &seminfo, sizeof(struct seminfo))) return -EFAULT; return (max_id < 0) ? 0: max_id; } @@ -871,7 +871,7 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid, tbuf.sem_ctime = sma->sem_ctime; tbuf.sem_nsems = sma->sem_nsems; sem_unlock(sma); - if (copy_semid_to_user (arg.buf, &tbuf, version)) + if (copy_semid_to_user(p, &tbuf, version)) return -EFAULT; return id; } @@ -883,8 +883,67 @@ out_unlock: return err; } +static int semctl_setval(struct ipc_namespace *ns, int semid, int semnum, + unsigned long arg) +{ + struct sem_undo *un; + struct sem_array *sma; + struct sem* curr; + int err; + int nsems; + struct list_head tasks; + int val; +#if defined(CONFIG_64BIT) && defined(__BIG_ENDIAN) + /* big-endian 64bit */ + val = arg >> 32; +#else + /* 32bit or little-endian 64bit */ + val = arg; +#endif + + sma = sem_lock_check(ns, semid); + if (IS_ERR(sma)) + return PTR_ERR(sma); + + INIT_LIST_HEAD(&tasks); + nsems = sma->sem_nsems; + + err = -EACCES; + if (ipcperms(ns, &sma->sem_perm, S_IWUGO)) + goto out_unlock; + + err = security_sem_semctl(sma, SETVAL); + if (err) + goto out_unlock; + + err = -EINVAL; + if(semnum < 0 || semnum >= nsems) + goto out_unlock; + + curr = &sma->sem_base[semnum]; + + err = -ERANGE; + if (val > SEMVMX || val < 0) + goto out_unlock; + + assert_spin_locked(&sma->sem_perm.lock); + list_for_each_entry(un, &sma->list_id, list_id) + un->semadj[semnum] = 0; + + curr->semval = val; + curr->sempid = task_tgid_vnr(current); + sma->sem_ctime = get_seconds(); + /* maybe some queued-up processes were waiting for this */ + do_smart_update(sma, NULL, 0, 0, &tasks); + err = 0; +out_unlock: + sem_unlock(sma); + wake_up_sem_queue_do(&tasks); + return err; +} + static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, - int cmd, int version, union semun arg) + int cmd, void __user *p) { struct sem_array *sma; struct sem* curr; @@ -903,7 +962,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, err = -EACCES; if (ipcperms(ns, &sma->sem_perm, - (cmd == SETVAL || cmd == SETALL) ? S_IWUGO : S_IRUGO)) + cmd == SETALL ? S_IWUGO : S_IRUGO)) goto out_unlock; err = security_sem_semctl(sma, cmd); @@ -914,7 +973,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, switch (cmd) { case GETALL: { - ushort __user *array = arg.array; + ushort __user *array = p; int i; if(nsems > SEMMSL_FAST) { @@ -957,7 +1016,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, } } - if (copy_from_user (sem_io, arg.array, nsems*sizeof(ushort))) { + if (copy_from_user (sem_io, p, nsems*sizeof(ushort))) { sem_putref(sma); err = -EFAULT; goto out_free; @@ -991,7 +1050,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, err = 0; goto out_unlock; } - /* GETVAL, GETPID, GETNCTN, GETZCNT, SETVAL: fall-through */ + /* GETVAL, GETPID, GETNCTN, GETZCNT: fall-through */ } err = -EINVAL; if(semnum < 0 || semnum >= nsems) @@ -1012,27 +1071,6 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, case GETZCNT: err = count_semzcnt(sma,semnum); goto out_unlock; - case SETVAL: - { - int val = arg.val; - struct sem_undo *un; - - err = -ERANGE; - if (val > SEMVMX || val < 0) - goto out_unlock; - - assert_spin_locked(&sma->sem_perm.lock); - list_for_each_entry(un, &sma->list_id, list_id) - un->semadj[semnum] = 0; - - curr->semval = val; - curr->sempid = task_tgid_vnr(current); - sma->sem_ctime = get_seconds(); - /* maybe some queued-up processes were waiting for this */ - do_smart_update(sma, NULL, 0, 0, &tasks); - err = 0; - goto out_unlock; - } } out_unlock: sem_unlock(sma); @@ -1076,7 +1114,7 @@ copy_semid_from_user(struct semid64_ds *out, void __user *buf, int version) * NOTE: no locks must be held, the rw_mutex is taken inside this function. */ static int semctl_down(struct ipc_namespace *ns, int semid, - int cmd, int version, union semun arg) + int cmd, int version, void __user *p) { struct sem_array *sma; int err; @@ -1084,7 +1122,7 @@ static int semctl_down(struct ipc_namespace *ns, int semid, struct kern_ipc_perm *ipcp; if(cmd == IPC_SET) { - if (copy_semid_from_user(&semid64, arg.buf, version)) + if (copy_semid_from_user(&semid64, p, version)) return -EFAULT; } @@ -1120,11 +1158,11 @@ out_up: return err; } -SYSCALL_DEFINE(semctl)(int semid, int semnum, int cmd, union semun arg) +SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, unsigned long, arg) { - int err = -EINVAL; int version; struct ipc_namespace *ns; + void __user *p = (void __user *)arg; if (semid < 0) return -EINVAL; @@ -1137,32 +1175,23 @@ SYSCALL_DEFINE(semctl)(int semid, int semnum, int cmd, union semun arg) case SEM_INFO: case IPC_STAT: case SEM_STAT: - err = semctl_nolock(ns, semid, cmd, version, arg); - return err; + return semctl_nolock(ns, semid, cmd, version, p); case GETALL: case GETVAL: case GETPID: case GETNCNT: case GETZCNT: - case SETVAL: case SETALL: - err = semctl_main(ns,semid,semnum,cmd,version,arg); - return err; + return semctl_main(ns, semid, semnum, cmd, p); + case SETVAL: + return semctl_setval(ns, semid, semnum, arg); case IPC_RMID: case IPC_SET: - err = semctl_down(ns, semid, cmd, version, arg); - return err; + return semctl_down(ns, semid, cmd, version, p); default: return -EINVAL; } } -#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS -asmlinkage long SyS_semctl(int semid, int semnum, int cmd, union semun arg) -{ - return SYSC_semctl((int) semid, (int) semnum, (int) cmd, arg); -} -SYSCALL_ALIAS(sys_semctl, SyS_semctl); -#endif /* If the task doesn't already have a undo_list, then allocate one * here. We guarantee there is only one thread using this undo list, diff --git a/ipc/syscall.c b/ipc/syscall.c index 0d1e32ce048e..52429489cde0 100644 --- a/ipc/syscall.c +++ b/ipc/syscall.c @@ -33,12 +33,12 @@ SYSCALL_DEFINE6(ipc, unsigned int, call, int, first, unsigned long, second, case SEMGET: return sys_semget(first, second, third); case SEMCTL: { - union semun fourth; + unsigned long arg; if (!ptr) return -EINVAL; - if (get_user(fourth.__pad, (void __user * __user *) ptr)) + if (get_user(arg, (unsigned long __user *) ptr)) return -EFAULT; - return sys_semctl(first, second, third, fourth); + return sys_semctl(first, second, third, arg); } case MSGSND: |