diff options
Diffstat (limited to 'ipc/compat.c')
| -rw-r--r-- | ipc/compat.c | 256 |
1 files changed, 134 insertions, 122 deletions
diff --git a/ipc/compat.c b/ipc/compat.c index a6df704f521..b5ef4f7946d 100644 --- a/ipc/compat.c +++ b/ipc/compat.c @@ -30,7 +30,7 @@ #include <linux/ptrace.h> #include <linux/mutex.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #include "util.h" @@ -113,12 +113,9 @@ struct compat_shm_info { compat_ulong_t swap_attempts, swap_successes; }; -extern int sem_ctls[]; -#define sc_semopm (sem_ctls[2]) - static inline int compat_ipc_parse_version(int *cmd) { -#ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC +#ifdef CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION int version = *cmd & IPC_64; /* this is tricky: architectures that have support for the old @@ -197,7 +194,7 @@ static inline int __put_compat_ipc_perm(struct ipc64_perm *p, static inline int get_compat_semid64_ds(struct semid64_ds *s64, struct compat_semid64_ds __user *up64) { - if (!access_ok (VERIFY_READ, up64, sizeof(*up64))) + if (!access_ok(VERIFY_READ, up64, sizeof(*up64))) return -EFAULT; return __get_compat_ipc64_perm(&s64->sem_perm, &up64->sem_perm); } @@ -205,7 +202,7 @@ static inline int get_compat_semid64_ds(struct semid64_ds *s64, static inline int get_compat_semid_ds(struct semid64_ds *s, struct compat_semid_ds __user *up) { - if (!access_ok (VERIFY_READ, up, sizeof(*up))) + if (!access_ok(VERIFY_READ, up, sizeof(*up))) return -EFAULT; return __get_compat_ipc_perm(&s->sem_perm, &up->sem_perm); } @@ -215,7 +212,7 @@ static inline int put_compat_semid64_ds(struct semid64_ds *s64, { int err; - if (!access_ok (VERIFY_WRITE, up64, sizeof(*up64))) + if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) return -EFAULT; err = __put_compat_ipc64_perm(&s64->sem_perm, &up64->sem_perm); err |= __put_user(s64->sem_otime, &up64->sem_otime); @@ -229,7 +226,7 @@ static inline int put_compat_semid_ds(struct semid64_ds *s, { int err; - if (!access_ok (VERIFY_WRITE, up, sizeof(*up))) + if (!access_ok(VERIFY_WRITE, up, sizeof(*up))) return -EFAULT; err = __put_compat_ipc_perm(&s->sem_perm, &up->sem_perm); err |= __put_user(s->sem_otime, &up->sem_otime); @@ -240,7 +237,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 +246,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 +270,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; @@ -284,18 +285,18 @@ static long do_compat_semctl(int first, int second, int third, u32 pad) break; case IPC_SET: - if (version == IPC_64) { + if (version == IPC_64) err = get_compat_semid64_ds(&s64, compat_ptr(pad)); - } else { + else err = get_compat_semid_ds(&s64, compat_ptr(pad)); - } + up64 = compat_alloc_user_space(sizeof(s64)); if (copy_to_user(up64, &s64, sizeof(s64))) err = -EFAULT; if (err) break; - fourth.__pad = up64; + fourth = (unsigned long)up64; err = sys_semctl(first, second, third, fourth); break; @@ -306,97 +307,131 @@ static long do_compat_semctl(int first, int second, int third, u32 pad) return err; } -#ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC -long compat_sys_semctl(int first, int second, int third, void __user *uptr) +static long compat_do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz) { - u32 pad; + struct compat_msgbuf __user *msgp = dest; + size_t msgsz; + + if (put_user(msg->m_type, &msgp->mtype)) + return -EFAULT; - if (!uptr) - return -EINVAL; - if (get_user(pad, (u32 __user *) uptr)) + msgsz = (bufsz > msg->m_ts) ? msg->m_ts : bufsz; + if (store_msg(msgp->mtext, msg, msgsz)) return -EFAULT; - return do_compat_semctl(first, second, third, pad); + return msgsz; } -long compat_sys_msgsnd(int first, int second, int third, void __user *uptr) +#ifndef COMPAT_SHMLBA +#define COMPAT_SHMLBA SHMLBA +#endif + +#ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC +COMPAT_SYSCALL_DEFINE6(ipc, u32, call, int, first, int, second, + u32, third, compat_uptr_t, ptr, u32, fifth) { - struct compat_msgbuf __user *up = uptr; - long type; + int version; + u32 pad; - if (first < 0) - return -EINVAL; - if (second < 0) - return -EINVAL; + 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); - if (get_user(type, &up->mtype)) - return -EFAULT; + case MSGSND: { + struct compat_msgbuf __user *up = compat_ptr(ptr); + compat_long_t type; - return do_msgsnd(first, type, up->mtext, second, third); -} + if (first < 0 || second < 0) + return -EINVAL; -long compat_sys_msgrcv(int first, int second, int msgtyp, int third, - int version, void __user *uptr) -{ - struct compat_msgbuf __user *up; - long type; - int err; - - if (first < 0) - return -EINVAL; - if (second < 0) - return -EINVAL; + if (get_user(type, &up->mtype)) + return -EFAULT; - if (!version) { - struct compat_ipc_kludge ipck; - err = -EINVAL; - if (!uptr) - goto out; - err = -EFAULT; - if (copy_from_user (&ipck, uptr, sizeof(ipck))) - goto out; - uptr = compat_ptr(ipck.msgp); - msgtyp = ipck.msgtyp; + return do_msgsnd(first, type, up->mtext, second, third); } - up = uptr; - err = do_msgrcv(first, &type, up->mtext, second, msgtyp, third); - if (err < 0) - goto out; - if (put_user(type, &up->mtype)) - err = -EFAULT; -out: - return err; + case MSGRCV: { + void __user *uptr = compat_ptr(ptr); + + if (first < 0 || second < 0) + return -EINVAL; + + 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, (s32)fifth, 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, - size_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, msgsz, msgflg); + return do_msgsnd(msqid, mtype, up->mtext, (ssize_t)msgsz, msgflg); } -long compat_sys_msgrcv(int msqid, struct compat_msgbuf __user *msgp, - size_t msgsz, long msgtyp, int msgflg) +COMPAT_SYSCALL_DEFINE5(msgrcv, int, msqid, compat_uptr_t, msgp, + compat_ssize_t, msgsz, compat_long_t, msgtyp, int, msgflg) { - long err, mtype; - - err = do_msgrcv(msqid, &mtype, msgp->mtext, msgsz, msgtyp, msgflg); - if (err < 0) - goto out; - - if (put_user(mtype, &msgp->mtype)) - err = -EFAULT; - out: - return err; + return do_msgrcv(msqid, compat_ptr(msgp), (ssize_t)msgsz, (long)msgtyp, + msgflg, compat_do_msg_fill); } -#endif static inline int get_compat_msqid64(struct msqid64_ds *m64, struct compat_msqid64_ds __user *up64) @@ -460,7 +495,7 @@ static inline int put_compat_msqid_ds(struct msqid64_ds *m, return err; } -long compat_sys_msgctl(int first, int second, void __user *uptr) +COMPAT_SYSCALL_DEFINE3(msgctl, int, first, int, second, void __user *, uptr) { int err, err2; struct msqid64_ds m64; @@ -477,11 +512,11 @@ long compat_sys_msgctl(int first, int second, void __user *uptr) break; case IPC_SET: - if (version == IPC_64) { + if (version == IPC_64) err = get_compat_msqid64(&m64, uptr); - } else { + else err = get_compat_msqid(&m64, uptr); - } + if (err) break; p = compat_alloc_user_space(sizeof(m64)); @@ -514,35 +549,17 @@ long compat_sys_msgctl(int first, int second, void __user *uptr) return err; } -#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); - 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; - err = do_shmat(shmid, compat_ptr(shmaddr), shmflg, &ret); + err = do_shmat(shmid, compat_ptr(shmaddr), shmflg, &ret, COMPAT_SHMLBA); if (err) return err; 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) @@ -648,7 +665,7 @@ static inline int put_compat_shm_info(struct shm_info __user *ip, return err; } -long compat_sys_shmctl(int first, int second, void __user *uptr) +COMPAT_SYSCALL_DEFINE3(shmctl, int, first, int, second, void __user *, uptr) { void __user *p; struct shmid64_ds s64; @@ -682,11 +699,11 @@ long compat_sys_shmctl(int first, int second, void __user *uptr) case IPC_SET: - if (version == IPC_64) { + if (version == IPC_64) err = get_compat_shmid64_ds(&s64, uptr); - } else { + else err = get_compat_shmid_ds(&s64, uptr); - } + if (err) break; p = compat_alloc_user_space(sizeof(s64)); @@ -729,17 +746,12 @@ long compat_sys_shmctl(int first, int second, void __user *uptr) return err; } -long compat_sys_semtimedop(int semid, struct sembuf __user *tsems, - unsigned nsops, const struct compat_timespec __user *timeout) +COMPAT_SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsems, + unsigned, nsops, + const struct compat_timespec __user *, timeout) { - struct timespec __user *ts64 = NULL; - if (timeout) { - struct timespec ts; - ts64 = compat_alloc_user_space(sizeof(*ts64)); - if (get_compat_timespec(&ts, timeout)) - return -EFAULT; - if (copy_to_user(ts64, &ts, sizeof(ts))) - return -EFAULT; - } + struct timespec __user *ts64; + if (compat_convert_timespec(&ts64, timeout)) + return -EFAULT; return sys_semtimedop(semid, tsems, nsops, ts64); } |
