Module: xenomai-3 Branch: next Commit: 053df824650bb072381ce83e3928165eea2ce03e URL: http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=053df824650bb072381ce83e3928165eea2ce03e
Author: Philippe Gerum <r...@xenomai.org> Date: Wed Oct 22 15:20:21 2014 +0200 drivers/rtipc: fixup for 32bit emulation --- kernel/drivers/ipc/bufp.c | 115 ++++++------- kernel/drivers/ipc/iddp.c | 123 +++++++------- kernel/drivers/ipc/internal.h | 41 ++++- kernel/drivers/ipc/rtipc.c | 365 ++++++++++++++++++++++++++++++++++++----- kernel/drivers/ipc/xddp.c | 113 ++++++------- 5 files changed, 520 insertions(+), 237 deletions(-) diff --git a/kernel/drivers/ipc/bufp.c b/kernel/drivers/ipc/bufp.c index 1e5ecf3..5ae166a 100644 --- a/kernel/drivers/ipc/bufp.c +++ b/kernel/drivers/ipc/bufp.c @@ -375,17 +375,16 @@ static ssize_t bufp_recvmsg(struct rtdm_fd *fd, return -EINVAL; /* Copy I/O vector in */ - if (rtipc_get_arg(fd, iov, msg->msg_iov, - sizeof(iov[0]) * msg->msg_iovlen)) - return -EFAULT; + ret = rtipc_get_iovec(fd, iov, msg); + if (ret) + return ret; ret = __bufp_recvmsg(fd, iov, msg->msg_iovlen, flags, &saddr); if (ret <= 0) return ret; /* Copy the updated I/O vector back */ - if (rtipc_put_arg(fd, msg->msg_iov, iov, - sizeof(iov[0]) * msg->msg_iovlen)) + if (rtipc_put_iovec(fd, iov, msg)) return -EFAULT; /* Copy the source address if required. */ @@ -620,8 +619,7 @@ static ssize_t bufp_sendmsg(struct rtdm_fd *fd, return -EINVAL; /* Fetch the destination address to send to. */ - if (rtipc_get_arg(fd, &daddr, - msg->msg_name, sizeof(daddr))) + if (rtipc_get_arg(fd, &daddr, msg->msg_name, sizeof(daddr))) return -EFAULT; if (daddr.sipc_port < 0 || @@ -639,20 +637,16 @@ static ssize_t bufp_sendmsg(struct rtdm_fd *fd, return -EINVAL; /* Copy I/O vector in */ - if (rtipc_get_arg(fd, iov, msg->msg_iov, - sizeof(iov[0]) * msg->msg_iovlen)) - return -EFAULT; + ret = rtipc_get_iovec(fd, iov, msg); + if (ret) + return ret; ret = __bufp_sendmsg(fd, iov, msg->msg_iovlen, flags, &daddr); if (ret <= 0) return ret; /* Copy updated I/O vector back */ - if (rtipc_put_arg(fd, msg->msg_iov, iov, - sizeof(iov[0]) * msg->msg_iovlen)) - return -EFAULT; - - return ret; + return rtipc_put_iovec(fd, iov, msg) ?: ret; } static ssize_t bufp_write(struct rtdm_fd *fd, @@ -829,30 +823,27 @@ static int __bufp_setsockopt(struct bufp_socket *sk, struct rtipc_port_label plabel; struct timeval tv; rtdm_lockctx_t s; - int ret = 0; size_t len; + int ret; - if (rtipc_get_arg(fd, &sopt, arg, sizeof(sopt))) - return -EFAULT; + ret = rtipc_get_sockoptin(fd, &sopt, arg); + if (ret) + return ret; if (sopt.level == SOL_SOCKET) { switch (sopt.optname) { case SO_RCVTIMEO: - if (sopt.optlen != sizeof(tv)) - return -EINVAL; - if (rtipc_get_arg(fd, &tv, - sopt.optval, sizeof(tv))) - return -EFAULT; + ret = rtipc_get_timeval(fd, &tv, sopt.optval, sopt.optlen); + if (ret) + return ret; sk->rx_timeout = rtipc_timeval_to_ns(&tv); break; case SO_SNDTIMEO: - if (sopt.optlen != sizeof(tv)) - return -EINVAL; - if (rtipc_get_arg(fd, &tv, - sopt.optval, sizeof(tv))) - return -EFAULT; + ret = rtipc_get_timeval(fd, &tv, sopt.optval, sopt.optlen); + if (ret) + return ret; sk->tx_timeout = rtipc_timeval_to_ns(&tv); break; @@ -869,11 +860,9 @@ static int __bufp_setsockopt(struct bufp_socket *sk, switch (sopt.optname) { case BUFP_BUFSZ: - if (sopt.optlen != sizeof(len)) - return -EINVAL; - if (rtipc_get_arg(fd, &len, - sopt.optval, sizeof(len))) - return -EFAULT; + ret = rtipc_get_length(fd, &len, sopt.optval, sopt.optlen); + if (ret) + return ret; if (len == 0) return -EINVAL; cobalt_atomic_enter(s); @@ -892,8 +881,7 @@ static int __bufp_setsockopt(struct bufp_socket *sk, case BUFP_LABEL: if (sopt.optlen < sizeof(plabel)) return -EINVAL; - if (rtipc_get_arg(fd, &plabel, - sopt.optval, sizeof(plabel))) + if (rtipc_get_arg(fd, &plabel, sopt.optval, sizeof(plabel))) return -EFAULT; cobalt_atomic_enter(s); /* @@ -925,10 +913,11 @@ static int __bufp_getsockopt(struct bufp_socket *sk, struct timeval tv; rtdm_lockctx_t s; socklen_t len; - int ret = 0; + int ret; - if (rtipc_get_arg(fd, &sopt, arg, sizeof(sopt))) - return -EFAULT; + ret = rtipc_get_sockoptout(fd, &sopt, arg); + if (ret) + return ret; if (rtipc_get_arg(fd, &len, sopt.optlen, sizeof(len))) return -EFAULT; @@ -937,21 +926,17 @@ static int __bufp_getsockopt(struct bufp_socket *sk, switch (sopt.optname) { case SO_RCVTIMEO: - if (len != sizeof(tv)) - return -EINVAL; rtipc_ns_to_timeval(&tv, sk->rx_timeout); - if (rtipc_put_arg(fd, sopt.optval, - &tv, sizeof(tv))) - return -EFAULT; + ret = rtipc_put_timeval(fd, sopt.optval, &tv, len); + if (ret) + return ret; break; case SO_SNDTIMEO: - if (len != sizeof(tv)) - return -EINVAL; rtipc_ns_to_timeval(&tv, sk->tx_timeout); - if (rtipc_put_arg(fd, sopt.optval, - &tv, sizeof(tv))) - return -EFAULT; + ret = rtipc_put_timeval(fd, sopt.optval, &tv, len); + if (ret) + return ret; break; default: @@ -972,8 +957,7 @@ static int __bufp_getsockopt(struct bufp_socket *sk, cobalt_atomic_enter(s); strcpy(plabel.label, sk->label); cobalt_atomic_leave(s); - if (rtipc_put_arg(fd, sopt.optval, - &plabel, sizeof(plabel))) + if (rtipc_put_arg(fd, sopt.optval, &plabel, sizeof(plabel))) return -EFAULT; break; @@ -994,15 +978,15 @@ static int __bufp_ioctl(struct rtdm_fd *fd, switch (request) { - case _RTIOC_CONNECT: - ret = rtipc_get_sockaddr(fd, arg, &saddrp); + COMPAT_CASE(_RTIOC_CONNECT): + ret = rtipc_get_sockaddr(fd, &saddrp, arg); if (ret) return ret; ret = __bufp_connect_socket(sk, saddrp); break; - case _RTIOC_BIND: - ret = rtipc_get_sockaddr(fd, arg, &saddrp); + COMPAT_CASE(_RTIOC_BIND): + ret = rtipc_get_sockaddr(fd, &saddrp, arg); if (ret) return ret; if (saddrp == NULL) @@ -1010,24 +994,24 @@ static int __bufp_ioctl(struct rtdm_fd *fd, ret = __bufp_bind_socket(priv, saddrp); break; - case _RTIOC_GETSOCKNAME: + COMPAT_CASE(_RTIOC_GETSOCKNAME): ret = rtipc_put_sockaddr(fd, arg, &sk->name); break; - case _RTIOC_GETPEERNAME: + COMPAT_CASE(_RTIOC_GETPEERNAME): ret = rtipc_put_sockaddr(fd, arg, &sk->peer); break; - case _RTIOC_SETSOCKOPT: + COMPAT_CASE(_RTIOC_SETSOCKOPT): ret = __bufp_setsockopt(sk, fd, arg); break; - case _RTIOC_GETSOCKOPT: + COMPAT_CASE(_RTIOC_GETSOCKOPT): ret = __bufp_getsockopt(sk, fd, arg); break; case _RTIOC_LISTEN: - case _RTIOC_ACCEPT: + COMPAT_CASE(_RTIOC_ACCEPT): ret = -EOPNOTSUPP; break; @@ -1045,10 +1029,17 @@ static int __bufp_ioctl(struct rtdm_fd *fd, static int bufp_ioctl(struct rtdm_fd *fd, unsigned int request, void *arg) { - if (rtdm_in_rt_context() && request == _RTIOC_BIND) - return -ENOSYS; /* Try downgrading to NRT */ + int ret; - return __bufp_ioctl(fd, request, arg); + switch (request) { + COMPAT_CASE(_RTIOC_BIND): + if (rtdm_in_rt_context()) + return -ENOSYS; /* Try downgrading to NRT */ + default: + ret = __bufp_ioctl(fd, request, arg); + } + + return ret; } static unsigned int bufp_pollstate(struct rtdm_fd *fd) diff --git a/kernel/drivers/ipc/iddp.c b/kernel/drivers/ipc/iddp.c index a2406da..d37c784 100644 --- a/kernel/drivers/ipc/iddp.c +++ b/kernel/drivers/ipc/iddp.c @@ -344,23 +344,21 @@ static ssize_t iddp_recvmsg(struct rtdm_fd *fd, return -EINVAL; /* Copy I/O vector in */ - if (rtipc_get_arg(fd, iov, msg->msg_iov, - sizeof(iov[0]) * msg->msg_iovlen)) - return -EFAULT; + ret = rtipc_get_iovec(fd, iov, msg); + if (ret) + return ret; ret = __iddp_recvmsg(fd, iov, msg->msg_iovlen, flags, &saddr); if (ret <= 0) return ret; /* Copy the updated I/O vector back */ - if (rtipc_put_arg(fd, msg->msg_iov, iov, - sizeof(iov[0]) * msg->msg_iovlen)) + if (rtipc_put_iovec(fd, iov, msg)) return -EFAULT; /* Copy the source address if required. */ if (msg->msg_name) { - if (rtipc_put_arg(fd, msg->msg_name, - &saddr, sizeof(saddr))) + if (rtipc_put_arg(fd, msg->msg_name, &saddr, sizeof(saddr))) return -EFAULT; msg->msg_namelen = sizeof(struct sockaddr_ipc); } @@ -484,8 +482,7 @@ static ssize_t iddp_sendmsg(struct rtdm_fd *fd, return -EINVAL; /* Fetch the destination address to send to. */ - if (rtipc_get_arg(fd, &daddr, - msg->msg_name, sizeof(daddr))) + if (rtipc_get_arg(fd, &daddr, msg->msg_name, sizeof(daddr))) return -EFAULT; if (daddr.sipc_port < 0 || @@ -503,20 +500,16 @@ static ssize_t iddp_sendmsg(struct rtdm_fd *fd, return -EINVAL; /* Copy I/O vector in */ - if (rtipc_get_arg(fd, iov, msg->msg_iov, - sizeof(iov[0]) * msg->msg_iovlen)) - return -EFAULT; + ret = rtipc_get_iovec(fd, iov, msg); + if (ret) + return ret; ret = __iddp_sendmsg(fd, iov, msg->msg_iovlen, flags, &daddr); if (ret <= 0) return ret; /* Copy updated I/O vector back */ - if (rtipc_put_arg(fd, msg->msg_iov, iov, - sizeof(iov[0]) * msg->msg_iovlen)) - return -EFAULT; - - return ret; + return rtipc_put_iovec(fd, iov, msg) ?: ret; } static ssize_t iddp_write(struct rtdm_fd *fd, @@ -706,30 +699,27 @@ static int __iddp_setsockopt(struct iddp_socket *sk, struct rtipc_port_label plabel; struct timeval tv; rtdm_lockctx_t s; - int ret = 0; size_t len; + int ret; - if (rtipc_get_arg(fd, &sopt, arg, sizeof(sopt))) - return -EFAULT; + ret = rtipc_get_sockoptin(fd, &sopt, arg); + if (ret) + return ret; if (sopt.level == SOL_SOCKET) { switch (sopt.optname) { case SO_RCVTIMEO: - if (sopt.optlen != sizeof(tv)) - return -EINVAL; - if (rtipc_get_arg(fd, &tv, - sopt.optval, sizeof(tv))) - return -EFAULT; + ret = rtipc_get_timeval(fd, &tv, sopt.optval, sopt.optlen); + if (ret) + return ret; sk->rx_timeout = rtipc_timeval_to_ns(&tv); break; case SO_SNDTIMEO: - if (sopt.optlen != sizeof(tv)) - return -EINVAL; - if (rtipc_get_arg(fd, &tv, - sopt.optval, sizeof(tv))) - return -EFAULT; + ret = rtipc_get_timeval(fd, &tv, sopt.optval, sopt.optlen); + if (ret) + return ret; sk->tx_timeout = rtipc_timeval_to_ns(&tv); break; @@ -746,11 +736,9 @@ static int __iddp_setsockopt(struct iddp_socket *sk, switch (sopt.optname) { case IDDP_POOLSZ: - if (sopt.optlen != sizeof(len)) - return -EINVAL; - if (rtipc_get_arg(fd, &len, - sopt.optval, sizeof(len))) - return -EFAULT; + ret = rtipc_get_length(fd, &len, sopt.optval, sopt.optlen); + if (ret) + return ret; if (len == 0) return -EINVAL; cobalt_atomic_enter(s); @@ -769,8 +757,7 @@ static int __iddp_setsockopt(struct iddp_socket *sk, case IDDP_LABEL: if (sopt.optlen < sizeof(plabel)) return -EINVAL; - if (rtipc_get_arg(fd, &plabel, - sopt.optval, sizeof(plabel))) + if (rtipc_get_arg(fd, &plabel, sopt.optval, sizeof(plabel))) return -EFAULT; cobalt_atomic_enter(s); /* @@ -802,33 +789,31 @@ static int __iddp_getsockopt(struct iddp_socket *sk, struct timeval tv; rtdm_lockctx_t s; socklen_t len; - int ret = 0; + int ret; - if (rtipc_get_arg(fd, &sopt, arg, sizeof(sopt))) - return -EFAULT; + ret = rtipc_get_sockoptout(fd, &sopt, arg); + if (ret) + return ret; - if (rtipc_get_arg(fd, &len, sopt.optlen, sizeof(len))) - return -EFAULT; + ret = rtipc_get_arg(fd, &len, sopt.optlen, sizeof(len)); + if (ret) + return ret; if (sopt.level == SOL_SOCKET) { switch (sopt.optname) { case SO_RCVTIMEO: - if (len != sizeof(tv)) - return -EINVAL; rtipc_ns_to_timeval(&tv, sk->rx_timeout); - if (rtipc_put_arg(fd, sopt.optval, - &tv, sizeof(tv))) - return -EFAULT; + ret = rtipc_put_timeval(fd, sopt.optval, &tv, len); + if (ret) + return ret; break; case SO_SNDTIMEO: - if (len != sizeof(tv)) - return -EINVAL; rtipc_ns_to_timeval(&tv, sk->tx_timeout); - if (rtipc_put_arg(fd, sopt.optval, - &tv, sizeof(tv))) - return -EFAULT; + ret = rtipc_put_timeval(fd, sopt.optval, &tv, len); + if (ret) + return ret; break; default: @@ -849,8 +834,7 @@ static int __iddp_getsockopt(struct iddp_socket *sk, cobalt_atomic_enter(s); strcpy(plabel.label, sk->label); cobalt_atomic_leave(s); - if (rtipc_put_arg(fd, sopt.optval, - &plabel, sizeof(plabel))) + if (rtipc_put_arg(fd, sopt.optval, &plabel, sizeof(plabel))) return -EFAULT; break; @@ -871,15 +855,15 @@ static int __iddp_ioctl(struct rtdm_fd *fd, switch (request) { - case _RTIOC_CONNECT: - ret = rtipc_get_sockaddr(fd, arg, &saddrp); + COMPAT_CASE(_RTIOC_CONNECT): + ret = rtipc_get_sockaddr(fd, &saddrp, arg); if (ret) return ret; ret = __iddp_connect_socket(sk, saddrp); break; - case _RTIOC_BIND: - ret = rtipc_get_sockaddr(fd, arg, &saddrp); + COMPAT_CASE(_RTIOC_BIND): + ret = rtipc_get_sockaddr(fd, &saddrp, arg); if (ret) return ret; if (saddrp == NULL) @@ -887,24 +871,24 @@ static int __iddp_ioctl(struct rtdm_fd *fd, ret = __iddp_bind_socket(fd, saddrp); break; - case _RTIOC_GETSOCKNAME: + COMPAT_CASE(_RTIOC_GETSOCKNAME): ret = rtipc_put_sockaddr(fd, arg, &sk->name); break; - case _RTIOC_GETPEERNAME: + COMPAT_CASE(_RTIOC_GETPEERNAME): ret = rtipc_put_sockaddr(fd, arg, &sk->peer); break; - case _RTIOC_SETSOCKOPT: + COMPAT_CASE(_RTIOC_SETSOCKOPT): ret = __iddp_setsockopt(sk, fd, arg); break; - case _RTIOC_GETSOCKOPT: + COMPAT_CASE(_RTIOC_GETSOCKOPT): ret = __iddp_getsockopt(sk, fd, arg); break; case _RTIOC_LISTEN: - case _RTIOC_ACCEPT: + COMPAT_CASE(_RTIOC_ACCEPT): ret = -EOPNOTSUPP; break; @@ -922,10 +906,17 @@ static int __iddp_ioctl(struct rtdm_fd *fd, static int iddp_ioctl(struct rtdm_fd *fd, unsigned int request, void *arg) { - if (rtdm_in_rt_context() && request == _RTIOC_BIND) - return -ENOSYS; /* Try downgrading to NRT */ + int ret; - return __iddp_ioctl(fd, request, arg); + switch (request) { + COMPAT_CASE(_RTIOC_BIND): + if (rtdm_in_rt_context()) + return -ENOSYS; /* Try downgrading to NRT */ + default: + ret = __iddp_ioctl(fd, request, arg); + } + + return ret; } static int iddp_init(void) diff --git a/kernel/drivers/ipc/internal.h b/kernel/drivers/ipc/internal.h index b857a40..aeb7abd 100644 --- a/kernel/drivers/ipc/internal.h +++ b/kernel/drivers/ipc/internal.h @@ -24,6 +24,7 @@ #include <cobalt/kernel/clock.h> #include <cobalt/kernel/select.h> #include <rtdm/rtdm.h> +#include <rtdm/compat.h> #include <rtdm/driver.h> #define RTIPC_IOV_MAX 64 @@ -83,18 +84,45 @@ static inline void rtipc_ns_to_timeval(struct timeval *tv, nanosecs_rel_t ns) tv->tv_usec = nsecs / 1000; } -int rtipc_get_arg(struct rtdm_fd *fd, - void *dst, const void *src, size_t len); +int rtipc_get_iovec(struct rtdm_fd *fd, struct iovec *iov, + const struct msghdr *msg); -int rtipc_put_arg(struct rtdm_fd *fd, - void *dst, const void *src, size_t len); +int rtipc_put_iovec(struct rtdm_fd *fd, const struct iovec *iov, + const struct msghdr *msg); int rtipc_get_sockaddr(struct rtdm_fd *fd, - const void *arg, struct sockaddr_ipc **saddrp); + struct sockaddr_ipc **saddrp, + const void *arg); int rtipc_put_sockaddr(struct rtdm_fd *fd, void *arg, const struct sockaddr_ipc *saddr); +int rtipc_get_sockoptout(struct rtdm_fd *fd, + struct _rtdm_getsockopt_args *sopt, + const void *arg); + +int rtipc_put_sockoptout(struct rtdm_fd *fd, void *arg, + const struct _rtdm_getsockopt_args *sopt); + +int rtipc_get_sockoptin(struct rtdm_fd *fd, + struct _rtdm_setsockopt_args *sopt, + const void *arg); + +int rtipc_get_timeval(struct rtdm_fd *fd, struct timeval *tv, + const void *arg, size_t arglen); + +int rtipc_put_timeval(struct rtdm_fd *fd, void *arg, + const struct timeval *tv, size_t arglen); + +int rtipc_get_length(struct rtdm_fd *fd, size_t *lenp, + const void *arg, size_t arglen); + +int rtipc_get_arg(struct rtdm_fd *fd, void *dst, const void *src, + size_t len); + +int rtipc_put_arg(struct rtdm_fd *fd, void *dst, const void *src, + size_t len); + ssize_t rtipc_get_iov_flatlen(struct iovec *iov, int iovlen); extern struct rtipc_protocol xddp_proto_driver; @@ -108,7 +136,8 @@ extern struct xnptree rtipc_ptree; #define rtipc_wait_context xnthread_wait_context #define rtipc_prepare_wait xnthread_prepare_wait #define rtipc_get_wait_context xnthread_get_wait_context - #define rtipc_peek_wait_head(obj) xnsynch_peek_pendq(&(obj)->synch_base) +#define COMPAT_CASE(__op) case __op __COMPAT_CASE(__op ## _COMPAT) + #endif /* !_RTIPC_INTERNAL_H */ diff --git a/kernel/drivers/ipc/rtipc.c b/kernel/drivers/ipc/rtipc.c index c0ea808..4c569c7 100644 --- a/kernel/drivers/ipc/rtipc.c +++ b/kernel/drivers/ipc/rtipc.c @@ -42,51 +42,139 @@ static struct rtipc_protocol *protocols[IPCPROTO_MAX] = { DEFINE_XNPTREE(rtipc_ptree, "rtipc"); -int rtipc_get_arg(struct rtdm_fd *fd, - void *dst, const void *src, size_t len) +int rtipc_get_arg(struct rtdm_fd *fd, void *dst, const void *src, size_t len) { - if (rtdm_fd_is_user(fd)) { - if (rtdm_safe_copy_from_user(fd, dst, src, len)) - return -EFAULT; - } else + if (!rtdm_fd_is_user(fd)) { memcpy(dst, src, len); + return 0; + } - return 0; + return rtdm_copy_from_user(fd, dst, src, len); } -int rtipc_put_arg(struct rtdm_fd *fd, - void *dst, const void *src, size_t len) +int rtipc_put_arg(struct rtdm_fd *fd, void *dst, const void *src, size_t len) { - if (rtdm_fd_is_user(fd)) { - if (rtdm_safe_copy_to_user(fd, dst, src, len)) - return -EFAULT; - } else + if (!rtdm_fd_is_user(fd)) { memcpy(dst, src, len); + return 0; + } - return 0; + return rtdm_copy_to_user(fd, dst, src, len); } -int rtipc_get_sockaddr(struct rtdm_fd *fd, - const void *arg, struct sockaddr_ipc **saddrp) +int rtipc_get_iovec(struct rtdm_fd *fd, struct iovec *iov, + const struct msghdr *msg) { - struct _rtdm_setsockaddr_args setaddr; + size_t len = sizeof(iov[0]) * msg->msg_iovlen; + if (!rtdm_fd_is_user(fd)) { + memcpy(iov, msg->msg_iov, len); + return 0; + } - if (rtipc_get_arg(fd, - &setaddr, arg, sizeof(setaddr))) - return -EFAULT; +#ifdef CONFIG_COMPAT + if (rtdm_fd_is_compat(fd)) { + struct compat_iovec ciov, __user *p; + int ret, n; + for (n = 0, p = (struct compat_iovec *)msg->msg_iov; + n < msg->msg_iovlen; n++, p++) { + ret = rtdm_copy_from_user(fd, &ciov, p, sizeof(ciov)); + if (ret) + return ret; + iov[n].iov_base = compat_ptr(ciov.iov_base); + iov[n].iov_len = ciov.iov_len; + } + return 0; + } +#endif - if (setaddr.addrlen > 0) { - if (setaddr.addrlen != sizeof(**saddrp)) - return -EINVAL; + return rtdm_copy_from_user(fd, iov, msg->msg_iov, len); +} + +int rtipc_put_iovec(struct rtdm_fd *fd, const struct iovec *iov, + const struct msghdr *msg) +{ + size_t len = sizeof(iov[0]) * msg->msg_iovlen; + + if (!rtdm_fd_is_user(fd)) { + memcpy(msg->msg_iov, iov, len); + return 0; + } + +#ifdef CONFIG_COMPAT + if (rtdm_fd_is_compat(fd)) { + struct compat_iovec ciov, __user *p; + int ret, n; + for (n = 0, p = (struct compat_iovec *)msg->msg_iov; + n < msg->msg_iovlen; n++, p++) { + ciov.iov_base = ptr_to_compat(iov[n].iov_base); + ciov.iov_len = iov[n].iov_len; + ret = rtdm_copy_to_user(fd, p, &ciov, sizeof(*p)); + if (ret) + return ret; + } + return 0; + } +#endif + + return rtdm_copy_to_user(fd, msg->msg_iov, iov, len); +} + +int rtipc_get_sockaddr(struct rtdm_fd *fd, struct sockaddr_ipc **saddrp, + const void *arg) +{ + const struct _rtdm_setsockaddr_args *p; + struct _rtdm_setsockaddr_args sreq; + int ret; - if (rtipc_get_arg(fd, *saddrp, - setaddr.addr, sizeof(**saddrp))) - return -EFAULT; - } else { - if (setaddr.addr) + if (!rtdm_fd_is_user(fd)) { + p = arg; + if (p->addrlen > 0) { + if (p->addrlen != sizeof(**saddrp)) + return -EINVAL; + memcpy(*saddrp, p->addr, sizeof(**saddrp)); + } else { + if (p->addr) + return -EINVAL; + *saddrp = NULL; + } + return 0; + } + +#ifdef CONFIG_COMPAT + if (rtdm_fd_is_compat(fd)) { + struct compat_rtdm_setsockaddr_args csreq; + ret = rtdm_safe_copy_from_user(fd, &csreq, arg, sizeof(csreq)); + if (ret) + return ret; + if (csreq.addrlen > 0) { + if (csreq.addrlen != sizeof(**saddrp)) + return -EINVAL; + return rtdm_safe_copy_from_user(fd, *saddrp, + compat_ptr(csreq.addr), + sizeof(**saddrp)); + } + if (csreq.addr) return -EINVAL; + *saddrp = NULL; + + return 0; } +#endif + + ret = rtdm_safe_copy_from_user(fd, &sreq, arg, sizeof(sreq)); + if (ret) + return ret; + if (sreq.addrlen > 0) { + if (sreq.addrlen != sizeof(**saddrp)) + return -EINVAL; + return rtdm_safe_copy_from_user(fd, *saddrp, + sreq.addr, sizeof(**saddrp)); + } + if (sreq.addr) + return -EINVAL; + + *saddrp = NULL; return 0; } @@ -94,30 +182,223 @@ int rtipc_get_sockaddr(struct rtdm_fd *fd, int rtipc_put_sockaddr(struct rtdm_fd *fd, void *arg, const struct sockaddr_ipc *saddr) { - struct _rtdm_getsockaddr_args getaddr; + const struct _rtdm_getsockaddr_args *p; + struct _rtdm_getsockaddr_args sreq; socklen_t len; + int ret; - if (rtipc_get_arg(fd, - &getaddr, arg, sizeof(getaddr))) - return -EFAULT; + if (!rtdm_fd_is_user(fd)) { + p = arg; + if (*p->addrlen < sizeof(*saddr)) + return -EINVAL; + memcpy(p->addr, saddr, sizeof(*saddr)); + *p->addrlen = sizeof(*saddr); + return 0; + } + +#ifdef CONFIG_COMPAT + if (rtdm_fd_is_compat(fd)) { + struct compat_rtdm_getsockaddr_args csreq; + ret = rtdm_safe_copy_from_user(fd, &csreq, arg, sizeof(csreq)); + if (ret) + return ret; + + ret = rtdm_safe_copy_from_user(fd, &len, + compat_ptr(csreq.addrlen), + sizeof(len)); + if (ret) + return ret; + + if (len < sizeof(*saddr)) + return -EINVAL; + + ret = rtdm_safe_copy_to_user(fd, compat_ptr(csreq.addr), + saddr, sizeof(*saddr)); + if (ret) + return ret; + + len = sizeof(*saddr); + return rtdm_safe_copy_to_user(fd, compat_ptr(csreq.addrlen), + &len, sizeof(len)); + } +#endif + + ret = rtdm_safe_copy_from_user(fd, &sreq, arg, sizeof(sreq)); + if (ret) + return ret; - if (rtipc_get_arg(fd, - &len, getaddr.addrlen, sizeof(len))) - return -EFAULT; + ret = rtdm_safe_copy_from_user(fd, &len, sreq.addrlen, sizeof(len)); + if (ret) + return ret; if (len < sizeof(*saddr)) return -EINVAL; - if (rtipc_put_arg(fd, - getaddr.addr, saddr, sizeof(*saddr))) - return -EFAULT; + ret = rtdm_safe_copy_to_user(fd, sreq.addr, saddr, sizeof(*saddr)); + if (ret) + return ret; len = sizeof(*saddr); - if (rtipc_put_arg(fd, - getaddr.addrlen, &len, sizeof(len))) - return -EFAULT; - return 0; + return rtdm_safe_copy_to_user(fd, sreq.addrlen, &len, sizeof(len)); +} + +int rtipc_get_sockoptout(struct rtdm_fd *fd, struct _rtdm_getsockopt_args *sopt, + const void *arg) +{ + if (!rtdm_fd_is_user(fd)) { + *sopt = *(struct _rtdm_getsockopt_args *)arg; + return 0; + } + +#ifdef CONFIG_COMPAT + if (rtdm_fd_is_compat(fd)) { + struct compat_rtdm_getsockopt_args csopt; + int ret; + ret = rtdm_safe_copy_from_user(fd, &csopt, arg, sizeof(csopt)); + if (ret) + return ret; + sopt->level = csopt.level; + sopt->optname = csopt.optname; + sopt->optval = compat_ptr(csopt.optval); + sopt->optlen = compat_ptr(csopt.optlen); + return 0; + } +#endif + + return rtdm_safe_copy_from_user(fd, sopt, arg, sizeof(*sopt)); +} + +int rtipc_put_sockoptout(struct rtdm_fd *fd, void *arg, + const struct _rtdm_getsockopt_args *sopt) +{ + if (!rtdm_fd_is_user(fd)) { + *(struct _rtdm_getsockopt_args *)arg = *sopt; + return 0; + } + +#ifdef CONFIG_COMPAT + if (rtdm_fd_is_compat(fd)) { + struct compat_rtdm_getsockopt_args csopt; + int ret; + csopt.level = sopt->level; + csopt.optname = sopt->optname; + csopt.optval = ptr_to_compat(sopt->optval); + csopt.optlen = ptr_to_compat(sopt->optlen); + ret = rtdm_safe_copy_to_user(fd, arg, &csopt, sizeof(csopt)); + if (ret) + return ret; + return 0; + } +#endif + + return rtdm_safe_copy_to_user(fd, arg, sopt, sizeof(*sopt)); +} + +int rtipc_get_sockoptin(struct rtdm_fd *fd, struct _rtdm_setsockopt_args *sopt, + const void *arg) +{ + if (!rtdm_fd_is_user(fd)) { + *sopt = *(struct _rtdm_setsockopt_args *)arg; + return 0; + } + +#ifdef CONFIG_COMPAT + if (rtdm_fd_is_compat(fd)) { + struct compat_rtdm_setsockopt_args csopt; + int ret; + ret = rtdm_safe_copy_from_user(fd, &csopt, arg, sizeof(csopt)); + if (ret) + return ret; + sopt->level = csopt.level; + sopt->optname = csopt.optname; + sopt->optval = compat_ptr(csopt.optval); + sopt->optlen = csopt.optlen; + return 0; + } +#endif + + return rtdm_safe_copy_from_user(fd, sopt, arg, sizeof(*sopt)); +} + +int rtipc_get_timeval(struct rtdm_fd *fd, struct timeval *tv, + const void *arg, size_t arglen) +{ +#ifdef CONFIG_COMPAT + if (rtdm_fd_is_compat(fd)) { + const struct compat_timeval *ctv; + if (arglen != sizeof(*ctv)) + return -EINVAL; + ctv = arg; + return (ctv == NULL || + !access_rok(ctv, sizeof(*ctv)) || + __xn_get_user(tv->tv_sec, &ctv->tv_sec) || + __xn_get_user(tv->tv_usec, &ctv->tv_usec)) ? -EFAULT : 0; + } +#endif + + if (arglen != sizeof(*tv)) + return -EINVAL; + + if (!rtdm_fd_is_user(fd)) { + *tv = *(struct timeval *)arg; + return 0; + } + + return rtdm_safe_copy_from_user(fd, tv, arg, sizeof(*tv)); +} + +int rtipc_put_timeval(struct rtdm_fd *fd, void *arg, + const struct timeval *tv, size_t arglen) +{ +#ifdef CONFIG_COMPAT + if (rtdm_fd_is_compat(fd)) { + struct compat_timeval *ctv; + if (arglen != sizeof(*ctv)) + return -EINVAL; + ctv = arg; + return (ctv == NULL || + !access_wok(ctv, sizeof(*ctv)) || + __xn_put_user(tv->tv_sec, &ctv->tv_sec) || + __xn_put_user(tv->tv_usec, &ctv->tv_usec)) ? -EFAULT : 0; + } +#endif + + if (arglen != sizeof(*tv)) + return -EINVAL; + + if (!rtdm_fd_is_user(fd)) { + *(struct timeval *)arg = *tv; + return 0; + } + + return rtdm_safe_copy_to_user(fd, arg, tv, sizeof(*tv)); +} + +int rtipc_get_length(struct rtdm_fd *fd, size_t *lenp, + const void *arg, size_t arglen) +{ +#ifdef CONFIG_COMPAT + if (rtdm_fd_is_compat(fd)) { + const compat_size_t *csz; + if (arglen != sizeof(*csz)) + return -EINVAL; + csz = arg; + return csz == NULL || + !access_rok(csz, sizeof(*csz)) || + __xn_get_user(*lenp, csz) ? -EFAULT : 0; + } +#endif + + if (arglen != sizeof(size_t)) + return -EINVAL; + + if (!rtdm_fd_is_user(fd)) { + *lenp = *(size_t *)arg; + return 0; + } + + return rtdm_safe_copy_from_user(fd, lenp, arg, sizeof(*lenp)); } ssize_t rtipc_get_iov_flatlen(struct iovec *iov, int iovlen) diff --git a/kernel/drivers/ipc/xddp.c b/kernel/drivers/ipc/xddp.c index aa6704a..8f1333d 100644 --- a/kernel/drivers/ipc/xddp.c +++ b/kernel/drivers/ipc/xddp.c @@ -349,23 +349,21 @@ static ssize_t xddp_recvmsg(struct rtdm_fd *fd, return -EINVAL; /* Copy I/O vector in */ - if (rtipc_get_arg(fd, iov, msg->msg_iov, - sizeof(iov[0]) * msg->msg_iovlen)) - return -EFAULT; + ret = rtipc_get_iovec(fd, iov, msg); + if (ret) + return ret; ret = __xddp_recvmsg(fd, iov, msg->msg_iovlen, flags, &saddr); if (ret <= 0) return ret; /* Copy the updated I/O vector back */ - if (rtipc_put_arg(fd, msg->msg_iov, iov, - sizeof(iov[0]) * msg->msg_iovlen)) + if (rtipc_put_iovec(fd, iov, msg)) return -EFAULT; /* Copy the source address if required. */ if (msg->msg_name) { - if (rtipc_put_arg(fd, msg->msg_name, - &saddr, sizeof(saddr))) + if (rtipc_put_arg(fd, msg->msg_name, &saddr, sizeof(saddr))) return -EFAULT; msg->msg_namelen = sizeof(struct sockaddr_ipc); } @@ -619,8 +617,7 @@ static ssize_t xddp_sendmsg(struct rtdm_fd *fd, return -EINVAL; /* Fetch the destination address to send to. */ - if (rtipc_get_arg(fd, &daddr, - msg->msg_name, sizeof(daddr))) + if (rtipc_get_arg(fd, &daddr, msg->msg_name, sizeof(daddr))) return -EFAULT; if (daddr.sipc_port < 0 || @@ -638,20 +635,16 @@ static ssize_t xddp_sendmsg(struct rtdm_fd *fd, return -EINVAL; /* Copy I/O vector in */ - if (rtipc_get_arg(fd, iov, msg->msg_iov, - sizeof(iov[0]) * msg->msg_iovlen)) - return -EFAULT; + ret = rtipc_get_iovec(fd, iov, msg); + if (ret) + return ret; ret = __xddp_sendmsg(fd, iov, msg->msg_iovlen, flags, &daddr); if (ret <= 0) return ret; /* Copy updated I/O vector back */ - if (rtipc_put_arg(fd, msg->msg_iov, iov, - sizeof(iov[0]) * msg->msg_iovlen)) - return -EFAULT; - - return ret; + return rtipc_put_iovec(fd, iov, msg) ?: ret; } static ssize_t xddp_write(struct rtdm_fd *fd, @@ -860,21 +853,20 @@ static int __xddp_setsockopt(struct xddp_socket *sk, struct rtipc_port_label plabel; struct timeval tv; rtdm_lockctx_t s; - int ret = 0; size_t len; + int ret; - if (rtipc_get_arg(fd, &sopt, arg, sizeof(sopt))) - return -EFAULT; + ret = rtipc_get_sockoptin(fd, &sopt, arg); + if (ret) + return ret; if (sopt.level == SOL_SOCKET) { switch (sopt.optname) { case SO_RCVTIMEO: - if (sopt.optlen != sizeof(tv)) - return -EINVAL; - if (rtipc_get_arg(fd, &tv, - sopt.optval, sizeof(tv))) - return -EFAULT; + ret = rtipc_get_timeval(fd, &tv, sopt.optval, sopt.optlen); + if (ret) + return ret; sk->timeout = rtipc_timeval_to_ns(&tv); break; @@ -891,11 +883,9 @@ static int __xddp_setsockopt(struct xddp_socket *sk, switch (sopt.optname) { case XDDP_BUFSZ: - if (sopt.optlen != sizeof(len)) - return -EINVAL; - if (rtipc_get_arg(fd, &len, - sopt.optval, sizeof(len))) - return -EFAULT; + ret = rtipc_get_length(fd, &len, sopt.optval, sopt.optlen); + if (ret) + return ret; if (len > 0) { len += sizeof(struct xddp_message); if (sk->bufpool && @@ -913,11 +903,9 @@ static int __xddp_setsockopt(struct xddp_socket *sk, break; case XDDP_POOLSZ: - if (sopt.optlen != sizeof(len)) - return -EINVAL; - if (rtipc_get_arg(fd, &len, - sopt.optval, sizeof(len))) - return -EFAULT; + ret = rtipc_get_length(fd, &len, sopt.optval, sopt.optlen); + if (ret) + return ret; if (len == 0) return -EINVAL; cobalt_atomic_enter(s); @@ -935,8 +923,7 @@ static int __xddp_setsockopt(struct xddp_socket *sk, return -EPERM; if (sopt.optlen != sizeof(monitor)) return -EINVAL; - if (rtipc_get_arg(NULL, &monitor, - sopt.optval, sizeof(monitor))) + if (rtipc_get_arg(NULL, &monitor, sopt.optval, sizeof(monitor))) return -EFAULT; sk->monitor = monitor; break; @@ -944,8 +931,7 @@ static int __xddp_setsockopt(struct xddp_socket *sk, case XDDP_LABEL: if (sopt.optlen < sizeof(plabel)) return -EINVAL; - if (rtipc_get_arg(fd, &plabel, - sopt.optval, sizeof(plabel))) + if (rtipc_get_arg(fd, &plabel, sopt.optval, sizeof(plabel))) return -EFAULT; cobalt_atomic_enter(s); if (test_bit(_XDDP_BOUND, &sk->status) || @@ -974,10 +960,11 @@ static int __xddp_getsockopt(struct xddp_socket *sk, struct timeval tv; rtdm_lockctx_t s; socklen_t len; - int ret = 0; + int ret; - if (rtipc_get_arg(fd, &sopt, arg, sizeof(sopt))) - return -EFAULT; + ret = rtipc_get_sockoptout(fd, &sopt, arg); + if (ret) + return ret; if (rtipc_get_arg(fd, &len, sopt.optlen, sizeof(len))) return -EFAULT; @@ -986,12 +973,10 @@ static int __xddp_getsockopt(struct xddp_socket *sk, switch (sopt.optname) { case SO_RCVTIMEO: - if (len != sizeof(tv)) - return -EINVAL; rtipc_ns_to_timeval(&tv, sk->timeout); - if (rtipc_put_arg(fd, sopt.optval, - &tv, sizeof(tv))) - return -EFAULT; + ret = rtipc_put_timeval(fd, sopt.optval, &tv, len); + if (ret) + return ret; break; default: @@ -1012,8 +997,7 @@ static int __xddp_getsockopt(struct xddp_socket *sk, cobalt_atomic_enter(s); strcpy(plabel.label, sk->label); cobalt_atomic_leave(s); - if (rtipc_put_arg(fd, sopt.optval, - &plabel, sizeof(plabel))) + if (rtipc_put_arg(fd, sopt.optval, &plabel, sizeof(plabel))) return -EFAULT; break; @@ -1034,14 +1018,14 @@ static int __xddp_ioctl(struct rtdm_fd *fd, switch (request) { - case _RTIOC_CONNECT: - ret = rtipc_get_sockaddr(fd, arg, &saddrp); + COMPAT_CASE(_RTIOC_CONNECT): + ret = rtipc_get_sockaddr(fd, &saddrp, arg); if (ret == 0) ret = __xddp_connect_socket(sk, saddrp); break; - case _RTIOC_BIND: - ret = rtipc_get_sockaddr(fd, arg, &saddrp); + COMPAT_CASE(_RTIOC_BIND): + ret = rtipc_get_sockaddr(fd, &saddrp, arg); if (ret) return ret; if (saddrp == NULL) @@ -1049,24 +1033,24 @@ static int __xddp_ioctl(struct rtdm_fd *fd, ret = __xddp_bind_socket(priv, saddrp); break; - case _RTIOC_GETSOCKNAME: + COMPAT_CASE(_RTIOC_GETSOCKNAME): ret = rtipc_put_sockaddr(fd, arg, &sk->name); break; - case _RTIOC_GETPEERNAME: + COMPAT_CASE(_RTIOC_GETPEERNAME): ret = rtipc_put_sockaddr(fd, arg, &sk->peer); break; - case _RTIOC_SETSOCKOPT: + COMPAT_CASE(_RTIOC_SETSOCKOPT): ret = __xddp_setsockopt(sk, fd, arg); break; - case _RTIOC_GETSOCKOPT: + COMPAT_CASE(_RTIOC_GETSOCKOPT): ret = __xddp_getsockopt(sk, fd, arg); break; case _RTIOC_LISTEN: - case _RTIOC_ACCEPT: + COMPAT_CASE(_RTIOC_ACCEPT): ret = -EOPNOTSUPP; break; @@ -1084,10 +1068,17 @@ static int __xddp_ioctl(struct rtdm_fd *fd, static int xddp_ioctl(struct rtdm_fd *fd, unsigned int request, void *arg) { - if (rtdm_in_rt_context() && request == _RTIOC_BIND) - return -ENOSYS; /* Try downgrading to NRT */ + int ret; + + switch (request) { + COMPAT_CASE(_RTIOC_BIND): + if (rtdm_in_rt_context()) + return -ENOSYS; /* Try downgrading to NRT */ + default: + ret = __xddp_ioctl(fd, request, arg); + } - return __xddp_ioctl(fd, request, arg); + return ret; } static unsigned int xddp_pollstate(struct rtdm_fd *fd) _______________________________________________ Xenomai-git mailing list Xenomai-git@xenomai.org http://www.xenomai.org/mailman/listinfo/xenomai-git