diff options
author | Atsushi Nemoto <anemo@mba.ocn.ne.jp> | 2006-11-07 18:02:44 +0900 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2006-12-04 22:43:12 +0000 |
commit | 05e4396651ca1cac51d8da9ff4992741c9dc1e39 (patch) | |
tree | 15881e19dfd7550dbe26245a356a10a979577086 /arch/mips/kernel/linux32.c | |
parent | 9567772f14f6d2692ea88ddc111a5a6b352fd512 (diff) | |
download | lwn-05e4396651ca1cac51d8da9ff4992741c9dc1e39.tar.gz lwn-05e4396651ca1cac51d8da9ff4992741c9dc1e39.zip |
[MIPS] Use SYSVIPC_COMPAT to fix various problems on N32
N32 SysV IPC system calls should use 32-bit compatible code.
arch/mips/kernel/linux32.c have similar compatible code for O32, but
ipc/compat.c seems more complete. We can use it for both N32 and O32.
This patch should fix these problems (and other possible problems):
http://www.linux-mips.org/cgi-bin/mesg.cgi?a=linux-mips&i=1149188824.6986.6.camel%40diimka-laptop
http://www.linux-mips.org/cgi-bin/mesg.cgi?a=linux-mips&i=44C6B829.8050508%40caviumnetworks.com
Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/kernel/linux32.c')
-rw-r--r-- | arch/mips/kernel/linux32.c | 578 |
1 files changed, 23 insertions, 555 deletions
diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c index 7a3ebbeba1f3..b061c9aa6302 100644 --- a/arch/mips/kernel/linux32.c +++ b/arch/mips/kernel/linux32.c @@ -382,531 +382,6 @@ asmlinkage int sys32_sched_rr_get_interval(compat_pid_t pid, return ret; } -struct msgbuf32 { s32 mtype; char mtext[1]; }; - -struct ipc_perm32 -{ - key_t key; - __compat_uid_t uid; - __compat_gid_t gid; - __compat_uid_t cuid; - __compat_gid_t cgid; - compat_mode_t mode; - unsigned short seq; -}; - -struct ipc64_perm32 { - key_t key; - __compat_uid_t uid; - __compat_gid_t gid; - __compat_uid_t cuid; - __compat_gid_t cgid; - compat_mode_t mode; - unsigned short seq; - unsigned short __pad1; - unsigned int __unused1; - unsigned int __unused2; -}; - -struct semid_ds32 { - struct ipc_perm32 sem_perm; /* permissions .. see ipc.h */ - compat_time_t sem_otime; /* last semop time */ - compat_time_t sem_ctime; /* last change time */ - u32 sem_base; /* ptr to first semaphore in array */ - u32 sem_pending; /* pending operations to be processed */ - u32 sem_pending_last; /* last pending operation */ - u32 undo; /* undo requests on this array */ - unsigned short sem_nsems; /* no. of semaphores in array */ -}; - -struct semid64_ds32 { - struct ipc64_perm32 sem_perm; - compat_time_t sem_otime; - compat_time_t sem_ctime; - unsigned int sem_nsems; - unsigned int __unused1; - unsigned int __unused2; -}; - -struct msqid_ds32 -{ - struct ipc_perm32 msg_perm; - u32 msg_first; - u32 msg_last; - compat_time_t msg_stime; - compat_time_t msg_rtime; - compat_time_t msg_ctime; - u32 wwait; - u32 rwait; - unsigned short msg_cbytes; - unsigned short msg_qnum; - unsigned short msg_qbytes; - compat_ipc_pid_t msg_lspid; - compat_ipc_pid_t msg_lrpid; -}; - -struct msqid64_ds32 { - struct ipc64_perm32 msg_perm; - compat_time_t msg_stime; - unsigned int __unused1; - compat_time_t msg_rtime; - unsigned int __unused2; - compat_time_t msg_ctime; - unsigned int __unused3; - unsigned int msg_cbytes; - unsigned int msg_qnum; - unsigned int msg_qbytes; - compat_pid_t msg_lspid; - compat_pid_t msg_lrpid; - unsigned int __unused4; - unsigned int __unused5; -}; - -struct shmid_ds32 { - struct ipc_perm32 shm_perm; - int shm_segsz; - compat_time_t shm_atime; - compat_time_t shm_dtime; - compat_time_t shm_ctime; - compat_ipc_pid_t shm_cpid; - compat_ipc_pid_t shm_lpid; - unsigned short shm_nattch; -}; - -struct shmid64_ds32 { - struct ipc64_perm32 shm_perm; - compat_size_t shm_segsz; - compat_time_t shm_atime; - compat_time_t shm_dtime; - compat_time_t shm_ctime; - compat_pid_t shm_cpid; - compat_pid_t shm_lpid; - unsigned int shm_nattch; - unsigned int __unused1; - unsigned int __unused2; -}; - -struct ipc_kludge32 { - u32 msgp; - s32 msgtyp; -}; - -static int -do_sys32_semctl(int first, int second, int third, void __user *uptr) -{ - union semun fourth; - u32 pad; - int err, err2; - struct semid64_ds s; - mm_segment_t old_fs; - - if (!uptr) - return -EINVAL; - err = -EFAULT; - if (get_user (pad, (u32 __user *)uptr)) - return err; - if ((third & ~IPC_64) == SETVAL) - fourth.val = (int)pad; - else - fourth.__pad = (void __user *)A(pad); - switch (third & ~IPC_64) { - case IPC_INFO: - case IPC_RMID: - case IPC_SET: - case SEM_INFO: - case GETVAL: - case GETPID: - case GETNCNT: - case GETZCNT: - case GETALL: - case SETVAL: - case SETALL: - err = sys_semctl (first, second, third, fourth); - break; - - case IPC_STAT: - case SEM_STAT: - fourth.__pad = (struct semid64_ds __user *)&s; - old_fs = get_fs(); - set_fs(KERNEL_DS); - err = sys_semctl(first, second, third | IPC_64, fourth); - set_fs(old_fs); - - if (third & IPC_64) { - struct semid64_ds32 __user *usp64 = (struct semid64_ds32 __user *) A(pad); - - if (!access_ok(VERIFY_WRITE, usp64, sizeof(*usp64))) { - err = -EFAULT; - break; - } - err2 = __put_user(s.sem_perm.key, &usp64->sem_perm.key); - err2 |= __put_user(s.sem_perm.uid, &usp64->sem_perm.uid); - err2 |= __put_user(s.sem_perm.gid, &usp64->sem_perm.gid); - err2 |= __put_user(s.sem_perm.cuid, &usp64->sem_perm.cuid); - err2 |= __put_user(s.sem_perm.cgid, &usp64->sem_perm.cgid); - err2 |= __put_user(s.sem_perm.mode, &usp64->sem_perm.mode); - err2 |= __put_user(s.sem_perm.seq, &usp64->sem_perm.seq); - err2 |= __put_user(s.sem_otime, &usp64->sem_otime); - err2 |= __put_user(s.sem_ctime, &usp64->sem_ctime); - err2 |= __put_user(s.sem_nsems, &usp64->sem_nsems); - } else { - struct semid_ds32 __user *usp32 = (struct semid_ds32 __user *) A(pad); - - if (!access_ok(VERIFY_WRITE, usp32, sizeof(*usp32))) { - err = -EFAULT; - break; - } - err2 = __put_user(s.sem_perm.key, &usp32->sem_perm.key); - err2 |= __put_user(s.sem_perm.uid, &usp32->sem_perm.uid); - err2 |= __put_user(s.sem_perm.gid, &usp32->sem_perm.gid); - err2 |= __put_user(s.sem_perm.cuid, &usp32->sem_perm.cuid); - err2 |= __put_user(s.sem_perm.cgid, &usp32->sem_perm.cgid); - err2 |= __put_user(s.sem_perm.mode, &usp32->sem_perm.mode); - err2 |= __put_user(s.sem_perm.seq, &usp32->sem_perm.seq); - err2 |= __put_user(s.sem_otime, &usp32->sem_otime); - err2 |= __put_user(s.sem_ctime, &usp32->sem_ctime); - err2 |= __put_user(s.sem_nsems, &usp32->sem_nsems); - } - if (err2) - err = -EFAULT; - break; - - default: - err = - EINVAL; - break; - } - - return err; -} - -static int -do_sys32_msgsnd (int first, int second, int third, void __user *uptr) -{ - struct msgbuf32 __user *up = (struct msgbuf32 __user *)uptr; - struct msgbuf *p; - mm_segment_t old_fs; - int err; - - if (second < 0) - return -EINVAL; - p = kmalloc (second + sizeof (struct msgbuf) - + 4, GFP_USER); - if (!p) - return -ENOMEM; - err = get_user (p->mtype, &up->mtype); - if (err) - goto out; - err |= __copy_from_user (p->mtext, &up->mtext, second); - if (err) - goto out; - old_fs = get_fs (); - set_fs (KERNEL_DS); - err = sys_msgsnd (first, (struct msgbuf __user *)p, second, third); - set_fs (old_fs); -out: - kfree (p); - - return err; -} - -static int -do_sys32_msgrcv (int first, int second, int msgtyp, int third, - int version, void __user *uptr) -{ - struct msgbuf32 __user *up; - struct msgbuf *p; - mm_segment_t old_fs; - int err; - - if (!version) { - struct ipc_kludge32 __user *uipck = (struct ipc_kludge32 __user *)uptr; - struct ipc_kludge32 ipck; - - err = -EINVAL; - if (!uptr) - goto out; - err = -EFAULT; - if (copy_from_user (&ipck, uipck, sizeof (struct ipc_kludge32))) - goto out; - uptr = (void __user *)AA(ipck.msgp); - msgtyp = ipck.msgtyp; - } - - if (second < 0) - return -EINVAL; - err = -ENOMEM; - p = kmalloc (second + sizeof (struct msgbuf) + 4, GFP_USER); - if (!p) - goto out; - old_fs = get_fs (); - set_fs (KERNEL_DS); - err = sys_msgrcv (first, (struct msgbuf __user *)p, second + 4, msgtyp, third); - set_fs (old_fs); - if (err < 0) - goto free_then_out; - up = (struct msgbuf32 __user *)uptr; - if (put_user (p->mtype, &up->mtype) || - __copy_to_user (&up->mtext, p->mtext, err)) - err = -EFAULT; -free_then_out: - kfree (p); -out: - return err; -} - -static int -do_sys32_msgctl (int first, int second, void __user *uptr) -{ - int err = -EINVAL, err2; - struct msqid64_ds m; - struct msqid_ds32 __user *up32 = (struct msqid_ds32 __user *)uptr; - struct msqid64_ds32 __user *up64 = (struct msqid64_ds32 __user *)uptr; - mm_segment_t old_fs; - - switch (second & ~IPC_64) { - case IPC_INFO: - case IPC_RMID: - case MSG_INFO: - err = sys_msgctl (first, second, (struct msqid_ds __user *)uptr); - break; - - case IPC_SET: - if (second & IPC_64) { - if (!access_ok(VERIFY_READ, up64, sizeof(*up64))) { - err = -EFAULT; - break; - } - err = __get_user(m.msg_perm.uid, &up64->msg_perm.uid); - err |= __get_user(m.msg_perm.gid, &up64->msg_perm.gid); - err |= __get_user(m.msg_perm.mode, &up64->msg_perm.mode); - err |= __get_user(m.msg_qbytes, &up64->msg_qbytes); - } else { - if (!access_ok(VERIFY_READ, up32, sizeof(*up32))) { - err = -EFAULT; - break; - } - err = __get_user(m.msg_perm.uid, &up32->msg_perm.uid); - err |= __get_user(m.msg_perm.gid, &up32->msg_perm.gid); - err |= __get_user(m.msg_perm.mode, &up32->msg_perm.mode); - err |= __get_user(m.msg_qbytes, &up32->msg_qbytes); - } - if (err) - break; - old_fs = get_fs(); - set_fs(KERNEL_DS); - err = sys_msgctl(first, second | IPC_64, (struct msqid_ds __user *)&m); - set_fs(old_fs); - break; - - case IPC_STAT: - case MSG_STAT: - old_fs = get_fs(); - set_fs(KERNEL_DS); - err = sys_msgctl(first, second | IPC_64, (struct msqid_ds __user *)&m); - set_fs(old_fs); - if (second & IPC_64) { - if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) { - err = -EFAULT; - break; - } - err2 = __put_user(m.msg_perm.key, &up64->msg_perm.key); - err2 |= __put_user(m.msg_perm.uid, &up64->msg_perm.uid); - err2 |= __put_user(m.msg_perm.gid, &up64->msg_perm.gid); - err2 |= __put_user(m.msg_perm.cuid, &up64->msg_perm.cuid); - err2 |= __put_user(m.msg_perm.cgid, &up64->msg_perm.cgid); - err2 |= __put_user(m.msg_perm.mode, &up64->msg_perm.mode); - err2 |= __put_user(m.msg_perm.seq, &up64->msg_perm.seq); - err2 |= __put_user(m.msg_stime, &up64->msg_stime); - err2 |= __put_user(m.msg_rtime, &up64->msg_rtime); - err2 |= __put_user(m.msg_ctime, &up64->msg_ctime); - err2 |= __put_user(m.msg_cbytes, &up64->msg_cbytes); - err2 |= __put_user(m.msg_qnum, &up64->msg_qnum); - err2 |= __put_user(m.msg_qbytes, &up64->msg_qbytes); - err2 |= __put_user(m.msg_lspid, &up64->msg_lspid); - err2 |= __put_user(m.msg_lrpid, &up64->msg_lrpid); - if (err2) - err = -EFAULT; - } else { - if (!access_ok(VERIFY_WRITE, up32, sizeof(*up32))) { - err = -EFAULT; - break; - } - err2 = __put_user(m.msg_perm.key, &up32->msg_perm.key); - err2 |= __put_user(m.msg_perm.uid, &up32->msg_perm.uid); - err2 |= __put_user(m.msg_perm.gid, &up32->msg_perm.gid); - err2 |= __put_user(m.msg_perm.cuid, &up32->msg_perm.cuid); - err2 |= __put_user(m.msg_perm.cgid, &up32->msg_perm.cgid); - err2 |= __put_user(m.msg_perm.mode, &up32->msg_perm.mode); - err2 |= __put_user(m.msg_perm.seq, &up32->msg_perm.seq); - err2 |= __put_user(m.msg_stime, &up32->msg_stime); - err2 |= __put_user(m.msg_rtime, &up32->msg_rtime); - err2 |= __put_user(m.msg_ctime, &up32->msg_ctime); - err2 |= __put_user(m.msg_cbytes, &up32->msg_cbytes); - err2 |= __put_user(m.msg_qnum, &up32->msg_qnum); - err2 |= __put_user(m.msg_qbytes, &up32->msg_qbytes); - err2 |= __put_user(m.msg_lspid, &up32->msg_lspid); - err2 |= __put_user(m.msg_lrpid, &up32->msg_lrpid); - if (err2) - err = -EFAULT; - } - break; - } - - return err; -} - -static int -do_sys32_shmat (int first, int second, int third, int version, void __user *uptr) -{ - unsigned long raddr; - u32 __user *uaddr = (u32 __user *)A((u32)third); - int err = -EINVAL; - - if (version == 1) - return err; - err = do_shmat (first, uptr, second, &raddr); - if (err) - return err; - err = put_user (raddr, uaddr); - return err; -} - -struct shm_info32 { - int used_ids; - u32 shm_tot, shm_rss, shm_swp; - u32 swap_attempts, swap_successes; -}; - -static int -do_sys32_shmctl (int first, int second, void __user *uptr) -{ - struct shmid64_ds32 __user *up64 = (struct shmid64_ds32 __user *)uptr; - struct shmid_ds32 __user *up32 = (struct shmid_ds32 __user *)uptr; - struct shm_info32 __user *uip = (struct shm_info32 __user *)uptr; - int err = -EFAULT, err2; - struct shmid64_ds s64; - mm_segment_t old_fs; - struct shm_info si; - struct shmid_ds s; - - switch (second & ~IPC_64) { - case IPC_INFO: - second = IPC_INFO; /* So that we don't have to translate it */ - case IPC_RMID: - case SHM_LOCK: - case SHM_UNLOCK: - err = sys_shmctl(first, second, (struct shmid_ds __user *)uptr); - break; - case IPC_SET: - if (second & IPC_64) { - err = get_user(s.shm_perm.uid, &up64->shm_perm.uid); - err |= get_user(s.shm_perm.gid, &up64->shm_perm.gid); - err |= get_user(s.shm_perm.mode, &up64->shm_perm.mode); - } else { - err = get_user(s.shm_perm.uid, &up32->shm_perm.uid); - err |= get_user(s.shm_perm.gid, &up32->shm_perm.gid); - err |= get_user(s.shm_perm.mode, &up32->shm_perm.mode); - } - if (err) - break; - old_fs = get_fs(); - set_fs(KERNEL_DS); - err = sys_shmctl(first, second & ~IPC_64, (struct shmid_ds __user *)&s); - set_fs(old_fs); - break; - - case IPC_STAT: - case SHM_STAT: - old_fs = get_fs(); - set_fs(KERNEL_DS); - err = sys_shmctl(first, second | IPC_64, (void __user *) &s64); - set_fs(old_fs); - if (err < 0) - break; - if (second & IPC_64) { - if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) { - err = -EFAULT; - break; - } - err2 = __put_user(s64.shm_perm.key, &up64->shm_perm.key); - err2 |= __put_user(s64.shm_perm.uid, &up64->shm_perm.uid); - err2 |= __put_user(s64.shm_perm.gid, &up64->shm_perm.gid); - err2 |= __put_user(s64.shm_perm.cuid, &up64->shm_perm.cuid); - err2 |= __put_user(s64.shm_perm.cgid, &up64->shm_perm.cgid); - err2 |= __put_user(s64.shm_perm.mode, &up64->shm_perm.mode); - err2 |= __put_user(s64.shm_perm.seq, &up64->shm_perm.seq); - err2 |= __put_user(s64.shm_atime, &up64->shm_atime); - err2 |= __put_user(s64.shm_dtime, &up64->shm_dtime); - err2 |= __put_user(s64.shm_ctime, &up64->shm_ctime); - err2 |= __put_user(s64.shm_segsz, &up64->shm_segsz); - err2 |= __put_user(s64.shm_nattch, &up64->shm_nattch); - err2 |= __put_user(s64.shm_cpid, &up64->shm_cpid); - err2 |= __put_user(s64.shm_lpid, &up64->shm_lpid); - } else { - if (!access_ok(VERIFY_WRITE, up32, sizeof(*up32))) { - err = -EFAULT; - break; - } - err2 = __put_user(s64.shm_perm.key, &up32->shm_perm.key); - err2 |= __put_user(s64.shm_perm.uid, &up32->shm_perm.uid); - err2 |= __put_user(s64.shm_perm.gid, &up32->shm_perm.gid); - err2 |= __put_user(s64.shm_perm.cuid, &up32->shm_perm.cuid); - err2 |= __put_user(s64.shm_perm.cgid, &up32->shm_perm.cgid); - err2 |= __put_user(s64.shm_perm.mode, &up32->shm_perm.mode); - err2 |= __put_user(s64.shm_perm.seq, &up32->shm_perm.seq); - err2 |= __put_user(s64.shm_atime, &up32->shm_atime); - err2 |= __put_user(s64.shm_dtime, &up32->shm_dtime); - err2 |= __put_user(s64.shm_ctime, &up32->shm_ctime); - err2 |= __put_user(s64.shm_segsz, &up32->shm_segsz); - err2 |= __put_user(s64.shm_nattch, &up32->shm_nattch); - err2 |= __put_user(s64.shm_cpid, &up32->shm_cpid); - err2 |= __put_user(s64.shm_lpid, &up32->shm_lpid); - } - if (err2) - err = -EFAULT; - break; - - case SHM_INFO: - old_fs = get_fs(); - set_fs(KERNEL_DS); - err = sys_shmctl(first, second, (void __user *)&si); - set_fs(old_fs); - if (err < 0) - break; - err2 = put_user(si.used_ids, &uip->used_ids); - err2 |= __put_user(si.shm_tot, &uip->shm_tot); - err2 |= __put_user(si.shm_rss, &uip->shm_rss); - err2 |= __put_user(si.shm_swp, &uip->shm_swp); - err2 |= __put_user(si.swap_attempts, &uip->swap_attempts); - err2 |= __put_user (si.swap_successes, &uip->swap_successes); - if (err2) - err = -EFAULT; - break; - - default: - err = -EINVAL; - break; - } - - return err; -} - -static int sys32_semtimedop(int semid, struct sembuf __user *tsems, int nsems, - const struct compat_timespec __user *timeout32) -{ - struct compat_timespec t32; - struct timespec __user *t64 = compat_alloc_user_space(sizeof(*t64)); - - if (copy_from_user(&t32, timeout32, sizeof(t32))) - return -EFAULT; - - if (put_user(t32.tv_sec, &t64->tv_sec) || - put_user(t32.tv_nsec, &t64->tv_nsec)) - return -EFAULT; - - return sys_semtimedop(semid, tsems, nsems, t64); -} - asmlinkage long sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth) { @@ -918,48 +393,43 @@ sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth) switch (call) { case SEMOP: /* struct sembuf is the same on 32 and 64bit :)) */ - err = sys_semtimedop (first, (struct sembuf __user *)AA(ptr), second, - NULL); + err = sys_semtimedop(first, compat_ptr(ptr), second, NULL); break; case SEMTIMEDOP: - err = sys32_semtimedop (first, (struct sembuf __user *)AA(ptr), second, - (const struct compat_timespec __user *)AA(fifth)); + err = compat_sys_semtimedop(first, compat_ptr(ptr), second, + compat_ptr(fifth)); break; case SEMGET: - err = sys_semget (first, second, third); + err = sys_semget(first, second, third); break; case SEMCTL: - err = do_sys32_semctl (first, second, third, - (void __user *)AA(ptr)); + err = compat_sys_semctl(first, second, third, compat_ptr(ptr)); break; - case MSGSND: - err = do_sys32_msgsnd (first, second, third, - (void __user *)AA(ptr)); + err = compat_sys_msgsnd(first, second, third, compat_ptr(ptr)); break; case MSGRCV: - err = do_sys32_msgrcv (first, second, fifth, third, - version, (void __user *)AA(ptr)); + err = compat_sys_msgrcv(first, second, fifth, third, + version, compat_ptr(ptr)); break; case MSGGET: - err = sys_msgget ((key_t) first, second); + err = sys_msgget((key_t) first, second); break; case MSGCTL: - err = do_sys32_msgctl (first, second, (void __user *)AA(ptr)); + err = compat_sys_msgctl(first, second, compat_ptr(ptr)); break; - case SHMAT: - err = do_sys32_shmat (first, second, third, - version, (void __user *)AA(ptr)); + err = compat_sys_shmat(first, second, third, version, + compat_ptr(ptr)); break; case SHMDT: - err = sys_shmdt ((char __user *)A(ptr)); + err = sys_shmdt(compat_ptr(ptr)); break; case SHMGET: - err = sys_shmget (first, (unsigned)second, third); + err = sys_shmget(first, (unsigned)second, third); break; case SHMCTL: - err = do_sys32_shmctl (first, second, (void __user *)AA(ptr)); + err = compat_sys_shmctl(first, second, compat_ptr(ptr)); break; default: err = -EINVAL; @@ -969,18 +439,16 @@ sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth) return err; } -asmlinkage long sys32_shmat(int shmid, char __user *shmaddr, - int shmflg, int32_t __user *addr) +#ifdef CONFIG_MIPS32_N32 +asmlinkage long sysn32_semctl(int semid, int semnum, int cmd, union semun arg) { - unsigned long raddr; - int err; - - err = do_shmat(shmid, shmaddr, shmflg, &raddr); - if (err) - return err; - - return put_user(raddr, addr); + /* compat_sys_semctl expects a pointer to union semun */ + u32 __user *uptr = compat_alloc_user_space(sizeof(u32)); + if (put_user(ptr_to_compat(arg.__pad), uptr)) + return -EFAULT; + return compat_sys_semctl(semid, semnum, cmd, uptr); } +#endif struct sysctl_args32 { |