64-bit kernel patch.
I have a number of patches for the o32 syscall wrapper/conversion routines, which is needed when running a 64-bit kernel on an o32 userland.
Here is the first one. Ralf, could you please apply it, so I can send the next one.
/Carsten
--
_ _ ____ ___ Carsten Langgaard Mailto:[email protected] |\ /|||___)(___ MIPS Denmark Direct: +45 4486 5527 | \/ ||| ____) Lautrupvang 4B Switch: +45 4486 5555 TECHNOLOGIES 2750 Ballerup Fax...: +45 4486 5556 Denmark http://www.mips.com
Index: arch/mips64/kernel/linux32.c
===================================================================
RCS file: /home/cvs/linux/arch/mips64/kernel/linux32.c,v retrieving revision 1.42.2.12
mips64/kernel/linux32.c +26 -1
@@ -179,7 +179,32 @@return err; } -asmlinkage int sys_mmap2(void) {return 0;} +asmlinkage unsigned long +sys32_mmap2 (unsigned long addr,size_t len,unsigned long prot, +unsigned long flags,unsigned long fd,unsigned long pgoff) +{ +struct file * file =NULL ; +unsigned long error; + + error = -EINVAL ; +if (!(flags &MAP_ANONYMOUS )) { + error = -EBADF ; + file =fget (fd); +if (!file) + goto out; + } + flags &= ~(MAP_EXECUTABLE |MAP_DENYWRITE ); + +down_write (¤t->mm->mmap_sem); + error =do_mmap_pgoff (file, addr, len, prot, flags, pgoff); +up_write (¤t->mm->mmap_sem); +if (file) +fput (file); + +out: +return error; +} +asmlinkage long sys_truncate (const char * path,unsigned long length);
Index: arch/mips64/kernel/scall_o32.S
===================================================================
RCS file: /home/cvs/linux/arch/mips64/kernel/scall_o32.S,v retrieving revision 1.48.2.15
mips64/kernel/scall_o32.S +1 -1
@@ -522,7 +522,7 @@ sys sys_sendfile 4 sys sys_ni_syscall 0 sys sys_ni_syscall 0 - sys sys_mmap2 6 /* 4210 */ + sys sys32_mmap2 6 /* 4210 */ sys sys_truncate64 2 sys sys_ftruncate64 2 sys sys_newstat 2
Quoted 5 lines · Carsten Langgaard
I have a number of patches for the o32 syscall wrapper/conversion routines, which is needed when running a 64-bit kernel on an o32 userland.
Here is the first one. Ralf, could you please apply it, so I can send the next one.
Do you have a fix for sys32_sendmsg/sys32_recvmsg as well? I just
started working on it and I'd prefer not to do a duplicate work.
As a side note -- arch/mips64/kernel/linux32.c is a huge collection of
often unrelated functions. It might be beneficial to split the file functionally, e.g. into fs32.c, net32.c, etc. or even with a finer grain, preferably in a subdirectory, e.g. arch/mips64/linux32/. What do you think?
Signature · 3 lines
+ Maciej W. Rozycki, Technical University of Gdansk, Poland + +--------------------------------------------------------------+ + e-mail: [email protected], PGP key available +
Quoted 10 lines · Maciej W. Rozycki
Quoted 5 lines · Carsten Langgaard
I have a number of patches for the o32 syscall wrapper/conversion routines, which is needed when running a 64-bit kernel on an o32 userland.
Here is the first one. Ralf, could you please apply it, so I can send the next one.Do you have a fix for sys32_sendmsg/sys32_recvmsg as well? I just
started working on it and I'd prefer not to do a duplicate work.
Yes, that's exactly the next one, I will be sending. So stay tuned.
Quoted 6 lines
As a side note --
arch/mips64/kernel/linux32.cis a huge collection of
often unrelated functions. It might be beneficial to split the file functionally, e.g. intofs32.c,net32.c, etc. or even with a finer grain, preferably in a subdirectory, e.g.arch/mips64/linux32/. What do you think?
That's probably a good idea, but I would like to get my patches out first, before splitting things up.
Review
Quoted 6 lines
--
(quoted diff) +3
-0+ Maciej W. Rozycki, Technical University of Gdansk, Poland + +--------------------------------------------------------------+ + e-mail: [email protected], PGP key available +
--
_ _ ____ ___ Carsten Langgaard Mailto:[email protected] |\ /|||___)(___ MIPS Denmark Direct: +45 4486 5527 | \/ ||| ____) Lautrupvang 4B Switch: +45 4486 5555 TECHNOLOGIES 2750 Ballerup Fax...: +45 4486 5556 Denmark http://www.mips.com
Quoted 5 lines · Maciej W. Rozycki
As a side note --
arch/mips64/kernel/linux32.cis a huge collection of
often unrelated functions. It might be beneficial to split the file functionally, e.g. intofs32.c,net32.c, etc. or even with a finer grain, preferably in a subdirectory, e.g.arch/mips64/linux32/. What do you think?
Much of the code is so generic it almost deserves to live in a directory even higher in the hierarchy. If you look at the 32-bit compat code for the various 64-bit architectures of Linux (in particular sparc64 and ia64), it's a single huge cut'n'paste session. Not much of that code is actually architecture dependant.
Ralf
Quoted 8 lines · Ralf Baechle
Quoted 5 lines · Maciej W. Rozycki
As a side note --
arch/mips64/kernel/linux32.cis a huge collection of
often unrelated functions. It might be beneficial to split the file functionally, e.g. intofs32.c,net32.c, etc. or even with a finer grain, preferably in a subdirectory, e.g.arch/mips64/linux32/. What do you think?
Quoted 5 lines
Much of the code is so generic it almost deserves to live in a directory even higher in the hierarchy. If you look at the 32-bit compat code for the various 64-bit architectures of Linux (in particular sparc64 and ia64), it's a single huge cut'n'paste session. Not much of that code is actually architecture dependant.
That would be even better, but unfortunately a lot of the structures used in the compat code is not exactly the same across architectures :-( But it should be possible to merges a lot this stuff into a generic (architecture independent) set of functions.
Quoted 2 lines
Ralf
--
_ _ ____ ___ Carsten Langgaard Mailto:[email protected] |\ /|||___)(___ MIPS Denmark Direct: +45 4486 5527 | \/ ||| ____) Lautrupvang 4B Switch: +45 4486 5555 TECHNOLOGIES 2750 Ballerup Fax...: +45 4486 5556 Denmark http://www.mips.com
Quoted 10 lines · Carsten Langgaard
Quoted 5 lines
Much of the code is so generic it almost deserves to live in a directory even higher in the hierarchy. If you look at the 32-bit compat code for the various 64-bit architectures of Linux (in particular sparc64 and ia64), it's a single huge cut'n'paste session. Not much of that code is actually architecture dependant.
That would be even better, but unfortunately a lot of the structures used in the compat code is not exactly the same across architectures :-( But it should be possible to merges a lot this stuff into a generic (architecture independent) set of functions.
True. The basic plan would be to provide the structure definitions and some architecture dependencies from headers and keep the generic compat code in a linux-32 directory.
The syscalls are still fairly harmless - the true pain are all the ioctls that keep growing and changing like weed ...
Ralf
Ok, here is the next patch.
It fixes the sys32_sendmsg and sys32_recvmsg.
/Carsten
Quoted 18 lines · Maciej W. Rozycki
Quoted 5 lines · Carsten Langgaard
I have a number of patches for the o32 syscall wrapper/conversion routines, which is needed when running a 64-bit kernel on an o32 userland.
Here is the first one. Ralf, could you please apply it, so I can send the next one.Do you have a fix for sys32_sendmsg/sys32_recvmsg as well? I just
started working on it and I'd prefer not to do a duplicate work.As a side note --
arch/mips64/kernel/linux32.cis a huge collection of
often unrelated functions. It might be beneficial to split the file functionally, e.g. intofs32.c,net32.c, etc. or even with a finer grain, preferably in a subdirectory, e.g.arch/mips64/linux32/. What do you think?--
Review
Quoted 3 lines
(quoted diff) +3
-0+ Maciej W. Rozycki, Technical University of Gdansk, Poland + +--------------------------------------------------------------+ + e-mail: [email protected], PGP key available +
--
_ _ ____ ___ Carsten Langgaard Mailto:[email protected] |\ /|||___)(___ MIPS Denmark Direct: +45 4486 5527 | \/ ||| ____) Lautrupvang 4B Switch: +45 4486 5555 TECHNOLOGIES 2750 Ballerup Fax...: +45 4486 5556 Denmark http://www.mips.com
Index: arch/mips64/kernel/linux32.c
===================================================================
RCS file: /home/cvs/linux/arch/mips64/kernel/linux32.c,v retrieving revision 1.42.2.13
mips64/kernel/linux32.c +456 -188
@@ -32,6 +32,7 @@#include <linux/dnotify.h> #include <linux/module.h> #include <net/sock.h> +#include <net/scm.h> #include <asm/uaccess.h> #include <asm/mman.h>
@@ -1712,6 +1713,7 @@return err; } +static int do_sys32_msgsnd (int first,int second,int third,void *uptr) {struct msgbuf32 *up = (struct msgbuf32 *)uptr;
@@ -2244,7 +2246,7 @@/* * Declare the 32-bit version of the msghdr */ - +struct msghdr32 {unsigned int msg_name;/* Socket name */ int msg_namelen;/* Length of name */
@@ -2255,74 +2257,132 @@unsigned msg_flags; }; -static inline int -shape_msg (struct msghdr *mp,struct msghdr32 *mp32) +struct cmsghdr32 { +__kernel_size_t32 cmsg_len; +int cmsg_level; +int cmsg_type; +}; + +/* Bleech... */ +#define __CMSG32_NXTHDR (ctl, len, cmsg, cmsglen) __cmsg32_nxthdr((ctl),(len),(cmsg),(cmsglen)) +#define CMSG32_NXTHDR (mhdr, cmsg, cmsglen) cmsg32_nxthdr((mhdr), (cmsg), (cmsglen)) + +#define CMSG32_ALIGN (len) ( ((len)+sizeof(int)-1) & ~(sizeof(int)-1) ) + +#define CMSG32_DATA (cmsg) ((void *)((char *)(cmsg) + CMSG32_ALIGN(sizeof(struct cmsghdr32)))) +#define CMSG32_SPACE (len) (CMSG32_ALIGN(sizeof(struct cmsghdr32)) + CMSG32_ALIGN(len)) +#define CMSG32_LEN (len) (CMSG32_ALIGN(sizeof(struct cmsghdr32)) + (len)) + +#define __CMSG32_FIRSTHDR (ctl,len) ((len) >= sizeof(struct cmsghdr32) ? \ + (struct cmsghdr32 *)(ctl) : \ + (struct cmsghdr32 *)NULL) +#define CMSG32_FIRSTHDR (msg) __CMSG32_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen) + +__inline__struct cmsghdr32 *__cmsg32_nxthdr (void *__ctl,__kernel_size_t __size, +struct cmsghdr32 *__cmsg,int __cmsg_len) { -int ret; -unsigned int i; +struct cmsghdr32 * __ptr; -if (!access_ok (VERIFY_READ , mp32,sizeof (*mp32))) -return (-EFAULT ); - ret =__get_user (i, &mp32->msg_name); - mp->msg_name = (void *)A (i); - ret |=__get_user (mp->msg_namelen, &mp32->msg_namelen); - ret |=__get_user (i, &mp32->msg_iov); - mp->msg_iov = (struct iovec *)A (i); - ret |=__get_user (mp->msg_iovlen, &mp32->msg_iovlen); - ret |=__get_user (i, &mp32->msg_control); - mp->msg_control = (void *)A (i); - ret |=__get_user (mp->msg_controllen, &mp32->msg_controllen); - ret |=__get_user (mp->msg_flags, &mp32->msg_flags); -return (ret ? -EFAULT :0 ); + __ptr = (struct cmsghdr32 *)(((unsigned char *) __cmsg) + +CMSG32_ALIGN (__cmsg_len)); +if ((unsigned long )((char *)(__ptr+1 ) - (char *) __ctl) > __size) +return NULL ; + +return __ptr; } -/* -* Verify & re-shape IA32 iovec. The caller must ensure that the -* iovec is big enough to hold the re-shaped message iovec. -* -* Save time not doing verify_area. copy_*_user will make this work -* in any case. -* -* Don't need to check the total size for overflow (cf net/core/iovec.c), -* 32-bit sizes can't overflow a 64-bit count. -*/ +__inline__struct cmsghdr32 *cmsg32_nxthdr (struct msghdr *__msg, +struct cmsghdr32 *__cmsg, +int __cmsg_len) +{ +return __cmsg32_nxthdr (__msg->msg_control, __msg->msg_controllen, + __cmsg, __cmsg_len); +} -static inline int -verify_iovec32 (struct msghdr *m,struct iovec *iov,char *address,int mode) +static inline int iov_from_user32_to_kern (struct iovec *kiov, +struct iovec32 *uiov32, +int niov) { -int size, err, ct; -struct iovec32 *iov32; +int tot_len =0 ; -if (m->msg_namelen) - { -if (mode==VERIFY_READ ) - { - err=move_addr_to_kernel (m->msg_name, m->msg_namelen, address); -if (err<0 ) - goto out; +while (niov >0 ) { +u32 len, buf; + +if (get_user (len, &uiov32->iov_len) || +get_user (buf, &uiov32->iov_base)) { + tot_len = -EFAULT ; +break ; } + tot_len += len; + kiov->iov_base = (void *)AA (buf); + kiov->iov_len = (__kernel_size_t ) len; + uiov32++; + kiov++; + niov--; + } +return tot_len; +} - m->msg_name = address; - }else - m->msg_name =NULL ; +static inline int msghdr_from_user32_to_kern (struct msghdr *kmsg, +struct msghdr32 *umsg) +{ +u32 tmp1, tmp2, tmp3; +int err; - err = -EFAULT ; - size = m->msg_iovlen *sizeof (struct iovec32 ); -if (copy_from_user (iov, m->msg_iov, size)) - goto out; - m->msg_iov=iov; + err =get_user (tmp1, &umsg->msg_name); + err |=__get_user (tmp2, &umsg->msg_iov); + err |=__get_user (tmp3, &umsg->msg_control); +if (err) +return -EFAULT ; - err =0 ; - iov32 = (struct iovec32 *)iov; -for (ct = m->msg_iovlen; ct-- >0 ; ) { - iov[ct].iov_len = (__kernel_size_t )iov32[ct].iov_len; - iov[ct].iov_base = (void *)A (iov32[ct].iov_base); - err += iov[ct].iov_len; - } -out: + kmsg->msg_name = (void *)AA (tmp1); + kmsg->msg_iov = (struct iovec *)AA (tmp2); + kmsg->msg_control = (void *)AA (tmp3); + + err =get_user (kmsg->msg_namelen, &umsg->msg_namelen); + err |=get_user (kmsg->msg_iovlen, &umsg->msg_iovlen); + err |=get_user (kmsg->msg_controllen, &umsg->msg_controllen); + err |=get_user (kmsg->msg_flags, &umsg->msg_flags); +return err; } +/* I've named the args so it is easy to tell whose space the pointers are in. */ +static int verify_iovec32 (struct msghdr *kern_msg,struct iovec *kern_iov, +char *kern_address,int mode) +{ +int tot_len; + +if (kern_msg->msg_namelen) { +if (mode==VERIFY_READ ) { +int err =move_addr_to_kernel (kern_msg->msg_name, + kern_msg->msg_namelen, + kern_address); +if (err <0 ) +return err; + } + kern_msg->msg_name = kern_address; + }else + kern_msg->msg_name =NULL ; + +if (kern_msg->msg_iovlen >UIO_FASTIOV ) { + kern_iov =kmalloc (kern_msg->msg_iovlen *sizeof (struct iovec ), +GFP_KERNEL ); +if (!kern_iov) +return -ENOMEM ; + } + + tot_len =iov_from_user32_to_kern (kern_iov, + (struct iovec32 *)kern_msg->msg_iov, + kern_msg->msg_iovlen); +if (tot_len >=0 ) + kern_msg->msg_iov = kern_iov; +else if (kern_msg->msg_iovlen >UIO_FASTIOV ) +kfree (kern_iov); + +return tot_len; +} +extern __inline__void sockfd_put (struct socket *sock) {
@@ -2330,177 +2390,385 @@ }/* XXX This really belongs in some header file... -DaveM */ -#define MAX_SOCK_ADDR 128/* 108 for Unix domain - +#define MAX_SOCK_ADDR 128/* 108 for Unix domain - 16 for IP, 16 for IPX, 24 for IPv6, about 80 for AX.25 */ extern struct socket *sockfd_lookup (int fd,int *err); -/* -* BSD sendmsg interface +/* There is a lot of hair here because the alignment rules (and +* thus placement) of cmsg headers and length are different for +* 32-bit apps. -DaveM */ - -int sys32_sendmsg (int fd,struct msghdr32 *msg,unsigned flags) +static int cmsghdr_from_user32_to_kern (struct msghdr *kmsg, +unsigned char *stackbuf,int stackbuf_size) { -struct socket *sock; -char address[MAX_SOCK_ADDR ]; -struct iovec iovstack[UIO_FASTIOV ], *iov = iovstack; -unsigned char ctl[sizeof (struct cmsghdr ) +20 ];/* 20 is size of ipv6_pktinfo */ -unsigned char *ctl_buf = ctl; -struct msghdr msg_sys; -int err, ctl_len, iov_size, total_len; +struct cmsghdr32 *ucmsg; +struct cmsghdr *kcmsg, *kcmsg_base; +__kernel_size_t32 ucmlen; +__kernel_size_t kcmlen, tmp; + + kcmlen =0 ; + kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf; + ucmsg =CMSG32_FIRSTHDR (kmsg); +while (ucmsg !=NULL ) { +if (get_user (ucmlen, &ucmsg->cmsg_len)) +return -EFAULT ; - err = -EFAULT ; -if (shape_msg (&msg_sys, msg)) - goto out; +/* Catch bogons. */ +if (CMSG32_ALIGN (ucmlen) < +CMSG32_ALIGN (sizeof (struct cmsghdr32 ))) +return -ENOBUFS ; +if ((unsigned long )(((char *)ucmsg - (char *)kmsg->msg_control) + + ucmlen) > kmsg->msg_controllen) +return -EINVAL ; + + tmp = ((ucmlen -CMSG32_ALIGN (sizeof (*ucmsg))) + +CMSG_ALIGN (sizeof (struct cmsghdr ))); + kcmlen += tmp; + ucmsg =CMSG32_NXTHDR (kmsg, ucmsg, ucmlen); + } +if (kcmlen ==0 ) +return -EINVAL ; - sock =sockfd_lookup (fd, &err); -if (!sock) - goto out; +/* The kcmlen holds the 64-bit version of the control length. +* It may not be modified as we do not stick it into the kmsg +* until we have successfully copied over all of the data +* from the user. +*/ +if (kcmlen > stackbuf_size) + kcmsg_base = kcmsg =kmalloc (kcmlen,GFP_KERNEL ); +if (kcmsg ==NULL ) +return -ENOBUFS ; + +/* Now copy them over neatly. */ +memset (kcmsg,0 , kcmlen); + ucmsg =CMSG32_FIRSTHDR (kmsg); +while (ucmsg !=NULL ) { +__get_user (ucmlen, &ucmsg->cmsg_len); + tmp = ((ucmlen -CMSG32_ALIGN (sizeof (*ucmsg))) + +CMSG_ALIGN (sizeof (struct cmsghdr ))); + kcmsg->cmsg_len = tmp; +__get_user (kcmsg->cmsg_level, &ucmsg->cmsg_level); +__get_user (kcmsg->cmsg_type, &ucmsg->cmsg_type); + +/* Copy over the data. */ +if (copy_from_user (CMSG_DATA (kcmsg), +CMSG32_DATA (ucmsg), + (ucmlen -CMSG32_ALIGN (sizeof (*ucmsg))))) + goto out_free_efault; + +/* Advance. */ + kcmsg = (struct cmsghdr *)((char *)kcmsg +CMSG_ALIGN (tmp)); + ucmsg =CMSG32_NXTHDR (kmsg, ucmsg, ucmlen); + } + +/* Ok, looks like we made it. Hook it up and return success. */ + kmsg->msg_control = kcmsg_base; + kmsg->msg_controllen = kcmlen; +return 0 ; -/* do not move before msg_sys is valid */ - err = -EINVAL ; -if (msg_sys.msg_iovlen >UIO_MAXIOV ) - goto out_put; +out_free_efault: +if (kcmsg_base != (struct cmsghdr *)stackbuf) +kfree (kcmsg_base); +return -EFAULT ; +} -/* Check whether to allocate the iovec area*/ - err = -ENOMEM ; - iov_size = msg_sys.msg_iovlen *sizeof (struct iovec32 ); -if (msg_sys.msg_iovlen >UIO_FASTIOV ) { - iov =sock_kmalloc (sock->sk, iov_size,GFP_KERNEL ); -if (!iov) - goto out_put; +static void put_cmsg32 (struct msghdr *kmsg,int level,int type, +int len,void *data) +{ +struct cmsghdr32 *cm = (struct cmsghdr32 *) kmsg->msg_control; +struct cmsghdr32 cmhdr; +int cmlen =CMSG32_LEN (len); + +if (cm ==NULL || kmsg->msg_controllen <sizeof (*cm)) { + kmsg->msg_flags |=MSG_CTRUNC ; +return ; } -/* This will also move the address data into kernel space */ - err =verify_iovec32 (&msg_sys, iov, address,VERIFY_READ ); -if (err <0 ) - goto out_freeiov; - total_len = err; +if (kmsg->msg_controllen < cmlen) { + kmsg->msg_flags |=MSG_CTRUNC ; + cmlen = kmsg->msg_controllen; + } + cmhdr.cmsg_level = level; + cmhdr.cmsg_type = type; + cmhdr.cmsg_len = cmlen; - err = -ENOBUFS ; +if (copy_to_user (cm, &cmhdr,sizeof cmhdr)) +return ; +if (copy_to_user (CMSG32_DATA (cm), data, cmlen -sizeof (struct cmsghdr32 ))) +return ; + cmlen =CMSG32_SPACE (len); + kmsg->msg_control += cmlen; + kmsg->msg_controllen -= cmlen; +} + +static void scm_detach_fds32 (struct msghdr *kmsg,struct scm_cookie *scm) +{ +struct cmsghdr32 *cm = (struct cmsghdr32 *) kmsg->msg_control; +int fdmax = (kmsg->msg_controllen -sizeof (struct cmsghdr32 )) /sizeof (int ); +int fdnum = scm->fp->count; +struct file **fp = scm->fp->fp; +int *cmfptr; +int err =0 , i; + +if (fdnum < fdmax) + fdmax = fdnum; + +for (i =0 , cmfptr = (int *)CMSG32_DATA (cm); i < fdmax; i++, cmfptr++) { +int new_fd; + err =get_unused_fd (); +if (err <0 ) +break ; + new_fd = err; + err =put_user (new_fd, cmfptr); +if (err) { +put_unused_fd (new_fd); +break ; + } +/* Bump the usage count and install the file. */ +get_file (fp[i]); +fd_install (new_fd, fp[i]); + } -if (msg_sys.msg_controllen >INT_MAX ) - goto out_freeiov; - ctl_len = msg_sys.msg_controllen; -if (ctl_len) - { -if (ctl_len >sizeof (ctl)) - { - err = -ENOBUFS ; - ctl_buf =sock_kmalloc (sock->sk, ctl_len,GFP_KERNEL ); -if (ctl_buf ==NULL ) - goto out_freeiov; +if (i >0 ) { +int cmlen =CMSG32_LEN (i *sizeof (int )); +if (!err) + err =put_user (SOL_SOCKET , &cm->cmsg_level); +if (!err) + err =put_user (SCM_RIGHTS , &cm->cmsg_type); +if (!err) + err =put_user (cmlen, &cm->cmsg_len); +if (!err) { + cmlen =CMSG32_SPACE (i *sizeof (int )); + kmsg->msg_control += cmlen; + kmsg->msg_controllen -= cmlen; } - err = -EFAULT ; -if (copy_from_user (ctl_buf, msg_sys.msg_control, ctl_len)) - goto out_freectl; - msg_sys.msg_control = ctl_buf; - } - msg_sys.msg_flags = flags; - -if (sock->file->f_flags &O_NONBLOCK ) - msg_sys.msg_flags |=MSG_DONTWAIT ; - err =sock_sendmsg (sock, &msg_sys, total_len); - -out_freectl: -if (ctl_buf != ctl) -sock_kfree_s (sock->sk, ctl_buf, ctl_len); -out_freeiov: -if (iov != iovstack) -sock_kfree_s (sock->sk, iov, iov_size); -out_put: -sockfd_put (sock); -out: -return err; + } +if (i < fdnum) + kmsg->msg_flags |=MSG_CTRUNC ; + +/* +* All of the files that fit in the message have had their +* usage counts incremented, so we just free the list. +*/ +__scm_destroy (scm); } -/* -* BSD recvmsg interface +/* In these cases we (currently) can just copy to data over verbatim +* because all CMSGs created by the kernel have well defined types which +* have the same layout in both the 32-bit and 64-bit API. One must add +* some special cased conversions here if we start sending control messages +* with incompatible types. +* +* SCM_RIGHTS and SCM_CREDENTIALS are done by hand in recvmsg32 right after +* we do our work. The remaining cases are: +* +* SOL_IP IP_PKTINFO struct in_pktinfo 32-bit clean +* IP_TTL int 32-bit clean +* IP_TOS __u8 32-bit clean +* IP_RECVOPTS variable length 32-bit clean +* IP_RETOPTS variable length 32-bit clean +* (these last two are clean because the types are defined +* by the IPv4 protocol) +* IP_RECVERR struct sock_extended_err + +* struct sockaddr_in 32-bit clean +* SOL_IPV6 IPV6_RECVERR struct sock_extended_err + +* struct sockaddr_in6 32-bit clean +* IPV6_PKTINFO struct in6_pktinfo 32-bit clean +* IPV6_HOPLIMIT int 32-bit clean +* IPV6_FLOWINFO u32 32-bit clean +* IPV6_HOPOPTS ipv6 hop exthdr 32-bit clean +* IPV6_DSTOPTS ipv6 dst exthdr(s) 32-bit clean +* IPV6_RTHDR ipv6 routing exthdr 32-bit clean +* IPV6_AUTHHDR ipv6 auth exthdr 32-bit clean */ - -int -sys32_recvmsg (int fd,struct msghdr32 *msg,unsigned int flags) +static void cmsg32_recvmsg_fixup (struct msghdr *kmsg,unsigned long orig_cmsg_uptr) { -struct socket *sock; -struct iovec iovstack[UIO_FASTIOV ]; -struct iovec *iov=iovstack; -struct msghdr msg_sys; -unsigned long cmsg_ptr; -int err, iov_size, total_len, len; +unsigned char *workbuf, *wp; +unsigned long bufsz, space_avail; +struct cmsghdr *ucmsg; + + bufsz = ((unsigned long )kmsg->msg_control) - orig_cmsg_uptr; + space_avail = kmsg->msg_controllen + bufsz; + wp = workbuf =kmalloc (bufsz,GFP_KERNEL ); +if (workbuf ==NULL ) + goto fail; + +/* To make this more sane we assume the kernel sends back properly +* formatted control messages. Because of how the kernel will truncate +* the cmsg_len for MSG_TRUNC cases, we need not check that case either. +*/ + ucmsg = (struct cmsghdr *) orig_cmsg_uptr; +while (((unsigned long )ucmsg) <= + (((unsigned long )kmsg->msg_control) -sizeof (struct cmsghdr ))) { +struct cmsghdr32 *kcmsg32 = (struct cmsghdr32 *) wp; +int clen64, clen32; + +/* UCMSG is the 64-bit format CMSG entry in user-space. +* KCMSG32 is within the kernel space temporary buffer +* we use to convert into a 32-bit style CMSG. +*/ +__get_user (kcmsg32->cmsg_len, &ucmsg->cmsg_len); +__get_user (kcmsg32->cmsg_level, &ucmsg->cmsg_level); +__get_user (kcmsg32->cmsg_type, &ucmsg->cmsg_type); + + clen64 = kcmsg32->cmsg_len; +copy_from_user (CMSG32_DATA (kcmsg32),CMSG_DATA (ucmsg), + clen64 -CMSG_ALIGN (sizeof (*ucmsg))); + clen32 = ((clen64 -CMSG_ALIGN (sizeof (*ucmsg))) + +CMSG32_ALIGN (sizeof (struct cmsghdr32 ))); + kcmsg32->cmsg_len = clen32; + + ucmsg = (struct cmsghdr *) (((char *)ucmsg) +CMSG_ALIGN (clen64)); + wp = (((char *)kcmsg32) +CMSG32_ALIGN (clen32)); + } + +/* Copy back fixed up data, and adjust pointers. */ + bufsz = (wp - workbuf); +copy_to_user ((void *)orig_cmsg_uptr, workbuf, bufsz); + + kmsg->msg_control = (struct cmsghdr *) + (((char *)orig_cmsg_uptr) + bufsz); + kmsg->msg_controllen = space_avail - bufsz; -/* kernel mode address */ -char addr[MAX_SOCK_ADDR ]; +kfree (workbuf); +return ; -/* user mode address pointers */ -struct sockaddr *uaddr; -int *uaddr_len; +fail: +/* If we leave the 64-bit format CMSG chunks in there, +* the application could get confused and crash. So to +* ensure greater recovery, we report no CMSGs. +*/ + kmsg->msg_controllen += bufsz; + kmsg->msg_control = (void *) orig_cmsg_uptr; +} - err=-EFAULT ; -if (shape_msg (&msg_sys, msg)) - goto out; +asmlinkage int sys32_sendmsg(int fd, struct msghdr32 *user_msg, unsigned user_flags) +{ +struct socket *sock; +char address[MAX_SOCK_ADDR ]; +struct iovec iov[UIO_FASTIOV ]; +unsigned char ctl[sizeof (struct cmsghdr ) +20 ]; +unsigned char *ctl_buf = ctl; +struct msghdr kern_msg; +int err, total_len; - sock =sockfd_lookup (fd, &err); -if (!sock) +if (msghdr_from_user32_to_kern (&kern_msg, user_msg)) +return -EFAULT ; +if (kern_msg.msg_iovlen >UIO_MAXIOV ) +return -EINVAL ; + err =verify_iovec32 (&kern_msg, iov, address,VERIFY_READ ); +if (err <0 ) goto out; + total_len = err; - err = -EINVAL ; -if (msg_sys.msg_iovlen >UIO_MAXIOV ) - goto out_put; +if (kern_msg.msg_controllen) { + err =cmsghdr_from_user32_to_kern (&kern_msg, ctl,sizeof (ctl)); +if (err) + goto out_freeiov; + ctl_buf = kern_msg.msg_control; + } + kern_msg.msg_flags = user_flags; -/* Check whether to allocate the iovec area*/ - err = -ENOMEM ; - iov_size = msg_sys.msg_iovlen *sizeof (struct iovec ); -if (msg_sys.msg_iovlen >UIO_FASTIOV ) { - iov =sock_kmalloc (sock->sk, iov_size,GFP_KERNEL ); -if (!iov) - goto out_put; + sock =sockfd_lookup (fd, &err); +if (sock !=NULL ) { +if (sock->file->f_flags &O_NONBLOCK ) + kern_msg.msg_flags |=MSG_DONTWAIT ; + err =sock_sendmsg (sock, &kern_msg, total_len); +sockfd_put (sock); } -/* -* Save the user-mode address (verify_iovec will change the -* kernel msghdr to use the kernel address space) -*/ +/* N.B. Use kfree here, as kern_msg.msg_controllen might change? */ +if (ctl_buf != ctl) +kfree (ctl_buf); +out_freeiov: +if (kern_msg.msg_iov != iov) +kfree (kern_msg.msg_iov); +out: +return err; +} - uaddr = msg_sys.msg_name; - uaddr_len = &msg->msg_namelen; - err =verify_iovec32 (&msg_sys, iov, addr,VERIFY_WRITE ); -if (err <0 ) - goto out_freeiov; - total_len=err; +asmlinkage int sys32_recvmsg(int fd, struct msghdr32 *user_msg, unsigned int user_flags) +{ +struct iovec iovstack[UIO_FASTIOV ]; +struct msghdr kern_msg; +char addr[MAX_SOCK_ADDR ]; +struct socket *sock; +struct iovec *iov = iovstack; +struct sockaddr *uaddr; +int *uaddr_len; +unsigned long cmsg_ptr; +int err, total_len, len =0 ; - cmsg_ptr = (unsigned long )msg_sys.msg_control; - msg_sys.msg_flags =0 ; +if (msghdr_from_user32_to_kern (&kern_msg, user_msg)) +return -EFAULT ; +if (kern_msg.msg_iovlen >UIO_MAXIOV ) +return -EINVAL ; -if (sock->file->f_flags &O_NONBLOCK ) - flags |=MSG_DONTWAIT ; - err =sock_recvmsg (sock, &msg_sys, total_len, flags); + uaddr = kern_msg.msg_name; + uaddr_len = &user_msg->msg_namelen; + err =verify_iovec32 (&kern_msg, iov, addr,VERIFY_WRITE );if (err <0 ) - goto out_freeiov; - len = err; + goto out; + total_len = err; -if (uaddr !=NULL ) { - err =move_addr_to_user (addr, msg_sys.msg_namelen, uaddr, uaddr_len); -if (err <0 ) - goto out_freeiov; + cmsg_ptr = (unsigned long ) kern_msg.msg_control; + kern_msg.msg_flags =0 ; + + sock =sockfd_lookup (fd, &err); +if (sock !=NULL ) { +struct scm_cookie scm; + +if (sock->file->f_flags &O_NONBLOCK ) + user_flags |=MSG_DONTWAIT ; +memset (&scm,0 ,sizeof (scm)); + err = sock->ops->recvmsg (sock, &kern_msg, total_len, + user_flags, &scm); +if (err >=0 ) { + len = err; +if (!kern_msg.msg_control) { +if (sock->passcred || scm.fp) + kern_msg.msg_flags |=MSG_CTRUNC ; +if (scm.fp) +__scm_destroy (&scm); + }else { +/* If recvmsg processing itself placed some +* control messages into user space, it's is +* using 64-bit CMSG processing, so we need +* to fix it up before we tack on more stuff. +*/ +if ((unsigned long ) kern_msg.msg_control != cmsg_ptr) +cmsg32_recvmsg_fixup (&kern_msg, cmsg_ptr); + +/* Wheee... */ +if (sock->passcred) +put_cmsg32 (&kern_msg, +SOL_SOCKET ,SCM_CREDENTIALS , +sizeof (scm.creds), &scm.creds); +if (scm.fp !=NULL ) +scm_detach_fds32 (&kern_msg, &scm); + } + } +sockfd_put (sock); } - err =__put_user (msg_sys.msg_flags, &msg->msg_flags); -if (err) - goto out_freeiov; - err =__put_user ((unsigned long )msg_sys.msg_control-cmsg_ptr, - &msg->msg_controllen); -if (err) - goto out_freeiov; - err = len; -out_freeiov: -if (iov != iovstack) -sock_kfree_s (sock->sk, iov, iov_size); -out_put: -sockfd_put (sock); +if (uaddr !=NULL && kern_msg.msg_namelen && err >=0 ) + err =move_addr_to_user (addr, kern_msg.msg_namelen, uaddr, uaddr_len); +if (cmsg_ptr !=0 && err >=0 ) { +unsigned long ucmsg_ptr = ((unsigned long )kern_msg.msg_control); +__kernel_size_t32 uclen = (__kernel_size_t32) (ucmsg_ptr - cmsg_ptr); + err |=__put_user (uclen, &user_msg->msg_controllen); + } +if (err >=0 ) + err =__put_user (kern_msg.msg_flags, &user_msg->msg_flags); +if (kern_msg.msg_iov != iov) +kfree (kern_msg.msg_iov); out: -return err; +if (err <0 ) +return err; +return len; } asmlinkage ssize_t sys_readahead(int fd, loff_t offset, size_t count);
Quoted 2 lines · Carsten Langgaard
Ok, here is the next patch.
It fixes thesys32_sendmsgandsys32_recvmsg.
Ok, in. Maciej, you can start the chainsawing ;-)
Ralf
Here is another linux32.c patch.
/Carsten
Quoted 8 lines · Ralf Baechle
Quoted 2 lines · Carsten Langgaard
Ok, here is the next patch.
It fixes thesys32_sendmsgandsys32_recvmsg.Ok, in. Maciej, you can start the chainsawing ;-)
Ralf
--
_ _ ____ ___ Carsten Langgaard Mailto:[email protected] |\ /|||___)(___ MIPS Denmark Direct: +45 4486 5527 | \/ ||| ____) Lautrupvang 4B Switch: +45 4486 5555 TECHNOLOGIES 2750 Ballerup Fax...: +45 4486 5556 Denmark http://www.mips.com
Index: arch/mips64/kernel/linux32.c
===================================================================
RCS file: /home/cvs/linux/arch/mips64/kernel/linux32.c,v retrieving revision 1.42.2.14
mips64/kernel/linux32.c +48 -16
@@ -1598,6 +1598,15 @@unsigned short sem_nsems;/* no. of semaphores in array */ }; +struct semid64_ds32 { +struct ipc64_perm32 sem_perm; +__kernel_time_t32 sem_otime; +__kernel_time_t32 sem_ctime; +unsigned int sem_nsems; +unsigned int __unused1; +unsigned int __unused2; +}; +struct msqid_ds32 {struct ipc_perm32 msg_perm;
@@ -1655,7 +1664,6 @@u32 pad;int err, err2;struct semid64_ds s; -struct semid_ds32 *usp;mm_segment_t old_fs;if (!uptr)
@@ -1668,7 +1676,6 @@else fourth.__pad = (void *)A (pad);switch (third & ~IPC_64 ) { -case IPC_INFO :case IPC_RMID :case IPC_SET :
@@ -1685,29 +1692,54 @@case IPC_STAT :case SEM_STAT : - usp = (struct semid_ds32 *)A (pad); fourth.__pad = &s; old_fs =get_fs ();set_fs (KERNEL_DS ); err =sys_semctl (first, second, third, fourth);set_fs (old_fs); - err2 =put_user (s.sem_perm.key, &usp->sem_perm.key); - err2 |=__put_user (s.sem_perm.uid, &usp->sem_perm.uid); - err2 |=__put_user (s.sem_perm.gid, &usp->sem_perm.gid); - err2 |=__put_user (s.sem_perm.cuid, - &usp->sem_perm.cuid); - err2 |=__put_user (s.sem_perm.cgid, - &usp->sem_perm.cgid); - err2 |=__put_user (s.sem_perm.mode, - &usp->sem_perm.mode); - err2 |=__put_user (s.sem_perm.seq, &usp->sem_perm.seq); - err2 |=__put_user (s.sem_otime, &usp->sem_otime); - err2 |=__put_user (s.sem_ctime, &usp->sem_ctime); - err2 |=__put_user (s.sem_nsems, &usp->sem_nsems); + +if (third &IPC_64 ) { +struct semid64_ds32 *usp64 = (struct semid64_ds32 *)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 *usp32 = (struct semid_ds32 *)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;
Here is the next patch in line.
/Carsten
Quoted 8 lines · Ralf Baechle
Quoted 2 lines · Carsten Langgaard
Ok, here is the next patch.
It fixes thesys32_sendmsgandsys32_recvmsg.Ok, in. Maciej, you can start the chainsawing ;-)
Ralf
--
_ _ ____ ___ Carsten Langgaard Mailto:[email protected] |\ /|||___)(___ MIPS Denmark Direct: +45 4486 5527 | \/ ||| ____) Lautrupvang 4B Switch: +45 4486 5555 TECHNOLOGIES 2750 Ballerup Fax...: +45 4486 5556 Denmark http://www.mips.com
Index: arch/mips64/kernel/linux32.c
===================================================================
RCS file: /home/cvs/linux/arch/mips64/kernel/linux32.c,v retrieving revision 1.42.2.15
mips64/kernel/linux32.c +21 -0
@@ -2803,6 +2803,27 @@return len; } +extern asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t count); + +asmlinkage int sys32_sendfile(int out_fd, int in_fd, __kernel_off_t32 *offset, s32 count) +{ +mm_segment_t old_fs =get_fs (); +int ret; +off_t of; + +if (offset &&get_user (of, offset)) +return -EFAULT ; + +set_fs (KERNEL_DS ); + ret =sys_sendfile (out_fd, in_fd, offset ? &of :NULL , count); +set_fs (old_fs); + +if (offset &&put_user (of, offset)) +return -EFAULT ; + +return ret; +} + asmlinkage ssize_t sys_readahead(int fd, loff_t offset, size_t count); asmlinkage ssize_t sys32_readahead(int fd, u32 pad0, u64 a2, u64 a3,
Index: arch/mips64/kernel/scall_o32.S
===================================================================
RCS file: /home/cvs/linux/arch/mips64/kernel/scall_o32.S,v retrieving revision 1.48.2.16
mips64/kernel/scall_o32.S +1 -1
@@ -519,7 +519,7 @@ sys sys_capget 2 sys sys_capset 2 /* 4205 */ sys sys32_sigaltstack 0 - sys sys_sendfile 4 + sys sys32_sendfile 4 sys sys_ni_syscall 0 sys sys_ni_syscall 0 sys sys32_mmap2 6 /* 4210 */
Quoted 4 lines · Ralf Baechle
Quoted 2 lines
Ok, here is the next patch.
It fixes thesys32_sendmsgandsys32_recvmsg.Ok, in. Maciej, you can start the chainsawing ;-)
Hmm, I couldn't test it as init now crashes with a SIGSEGV soon after
starting. I had no time to investigate it further. I fear it might be related, though -- /dev/initctl communication?
Signature · 3 lines
+ Maciej W. Rozycki, Technical University of Gdansk, Poland + +--------------------------------------------------------------+ + e-mail: [email protected], PGP key available +
Hmm, are you sure it's related ?
It works fine for me, and it fixes the problems I had before I added this fix.
/Carsten
Quoted 12 lines · Maciej W. Rozycki
Quoted 4 lines · Ralf Baechle
Quoted 2 lines
Ok, here is the next patch.
It fixes thesys32_sendmsgandsys32_recvmsg.Ok, in. Maciej, you can start the chainsawing ;-)
Hmm, I couldn't test it as init now crashes with a SIGSEGV soon after
starting. I had no time to investigate it further. I fear it might be related, though --/dev/initctlcommunication?--
Review
Quoted 3 lines
(quoted diff) +3
-0+ Maciej W. Rozycki, Technical University of Gdansk, Poland + +--------------------------------------------------------------+ + e-mail: [email protected], PGP key available +
--
_ _ ____ ___ Carsten Langgaard Mailto:[email protected] |\ /|||___)(___ MIPS Denmark Direct: +45 4486 5527 | \/ ||| ____) Lautrupvang 4B Switch: +45 4486 5555 TECHNOLOGIES 2750 Ballerup Fax...: +45 4486 5556 Denmark http://www.mips.com
Quoted 1 line · Carsten Langgaard
Hmm, are you sure it's related ?
No, I wasn't -- as I wrote I had no time to investigate it further and I
was asking for comments from people. Now I'm sure it is not.
Quoted 2 lines
It works fine for me, and it fixes the problems I had before I added this fix.
Yep, it works here with openssh, which used not to work before. Thanks a
lot.
The reason of the failure was a recent r4kcache.h breakage -- this is the
kind of mistakes that makes me consider a run-time check a necessity even for supposedly trivial and innocent changes (well, a compilation should actually suffice for lone comment updates).
Signature · 3 lines
+ Maciej W. Rozycki, Technical University of Gdansk, Poland + +--------------------------------------------------------------+ + e-mail: [email protected], PGP key available +