|
View:
New views
12 Messages
—
Rating Filter:
Alert me
|
|
|
MPSAFE TTY: Linux PTY'sHello Emulation folks,
I just wanted to send you all a message to say one of the things I tried to improve in the MPSAFE TTY branch was support for PTY's for Linux binaries. At home I've got a FreeBSD Jail running Debian Etch. Unfortunately, Linux sendmsg() is a little broken on FreeBSD/amd64, but so far I've been able to at least get OpenSSH (as root) and GNU Screen working. So if you folks run into any problems related to TTY's that you think can easily be solved, just send me an email. Thanks! -- Ed Schouten <ed@...> WWW: http://80386.nl/ |
|
|
Re: MPSAFE TTY: Linux PTY'sOn Fri, Aug 22, 2008 at 01:29:27PM +0200, Ed Schouten wrote:
> Hello Emulation folks, > > I just wanted to send you all a message to say one of the things I tried > to improve in the MPSAFE TTY branch was support for PTY's for Linux > binaries. > > At home I've got a FreeBSD Jail running Debian Etch. Unfortunately, > Linux sendmsg() is a little broken on FreeBSD/amd64, but so far I've > been able to at least get OpenSSH (as root) and GNU Screen working. I believe dmitry has a patch for this.. _______________________________________________ freebsd-emulation@... mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-emulation To unsubscribe, send any mail to "freebsd-emulation-unsubscribe@..." |
|
|
Re: MPSAFE TTY: Linux PTY'sOn Fri, Aug 22, 2008 at 01:29:46PM +0200, Roman Divacky wrote:
> On Fri, Aug 22, 2008 at 01:29:27PM +0200, Ed Schouten wrote: > > Hello Emulation folks, > > > > I just wanted to send you all a message to say one of the things I tried > > to improve in the MPSAFE TTY branch was support for PTY's for Linux > > binaries. > > > > At home I've got a FreeBSD Jail running Debian Etch. Unfortunately, > > Linux sendmsg() is a little broken on FreeBSD/amd64, but so far I've > > been able to at least get OpenSSH (as root) and GNU Screen working. > > I believe dmitry has a patch for this.. the patch is bellow, I tested a patch only on LTP tests (with little changes), it's necessary to test on real apps, it will be good if Ed will test.. diff --git a/src/sys/compat/linux/linux_socket.c b/src/sys/compat/linux/linux_socket.c index 7202944..41556bb 100644 --- a/src/sys/compat/linux/linux_socket.c +++ b/src/sys/compat/linux/linux_socket.c @@ -421,6 +421,65 @@ linux_sa_put(struct osockaddr *osa) } static int +linux_to_bsd_cmsg_type(int cmsg_type) +{ + + switch (cmsg_type) { + case LINUX_SCM_RIGHTS: + return (SCM_RIGHTS); + case LINUX_SCM_CREDENTIALS: + return (SCM_CREDS); + } + return (cmsg_type); +} + +static int +bsd_to_linux_cmsg_type(int cmsg_type) +{ + + switch (cmsg_type) { + case SCM_RIGHTS: + return (LINUX_SCM_RIGHTS); + case SCM_CREDS: + return (LINUX_SCM_CREDENTIALS); + } + return (cmsg_type); +} + + + +static int +linux_to_bsd_msghdr(struct msghdr *bhdr, const struct l_msghdr *lhdr) +{ + if (lhdr->msg_controllen > INT_MAX) + return (ENOBUFS); + + bhdr->msg_name = PTRIN(lhdr->msg_name); + bhdr->msg_namelen = lhdr->msg_namelen; + bhdr->msg_iov = PTRIN(lhdr->msg_iov); + bhdr->msg_iovlen = lhdr->msg_iovlen; + bhdr->msg_control = PTRIN(lhdr->msg_control); + bhdr->msg_controllen = lhdr->msg_controllen; + bhdr->msg_flags = lhdr->msg_flags; + return (0); +} + +static int +bsd_to_linux_msghdr(const struct msghdr *bhdr, struct l_msghdr *lhdr) +{ + lhdr->msg_name = bhdr->msg_name; + lhdr->msg_namelen = bhdr->msg_namelen; + lhdr->msg_iov = bhdr->msg_iov; + lhdr->msg_iovlen = bhdr->msg_iovlen; + lhdr->msg_control = bhdr->msg_control; + lhdr->msg_controllen = bhdr->msg_controllen; + return (0); +} + +#define CMSGHDR_SIZE CMSG_LEN(0) +#define L_CMSGHDR_SIZE LINUX_CMSG_LEN(0) + +static int linux_sendit(struct thread *td, int s, struct msghdr *mp, int flags, enum uio_seg segflg) { @@ -437,25 +496,57 @@ linux_sendit(struct thread *td, int s, struct msghdr *mp, int flags, to = NULL; if (mp->msg_control != NULL) { + struct l_cmsghdr *ptr_cmsg; + struct l_cmsghdr linux_cmsg; struct cmsghdr *cmsg; - - if (mp->msg_controllen < sizeof(struct cmsghdr)) { - error = EINVAL; - goto bad; - } - error = sockargs(&control, mp->msg_control, - mp->msg_controllen, MT_CONTROL); - if (error) - goto bad; - - cmsg = mtod(control, struct cmsghdr *); - cmsg->cmsg_level = linux_to_bsd_sockopt_level(cmsg->cmsg_level); + void *data; + socklen_t datalen; + + cmsg = malloc(CMSGHDR_SIZE, M_TEMP, M_WAITOK | M_ZERO); + control = m_get(M_WAIT, MT_CONTROL); + ptr_cmsg = LINUX_CMSG_FIRSTHDR(mp); + + do { + error = copyin(ptr_cmsg, &linux_cmsg, + sizeof(struct l_cmsghdr)); + if (error) + goto bad; + if (linux_cmsg.cmsg_len < sizeof(struct l_cmsghdr) || + linux_cmsg.cmsg_len > INT_MAX) { + error = EINVAL; + goto bad; + } + + switch (linux_cmsg.cmsg_type) { + case LINUX_SCM_RIGHTS: + cmsg->cmsg_type = + linux_to_bsd_cmsg_type(linux_cmsg.cmsg_type); + break; + default: + error = EINVAL; + goto bad; + } + cmsg->cmsg_level = + linux_to_bsd_sockopt_level(linux_cmsg.cmsg_level); + + datalen = linux_cmsg.cmsg_len - L_CMSGHDR_SIZE; + cmsg->cmsg_len = CMSG_LEN(datalen); + data = LINUX_CMSG_DATA(ptr_cmsg); + + error = ENOBUFS; + if (!m_append(control, CMSGHDR_SIZE, (c_caddr_t) cmsg)) + goto bad; + if (!m_append(control, datalen, (c_caddr_t) data)) + goto bad; + + } while ((ptr_cmsg = LINUX_CMSG_NXTHDR(mp, ptr_cmsg))); + + free(cmsg, M_TEMP); } else control = NULL; error = kern_sendit(td, s, mp, linux_to_bsd_msg_flags(flags), control, segflg); - bad: if (to) FREE(to, M_SONAME); @@ -1014,17 +1105,15 @@ struct linux_sendmsg_args { static int linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args) { - struct linux_sendmsg_args linux_args; struct msghdr msg; + struct l_msghdr linux_msg; struct iovec *iov; int error; - /* XXXTJR sendmsg is broken on amd64 */ - - error = copyin(args, &linux_args, sizeof(linux_args)); + error = copyin(PTRIN(args->msg), &linux_msg, sizeof(linux_msg)); if (error) return (error); - error = copyin(PTRIN(linux_args.msg), &msg, sizeof(msg)); + error = linux_to_bsd_msghdr(&msg, &linux_msg); if (error) return (error); @@ -1042,8 +1131,7 @@ linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args) return (error); msg.msg_iov = iov; msg.msg_flags = 0; - error = linux_sendit(td, linux_args.s, &msg, linux_args.flags, - UIO_USERSPACE); + error = linux_sendit(td, args->s, &msg, args->flags, UIO_USERSPACE); free(iov, M_IOV); return (error); } @@ -1057,48 +1145,116 @@ struct linux_recvmsg_args { static int linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args) { - struct linux_recvmsg_args linux_args; - struct recvmsg_args /* { - int s; - struct msghdr *msg; - int flags; - } */ bsd_args; struct msghdr msg; - struct cmsghdr *cmsg; + struct l_msghdr linux_msg; + struct iovec *uiov, *iov; + struct mbuf *control = NULL; + struct mbuf **controlp; + struct l_cmsghdr *cmsg = NULL; int error; - /* XXXTJR recvmsg is broken on amd64 */ - - if ((error = copyin(args, &linux_args, sizeof(linux_args)))) + error = copyin(PTRIN(args->msg), &linux_msg, sizeof (linux_msg)); + if (error) return (error); - - if ((error = copyin(PTRIN(args->msg), &msg, sizeof (msg)))) + error = linux_to_bsd_msghdr(&msg, &linux_msg); + if (error) return (error); - - bsd_args.s = linux_args.s; - bsd_args.msg = PTRIN(linux_args.msg); - bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags); - if (msg.msg_name) { - linux_to_bsd_sockaddr((struct sockaddr *)msg.msg_name, - msg.msg_namelen); - error = recvmsg(td, &bsd_args); - bsd_to_linux_sockaddr((struct sockaddr *)msg.msg_name); - } else - error = recvmsg(td, &bsd_args); + error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE); if (error) return (error); - if (bsd_args.msg->msg_control != NULL && - bsd_args.msg->msg_controllen > 0) { - cmsg = (struct cmsghdr*)bsd_args.msg->msg_control; - cmsg->cmsg_level = bsd_to_linux_sockopt_level(cmsg->cmsg_level); + uiov = msg.msg_iov; + msg.msg_iov = iov; + msg.msg_flags = linux_to_bsd_msg_flags(linux_msg.msg_flags); + + if (msg.msg_name) { + error = linux_to_bsd_sockaddr((struct sockaddr *)msg.msg_name, + msg.msg_namelen); + if (error) + goto bad; } - error = copyin(PTRIN(linux_args.msg), &msg, sizeof(msg)); + controlp = (msg.msg_control != NULL) ? &control : NULL; + error = kern_recvit(td, args->s, &msg, UIO_USERSPACE, controlp); if (error) - return (error); - if (msg.msg_name && msg.msg_namelen > 2) - error = linux_sa_put(msg.msg_name); + goto bad; + + msg.msg_iov = uiov; + + error = bsd_to_linux_msghdr(&msg, &linux_msg); + if (error) + goto bad; + + if (linux_msg.msg_name) + bsd_to_linux_sockaddr((struct sockaddr *)linux_msg.msg_name); + if (linux_msg.msg_name && linux_msg.msg_namelen > 2) { + error = linux_sa_put(linux_msg.msg_name); + if (error) + goto bad; + } + + if (control) { + caddr_t outbuf; + struct cmsghdr *cm; + + socklen_t datalen, outlen; + socklen_t clen; + void *data; + + cmsg = malloc(L_CMSGHDR_SIZE, M_TEMP, M_WAITOK | M_ZERO); + outbuf = linux_msg.msg_control; + cm = mtod(control, struct cmsghdr *); + outlen = 0; + clen = control->m_len; + + while (cm != NULL) { + data = CMSG_DATA(cm); + datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data; + + outlen += LINUX_CMSG_LEN(datalen); + if (outlen > linux_msg.msg_controllen) { + linux_msg.msg_flags |= LINUX_MSG_CTRUNC; + break; + } + + /* + * XXX here special handler of SCM_CREDS + */ + + cmsg->cmsg_len = LINUX_CMSG_LEN(datalen); + cmsg->cmsg_type = bsd_to_linux_cmsg_type(cm->cmsg_type); + cmsg->cmsg_level = + bsd_to_linux_sockopt_level(cm->cmsg_level); + + error = copyout(cmsg, outbuf, L_CMSGHDR_SIZE); + if (error) + goto bad; + outbuf += L_CMSGHDR_SIZE; + + error = copyout(data, outbuf, datalen); + if (error) + goto bad; + outbuf += LINUX_CMSG_ALIGN(datalen); + linux_msg.msg_controllen = outlen; + + if (CMSG_SPACE(datalen) < clen) { + clen -= CMSG_SPACE(datalen); + cm = (struct cmsghdr *) + ((caddr_t)cm + CMSG_SPACE(datalen)); + } else + cm = NULL; + } + } + + error = copyout(&linux_msg, PTRIN(args->msg), sizeof(linux_msg)); + +bad: + free(iov, M_IOV); + + if (control != NULL) + m_freem(control); + if (cmsg != NULL) + free(cmsg, M_TEMP); return (error); } diff --git a/src/sys/compat/linux/linux_socket.h b/src/sys/compat/linux/linux_socket.h index 074e8e0..668ec7f 100644 --- a/src/sys/compat/linux/linux_socket.h +++ b/src/sys/compat/linux/linux_socket.h @@ -49,4 +49,49 @@ #define LINUX_MSG_ERRQUEUE 0x2000 #define LINUX_MSG_NOSIGNAL 0x4000 +/* Socket-level control message types */ + +#define LINUX_SCM_RIGHTS 0x01 +#define LINUX_SCM_CREDENTIALS 0x02 + +struct l_msghdr { + void *msg_name; + l_int msg_namelen; + struct iovec *msg_iov; + l_size_t msg_iovlen; + void *msg_control; + l_size_t msg_controllen; + unsigned msg_flags; +}; + +struct l_cmsghdr { + l_size_t cmsg_len; + l_int cmsg_level; + l_int cmsg_type; +}; + +/* Ancilliary data object information macros */ + +#define LINUX_CMSG_ALIGN(len) (((len) + sizeof(long)-1) & ~(sizeof(long)-1)) +#define LINUX_CMSG_DATA(cmsg) ((void *)((char *)(cmsg) + \ + LINUX_CMSG_ALIGN(sizeof(struct l_cmsghdr)))) +#define LINUX_CMSG_SPACE(len) (LINUX_CMSG_ALIGN(sizeof(struct l_cmsghdr)) + \ + LINUX_CMSG_ALIGN(len)) +#define LINUX_CMSG_LEN(len) (LINUX_CMSG_ALIGN(sizeof(struct l_cmsghdr)) + \ + (len)) +#define LINUX_CMSG_FIRSTHDR(msg) \ + ((msg)->msg_controllen >= \ + sizeof(struct l_cmsghdr) ? \ + (struct l_cmsghdr *)((msg)->msg_control) : \ + (struct l_cmsghdr *)(NULL)) +#define LINUX_CMSG_NXTHDR(msg, cmsg) \ + ((((char *)(cmsg) + \ + LINUX_CMSG_ALIGN((cmsg)->cmsg_len) + \ + sizeof(*(cmsg))) > \ + (((char *)(msg)->msg_control) + \ + (msg)->msg_controllen)) ? \ + (struct l_cmsghdr *) NULL : \ + (struct l_cmsghdr *)((char *)(cmsg) + \ + LINUX_CMSG_ALIGN((cmsg)->cmsg_len))) + #endif /* _LINUX_SOCKET_H_ */ -- Have fun! chd _______________________________________________ freebsd-emulation@... mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-emulation To unsubscribe, send any mail to "freebsd-emulation-unsubscribe@..." |
|
|
Re: MPSAFE TTY: Linux PTY'sOn Sun, Aug 31, 2008 at 03:06:10PM +0400, Chagin Dmitry wrote:
> On Fri, Aug 22, 2008 at 01:29:46PM +0200, Roman Divacky wrote: > > On Fri, Aug 22, 2008 at 01:29:27PM +0200, Ed Schouten wrote: > > > Hello Emulation folks, > > > > > > I just wanted to send you all a message to say one of the things I tried > > > to improve in the MPSAFE TTY branch was support for PTY's for Linux > > > binaries. > > > > > > At home I've got a FreeBSD Jail running Debian Etch. Unfortunately, > > > Linux sendmsg() is a little broken on FreeBSD/amd64, but so far I've > > > been able to at least get OpenSSH (as root) and GNU Screen working. > > > > I believe dmitry has a patch for this.. > > the patch is bellow, I tested a patch only on LTP tests (with little changes), > it's necessary to test on real apps, it will be good if Ed will test.. this should be reviewed by someone with a knowledge of how networking works in FreeBSD. Any volunteer? Dmitry, can you send a mail to net@ describing the changes in the patch and ask for a review there? thnx! roman _______________________________________________ freebsd-emulation@... mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-emulation To unsubscribe, send any mail to "freebsd-emulation-unsubscribe@..." |
|
|
[PATCH] recvmsg() sendmsg() linux emulationOn Tue, Sep 02, 2008 at 10:56:23AM +0200, Roman Divacky wrote:
> On Sun, Aug 31, 2008 at 03:06:10PM +0400, Chagin Dmitry wrote: > > On Fri, Aug 22, 2008 at 01:29:46PM +0200, Roman Divacky wrote: > > > On Fri, Aug 22, 2008 at 01:29:27PM +0200, Ed Schouten wrote: > > > > Hello Emulation folks, > > > > > > > > I just wanted to send you all a message to say one of the things I tried > > > > to improve in the MPSAFE TTY branch was support for PTY's for Linux > > > > binaries. > > > > > > > > At home I've got a FreeBSD Jail running Debian Etch. Unfortunately, > > > > Linux sendmsg() is a little broken on FreeBSD/amd64, but so far I've > > > > been able to at least get OpenSSH (as root) and GNU Screen working. > > > > > > I believe dmitry has a patch for this.. > > > > the patch is bellow, I tested a patch only on LTP tests (with little changes), > > it's necessary to test on real apps, it will be good if Ed will test.. > > this should be reviewed by someone with a knowledge of how networking works in > FreeBSD. Any volunteer? Dmitry, can you send a mail to net@ describing the changes > in the patch and ask for a review there? > Hi, So, a patch bellow. The patch corrects sendmsg() recvmsg() in our linuxulator, also adds SO_PASSCRED option to linuxulator setsockopt() getsockopt() it's necessary for implementing Linux analogue of FreeBSD SCM_CREDS control message. I have tested it on i386 && ia32@amd64 linuxulators, it works for me now. Please review, any comment will be helpful. thnx! diff --git a/src/sys/amd64/linux32/linux.h b/src/sys/amd64/linux32/linux.h index 8940289..9439900 100644 --- a/src/sys/amd64/linux32/linux.h +++ b/src/sys/amd64/linux32/linux.h @@ -685,6 +685,7 @@ union l_semun { #define LINUX_SO_NO_CHECK 11 #define LINUX_SO_PRIORITY 12 #define LINUX_SO_LINGER 13 +#define LINUX_SO_PASSCRED 16 #define LINUX_SO_PEERCRED 17 #define LINUX_SO_RCVLOWAT 18 #define LINUX_SO_SNDLOWAT 19 @@ -709,6 +710,28 @@ struct l_sockaddr { char sa_data[14]; } __packed; +struct l_msghdr { + l_uintptr_t msg_name; + l_int msg_namelen; + l_uintptr_t msg_iov; + l_size_t msg_iovlen; + l_uintptr_t msg_control; + l_size_t msg_controllen; + l_uint msg_flags; +} __packed; + +struct l_cmsghdr { + l_size_t cmsg_len; + l_int cmsg_level; + l_int cmsg_type; +} __packed; + +struct l_ucred { + uint32_t pid; + uint32_t uid; + uint32_t gid; +} __packed; + struct l_ifmap { l_ulong mem_start; l_ulong mem_end; diff --git a/src/sys/amd64/linux32/linux32_machdep.c b/src/sys/amd64/linux32/linux32_machdep.c index 32cbe0b..26459c9 100644 --- a/src/sys/amd64/linux32/linux32_machdep.c +++ b/src/sys/amd64/linux32/linux32_machdep.c @@ -65,6 +65,7 @@ __FBSDID("$FreeBSD: src/sys/amd64/linux32/linux32_machdep.c,v 1.49 2008/09/08 09 #include <vm/vm_map.h> #include <amd64/linux32/linux.h> +#include <amd64/linux32/linux32_io.h> #include <amd64/linux32/linux32_proto.h> #include <compat/linux/linux_ipc.h> #include <compat/linux/linux_signal.h> @@ -232,13 +233,6 @@ linux_execve(struct thread *td, struct linux_execve_args *args) return (error); } -struct iovec32 { - u_int32_t iov_base; - int iov_len; -}; - -CTASSERT(sizeof(struct iovec32) == 8); - static int linux32_copyinuio(struct iovec32 *iovp, u_int iovcnt, struct uio **uiop) { @@ -281,6 +275,34 @@ linux32_copyinuio(struct iovec32 *iovp, u_int iovcnt, struct uio **uiop) } int +linux32_copyiniov(struct iovec32 *iovp32, u_int iovcnt, struct iovec **iovp, + int error) +{ + struct iovec32 iov32; + struct iovec *iov; + u_int iovlen; + int i; + + *iovp = NULL; + if (iovcnt > UIO_MAXIOV) + return (error); + iovlen = iovcnt * sizeof(struct iovec); + iov = malloc(iovlen, M_IOV, M_WAITOK); + for (i = 0; i < iovcnt; i++) { + error = copyin(&iovp32[i], &iov32, sizeof(struct iovec32)); + if (error) { + free(iov, M_IOV); + return (error); + } + iov[i].iov_base = PTRIN(iov32.iov_base); + iov[i].iov_len = iov32.iov_len; + } + *iovp = iov; + return(0); + +} + +int linux_readv(struct thread *td, struct linux_readv_args *uap) { struct uio *auio; diff --git a/src/sys/compat/linux/linux_socket.c b/src/sys/compat/linux/linux_socket.c index f97aa23..34e25dc 100644 --- a/src/sys/compat/linux/linux_socket.c +++ b/src/sys/compat/linux/linux_socket.c @@ -62,6 +62,7 @@ __FBSDID("$FreeBSD: src/sys/compat/linux/linux_socket.c,v 1.76 2008/09/09 13:01: #ifdef COMPAT_LINUX32 #include <machine/../linux32/linux.h> +#include <machine/../linux32/linux32_io.h> #include <machine/../linux32/linux32_proto.h> #else #include <machine/../linux/linux.h> @@ -294,6 +295,8 @@ linux_to_bsd_so_sockopt(int opt) return (SO_OOBINLINE); case LINUX_SO_LINGER: return (SO_LINGER); + case LINUX_SO_PASSCRED: + return (LOCAL_CREDS); case LINUX_SO_PEERCRED: return (LOCAL_PEERCRED); case LINUX_SO_RCVLOWAT: @@ -421,6 +424,63 @@ linux_sa_put(struct osockaddr *osa) } static int +linux_to_bsd_cmsg_type(int cmsg_type) +{ + + switch (cmsg_type) { + case LINUX_SCM_RIGHTS: + return (SCM_RIGHTS); + case LINUX_SCM_CREDENTIALS: + return (SCM_CREDS); + } + return (cmsg_type); +} + +static int +bsd_to_linux_cmsg_type(int cmsg_type) +{ + + switch (cmsg_type) { + case SCM_RIGHTS: + return (LINUX_SCM_RIGHTS); + case SCM_CREDS: + return (LINUX_SCM_CREDENTIALS); + } + return (cmsg_type); +} + + + +static int +linux_to_bsd_msghdr(struct msghdr *bhdr, const struct l_msghdr *lhdr) +{ + if (lhdr->msg_controllen > INT_MAX) + return (ENOBUFS); + + bhdr->msg_name = PTRIN(lhdr->msg_name); + bhdr->msg_namelen = lhdr->msg_namelen; + bhdr->msg_iov = PTRIN(lhdr->msg_iov); + bhdr->msg_iovlen = lhdr->msg_iovlen; + bhdr->msg_control = PTRIN(lhdr->msg_control); + bhdr->msg_controllen = lhdr->msg_controllen; + bhdr->msg_flags = linux_to_bsd_msg_flags(lhdr->msg_flags); + return (0); +} + +static int +bsd_to_linux_msghdr(const struct msghdr *bhdr, struct l_msghdr *lhdr) +{ + lhdr->msg_name = PTROUT(bhdr->msg_name); + lhdr->msg_namelen = bhdr->msg_namelen; + lhdr->msg_iov = PTROUT(bhdr->msg_iov); + lhdr->msg_iovlen = bhdr->msg_iovlen; + lhdr->msg_control = PTROUT(bhdr->msg_control); + lhdr->msg_controllen = bhdr->msg_controllen; + /* msg_flags skipped */ + return (0); +} + +static int linux_sendit(struct thread *td, int s, struct msghdr *mp, int flags, enum uio_seg segflg) { @@ -437,25 +497,57 @@ linux_sendit(struct thread *td, int s, struct msghdr *mp, int flags, to = NULL; if (mp->msg_control != NULL) { + struct l_cmsghdr *ptr_cmsg; + struct l_cmsghdr linux_cmsg; struct cmsghdr *cmsg; - - if (mp->msg_controllen < sizeof(struct cmsghdr)) { - error = EINVAL; - goto bad; - } - error = sockargs(&control, mp->msg_control, - mp->msg_controllen, MT_CONTROL); - if (error) - goto bad; - - cmsg = mtod(control, struct cmsghdr *); - cmsg->cmsg_level = linux_to_bsd_sockopt_level(cmsg->cmsg_level); + void *data; + socklen_t datalen; + + cmsg = malloc(CMSG_HDRSZ, M_TEMP, M_WAITOK | M_ZERO); + control = m_get(M_WAIT, MT_CONTROL); + ptr_cmsg = LINUX_CMSG_FIRSTHDR(mp); + + do { + error = copyin(ptr_cmsg, &linux_cmsg, + sizeof(struct l_cmsghdr)); + if (error) + goto bad; + if (linux_cmsg.cmsg_len < sizeof(struct l_cmsghdr) || + linux_cmsg.cmsg_len > INT_MAX) { + error = EINVAL; + goto bad; + } + + switch (linux_cmsg.cmsg_type) { + case LINUX_SCM_RIGHTS: + cmsg->cmsg_type = + linux_to_bsd_cmsg_type(linux_cmsg.cmsg_type); + break; + default: + error = EINVAL; + goto bad; + } + cmsg->cmsg_level = + linux_to_bsd_sockopt_level(linux_cmsg.cmsg_level); + + datalen = linux_cmsg.cmsg_len - L_CMSG_HDRSZ; + cmsg->cmsg_len = CMSG_LEN(datalen); + data = LINUX_CMSG_DATA(ptr_cmsg); + + error = ENOBUFS; + if (!m_append(control, CMSG_HDRSZ, (c_caddr_t) cmsg)) + goto bad; + if (!m_append(control, datalen, (c_caddr_t) data)) + goto bad; + + } while ((ptr_cmsg = LINUX_CMSG_NXTHDR(mp, ptr_cmsg))); + + free(cmsg, M_TEMP); } else control = NULL; error = kern_sendit(td, s, mp, linux_to_bsd_msg_flags(flags), control, segflg); - bad: if (to) FREE(to, M_SONAME); @@ -960,12 +1052,14 @@ static int linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args) { struct msghdr msg; + struct l_msghdr linux_msg; struct iovec *iov; int error; - /* XXXTJR sendmsg is broken on amd64 */ - - error = copyin(PTRIN(args->msg), &msg, sizeof(msg)); + error = copyin(PTRIN(args->msg), &linux_msg, sizeof(linux_msg)); + if (error) + return (error); + error = linux_to_bsd_msghdr(&msg, &linux_msg); if (error) return (error); @@ -978,9 +1072,13 @@ linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args) */ if (msg.msg_control != NULL && msg.msg_controllen == 0) msg.msg_control = NULL; + +#if defined(__amd64__) && defined(COMPAT_LINUX32) + error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen, + &iov, EMSGSIZE); +#else error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE); - if (error) - return (error); +#endif msg.msg_iov = iov; msg.msg_flags = 0; error = linux_sendit(td, args->s, &msg, args->flags, UIO_USERSPACE); @@ -997,44 +1095,168 @@ struct linux_recvmsg_args { static int linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args) { - struct recvmsg_args /* { - int s; - struct msghdr *msg; - int flags; - } */ bsd_args; struct msghdr msg; - struct cmsghdr *cmsg; + struct l_msghdr linux_msg; + struct l_cmsghdr *linux_cmsg = NULL; + struct iovec *iov, *uiov; + struct mbuf *control = NULL; + struct mbuf **controlp; int error; - /* XXXTJR recvmsg is broken on amd64 */ + error = copyin(PTRIN(args->msg), &linux_msg, sizeof(linux_msg)); + if (error) + return (error); - if ((error = copyin(PTRIN(args->msg), &msg, sizeof (msg)))) + error = linux_to_bsd_msghdr(&msg, &linux_msg); + if (error) return (error); - bsd_args.s = args->s; - bsd_args.msg = PTRIN(args->msg); - bsd_args.flags = linux_to_bsd_msg_flags(args->flags); - if (msg.msg_name) { - linux_to_bsd_sockaddr((struct sockaddr *)msg.msg_name, - msg.msg_namelen); - error = recvmsg(td, &bsd_args); - bsd_to_linux_sockaddr((struct sockaddr *)msg.msg_name); - } else - error = recvmsg(td, &bsd_args); +#if defined(__amd64__) && defined(COMPAT_LINUX32) + error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen, + &iov, EMSGSIZE); +#else + error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE); +#endif if (error) return (error); - if (bsd_args.msg->msg_control != NULL && - bsd_args.msg->msg_controllen > 0) { - cmsg = (struct cmsghdr*)bsd_args.msg->msg_control; - cmsg->cmsg_level = bsd_to_linux_sockopt_level(cmsg->cmsg_level); + if (msg.msg_name) { + error = linux_to_bsd_sockaddr((struct sockaddr *)msg.msg_name, + msg.msg_namelen); + if (error) + goto bad; } - error = copyin(PTRIN(args->msg), &msg, sizeof(msg)); + uiov = msg.msg_iov; + msg.msg_iov = iov; + controlp = (msg.msg_control != NULL) ? &control : NULL; + error = kern_recvit(td, args->s, &msg, UIO_USERSPACE, controlp); + msg.msg_iov = uiov; if (error) - return (error); - if (msg.msg_name && msg.msg_namelen > 2) - error = linux_sa_put(msg.msg_name); + goto bad; + + error = bsd_to_linux_msghdr(&msg, &linux_msg); + if (error) + goto bad; + + if (linux_msg.msg_name) { + error = bsd_to_linux_sockaddr((struct sockaddr *) + PTRIN(linux_msg.msg_name)); + if (error) + goto bad; + } + if (linux_msg.msg_name && linux_msg.msg_namelen > 2) { + error = linux_sa_put(PTRIN(linux_msg.msg_name)); + if (error) + goto bad; + } + + if (control) { + caddr_t outbuf; + struct cmsghdr *cm; + socklen_t datalen, outlen; + socklen_t clen; + void *data; + struct sockcred *scred; + struct l_ucred lcred; + + linux_cmsg = malloc(L_CMSG_HDRSZ, M_TEMP, M_WAITOK | M_ZERO); + outbuf = PTRIN(linux_msg.msg_control); + cm = mtod(control, struct cmsghdr *); + outlen = 0; + clen = control->m_len; + + while (cm != NULL) { + + switch (cm->cmsg_type) { + case SCM_CREDS: + + scred = (struct sockcred *)CMSG_DATA(cm); + datalen = (caddr_t)cm + cm->cmsg_len - + (caddr_t)scred; + + if (outlen + LINUX_CMSG_LEN(sizeof(lcred)) > + linux_msg.msg_controllen) { + linux_msg.msg_flags |= LINUX_MSG_CTRUNC; + goto out; + } + + lcred.pid = -1; + lcred.uid = scred->sc_uid; + lcred.gid = scred->sc_gid; + + linux_cmsg->cmsg_len = + LINUX_CMSG_LEN(sizeof(lcred)); + linux_cmsg->cmsg_type = + bsd_to_linux_cmsg_type(cm->cmsg_type); + linux_cmsg->cmsg_level = + bsd_to_linux_sockopt_level(cm->cmsg_level); + + error = copyout(linux_cmsg, outbuf, L_CMSG_HDRSZ); + if (error) + goto bad; + outbuf += L_CMSG_HDRSZ; + + error = copyout(&lcred, outbuf, sizeof(lcred)); + if (error) + goto bad; + + outbuf += LINUX_CMSG_ALIGN(sizeof(lcred)); + outlen += LINUX_CMSG_LEN(sizeof(lcred)); + linux_msg.msg_controllen = outlen; + break; + + default: + + data = CMSG_DATA(cm); + datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data; + + if (outlen + LINUX_CMSG_LEN(datalen) > + linux_msg.msg_controllen) { + linux_msg.msg_flags |= LINUX_MSG_CTRUNC; + goto out; + } + + linux_cmsg->cmsg_len = LINUX_CMSG_LEN(datalen); + linux_cmsg->cmsg_type = + bsd_to_linux_cmsg_type(cm->cmsg_type); + linux_cmsg->cmsg_level = + bsd_to_linux_sockopt_level(cm->cmsg_level); + + error = copyout(linux_cmsg, outbuf, L_CMSG_HDRSZ); + if (error) + goto bad; + outbuf += L_CMSG_HDRSZ; + + error = copyout(data, outbuf, datalen); + if (error) + goto bad; + + outbuf += LINUX_CMSG_ALIGN(datalen); + outlen += LINUX_CMSG_LEN(datalen); + linux_msg.msg_controllen = outlen; + break; + } + + if (CMSG_SPACE(datalen) < clen) { + clen -= CMSG_SPACE(datalen); + cm = (struct cmsghdr *) + ((caddr_t)cm + CMSG_SPACE(datalen)); + } else + cm = NULL; + } + } + +out: + error = copyout(&linux_msg, PTRIN(args->msg), sizeof(linux_msg)); + +bad: + free(iov, M_IOV); + if (control != NULL) + m_freem(control); + if (linux_cmsg != NULL) + free(linux_cmsg, M_TEMP); + return (error); } @@ -1081,6 +1303,12 @@ linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args) switch (bsd_args.level) { case SOL_SOCKET: name = linux_to_bsd_so_sockopt(args->optname); + switch (args->optname) { + case LINUX_SO_PASSCRED: + /* FreeBSD bug? socket level opts at non socket level */ + bsd_args.level = 0; + break; + } break; case IPPROTO_IP: name = linux_to_bsd_ip_sockopt(args->optname); @@ -1136,6 +1364,11 @@ linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args) switch (bsd_args.level) { case SOL_SOCKET: name = linux_to_bsd_so_sockopt(args->optname); + switch (args->optname) { + case LINUX_SO_PASSCRED: + bsd_args.level = 0; + break; + } break; case IPPROTO_IP: name = linux_to_bsd_ip_sockopt(args->optname); diff --git a/src/sys/compat/linux/linux_socket.h b/src/sys/compat/linux/linux_socket.h index 074e8e0..e8c2ec8 100644 --- a/src/sys/compat/linux/linux_socket.h +++ b/src/sys/compat/linux/linux_socket.h @@ -49,4 +49,36 @@ #define LINUX_MSG_ERRQUEUE 0x2000 #define LINUX_MSG_NOSIGNAL 0x4000 +/* Socket-level control message types */ + +#define LINUX_SCM_RIGHTS 0x01 +#define LINUX_SCM_CREDENTIALS 0x02 + +/* Ancilliary data object information macros */ + +#define LINUX_CMSG_ALIGN(len) (((len) + sizeof(l_long)-1) & ~(sizeof(l_long)-1)) +#define LINUX_CMSG_DATA(cmsg) ((void *)((char *)(cmsg) + \ + LINUX_CMSG_ALIGN(sizeof(struct l_cmsghdr)))) +#define LINUX_CMSG_SPACE(len) (LINUX_CMSG_ALIGN(sizeof(struct l_cmsghdr)) + \ + LINUX_CMSG_ALIGN(len)) +#define LINUX_CMSG_LEN(len) (LINUX_CMSG_ALIGN(sizeof(struct l_cmsghdr)) + \ + (len)) +#define LINUX_CMSG_FIRSTHDR(msg) \ + ((msg)->msg_controllen >= \ + sizeof(struct l_cmsghdr) ? \ + (struct l_cmsghdr *)((msg)->msg_control) : \ + (struct l_cmsghdr *)(NULL)) +#define LINUX_CMSG_NXTHDR(msg, cmsg) \ + ((((char *)(cmsg) + \ + LINUX_CMSG_ALIGN((cmsg)->cmsg_len) + \ + sizeof(*(cmsg))) > \ + (((char *)(msg)->msg_control) + \ + (msg)->msg_controllen)) ? \ + (struct l_cmsghdr *) NULL : \ + (struct l_cmsghdr *)((char *)(cmsg) + \ + LINUX_CMSG_ALIGN((cmsg)->cmsg_len))) + +#define CMSG_HDRSZ CMSG_LEN(0) +#define L_CMSG_HDRSZ LINUX_CMSG_LEN(0) + #endif /* _LINUX_SOCKET_H_ */ diff --git a/src/sys/i386/linux/linux.h b/src/sys/i386/linux/linux.h index 1c3627d..28655fe 100644 --- a/src/sys/i386/linux/linux.h +++ b/src/sys/i386/linux/linux.h @@ -656,6 +656,7 @@ union l_semun { #define LINUX_SO_NO_CHECK 11 #define LINUX_SO_PRIORITY 12 #define LINUX_SO_LINGER 13 +#define LINUX_SO_PASSCRED 16 #define LINUX_SO_PEERCRED 17 #define LINUX_SO_RCVLOWAT 18 #define LINUX_SO_SNDLOWAT 19 @@ -680,6 +681,28 @@ struct l_sockaddr { char sa_data[14]; }; +struct l_msghdr { + l_uintptr_t msg_name; + l_int msg_namelen; + l_uintptr_t msg_iov; + l_size_t msg_iovlen; + l_uintptr_t msg_control; + l_size_t msg_controllen; + l_uint msg_flags; +}; + +struct l_cmsghdr { + l_size_t cmsg_len; + l_int cmsg_level; + l_int cmsg_type; +}; + +struct l_ucred { + uint32_t pid; + uint32_t uid; + uint32_t gid; +}; + struct l_ifmap { l_ulong mem_start; l_ulong mem_end; -- Have fun! chd _______________________________________________ freebsd-emulation@... mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-emulation To unsubscribe, send any mail to "freebsd-emulation-unsubscribe@..." |
|
|
Re: [PATCH] recvmsg() sendmsg() linux emulationOn Wed, Sep 17, 2008 at 10:38:01PM +0400, Chagin Dmitry wrote:
> > Please review, any comment will be helpful. > thnx! > ups... I have lost a new file, the previous patch is incorrect. sorry. diff --git a/src/sys/amd64/linux32/linux.h b/src/sys/amd64/linux32/linux.h index 8940289..9439900 100644 --- a/src/sys/amd64/linux32/linux.h +++ b/src/sys/amd64/linux32/linux.h @@ -685,6 +685,7 @@ union l_semun { #define LINUX_SO_NO_CHECK 11 #define LINUX_SO_PRIORITY 12 #define LINUX_SO_LINGER 13 +#define LINUX_SO_PASSCRED 16 #define LINUX_SO_PEERCRED 17 #define LINUX_SO_RCVLOWAT 18 #define LINUX_SO_SNDLOWAT 19 @@ -709,6 +710,28 @@ struct l_sockaddr { char sa_data[14]; } __packed; +struct l_msghdr { + l_uintptr_t msg_name; + l_int msg_namelen; + l_uintptr_t msg_iov; + l_size_t msg_iovlen; + l_uintptr_t msg_control; + l_size_t msg_controllen; + l_uint msg_flags; +} __packed; + +struct l_cmsghdr { + l_size_t cmsg_len; + l_int cmsg_level; + l_int cmsg_type; +} __packed; + +struct l_ucred { + uint32_t pid; + uint32_t uid; + uint32_t gid; +} __packed; + struct l_ifmap { l_ulong mem_start; l_ulong mem_end; diff --git a/src/sys/amd64/linux32/linux32_io.h b/src/sys/amd64/linux32/linux32_io.h new file mode 100644 index 0000000..c1a9f1c --- /dev/null +++ b/src/sys/amd64/linux32/linux32_io.h @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 2004 Tim J. Robbins + * Copyright (c) 2001 Doug Rabson + * Copyright (c) 1994-1996 SЬren Schmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _AMD64_LINUX32_IO_H_ +#define _AMD64_LINUX32_IO_H_ + + +struct iovec32 { + u_int32_t iov_base; + int iov_len; +}; + +CTASSERT(sizeof(struct iovec32) == 8); + +int linux32_copyiniov(struct iovec32 *iovp32, u_int iovcnt, struct iovec **iovp, + int error); + +#endif /* !_AMD64_LINUX32_IO_H_ */ diff --git a/src/sys/amd64/linux32/linux32_machdep.c b/src/sys/amd64/linux32/linux32_machdep.c index 32cbe0b..26459c9 100644 --- a/src/sys/amd64/linux32/linux32_machdep.c +++ b/src/sys/amd64/linux32/linux32_machdep.c @@ -65,6 +65,7 @@ __FBSDID("$FreeBSD: src/sys/amd64/linux32/linux32_machdep.c,v 1.49 2008/09/08 09 #include <vm/vm_map.h> #include <amd64/linux32/linux.h> +#include <amd64/linux32/linux32_io.h> #include <amd64/linux32/linux32_proto.h> #include <compat/linux/linux_ipc.h> #include <compat/linux/linux_signal.h> @@ -232,13 +233,6 @@ linux_execve(struct thread *td, struct linux_execve_args *args) return (error); } -struct iovec32 { - u_int32_t iov_base; - int iov_len; -}; - -CTASSERT(sizeof(struct iovec32) == 8); - static int linux32_copyinuio(struct iovec32 *iovp, u_int iovcnt, struct uio **uiop) { @@ -281,6 +275,34 @@ linux32_copyinuio(struct iovec32 *iovp, u_int iovcnt, struct uio **uiop) } int +linux32_copyiniov(struct iovec32 *iovp32, u_int iovcnt, struct iovec **iovp, + int error) +{ + struct iovec32 iov32; + struct iovec *iov; + u_int iovlen; + int i; + + *iovp = NULL; + if (iovcnt > UIO_MAXIOV) + return (error); + iovlen = iovcnt * sizeof(struct iovec); + iov = malloc(iovlen, M_IOV, M_WAITOK); + for (i = 0; i < iovcnt; i++) { + error = copyin(&iovp32[i], &iov32, sizeof(struct iovec32)); + if (error) { + free(iov, M_IOV); + return (error); + } + iov[i].iov_base = PTRIN(iov32.iov_base); + iov[i].iov_len = iov32.iov_len; + } + *iovp = iov; + return(0); + +} + +int linux_readv(struct thread *td, struct linux_readv_args *uap) { struct uio *auio; diff --git a/src/sys/compat/linux/linux_socket.c b/src/sys/compat/linux/linux_socket.c index f97aa23..34e25dc 100644 --- a/src/sys/compat/linux/linux_socket.c +++ b/src/sys/compat/linux/linux_socket.c @@ -62,6 +62,7 @@ __FBSDID("$FreeBSD: src/sys/compat/linux/linux_socket.c,v 1.76 2008/09/09 13:01: #ifdef COMPAT_LINUX32 #include <machine/../linux32/linux.h> +#include <machine/../linux32/linux32_io.h> #include <machine/../linux32/linux32_proto.h> #else #include <machine/../linux/linux.h> @@ -294,6 +295,8 @@ linux_to_bsd_so_sockopt(int opt) return (SO_OOBINLINE); case LINUX_SO_LINGER: return (SO_LINGER); + case LINUX_SO_PASSCRED: + return (LOCAL_CREDS); case LINUX_SO_PEERCRED: return (LOCAL_PEERCRED); case LINUX_SO_RCVLOWAT: @@ -421,6 +424,63 @@ linux_sa_put(struct osockaddr *osa) } static int +linux_to_bsd_cmsg_type(int cmsg_type) +{ + + switch (cmsg_type) { + case LINUX_SCM_RIGHTS: + return (SCM_RIGHTS); + case LINUX_SCM_CREDENTIALS: + return (SCM_CREDS); + } + return (cmsg_type); +} + +static int +bsd_to_linux_cmsg_type(int cmsg_type) +{ + + switch (cmsg_type) { + case SCM_RIGHTS: + return (LINUX_SCM_RIGHTS); + case SCM_CREDS: + return (LINUX_SCM_CREDENTIALS); + } + return (cmsg_type); +} + + + +static int +linux_to_bsd_msghdr(struct msghdr *bhdr, const struct l_msghdr *lhdr) +{ + if (lhdr->msg_controllen > INT_MAX) + return (ENOBUFS); + + bhdr->msg_name = PTRIN(lhdr->msg_name); + bhdr->msg_namelen = lhdr->msg_namelen; + bhdr->msg_iov = PTRIN(lhdr->msg_iov); + bhdr->msg_iovlen = lhdr->msg_iovlen; + bhdr->msg_control = PTRIN(lhdr->msg_control); + bhdr->msg_controllen = lhdr->msg_controllen; + bhdr->msg_flags = linux_to_bsd_msg_flags(lhdr->msg_flags); + return (0); +} + +static int +bsd_to_linux_msghdr(const struct msghdr *bhdr, struct l_msghdr *lhdr) +{ + lhdr->msg_name = PTROUT(bhdr->msg_name); + lhdr->msg_namelen = bhdr->msg_namelen; + lhdr->msg_iov = PTROUT(bhdr->msg_iov); + lhdr->msg_iovlen = bhdr->msg_iovlen; + lhdr->msg_control = PTROUT(bhdr->msg_control); + lhdr->msg_controllen = bhdr->msg_controllen; + /* msg_flags skipped */ + return (0); +} + +static int linux_sendit(struct thread *td, int s, struct msghdr *mp, int flags, enum uio_seg segflg) { @@ -437,25 +497,57 @@ linux_sendit(struct thread *td, int s, struct msghdr *mp, int flags, to = NULL; if (mp->msg_control != NULL) { + struct l_cmsghdr *ptr_cmsg; + struct l_cmsghdr linux_cmsg; struct cmsghdr *cmsg; - - if (mp->msg_controllen < sizeof(struct cmsghdr)) { - error = EINVAL; - goto bad; - } - error = sockargs(&control, mp->msg_control, - mp->msg_controllen, MT_CONTROL); - if (error) - goto bad; - - cmsg = mtod(control, struct cmsghdr *); - cmsg->cmsg_level = linux_to_bsd_sockopt_level(cmsg->cmsg_level); + void *data; + socklen_t datalen; + + cmsg = malloc(CMSG_HDRSZ, M_TEMP, M_WAITOK | M_ZERO); + control = m_get(M_WAIT, MT_CONTROL); + ptr_cmsg = LINUX_CMSG_FIRSTHDR(mp); + + do { + error = copyin(ptr_cmsg, &linux_cmsg, + sizeof(struct l_cmsghdr)); + if (error) + goto bad; + if (linux_cmsg.cmsg_len < sizeof(struct l_cmsghdr) || + linux_cmsg.cmsg_len > INT_MAX) { + error = EINVAL; + goto bad; + } + + switch (linux_cmsg.cmsg_type) { + case LINUX_SCM_RIGHTS: + cmsg->cmsg_type = + linux_to_bsd_cmsg_type(linux_cmsg.cmsg_type); + break; + default: + error = EINVAL; + goto bad; + } + cmsg->cmsg_level = + linux_to_bsd_sockopt_level(linux_cmsg.cmsg_level); + + datalen = linux_cmsg.cmsg_len - L_CMSG_HDRSZ; + cmsg->cmsg_len = CMSG_LEN(datalen); + data = LINUX_CMSG_DATA(ptr_cmsg); + + error = ENOBUFS; + if (!m_append(control, CMSG_HDRSZ, (c_caddr_t) cmsg)) + goto bad; + if (!m_append(control, datalen, (c_caddr_t) data)) + goto bad; + + } while ((ptr_cmsg = LINUX_CMSG_NXTHDR(mp, ptr_cmsg))); + + free(cmsg, M_TEMP); } else control = NULL; error = kern_sendit(td, s, mp, linux_to_bsd_msg_flags(flags), control, segflg); - bad: if (to) FREE(to, M_SONAME); @@ -960,12 +1052,14 @@ static int linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args) { struct msghdr msg; + struct l_msghdr linux_msg; struct iovec *iov; int error; - /* XXXTJR sendmsg is broken on amd64 */ - - error = copyin(PTRIN(args->msg), &msg, sizeof(msg)); + error = copyin(PTRIN(args->msg), &linux_msg, sizeof(linux_msg)); + if (error) + return (error); + error = linux_to_bsd_msghdr(&msg, &linux_msg); if (error) return (error); @@ -978,9 +1072,13 @@ linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args) */ if (msg.msg_control != NULL && msg.msg_controllen == 0) msg.msg_control = NULL; + +#if defined(__amd64__) && defined(COMPAT_LINUX32) + error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen, + &iov, EMSGSIZE); +#else error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE); - if (error) - return (error); +#endif msg.msg_iov = iov; msg.msg_flags = 0; error = linux_sendit(td, args->s, &msg, args->flags, UIO_USERSPACE); @@ -997,44 +1095,168 @@ struct linux_recvmsg_args { static int linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args) { - struct recvmsg_args /* { - int s; - struct msghdr *msg; - int flags; - } */ bsd_args; struct msghdr msg; - struct cmsghdr *cmsg; + struct l_msghdr linux_msg; + struct l_cmsghdr *linux_cmsg = NULL; + struct iovec *iov, *uiov; + struct mbuf *control = NULL; + struct mbuf **controlp; int error; - /* XXXTJR recvmsg is broken on amd64 */ + error = copyin(PTRIN(args->msg), &linux_msg, sizeof(linux_msg)); + if (error) + return (error); - if ((error = copyin(PTRIN(args->msg), &msg, sizeof (msg)))) + error = linux_to_bsd_msghdr(&msg, &linux_msg); + if (error) return (error); - bsd_args.s = args->s; - bsd_args.msg = PTRIN(args->msg); - bsd_args.flags = linux_to_bsd_msg_flags(args->flags); - if (msg.msg_name) { - linux_to_bsd_sockaddr((struct sockaddr *)msg.msg_name, - msg.msg_namelen); - error = recvmsg(td, &bsd_args); - bsd_to_linux_sockaddr((struct sockaddr *)msg.msg_name); - } else - error = recvmsg(td, &bsd_args); +#if defined(__amd64__) && defined(COMPAT_LINUX32) + error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen, + &iov, EMSGSIZE); +#else + error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE); +#endif if (error) return (error); - if (bsd_args.msg->msg_control != NULL && - bsd_args.msg->msg_controllen > 0) { - cmsg = (struct cmsghdr*)bsd_args.msg->msg_control; - cmsg->cmsg_level = bsd_to_linux_sockopt_level(cmsg->cmsg_level); + if (msg.msg_name) { + error = linux_to_bsd_sockaddr((struct sockaddr *)msg.msg_name, + msg.msg_namelen); + if (error) + goto bad; } - error = copyin(PTRIN(args->msg), &msg, sizeof(msg)); + uiov = msg.msg_iov; + msg.msg_iov = iov; + controlp = (msg.msg_control != NULL) ? &control : NULL; + error = kern_recvit(td, args->s, &msg, UIO_USERSPACE, controlp); + msg.msg_iov = uiov; if (error) - return (error); - if (msg.msg_name && msg.msg_namelen > 2) - error = linux_sa_put(msg.msg_name); + goto bad; + + error = bsd_to_linux_msghdr(&msg, &linux_msg); + if (error) + goto bad; + + if (linux_msg.msg_name) { + error = bsd_to_linux_sockaddr((struct sockaddr *) + PTRIN(linux_msg.msg_name)); + if (error) + goto bad; + } + if (linux_msg.msg_name && linux_msg.msg_namelen > 2) { + error = linux_sa_put(PTRIN(linux_msg.msg_name)); + if (error) + goto bad; + } + + if (control) { + caddr_t outbuf; + struct cmsghdr *cm; + socklen_t datalen, outlen; + socklen_t clen; + void *data; + struct sockcred *scred; + struct l_ucred lcred; + + linux_cmsg = malloc(L_CMSG_HDRSZ, M_TEMP, M_WAITOK | M_ZERO); + outbuf = PTRIN(linux_msg.msg_control); + cm = mtod(control, struct cmsghdr *); + outlen = 0; + clen = control->m_len; + + while (cm != NULL) { + + switch (cm->cmsg_type) { + case SCM_CREDS: + + scred = (struct sockcred *)CMSG_DATA(cm); + datalen = (caddr_t)cm + cm->cmsg_len - + (caddr_t)scred; + + if (outlen + LINUX_CMSG_LEN(sizeof(lcred)) > + linux_msg.msg_controllen) { + linux_msg.msg_flags |= LINUX_MSG_CTRUNC; + goto out; + } + + lcred.pid = -1; + lcred.uid = scred->sc_uid; + lcred.gid = scred->sc_gid; + + linux_cmsg->cmsg_len = + LINUX_CMSG_LEN(sizeof(lcred)); + linux_cmsg->cmsg_type = + bsd_to_linux_cmsg_type(cm->cmsg_type); + linux_cmsg->cmsg_level = + bsd_to_linux_sockopt_level(cm->cmsg_level); + + error = copyout(linux_cmsg, outbuf, L_CMSG_HDRSZ); + if (error) + goto bad; + outbuf += L_CMSG_HDRSZ; + + error = copyout(&lcred, outbuf, sizeof(lcred)); + if (error) + goto bad; + + outbuf += LINUX_CMSG_ALIGN(sizeof(lcred)); + outlen += LINUX_CMSG_LEN(sizeof(lcred)); + linux_msg.msg_controllen = outlen; + break; + + default: + + data = CMSG_DATA(cm); + datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data; + + if (outlen + LINUX_CMSG_LEN(datalen) > + linux_msg.msg_controllen) { + linux_msg.msg_flags |= LINUX_MSG_CTRUNC; + goto out; + } + + linux_cmsg->cmsg_len = LINUX_CMSG_LEN(datalen); + linux_cmsg->cmsg_type = + bsd_to_linux_cmsg_type(cm->cmsg_type); + linux_cmsg->cmsg_level = + bsd_to_linux_sockopt_level(cm->cmsg_level); + + error = copyout(linux_cmsg, outbuf, L_CMSG_HDRSZ); + if (error) + goto bad; + outbuf += L_CMSG_HDRSZ; + + error = copyout(data, outbuf, datalen); + if (error) + goto bad; + + outbuf += LINUX_CMSG_ALIGN(datalen); + outlen += LINUX_CMSG_LEN(datalen); + linux_msg.msg_controllen = outlen; + break; + } + + if (CMSG_SPACE(datalen) < clen) { + clen -= CMSG_SPACE(datalen); + cm = (struct cmsghdr *) + ((caddr_t)cm + CMSG_SPACE(datalen)); + } else + cm = NULL; + } + } + +out: + error = copyout(&linux_msg, PTRIN(args->msg), sizeof(linux_msg)); + +bad: + free(iov, M_IOV); + if (control != NULL) + m_freem(control); + if (linux_cmsg != NULL) + free(linux_cmsg, M_TEMP); + return (error); } @@ -1081,6 +1303,12 @@ linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args) switch (bsd_args.level) { case SOL_SOCKET: name = linux_to_bsd_so_sockopt(args->optname); + switch (args->optname) { + case LINUX_SO_PASSCRED: + /* FreeBSD bug? socket level opts at non socket level */ + bsd_args.level = 0; + break; + } break; case IPPROTO_IP: name = linux_to_bsd_ip_sockopt(args->optname); @@ -1136,6 +1364,11 @@ linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args) switch (bsd_args.level) { case SOL_SOCKET: name = linux_to_bsd_so_sockopt(args->optname); + switch (args->optname) { + case LINUX_SO_PASSCRED: + bsd_args.level = 0; + break; + } break; case IPPROTO_IP: name = linux_to_bsd_ip_sockopt(args->optname); diff --git a/src/sys/compat/linux/linux_socket.h b/src/sys/compat/linux/linux_socket.h index 074e8e0..e8c2ec8 100644 --- a/src/sys/compat/linux/linux_socket.h +++ b/src/sys/compat/linux/linux_socket.h @@ -49,4 +49,36 @@ #define LINUX_MSG_ERRQUEUE 0x2000 #define LINUX_MSG_NOSIGNAL 0x4000 +/* Socket-level control message types */ + +#define LINUX_SCM_RIGHTS 0x01 +#define LINUX_SCM_CREDENTIALS 0x02 + +/* Ancilliary data object information macros */ + +#define LINUX_CMSG_ALIGN(len) (((len) + sizeof(l_long)-1) & ~(sizeof(l_long)-1)) +#define LINUX_CMSG_DATA(cmsg) ((void *)((char *)(cmsg) + \ + LINUX_CMSG_ALIGN(sizeof(struct l_cmsghdr)))) +#define LINUX_CMSG_SPACE(len) (LINUX_CMSG_ALIGN(sizeof(struct l_cmsghdr)) + \ + LINUX_CMSG_ALIGN(len)) +#define LINUX_CMSG_LEN(len) (LINUX_CMSG_ALIGN(sizeof(struct l_cmsghdr)) + \ + (len)) +#define LINUX_CMSG_FIRSTHDR(msg) \ + ((msg)->msg_controllen >= \ + sizeof(struct l_cmsghdr) ? \ + (struct l_cmsghdr *)((msg)->msg_control) : \ + (struct l_cmsghdr *)(NULL)) +#define LINUX_CMSG_NXTHDR(msg, cmsg) \ + ((((char *)(cmsg) + \ + LINUX_CMSG_ALIGN((cmsg)->cmsg_len) + \ + sizeof(*(cmsg))) > \ + (((char *)(msg)->msg_control) + \ + (msg)->msg_controllen)) ? \ + (struct l_cmsghdr *) NULL : \ + (struct l_cmsghdr *)((char *)(cmsg) + \ + LINUX_CMSG_ALIGN((cmsg)->cmsg_len))) + +#define CMSG_HDRSZ CMSG_LEN(0) +#define L_CMSG_HDRSZ LINUX_CMSG_LEN(0) + #endif /* _LINUX_SOCKET_H_ */ diff --git a/src/sys/i386/linux/linux.h b/src/sys/i386/linux/linux.h index 1c3627d..28655fe 100644 --- a/src/sys/i386/linux/linux.h +++ b/src/sys/i386/linux/linux.h @@ -656,6 +656,7 @@ union l_semun { #define LINUX_SO_NO_CHECK 11 #define LINUX_SO_PRIORITY 12 #define LINUX_SO_LINGER 13 +#define LINUX_SO_PASSCRED 16 #define LINUX_SO_PEERCRED 17 #define LINUX_SO_RCVLOWAT 18 #define LINUX_SO_SNDLOWAT 19 @@ -680,6 +681,28 @@ struct l_sockaddr { char sa_data[14]; }; +struct l_msghdr { + l_uintptr_t msg_name; + l_int msg_namelen; + l_uintptr_t msg_iov; + l_size_t msg_iovlen; + l_uintptr_t msg_control; + l_size_t msg_controllen; + l_uint msg_flags; +}; + +struct l_cmsghdr { + l_size_t cmsg_len; + l_int cmsg_level; + l_int cmsg_type; +}; + +struct l_ucred { + uint32_t pid; + uint32_t uid; + uint32_t gid; +}; + struct l_ifmap { l_ulong mem_start; l_ulong mem_end; -- Have fun! chd _______________________________________________ freebsd-emulation@... mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-emulation To unsubscribe, send any mail to "freebsd-emulation-unsubscribe@..." |
|
|
Re: [PATCH] recvmsg() sendmsg() linux emulationQuoting "Chagin Dmitry" <dchagin@...> (from Wed, 17 Sep 2008
23:02:30 +0400): > On Wed, Sep 17, 2008 at 10:38:01PM +0400, Chagin Dmitry wrote: >> >> Please review, any comment will be helpful. I did just a very quick look... > @@ -978,9 +1072,13 @@ linux_sendmsg(struct thread *td, struct > linux_sendmsg_args *args) > */ > if (msg.msg_control != NULL && msg.msg_controllen == 0) > msg.msg_control = NULL; > + > +#if defined(__amd64__) && defined(COMPAT_LINUX32) > + error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen, > + &iov, EMSGSIZE); > +#else > error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE); > - if (error) > - return (error); > +#endif > msg.msg_iov = iov; > msg.msg_flags = 0; > error = linux_sendit(td, args->s, &msg, args->flags, UIO_USERSPACE); You've lost the error handling in the conditional. Bye, Alexander. -- BOFH excuse #266: All of the packets are empty http://www.Leidinger.net Alexander @ Leidinger.net: PGP ID = B0063FE7 http://www.FreeBSD.org netchild @ FreeBSD.org : PGP ID = 72077137 _______________________________________________ freebsd-emulation@... mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-emulation To unsubscribe, send any mail to "freebsd-emulation-unsubscribe@..." |
|
|
Re: [PATCH] recvmsg() sendmsg() linux emulationOn Thu, Sep 18, 2008 at 09:38:31AM +0200, Alexander Leidinger wrote:
> Quoting "Chagin Dmitry" <dchagin@...> (from Wed, 17 Sep 2008 > 23:02:30 +0400): > > >On Wed, Sep 17, 2008 at 10:38:01PM +0400, Chagin Dmitry wrote: > >> > >>Please review, any comment will be helpful. > > I did just a very quick look... > > >@@ -978,9 +1072,13 @@ linux_sendmsg(struct thread *td, struct > >linux_sendmsg_args *args) > > */ > > if (msg.msg_control != NULL && msg.msg_controllen == 0) > > msg.msg_control = NULL; > >+ > >+#if defined(__amd64__) && defined(COMPAT_LINUX32) > >+ error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen, > >+ &iov, EMSGSIZE); > >+#else > > error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE); > >- if (error) > >- return (error); > >+#endif > > msg.msg_iov = iov; > > msg.msg_flags = 0; > > error = linux_sendit(td, args->s, &msg, args->flags, UIO_USERSPACE); > > You've lost the error handling in the conditional. > It's accepted, thnx! diff --git a/src/sys/amd64/linux32/linux.h b/src/sys/amd64/linux32/linux.h index 8940289..9439900 100644 --- a/src/sys/amd64/linux32/linux.h +++ b/src/sys/amd64/linux32/linux.h @@ -685,6 +685,7 @@ union l_semun { #define LINUX_SO_NO_CHECK 11 #define LINUX_SO_PRIORITY 12 #define LINUX_SO_LINGER 13 +#define LINUX_SO_PASSCRED 16 #define LINUX_SO_PEERCRED 17 #define LINUX_SO_RCVLOWAT 18 #define LINUX_SO_SNDLOWAT 19 @@ -709,6 +710,28 @@ struct l_sockaddr { char sa_data[14]; } __packed; +struct l_msghdr { + l_uintptr_t msg_name; + l_int msg_namelen; + l_uintptr_t msg_iov; + l_size_t msg_iovlen; + l_uintptr_t msg_control; + l_size_t msg_controllen; + l_uint msg_flags; +} __packed; + +struct l_cmsghdr { + l_size_t cmsg_len; + l_int cmsg_level; + l_int cmsg_type; +} __packed; + +struct l_ucred { + uint32_t pid; + uint32_t uid; + uint32_t gid; +} __packed; + struct l_ifmap { l_ulong mem_start; l_ulong mem_end; diff --git a/src/sys/amd64/linux32/linux32_io.h b/src/sys/amd64/linux32/linux32_io.h new file mode 100644 index 0000000..c1a9f1c --- /dev/null +++ b/src/sys/amd64/linux32/linux32_io.h @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 2004 Tim J. Robbins + * Copyright (c) 2001 Doug Rabson + * Copyright (c) 1994-1996 SЬren Schmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _AMD64_LINUX32_IO_H_ +#define _AMD64_LINUX32_IO_H_ + + +struct iovec32 { + u_int32_t iov_base; + int iov_len; +}; + +CTASSERT(sizeof(struct iovec32) == 8); + +int linux32_copyiniov(struct iovec32 *iovp32, u_int iovcnt, struct iovec **iovp, + int error); + +#endif /* !_AMD64_LINUX32_IO_H_ */ diff --git a/src/sys/amd64/linux32/linux32_machdep.c b/src/sys/amd64/linux32/linux32_machdep.c index 32cbe0b..26459c9 100644 --- a/src/sys/amd64/linux32/linux32_machdep.c +++ b/src/sys/amd64/linux32/linux32_machdep.c @@ -65,6 +65,7 @@ __FBSDID("$FreeBSD: src/sys/amd64/linux32/linux32_machdep.c,v 1.49 2008/09/08 09 #include <vm/vm_map.h> #include <amd64/linux32/linux.h> +#include <amd64/linux32/linux32_io.h> #include <amd64/linux32/linux32_proto.h> #include <compat/linux/linux_ipc.h> #include <compat/linux/linux_signal.h> @@ -232,13 +233,6 @@ linux_execve(struct thread *td, struct linux_execve_args *args) return (error); } -struct iovec32 { - u_int32_t iov_base; - int iov_len; -}; - -CTASSERT(sizeof(struct iovec32) == 8); - static int linux32_copyinuio(struct iovec32 *iovp, u_int iovcnt, struct uio **uiop) { @@ -281,6 +275,34 @@ linux32_copyinuio(struct iovec32 *iovp, u_int iovcnt, struct uio **uiop) } int +linux32_copyiniov(struct iovec32 *iovp32, u_int iovcnt, struct iovec **iovp, + int error) +{ + struct iovec32 iov32; + struct iovec *iov; + u_int iovlen; + int i; + + *iovp = NULL; + if (iovcnt > UIO_MAXIOV) + return (error); + iovlen = iovcnt * sizeof(struct iovec); + iov = malloc(iovlen, M_IOV, M_WAITOK); + for (i = 0; i < iovcnt; i++) { + error = copyin(&iovp32[i], &iov32, sizeof(struct iovec32)); + if (error) { + free(iov, M_IOV); + return (error); + } + iov[i].iov_base = PTRIN(iov32.iov_base); + iov[i].iov_len = iov32.iov_len; + } + *iovp = iov; + return(0); + +} + +int linux_readv(struct thread *td, struct linux_readv_args *uap) { struct uio *auio; diff --git a/src/sys/compat/linux/linux_socket.c b/src/sys/compat/linux/linux_socket.c index f97aa23..634389d 100644 --- a/src/sys/compat/linux/linux_socket.c +++ b/src/sys/compat/linux/linux_socket.c @@ -62,6 +62,7 @@ __FBSDID("$FreeBSD: src/sys/compat/linux/linux_socket.c,v 1.76 2008/09/09 13:01: #ifdef COMPAT_LINUX32 #include <machine/../linux32/linux.h> +#include <machine/../linux32/linux32_io.h> #include <machine/../linux32/linux32_proto.h> #else #include <machine/../linux/linux.h> @@ -294,6 +295,8 @@ linux_to_bsd_so_sockopt(int opt) return (SO_OOBINLINE); case LINUX_SO_LINGER: return (SO_LINGER); + case LINUX_SO_PASSCRED: + return (LOCAL_CREDS); case LINUX_SO_PEERCRED: return (LOCAL_PEERCRED); case LINUX_SO_RCVLOWAT: @@ -414,9 +417,64 @@ linux_sa_put(struct osockaddr *osa) sa.sa_family = bdom; error = copyout(&sa, osa, sizeof(sa.sa_family)); - if (error) - return (error); + return (error); +} + +static int +linux_to_bsd_cmsg_type(int cmsg_type) +{ + + switch (cmsg_type) { + case LINUX_SCM_RIGHTS: + return (SCM_RIGHTS); + case LINUX_SCM_CREDENTIALS: + return (SCM_CREDS); + } + return (cmsg_type); +} + +static int +bsd_to_linux_cmsg_type(int cmsg_type) +{ + + switch (cmsg_type) { + case SCM_RIGHTS: + return (LINUX_SCM_RIGHTS); + case SCM_CREDS: + return (LINUX_SCM_CREDENTIALS); + } + return (cmsg_type); +} + + + +static int +linux_to_bsd_msghdr(struct msghdr *bhdr, const struct l_msghdr *lhdr) +{ + if (lhdr->msg_controllen > INT_MAX) + return (ENOBUFS); + + bhdr->msg_name = PTRIN(lhdr->msg_name); + bhdr->msg_namelen = lhdr->msg_namelen; + bhdr->msg_iov = PTRIN(lhdr->msg_iov); + bhdr->msg_iovlen = lhdr->msg_iovlen; + bhdr->msg_control = PTRIN(lhdr->msg_control); + bhdr->msg_controllen = lhdr->msg_controllen; + bhdr->msg_flags = linux_to_bsd_msg_flags(lhdr->msg_flags); + return (0); +} + +static int +bsd_to_linux_msghdr(const struct msghdr *bhdr, struct l_msghdr *lhdr) +{ + lhdr->msg_name = PTROUT(bhdr->msg_name); + lhdr->msg_namelen = bhdr->msg_namelen; + lhdr->msg_iov = PTROUT(bhdr->msg_iov); + lhdr->msg_iovlen = bhdr->msg_iovlen; + lhdr->msg_control = PTROUT(bhdr->msg_control); + lhdr->msg_controllen = bhdr->msg_controllen; + /* msg_flags skipped */ return (0); } @@ -437,25 +495,57 @@ linux_sendit(struct thread *td, int s, struct msghdr *mp, int flags, to = NULL; if (mp->msg_control != NULL) { + struct l_cmsghdr *ptr_cmsg; + struct l_cmsghdr linux_cmsg; struct cmsghdr *cmsg; - - if (mp->msg_controllen < sizeof(struct cmsghdr)) { - error = EINVAL; - goto bad; - } - error = sockargs(&control, mp->msg_control, - mp->msg_controllen, MT_CONTROL); - if (error) - goto bad; - - cmsg = mtod(control, struct cmsghdr *); - cmsg->cmsg_level = linux_to_bsd_sockopt_level(cmsg->cmsg_level); + void *data; + socklen_t datalen; + + cmsg = malloc(CMSG_HDRSZ, M_TEMP, M_WAITOK | M_ZERO); + control = m_get(M_WAIT, MT_CONTROL); + ptr_cmsg = LINUX_CMSG_FIRSTHDR(mp); + + do { + error = copyin(ptr_cmsg, &linux_cmsg, + sizeof(struct l_cmsghdr)); + if (error) + goto bad; + if (linux_cmsg.cmsg_len < sizeof(struct l_cmsghdr) || + linux_cmsg.cmsg_len > INT_MAX) { + error = EINVAL; + goto bad; + } + + switch (linux_cmsg.cmsg_type) { + case LINUX_SCM_RIGHTS: + cmsg->cmsg_type = + linux_to_bsd_cmsg_type(linux_cmsg.cmsg_type); + break; + default: + error = EINVAL; + goto bad; + } + cmsg->cmsg_level = + linux_to_bsd_sockopt_level(linux_cmsg.cmsg_level); + + datalen = linux_cmsg.cmsg_len - L_CMSG_HDRSZ; + cmsg->cmsg_len = CMSG_LEN(datalen); + data = LINUX_CMSG_DATA(ptr_cmsg); + + error = ENOBUFS; + if (!m_append(control, CMSG_HDRSZ, (c_caddr_t) cmsg)) + goto bad; + if (!m_append(control, datalen, (c_caddr_t) data)) + goto bad; + + } while ((ptr_cmsg = LINUX_CMSG_NXTHDR(mp, ptr_cmsg))); + + free(cmsg, M_TEMP); } else control = NULL; error = kern_sendit(td, s, mp, linux_to_bsd_msg_flags(flags), control, segflg); - bad: if (to) FREE(to, M_SONAME); @@ -960,12 +1050,14 @@ static int linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args) { struct msghdr msg; + struct l_msghdr linux_msg; struct iovec *iov; int error; - /* XXXTJR sendmsg is broken on amd64 */ - - error = copyin(PTRIN(args->msg), &msg, sizeof(msg)); + error = copyin(PTRIN(args->msg), &linux_msg, sizeof(linux_msg)); + if (error) + return (error); + error = linux_to_bsd_msghdr(&msg, &linux_msg); if (error) return (error); @@ -978,7 +1070,13 @@ linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args) */ if (msg.msg_control != NULL && msg.msg_controllen == 0) msg.msg_control = NULL; + +#if defined(__amd64__) && defined(COMPAT_LINUX32) + error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen, + &iov, EMSGSIZE); +#else error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE); +#endif if (error) return (error); msg.msg_iov = iov; @@ -997,44 +1095,168 @@ struct linux_recvmsg_args { static int linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args) { - struct recvmsg_args /* { - int s; - struct msghdr *msg; - int flags; - } */ bsd_args; struct msghdr msg; - struct cmsghdr *cmsg; + struct l_msghdr linux_msg; + struct l_cmsghdr *linux_cmsg = NULL; + struct iovec *iov, *uiov; + struct mbuf *control = NULL; + struct mbuf **controlp; int error; - /* XXXTJR recvmsg is broken on amd64 */ + error = copyin(PTRIN(args->msg), &linux_msg, sizeof(linux_msg)); + if (error) + return (error); - if ((error = copyin(PTRIN(args->msg), &msg, sizeof (msg)))) + error = linux_to_bsd_msghdr(&msg, &linux_msg); + if (error) return (error); - bsd_args.s = args->s; - bsd_args.msg = PTRIN(args->msg); - bsd_args.flags = linux_to_bsd_msg_flags(args->flags); - if (msg.msg_name) { - linux_to_bsd_sockaddr((struct sockaddr *)msg.msg_name, - msg.msg_namelen); - error = recvmsg(td, &bsd_args); - bsd_to_linux_sockaddr((struct sockaddr *)msg.msg_name); - } else - error = recvmsg(td, &bsd_args); +#if defined(__amd64__) && defined(COMPAT_LINUX32) + error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen, + &iov, EMSGSIZE); +#else + error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE); +#endif if (error) return (error); - if (bsd_args.msg->msg_control != NULL && - bsd_args.msg->msg_controllen > 0) { - cmsg = (struct cmsghdr*)bsd_args.msg->msg_control; - cmsg->cmsg_level = bsd_to_linux_sockopt_level(cmsg->cmsg_level); + if (msg.msg_name) { + error = linux_to_bsd_sockaddr((struct sockaddr *)msg.msg_name, + msg.msg_namelen); + if (error) + goto bad; }   |