From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from oss.sgi.com (localhost [127.0.0.1]) by oss.sgi.com (8.12.5/8.12.5) with ESMTP id g7D3h8Rw013521 for ; Mon, 12 Aug 2002 20:43:08 -0700 Received: (from majordomo@localhost) by oss.sgi.com (8.12.5/8.12.3/Submit) id g7D3h8e4013520 for linux-mips-outgoing; Mon, 12 Aug 2002 20:43:08 -0700 X-Authentication-Warning: oss.sgi.com: majordomo set sender to owner-linux-mips@oss.sgi.com using -f Received: from sgi.com (sgi-too.SGI.COM [204.94.211.39]) by oss.sgi.com (8.12.5/8.12.5) with SMTP id g7D3gPRw013508 for ; Mon, 12 Aug 2002 20:42:25 -0700 Received: from dea.linux-mips.net (c-180-196-67.ka.dial.de.ignite.net [62.180.196.67]) by sgi.com (980327.SGI.8.8.8-aspam/980304.SGI-aspam: SGI does not authorize the use of its proprietary systems or networks for unsolicited or bulk email from the Internet.) via ESMTP id UAA09587 for ; Mon, 12 Aug 2002 20:45:24 -0700 (PDT) mail_from (ralf@linux-mips.org) Received: (from ralf@localhost) by dea.linux-mips.net (8.11.6/8.11.6) id g7D3NOe22453; Tue, 13 Aug 2002 05:23:24 +0200 Date: Tue, 13 Aug 2002 05:23:24 +0200 From: Ralf Baechle To: Carsten Langgaard Cc: "Maciej W. Rozycki" , linux-mips@oss.sgi.com Subject: Re: IPC syscall fixup (o32 conversion layer) Message-ID: <20020813052324.A22438@linux-mips.org> References: <3D5131C7.17F9E00@mips.com> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.2.5.1i In-Reply-To: <3D5131C7.17F9E00@mips.com>; from carstenl@mips.com on Wed, Aug 07, 2002 at 04:42:15PM +0200 X-Spam-Status: No, hits=-4.4 required=5.0 tests=IN_REP_TO version=2.20 X-Spam-Level: Sender: owner-linux-mips@oss.sgi.com Precedence: bulk Carsten, On Wed, Aug 07, 2002 at 04:42:15PM +0200, Carsten Langgaard wrote: > Here is a patch that fixes the ipc syscalls in the o32 > wrapper/conversion routines. > Needed when running a 64-bit kernel on an o32 userland. before I finally apply this one, can you do me a favour and check your code is still working correctly even after I applied yesterdays fix which changes struct msqid64_id to eleminate the mismatch of the kernel and libc definitions? Thanks, Ralf > Index: arch/mips64/kernel/linux32.c > =================================================================== > RCS file: /cvs/linux/arch/mips64/kernel/linux32.c,v > retrieving revision 1.42.2.9 > diff -u -r1.42.2.9 linux32.c > --- arch/mips64/kernel/linux32.c 2002/07/23 12:26:09 1.42.2.9 > +++ arch/mips64/kernel/linux32.c 2002/08/07 14:28:03 > @@ -35,8 +35,16 @@ > #include > #include > > - > +/* Use this to get at 32-bit user passed pointers. */ > +/* A() macro should be used for places where you e.g. > + have some internal variable u32 and just want to get > + rid of a compiler warning. AA() has to be used in > + places where you want to convert a function argument > + to 32bit pointer or when you e.g. access pt_regs > + structure and want to consider 32bit registers only. > + */ > #define A(__x) ((unsigned long)(__x)) > +#define AA(__x) ((unsigned long)((int)__x)) > > #ifdef __MIPSEB__ > #define merge_64(r1,r2) ((((r1) & 0xffffffffUL) << 32) + ((r2) & 0xffffffffUL)) > @@ -1494,6 +1502,19 @@ > unsigned short seq; > }; > > +struct ipc64_perm32 { > + key_t key; > + __kernel_uid_t32 uid; > + __kernel_gid_t32 gid; > + __kernel_uid_t32 cuid; > + __kernel_gid_t32 cgid; > + __kernel_mode_t32 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 */ > __kernel_time_t32 sem_otime; /* last semop time */ > @@ -1522,6 +1543,23 @@ > __kernel_ipc_pid_t32 msg_lrpid; > }; > > +struct msqid64_ds32 { > + struct ipc64_perm32 msg_perm; > + __kernel_time_t32 msg_stime; > + unsigned int __unused1; > + __kernel_time_t32 msg_rtime; > + unsigned int __unused2; > + __kernel_time_t32 msg_ctime; > + unsigned int __unused3; > + unsigned int msg_cbytes; > + unsigned int msg_qnum; > + unsigned int msg_qbytes; > + __kernel_pid_t32 msg_lspid; > + __kernel_pid_t32 msg_lrpid; > + unsigned int __unused4; > + unsigned int __unused5; > +}; > + > struct shmid_ds32 { > struct ipc_perm32 shm_perm; > int shm_segsz; > @@ -1533,9 +1571,25 @@ > unsigned short shm_nattch; > }; > > +struct ipc_kludge32 { > + u32 msgp; > + s32 msgtyp; > +}; > + > #define IPCOP_MASK(__x) (1UL << (__x)) > > static int > +ipc_parse_version32(int *cmd) > +{ > + if (*cmd & IPC_64) { > + *cmd ^= IPC_64; > + return IPC_64; > + } else { > + return IPC_OLD; > + } > +} > + > +static int > do_sys32_semctl(int first, int second, int third, void *uptr) > { > union semun fourth; > @@ -1603,12 +1657,15 @@ > static int > do_sys32_msgsnd (int first, int second, int third, void *uptr) > { > - struct msgbuf *p = kmalloc (second + sizeof (struct msgbuf) > - + 4, GFP_USER); > struct msgbuf32 *up = (struct msgbuf32 *)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); > @@ -1636,18 +1693,21 @@ > int err; > > if (!version) { > - struct ipc_kludge *uipck = (struct ipc_kludge *)uptr; > - struct ipc_kludge ipck; > + struct ipc_kludge32 *uipck = (struct ipc_kludge32 *)uptr; > + struct ipc_kludge32 ipck; > > err = -EINVAL; > if (!uptr) > goto out; > err = -EFAULT; > - if (copy_from_user (&ipck, uipck, sizeof (struct ipc_kludge))) > + if (copy_from_user (&ipck, uipck, sizeof (struct ipc_kludge32))) > goto out; > - uptr = (void *)A(ipck.msgp); > + uptr = (void *)AA(ipck.msgp); > msgtyp = ipck.msgtyp; > } > + > + if (second < 0) > + return -EINVAL; > err = -ENOMEM; > p = kmalloc (second + sizeof (struct msgbuf) + 4, GFP_USER); > if (!p) > @@ -1673,9 +1733,10 @@ > { > int err = -EINVAL, err2; > struct msqid_ds m; > - struct msqid64_ds m64; > - struct msqid_ds32 *up = (struct msqid_ds32 *)uptr; > + struct msqid_ds32 *up32 = (struct msqid_ds32 *)uptr; > + struct msqid64_ds32 *up64 = (struct msqid64_ds32 *)uptr; > mm_segment_t old_fs; > + int version = ipc_parse_version32(&second); > > switch (second) { > > @@ -1686,10 +1747,25 @@ > break; > > case IPC_SET: > - err = get_user (m.msg_perm.uid, &up->msg_perm.uid); > - err |= __get_user (m.msg_perm.gid, &up->msg_perm.gid); > - err |= __get_user (m.msg_perm.mode, &up->msg_perm.mode); > - err |= __get_user (m.msg_qbytes, &up->msg_qbytes); > + if (version == 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 (); > @@ -1702,27 +1778,54 @@ > case MSG_STAT: > old_fs = get_fs (); > set_fs (KERNEL_DS); > - err = sys_msgctl (first, second, (void *) &m64); > + err = sys_msgctl (first, second, &m); > set_fs (old_fs); > - err2 = put_user (m64.msg_perm.key, &up->msg_perm.key); > - err2 |= __put_user(m64.msg_perm.uid, &up->msg_perm.uid); > - err2 |= __put_user(m64.msg_perm.gid, &up->msg_perm.gid); > - err2 |= __put_user(m64.msg_perm.cuid, &up->msg_perm.cuid); > - err2 |= __put_user(m64.msg_perm.cgid, &up->msg_perm.cgid); > - err2 |= __put_user(m64.msg_perm.mode, &up->msg_perm.mode); > - err2 |= __put_user(m64.msg_perm.seq, &up->msg_perm.seq); > - err2 |= __put_user(m64.msg_stime, &up->msg_stime); > - err2 |= __put_user(m64.msg_rtime, &up->msg_rtime); > - err2 |= __put_user(m64.msg_ctime, &up->msg_ctime); > - err2 |= __put_user(m64.msg_cbytes, &up->msg_cbytes); > - err2 |= __put_user(m64.msg_qnum, &up->msg_qnum); > - err2 |= __put_user(m64.msg_qbytes, &up->msg_qbytes); > - err2 |= __put_user(m64.msg_lspid, &up->msg_lspid); > - err2 |= __put_user(m64.msg_lrpid, &up->msg_lrpid); > - if (err2) > - err = -EFAULT; > + if (version == 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; > @@ -1845,7 +1948,7 @@ > > case SEMOP: > /* struct sembuf is the same on 32 and 64bit :)) */ > - err = sys_semop (first, (struct sembuf *)A(ptr), > + err = sys_semop (first, (struct sembuf *)AA(ptr), > second); > break; > case SEMGET: > @@ -1853,36 +1956,36 @@ > break; > case SEMCTL: > err = do_sys32_semctl (first, second, third, > - (void *)A(ptr)); > + (void *)AA(ptr)); > break; > > case MSGSND: > err = do_sys32_msgsnd (first, second, third, > - (void *)A(ptr)); > + (void *)AA(ptr)); > break; > case MSGRCV: > err = do_sys32_msgrcv (first, second, fifth, third, > - version, (void *)A(ptr)); > + version, (void *)AA(ptr)); > break; > case MSGGET: > err = sys_msgget ((key_t) first, second); > break; > case MSGCTL: > - err = do_sys32_msgctl (first, second, (void *)A(ptr)); > + err = do_sys32_msgctl (first, second, (void *)AA(ptr)); > break; > > case SHMAT: > err = do_sys32_shmat (first, second, third, > - version, (void *)A(ptr)); > + version, (void *)AA(ptr)); > break; > case SHMDT: > - err = sys_shmdt ((char *)A(ptr)); > + err = sys_shmdt ((char *)AA(ptr)); > break; > case SHMGET: > err = sys_shmget (first, second, third); > break; > case SHMCTL: > - err = do_sys32_shmctl (first, second, (void *)A(ptr)); > + err = do_sys32_shmctl (first, second, (void *)AA(ptr)); > break; > default: > err = -EINVAL;