[Xenomai-git] Philippe Gerum : net/udp: recvmsg: remove direct references to user memory
Module: xenomai-3 Branch: stable-3.0.x Commit: 3e3eea9623f5e172972a9f09b172323d42a6d2dd URL: http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=3e3eea9623f5e172972a9f09b172323d42a6d2dd Author: Philippe Gerum Date: Wed Dec 6 12:45:31 2017 +0100 net/udp: recvmsg: remove direct references to user memory --- kernel/drivers/net/stack/ipv4/udp/udp.c | 222 +++ 1 file changed, 138 insertions(+), 84 deletions(-) diff --git a/kernel/drivers/net/stack/ipv4/udp/udp.c b/kernel/drivers/net/stack/ipv4/udp/udp.c index 6d624e0..903e897 100644 --- a/kernel/drivers/net/stack/ipv4/udp/udp.c +++ b/kernel/drivers/net/stack/ipv4/udp/udp.c @@ -154,18 +154,24 @@ static inline struct rtsocket *rt_udp_v4_lookup(u32 daddr, u16 dport) * @s: socket * @addr: local address */ -int rt_udp_bind(struct rtsocket *sock, const struct sockaddr *addr, -socklen_t addrlen) +int rt_udp_bind(struct rtdm_fd *fd, struct rtsocket *sock, + const struct sockaddr __user *addr, socklen_t addrlen) { -struct sockaddr_in *usin = (struct sockaddr_in *)addr; +struct sockaddr_in _sin, *sin; rtdm_lockctx_t context; int index; int err = 0; -if ((addrlen < (int)sizeof(struct sockaddr_in)) || -((usin->sin_port & auto_port_mask) == auto_port_start)) -return -EINVAL; +if (addrlen < sizeof(struct sockaddr_in)) + return -EINVAL; + +sin = rtnet_get_arg(fd, &_sin, addr, sizeof(_sin)); +if (IS_ERR(sin)) + return PTR_ERR(sin); + +if ((sin->sin_port & auto_port_mask) == auto_port_start) + return -EINVAL; rtdm_lock_get_irqsave(&udp_socket_base_lock, context); @@ -181,8 +187,8 @@ int rt_udp_bind(struct rtsocket *sock, const struct sockaddr *addr, port_hash_del(&port_registry[index]); if (port_hash_insert(&port_registry[index], - usin->sin_addr.s_addr, - usin->sin_port ?: index + auto_port_start)) { + sin->sin_addr.s_addr, + sin->sin_port ?: index + auto_port_start)) { port_hash_insert(&port_registry[index], port_registry[index].saddr, port_registry[index].sport); @@ -207,51 +213,64 @@ int rt_udp_bind(struct rtsocket *sock, const struct sockaddr *addr, /*** * rt_udp_connect */ -int rt_udp_connect(struct rtsocket *sock, const struct sockaddr *serv_addr, - socklen_t addrlen) +int rt_udp_connect(struct rtdm_fd *fd, struct rtsocket *sock, + const struct sockaddr __user *serv_addr, socklen_t addrlen) { -struct sockaddr_in *usin = (struct sockaddr_in *) serv_addr; -rtdm_lockctx_t context; -int index; - - -if (usin->sin_family == AF_UNSPEC) { -if ((index = sock->prot.inet.reg_index) < 0) -/* socket is being closed */ -return -EBADF; - -rtdm_lock_get_irqsave(&udp_socket_base_lock, context); - -sock->prot.inet.saddr = INADDR_ANY; -/* Note: The following line differs from standard stacks, and we also - don't remove the socket from the port list. Might get fixed in - the future... */ -sock->prot.inet.sport = index + auto_port_start; -sock->prot.inet.daddr = INADDR_ANY; -sock->prot.inet.dport = 0; -sock->prot.inet.state = TCP_CLOSE; - -rtdm_lock_put_irqrestore(&udp_socket_base_lock, context); -} else { -if ((addrlen < (int)sizeof(struct sockaddr_in)) || -(usin->sin_family != AF_INET)) -return -EINVAL; - -rtdm_lock_get_irqsave(&udp_socket_base_lock, context); - -if (sock->prot.inet.state != TCP_CLOSE) { -rtdm_lock_put_irqrestore(&udp_socket_base_lock, context); -return -EINVAL; -} - -sock->prot.inet.state = TCP_ESTABLISHED; -sock->prot.inet.daddr = usin->sin_addr.s_addr; -sock->prot.inet.dport = usin->sin_port; - -rtdm_lock_put_irqrestore(&udp_socket_base_lock, context); -} + struct sockaddr _sa, *sa; + struct sockaddr_in _sin, *sin; + rtdm_lockctx_t context; + int index; + + if (addrlen < sizeof(struct sockaddr)) + return -EINVAL; + + sa = rtnet_get_arg(fd, &_sa, serv_addr, sizeof(_sa)); + if (IS_ERR(sa)) + return PTR_ERR(sa); + + if (sa->sa_family == AF_UNSPEC) { + if ((index = sock->prot.inet.reg_index) < 0) + /* socket is being closed */ + return -EBADF; + + rtdm_lock_get_irqsave(&udp_socket_base_lock, context); + + sock->prot.inet.saddr = INADDR_ANY; + /* Note: The following line differs from standard + stacks, and we also don't remove t
[Xenomai-git] Philippe Gerum : net/udp: recvmsg: remove direct references to user memory
Module: xenomai-3 Branch: wip/rtnet-fixes Commit: 3d5f95ed7f5f517ce1596e5d5a429c2e43319631 URL: http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=3d5f95ed7f5f517ce1596e5d5a429c2e43319631 Author: Philippe Gerum Date: Wed Dec 6 12:45:31 2017 +0100 net/udp: recvmsg: remove direct references to user memory --- kernel/drivers/net/stack/ipv4/udp/udp.c | 222 +++ 1 file changed, 138 insertions(+), 84 deletions(-) diff --git a/kernel/drivers/net/stack/ipv4/udp/udp.c b/kernel/drivers/net/stack/ipv4/udp/udp.c index 6d624e0..903e897 100644 --- a/kernel/drivers/net/stack/ipv4/udp/udp.c +++ b/kernel/drivers/net/stack/ipv4/udp/udp.c @@ -154,18 +154,24 @@ static inline struct rtsocket *rt_udp_v4_lookup(u32 daddr, u16 dport) * @s: socket * @addr: local address */ -int rt_udp_bind(struct rtsocket *sock, const struct sockaddr *addr, -socklen_t addrlen) +int rt_udp_bind(struct rtdm_fd *fd, struct rtsocket *sock, + const struct sockaddr __user *addr, socklen_t addrlen) { -struct sockaddr_in *usin = (struct sockaddr_in *)addr; +struct sockaddr_in _sin, *sin; rtdm_lockctx_t context; int index; int err = 0; -if ((addrlen < (int)sizeof(struct sockaddr_in)) || -((usin->sin_port & auto_port_mask) == auto_port_start)) -return -EINVAL; +if (addrlen < sizeof(struct sockaddr_in)) + return -EINVAL; + +sin = rtnet_get_arg(fd, &_sin, addr, sizeof(_sin)); +if (IS_ERR(sin)) + return PTR_ERR(sin); + +if ((sin->sin_port & auto_port_mask) == auto_port_start) + return -EINVAL; rtdm_lock_get_irqsave(&udp_socket_base_lock, context); @@ -181,8 +187,8 @@ int rt_udp_bind(struct rtsocket *sock, const struct sockaddr *addr, port_hash_del(&port_registry[index]); if (port_hash_insert(&port_registry[index], - usin->sin_addr.s_addr, - usin->sin_port ?: index + auto_port_start)) { + sin->sin_addr.s_addr, + sin->sin_port ?: index + auto_port_start)) { port_hash_insert(&port_registry[index], port_registry[index].saddr, port_registry[index].sport); @@ -207,51 +213,64 @@ int rt_udp_bind(struct rtsocket *sock, const struct sockaddr *addr, /*** * rt_udp_connect */ -int rt_udp_connect(struct rtsocket *sock, const struct sockaddr *serv_addr, - socklen_t addrlen) +int rt_udp_connect(struct rtdm_fd *fd, struct rtsocket *sock, + const struct sockaddr __user *serv_addr, socklen_t addrlen) { -struct sockaddr_in *usin = (struct sockaddr_in *) serv_addr; -rtdm_lockctx_t context; -int index; - - -if (usin->sin_family == AF_UNSPEC) { -if ((index = sock->prot.inet.reg_index) < 0) -/* socket is being closed */ -return -EBADF; - -rtdm_lock_get_irqsave(&udp_socket_base_lock, context); - -sock->prot.inet.saddr = INADDR_ANY; -/* Note: The following line differs from standard stacks, and we also - don't remove the socket from the port list. Might get fixed in - the future... */ -sock->prot.inet.sport = index + auto_port_start; -sock->prot.inet.daddr = INADDR_ANY; -sock->prot.inet.dport = 0; -sock->prot.inet.state = TCP_CLOSE; - -rtdm_lock_put_irqrestore(&udp_socket_base_lock, context); -} else { -if ((addrlen < (int)sizeof(struct sockaddr_in)) || -(usin->sin_family != AF_INET)) -return -EINVAL; - -rtdm_lock_get_irqsave(&udp_socket_base_lock, context); - -if (sock->prot.inet.state != TCP_CLOSE) { -rtdm_lock_put_irqrestore(&udp_socket_base_lock, context); -return -EINVAL; -} - -sock->prot.inet.state = TCP_ESTABLISHED; -sock->prot.inet.daddr = usin->sin_addr.s_addr; -sock->prot.inet.dport = usin->sin_port; - -rtdm_lock_put_irqrestore(&udp_socket_base_lock, context); -} + struct sockaddr _sa, *sa; + struct sockaddr_in _sin, *sin; + rtdm_lockctx_t context; + int index; + + if (addrlen < sizeof(struct sockaddr)) + return -EINVAL; + + sa = rtnet_get_arg(fd, &_sa, serv_addr, sizeof(_sa)); + if (IS_ERR(sa)) + return PTR_ERR(sa); + + if (sa->sa_family == AF_UNSPEC) { + if ((index = sock->prot.inet.reg_index) < 0) + /* socket is being closed */ + return -EBADF; + + rtdm_lock_get_irqsave(&udp_socket_base_lock, context); + + sock->prot.inet.saddr = INADDR_ANY; + /* Note: The following line differs from standard + stacks, and we also don't remov
[Xenomai-git] Philippe Gerum : net/udp: recvmsg: remove direct references to user memory
Module: xenomai-3 Branch: wip/rtnet-fixes Commit: 79879ab9d67eeef2195b221378ce246309a24fab URL: http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=79879ab9d67eeef2195b221378ce246309a24fab Author: Philippe Gerum Date: Wed Dec 6 12:45:31 2017 +0100 net/udp: recvmsg: remove direct references to user memory --- kernel/drivers/net/stack/ipv4/udp/udp.c | 95 +-- 1 file changed, 65 insertions(+), 30 deletions(-) diff --git a/kernel/drivers/net/stack/ipv4/udp/udp.c b/kernel/drivers/net/stack/ipv4/udp/udp.c index f8eeadd..8284ff7 100644 --- a/kernel/drivers/net/stack/ipv4/udp/udp.c +++ b/kernel/drivers/net/stack/ipv4/udp/udp.c @@ -377,20 +377,39 @@ int rt_udp_ioctl(struct rtdm_fd *fd, unsigned int request, void __user *arg) /*** * rt_udp_recvmsg */ +/*** + * rt_udp_recvmsg + */ ssize_t rt_udp_recvmsg(struct rtdm_fd *fd, struct user_msghdr *msg, int msg_flags) { struct rtsocket *sock = rtdm_fd_to_private(fd); -size_t len = rt_iovec_len(msg->msg_iov, msg->msg_iovlen); +size_t len; struct rtskb*skb; struct rtskb*first_skb; size_t copied = 0; size_t block_size; size_t data_len; struct udphdr *uh; -struct sockaddr_in *sin; +struct sockaddr_in sin; nanosecs_rel_t timeout = sock->timeout; -int ret; +int ret, flags; +struct user_msghdr _msg; +socklen_t namelen; +struct iovec iov_fast[RTDM_IOV_FASTMAX], *iov; + +msg = rtnet_get_arg(fd, &_msg, msg, sizeof(*msg)); +if (IS_ERR(msg)) + return PTR_ERR(msg); +if (msg->msg_iovlen < 0) + return -EINVAL; + +if (msg->msg_iovlen == 0) + return 0; + +ret = rtdm_get_iovec(fd, &iov, msg, iov_fast); +if (ret) + return ret; /* non-blocking receive? */ if (msg_flags & MSG_DONTWAIT) @@ -398,35 +417,44 @@ ssize_t rt_udp_recvmsg(struct rtdm_fd *fd, struct user_msghdr *msg, int msg_flag ret = rtdm_sem_timeddown(&sock->pending_sem, timeout, NULL); if (unlikely(ret < 0)) -switch (ret) { -case -EWOULDBLOCK: -case -ETIMEDOUT: -case -EINTR: -return ret; - -default: -return -EBADF; /* socket has been closed */ -} + switch (ret) { + default: + ret = -EBADF; /* socket has been closed */ + case -EWOULDBLOCK: + case -ETIMEDOUT: + case -EINTR: + rtdm_drop_iovec(iov, iov_fast); + return ret; + } skb = rtskb_dequeue_chain(&sock->incoming); RTNET_ASSERT(skb != NULL, return -EFAULT;); - uh = skb->h.uh; -data_len = ntohs(uh->len) - sizeof(struct udphdr); -sin = msg->msg_name; +first_skb = skb; +namelen = sizeof(sin); +ret = rtnet_put_arg(fd, &msg->msg_namelen, &namelen, sizeof(namelen)); +if (ret) + goto fail; + /* copy the address */ -msg->msg_namelen = sizeof(*sin); -if (sin) { -sin->sin_family = AF_INET; -sin->sin_port= uh->source; -sin->sin_addr.s_addr = skb->nh.iph->saddr; +if (msg->msg_name) { + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port= uh->source; + sin.sin_addr.s_addr = skb->nh.iph->saddr; + ret = rtnet_put_arg(fd, &msg->msg_name, &sin, sizeof(sin)); + if (ret) + goto fail; } +data_len = ntohs(uh->len) - sizeof(struct udphdr); + /* remove the UDP header */ __rtskb_pull(skb, sizeof(struct udphdr)); -first_skb = skb; +flags = msg->msg_flags & ~MSG_TRUNC; +len = rt_iovec_len(iov, msg->msg_iovlen); /* iterate over all IP fragments */ do { @@ -440,25 +468,28 @@ ssize_t rt_udp_recvmsg(struct rtdm_fd *fd, struct user_msghdr *msg, int msg_flag if (copied > len) { block_size -= copied - len; copied = len; -msg->msg_flags |= MSG_TRUNC; - -/* copy the data */ -rt_memcpy_tokerneliovec(msg->msg_iov, skb->data, block_size); - -break; + flags |= MSG_TRUNC; } /* copy the data */ -rt_memcpy_tokerneliovec(msg->msg_iov, skb->data, block_size); + ret = rtnet_write_to_iov(fd, iov, msg->msg_iovlen, skb->data, block_size); + if (ret) + goto fail; /* next fragment */ skb = skb->next; -} while (skb != NULL); +} while (skb && !(flags & MSG_TRUNC)); /* did we copied all bytes? */ if (data_len > 0) -msg->msg_flags |= MSG_TRUNC; + flags |= MSG_TRUNC; +if (flags != msg->msg_flags) { + ret = rtnet_put_arg(fd, &msg->msg_flags, &flags, sizeof(flags)); + if (ret) + goto fail;
[Xenomai-git] Philippe Gerum : net/udp: recvmsg: remove direct references to user memory
Module: xenomai-3 Branch: next Commit: 8321553d5c0143eca979b99b3148ecdc67d24166 URL: http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=8321553d5c0143eca979b99b3148ecdc67d24166 Author: Philippe Gerum Date: Wed Dec 6 12:45:31 2017 +0100 net/udp: recvmsg: remove direct references to user memory --- kernel/drivers/net/stack/ipv4/udp/udp.c | 95 +-- 1 file changed, 65 insertions(+), 30 deletions(-) diff --git a/kernel/drivers/net/stack/ipv4/udp/udp.c b/kernel/drivers/net/stack/ipv4/udp/udp.c index f8eeadd..8284ff7 100644 --- a/kernel/drivers/net/stack/ipv4/udp/udp.c +++ b/kernel/drivers/net/stack/ipv4/udp/udp.c @@ -377,20 +377,39 @@ int rt_udp_ioctl(struct rtdm_fd *fd, unsigned int request, void __user *arg) /*** * rt_udp_recvmsg */ +/*** + * rt_udp_recvmsg + */ ssize_t rt_udp_recvmsg(struct rtdm_fd *fd, struct user_msghdr *msg, int msg_flags) { struct rtsocket *sock = rtdm_fd_to_private(fd); -size_t len = rt_iovec_len(msg->msg_iov, msg->msg_iovlen); +size_t len; struct rtskb*skb; struct rtskb*first_skb; size_t copied = 0; size_t block_size; size_t data_len; struct udphdr *uh; -struct sockaddr_in *sin; +struct sockaddr_in sin; nanosecs_rel_t timeout = sock->timeout; -int ret; +int ret, flags; +struct user_msghdr _msg; +socklen_t namelen; +struct iovec iov_fast[RTDM_IOV_FASTMAX], *iov; + +msg = rtnet_get_arg(fd, &_msg, msg, sizeof(*msg)); +if (IS_ERR(msg)) + return PTR_ERR(msg); +if (msg->msg_iovlen < 0) + return -EINVAL; + +if (msg->msg_iovlen == 0) + return 0; + +ret = rtdm_get_iovec(fd, &iov, msg, iov_fast); +if (ret) + return ret; /* non-blocking receive? */ if (msg_flags & MSG_DONTWAIT) @@ -398,35 +417,44 @@ ssize_t rt_udp_recvmsg(struct rtdm_fd *fd, struct user_msghdr *msg, int msg_flag ret = rtdm_sem_timeddown(&sock->pending_sem, timeout, NULL); if (unlikely(ret < 0)) -switch (ret) { -case -EWOULDBLOCK: -case -ETIMEDOUT: -case -EINTR: -return ret; - -default: -return -EBADF; /* socket has been closed */ -} + switch (ret) { + default: + ret = -EBADF; /* socket has been closed */ + case -EWOULDBLOCK: + case -ETIMEDOUT: + case -EINTR: + rtdm_drop_iovec(iov, iov_fast); + return ret; + } skb = rtskb_dequeue_chain(&sock->incoming); RTNET_ASSERT(skb != NULL, return -EFAULT;); - uh = skb->h.uh; -data_len = ntohs(uh->len) - sizeof(struct udphdr); -sin = msg->msg_name; +first_skb = skb; +namelen = sizeof(sin); +ret = rtnet_put_arg(fd, &msg->msg_namelen, &namelen, sizeof(namelen)); +if (ret) + goto fail; + /* copy the address */ -msg->msg_namelen = sizeof(*sin); -if (sin) { -sin->sin_family = AF_INET; -sin->sin_port= uh->source; -sin->sin_addr.s_addr = skb->nh.iph->saddr; +if (msg->msg_name) { + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port= uh->source; + sin.sin_addr.s_addr = skb->nh.iph->saddr; + ret = rtnet_put_arg(fd, &msg->msg_name, &sin, sizeof(sin)); + if (ret) + goto fail; } +data_len = ntohs(uh->len) - sizeof(struct udphdr); + /* remove the UDP header */ __rtskb_pull(skb, sizeof(struct udphdr)); -first_skb = skb; +flags = msg->msg_flags & ~MSG_TRUNC; +len = rt_iovec_len(iov, msg->msg_iovlen); /* iterate over all IP fragments */ do { @@ -440,25 +468,28 @@ ssize_t rt_udp_recvmsg(struct rtdm_fd *fd, struct user_msghdr *msg, int msg_flag if (copied > len) { block_size -= copied - len; copied = len; -msg->msg_flags |= MSG_TRUNC; - -/* copy the data */ -rt_memcpy_tokerneliovec(msg->msg_iov, skb->data, block_size); - -break; + flags |= MSG_TRUNC; } /* copy the data */ -rt_memcpy_tokerneliovec(msg->msg_iov, skb->data, block_size); + ret = rtnet_write_to_iov(fd, iov, msg->msg_iovlen, skb->data, block_size); + if (ret) + goto fail; /* next fragment */ skb = skb->next; -} while (skb != NULL); +} while (skb && !(flags & MSG_TRUNC)); /* did we copied all bytes? */ if (data_len > 0) -msg->msg_flags |= MSG_TRUNC; + flags |= MSG_TRUNC; +if (flags != msg->msg_flags) { + ret = rtnet_put_arg(fd, &msg->msg_flags, &flags, sizeof(flags)); + if (ret) + goto fail; +} +out
[Xenomai-git] Philippe Gerum : net/udp: recvmsg: remove direct references to user memory
Module: xenomai-3 Branch: next Commit: 9ab984cb49fb2ad1efb44c3a295017d0c2ad52e8 URL: http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=9ab984cb49fb2ad1efb44c3a295017d0c2ad52e8 Author: Philippe Gerum Date: Wed Dec 6 12:45:31 2017 +0100 net/udp: recvmsg: remove direct references to user memory --- kernel/drivers/net/stack/ipv4/udp/udp.c | 95 +-- 1 file changed, 65 insertions(+), 30 deletions(-) diff --git a/kernel/drivers/net/stack/ipv4/udp/udp.c b/kernel/drivers/net/stack/ipv4/udp/udp.c index f8eeadd..8284ff7 100644 --- a/kernel/drivers/net/stack/ipv4/udp/udp.c +++ b/kernel/drivers/net/stack/ipv4/udp/udp.c @@ -377,20 +377,39 @@ int rt_udp_ioctl(struct rtdm_fd *fd, unsigned int request, void __user *arg) /*** * rt_udp_recvmsg */ +/*** + * rt_udp_recvmsg + */ ssize_t rt_udp_recvmsg(struct rtdm_fd *fd, struct user_msghdr *msg, int msg_flags) { struct rtsocket *sock = rtdm_fd_to_private(fd); -size_t len = rt_iovec_len(msg->msg_iov, msg->msg_iovlen); +size_t len; struct rtskb*skb; struct rtskb*first_skb; size_t copied = 0; size_t block_size; size_t data_len; struct udphdr *uh; -struct sockaddr_in *sin; +struct sockaddr_in sin; nanosecs_rel_t timeout = sock->timeout; -int ret; +int ret, flags; +struct user_msghdr _msg; +socklen_t namelen; +struct iovec iov_fast[RTDM_IOV_FASTMAX], *iov; + +msg = rtnet_get_arg(fd, &_msg, msg, sizeof(*msg)); +if (IS_ERR(msg)) + return PTR_ERR(msg); +if (msg->msg_iovlen < 0) + return -EINVAL; + +if (msg->msg_iovlen == 0) + return 0; + +ret = rtdm_get_iovec(fd, &iov, msg, iov_fast); +if (ret) + return ret; /* non-blocking receive? */ if (msg_flags & MSG_DONTWAIT) @@ -398,35 +417,44 @@ ssize_t rt_udp_recvmsg(struct rtdm_fd *fd, struct user_msghdr *msg, int msg_flag ret = rtdm_sem_timeddown(&sock->pending_sem, timeout, NULL); if (unlikely(ret < 0)) -switch (ret) { -case -EWOULDBLOCK: -case -ETIMEDOUT: -case -EINTR: -return ret; - -default: -return -EBADF; /* socket has been closed */ -} + switch (ret) { + default: + ret = -EBADF; /* socket has been closed */ + case -EWOULDBLOCK: + case -ETIMEDOUT: + case -EINTR: + rtdm_drop_iovec(iov, iov_fast); + return ret; + } skb = rtskb_dequeue_chain(&sock->incoming); RTNET_ASSERT(skb != NULL, return -EFAULT;); - uh = skb->h.uh; -data_len = ntohs(uh->len) - sizeof(struct udphdr); -sin = msg->msg_name; +first_skb = skb; +namelen = sizeof(sin); +ret = rtnet_put_arg(fd, &msg->msg_namelen, &namelen, sizeof(namelen)); +if (ret) + goto fail; + /* copy the address */ -msg->msg_namelen = sizeof(*sin); -if (sin) { -sin->sin_family = AF_INET; -sin->sin_port= uh->source; -sin->sin_addr.s_addr = skb->nh.iph->saddr; +if (msg->msg_name) { + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port= uh->source; + sin.sin_addr.s_addr = skb->nh.iph->saddr; + ret = rtnet_put_arg(fd, &msg->msg_name, &sin, sizeof(sin)); + if (ret) + goto fail; } +data_len = ntohs(uh->len) - sizeof(struct udphdr); + /* remove the UDP header */ __rtskb_pull(skb, sizeof(struct udphdr)); -first_skb = skb; +flags = msg->msg_flags & ~MSG_TRUNC; +len = rt_iovec_len(iov, msg->msg_iovlen); /* iterate over all IP fragments */ do { @@ -440,25 +468,28 @@ ssize_t rt_udp_recvmsg(struct rtdm_fd *fd, struct user_msghdr *msg, int msg_flag if (copied > len) { block_size -= copied - len; copied = len; -msg->msg_flags |= MSG_TRUNC; - -/* copy the data */ -rt_memcpy_tokerneliovec(msg->msg_iov, skb->data, block_size); - -break; + flags |= MSG_TRUNC; } /* copy the data */ -rt_memcpy_tokerneliovec(msg->msg_iov, skb->data, block_size); + ret = rtnet_write_to_iov(fd, iov, msg->msg_iovlen, skb->data, block_size); + if (ret) + goto fail; /* next fragment */ skb = skb->next; -} while (skb != NULL); +} while (skb && !(flags & MSG_TRUNC)); /* did we copied all bytes? */ if (data_len > 0) -msg->msg_flags |= MSG_TRUNC; + flags |= MSG_TRUNC; +if (flags != msg->msg_flags) { + ret = rtnet_put_arg(fd, &msg->msg_flags, &flags, sizeof(flags)); + if (ret) + goto fail; +} +out
[Xenomai-git] Philippe Gerum : net/udp: recvmsg: remove direct references to user memory
Module: xenomai-3 Branch: next Commit: bc0ed268adf016f79559aa53204b046b03c99837 URL: http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=bc0ed268adf016f79559aa53204b046b03c99837 Author: Philippe Gerum Date: Wed Dec 6 12:45:31 2017 +0100 net/udp: recvmsg: remove direct references to user memory --- kernel/drivers/net/stack/ipv4/udp/udp.c | 95 +-- 1 file changed, 65 insertions(+), 30 deletions(-) diff --git a/kernel/drivers/net/stack/ipv4/udp/udp.c b/kernel/drivers/net/stack/ipv4/udp/udp.c index f8eeadd..8284ff7 100644 --- a/kernel/drivers/net/stack/ipv4/udp/udp.c +++ b/kernel/drivers/net/stack/ipv4/udp/udp.c @@ -377,20 +377,39 @@ int rt_udp_ioctl(struct rtdm_fd *fd, unsigned int request, void __user *arg) /*** * rt_udp_recvmsg */ +/*** + * rt_udp_recvmsg + */ ssize_t rt_udp_recvmsg(struct rtdm_fd *fd, struct user_msghdr *msg, int msg_flags) { struct rtsocket *sock = rtdm_fd_to_private(fd); -size_t len = rt_iovec_len(msg->msg_iov, msg->msg_iovlen); +size_t len; struct rtskb*skb; struct rtskb*first_skb; size_t copied = 0; size_t block_size; size_t data_len; struct udphdr *uh; -struct sockaddr_in *sin; +struct sockaddr_in sin; nanosecs_rel_t timeout = sock->timeout; -int ret; +int ret, flags; +struct user_msghdr _msg; +socklen_t namelen; +struct iovec iov_fast[RTDM_IOV_FASTMAX], *iov; + +msg = rtnet_get_arg(fd, &_msg, msg, sizeof(*msg)); +if (IS_ERR(msg)) + return PTR_ERR(msg); +if (msg->msg_iovlen < 0) + return -EINVAL; + +if (msg->msg_iovlen == 0) + return 0; + +ret = rtdm_get_iovec(fd, &iov, msg, iov_fast); +if (ret) + return ret; /* non-blocking receive? */ if (msg_flags & MSG_DONTWAIT) @@ -398,35 +417,44 @@ ssize_t rt_udp_recvmsg(struct rtdm_fd *fd, struct user_msghdr *msg, int msg_flag ret = rtdm_sem_timeddown(&sock->pending_sem, timeout, NULL); if (unlikely(ret < 0)) -switch (ret) { -case -EWOULDBLOCK: -case -ETIMEDOUT: -case -EINTR: -return ret; - -default: -return -EBADF; /* socket has been closed */ -} + switch (ret) { + default: + ret = -EBADF; /* socket has been closed */ + case -EWOULDBLOCK: + case -ETIMEDOUT: + case -EINTR: + rtdm_drop_iovec(iov, iov_fast); + return ret; + } skb = rtskb_dequeue_chain(&sock->incoming); RTNET_ASSERT(skb != NULL, return -EFAULT;); - uh = skb->h.uh; -data_len = ntohs(uh->len) - sizeof(struct udphdr); -sin = msg->msg_name; +first_skb = skb; +namelen = sizeof(sin); +ret = rtnet_put_arg(fd, &msg->msg_namelen, &namelen, sizeof(namelen)); +if (ret) + goto fail; + /* copy the address */ -msg->msg_namelen = sizeof(*sin); -if (sin) { -sin->sin_family = AF_INET; -sin->sin_port= uh->source; -sin->sin_addr.s_addr = skb->nh.iph->saddr; +if (msg->msg_name) { + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port= uh->source; + sin.sin_addr.s_addr = skb->nh.iph->saddr; + ret = rtnet_put_arg(fd, &msg->msg_name, &sin, sizeof(sin)); + if (ret) + goto fail; } +data_len = ntohs(uh->len) - sizeof(struct udphdr); + /* remove the UDP header */ __rtskb_pull(skb, sizeof(struct udphdr)); -first_skb = skb; +flags = msg->msg_flags & ~MSG_TRUNC; +len = rt_iovec_len(iov, msg->msg_iovlen); /* iterate over all IP fragments */ do { @@ -440,25 +468,28 @@ ssize_t rt_udp_recvmsg(struct rtdm_fd *fd, struct user_msghdr *msg, int msg_flag if (copied > len) { block_size -= copied - len; copied = len; -msg->msg_flags |= MSG_TRUNC; - -/* copy the data */ -rt_memcpy_tokerneliovec(msg->msg_iov, skb->data, block_size); - -break; + flags |= MSG_TRUNC; } /* copy the data */ -rt_memcpy_tokerneliovec(msg->msg_iov, skb->data, block_size); + ret = rtnet_write_to_iov(fd, iov, msg->msg_iovlen, skb->data, block_size); + if (ret) + goto fail; /* next fragment */ skb = skb->next; -} while (skb != NULL); +} while (skb && !(flags & MSG_TRUNC)); /* did we copied all bytes? */ if (data_len > 0) -msg->msg_flags |= MSG_TRUNC; + flags |= MSG_TRUNC; +if (flags != msg->msg_flags) { + ret = rtnet_put_arg(fd, &msg->msg_flags, &flags, sizeof(flags)); + if (ret) + goto fail; +} +out
[Xenomai-git] Philippe Gerum : net/udp: recvmsg: remove direct references to user memory
Module: xenomai-3 Branch: wip/rtnet-fixes Commit: f941ede5d624adefebb233e244996d49cf5efcfa URL: http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=f941ede5d624adefebb233e244996d49cf5efcfa Author: Philippe Gerum Date: Wed Dec 6 12:45:31 2017 +0100 net/udp: recvmsg: remove direct references to user memory --- kernel/drivers/net/stack/ipv4/udp/udp.c | 95 +-- 1 file changed, 65 insertions(+), 30 deletions(-) diff --git a/kernel/drivers/net/stack/ipv4/udp/udp.c b/kernel/drivers/net/stack/ipv4/udp/udp.c index f8eeadd..8284ff7 100644 --- a/kernel/drivers/net/stack/ipv4/udp/udp.c +++ b/kernel/drivers/net/stack/ipv4/udp/udp.c @@ -377,20 +377,39 @@ int rt_udp_ioctl(struct rtdm_fd *fd, unsigned int request, void __user *arg) /*** * rt_udp_recvmsg */ +/*** + * rt_udp_recvmsg + */ ssize_t rt_udp_recvmsg(struct rtdm_fd *fd, struct user_msghdr *msg, int msg_flags) { struct rtsocket *sock = rtdm_fd_to_private(fd); -size_t len = rt_iovec_len(msg->msg_iov, msg->msg_iovlen); +size_t len; struct rtskb*skb; struct rtskb*first_skb; size_t copied = 0; size_t block_size; size_t data_len; struct udphdr *uh; -struct sockaddr_in *sin; +struct sockaddr_in sin; nanosecs_rel_t timeout = sock->timeout; -int ret; +int ret, flags; +struct user_msghdr _msg; +socklen_t namelen; +struct iovec iov_fast[RTDM_IOV_FASTMAX], *iov; + +msg = rtnet_get_arg(fd, &_msg, msg, sizeof(*msg)); +if (IS_ERR(msg)) + return PTR_ERR(msg); +if (msg->msg_iovlen < 0) + return -EINVAL; + +if (msg->msg_iovlen == 0) + return 0; + +ret = rtdm_get_iovec(fd, &iov, msg, iov_fast); +if (ret) + return ret; /* non-blocking receive? */ if (msg_flags & MSG_DONTWAIT) @@ -398,35 +417,44 @@ ssize_t rt_udp_recvmsg(struct rtdm_fd *fd, struct user_msghdr *msg, int msg_flag ret = rtdm_sem_timeddown(&sock->pending_sem, timeout, NULL); if (unlikely(ret < 0)) -switch (ret) { -case -EWOULDBLOCK: -case -ETIMEDOUT: -case -EINTR: -return ret; - -default: -return -EBADF; /* socket has been closed */ -} + switch (ret) { + default: + ret = -EBADF; /* socket has been closed */ + case -EWOULDBLOCK: + case -ETIMEDOUT: + case -EINTR: + rtdm_drop_iovec(iov, iov_fast); + return ret; + } skb = rtskb_dequeue_chain(&sock->incoming); RTNET_ASSERT(skb != NULL, return -EFAULT;); - uh = skb->h.uh; -data_len = ntohs(uh->len) - sizeof(struct udphdr); -sin = msg->msg_name; +first_skb = skb; +namelen = sizeof(sin); +ret = rtnet_put_arg(fd, &msg->msg_namelen, &namelen, sizeof(namelen)); +if (ret) + goto fail; + /* copy the address */ -msg->msg_namelen = sizeof(*sin); -if (sin) { -sin->sin_family = AF_INET; -sin->sin_port= uh->source; -sin->sin_addr.s_addr = skb->nh.iph->saddr; +if (msg->msg_name) { + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port= uh->source; + sin.sin_addr.s_addr = skb->nh.iph->saddr; + ret = rtnet_put_arg(fd, &msg->msg_name, &sin, sizeof(sin)); + if (ret) + goto fail; } +data_len = ntohs(uh->len) - sizeof(struct udphdr); + /* remove the UDP header */ __rtskb_pull(skb, sizeof(struct udphdr)); -first_skb = skb; +flags = msg->msg_flags & ~MSG_TRUNC; +len = rt_iovec_len(iov, msg->msg_iovlen); /* iterate over all IP fragments */ do { @@ -440,25 +468,28 @@ ssize_t rt_udp_recvmsg(struct rtdm_fd *fd, struct user_msghdr *msg, int msg_flag if (copied > len) { block_size -= copied - len; copied = len; -msg->msg_flags |= MSG_TRUNC; - -/* copy the data */ -rt_memcpy_tokerneliovec(msg->msg_iov, skb->data, block_size); - -break; + flags |= MSG_TRUNC; } /* copy the data */ -rt_memcpy_tokerneliovec(msg->msg_iov, skb->data, block_size); + ret = rtnet_write_to_iov(fd, iov, msg->msg_iovlen, skb->data, block_size); + if (ret) + goto fail; /* next fragment */ skb = skb->next; -} while (skb != NULL); +} while (skb && !(flags & MSG_TRUNC)); /* did we copied all bytes? */ if (data_len > 0) -msg->msg_flags |= MSG_TRUNC; + flags |= MSG_TRUNC; +if (flags != msg->msg_flags) { + ret = rtnet_put_arg(fd, &msg->msg_flags, &flags, sizeof(flags)); + if (ret) + goto fail;
[Xenomai-git] Philippe Gerum : net/udp: recvmsg: remove direct references to user memory
Module: xenomai-3 Branch: wip/rtnet-fixes Commit: 0773253d7f8d47b7a6e9a8d6dd8f4cd4d3240e87 URL: http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=0773253d7f8d47b7a6e9a8d6dd8f4cd4d3240e87 Author: Philippe Gerum Date: Wed Dec 6 12:45:31 2017 +0100 net/udp: recvmsg: remove direct references to user memory --- kernel/drivers/net/stack/ipv4/udp/udp.c | 95 +-- 1 file changed, 65 insertions(+), 30 deletions(-) diff --git a/kernel/drivers/net/stack/ipv4/udp/udp.c b/kernel/drivers/net/stack/ipv4/udp/udp.c index f8eeadd..8284ff7 100644 --- a/kernel/drivers/net/stack/ipv4/udp/udp.c +++ b/kernel/drivers/net/stack/ipv4/udp/udp.c @@ -377,20 +377,39 @@ int rt_udp_ioctl(struct rtdm_fd *fd, unsigned int request, void __user *arg) /*** * rt_udp_recvmsg */ +/*** + * rt_udp_recvmsg + */ ssize_t rt_udp_recvmsg(struct rtdm_fd *fd, struct user_msghdr *msg, int msg_flags) { struct rtsocket *sock = rtdm_fd_to_private(fd); -size_t len = rt_iovec_len(msg->msg_iov, msg->msg_iovlen); +size_t len; struct rtskb*skb; struct rtskb*first_skb; size_t copied = 0; size_t block_size; size_t data_len; struct udphdr *uh; -struct sockaddr_in *sin; +struct sockaddr_in sin; nanosecs_rel_t timeout = sock->timeout; -int ret; +int ret, flags; +struct user_msghdr _msg; +socklen_t namelen; +struct iovec iov_fast[RTDM_IOV_FASTMAX], *iov; + +msg = rtnet_get_arg(fd, &_msg, msg, sizeof(*msg)); +if (IS_ERR(msg)) + return PTR_ERR(msg); +if (msg->msg_iovlen < 0) + return -EINVAL; + +if (msg->msg_iovlen == 0) + return 0; + +ret = rtdm_get_iovec(fd, &iov, msg, iov_fast); +if (ret) + return ret; /* non-blocking receive? */ if (msg_flags & MSG_DONTWAIT) @@ -398,35 +417,44 @@ ssize_t rt_udp_recvmsg(struct rtdm_fd *fd, struct user_msghdr *msg, int msg_flag ret = rtdm_sem_timeddown(&sock->pending_sem, timeout, NULL); if (unlikely(ret < 0)) -switch (ret) { -case -EWOULDBLOCK: -case -ETIMEDOUT: -case -EINTR: -return ret; - -default: -return -EBADF; /* socket has been closed */ -} + switch (ret) { + default: + ret = -EBADF; /* socket has been closed */ + case -EWOULDBLOCK: + case -ETIMEDOUT: + case -EINTR: + rtdm_drop_iovec(iov, iov_fast); + return ret; + } skb = rtskb_dequeue_chain(&sock->incoming); RTNET_ASSERT(skb != NULL, return -EFAULT;); - uh = skb->h.uh; -data_len = ntohs(uh->len) - sizeof(struct udphdr); -sin = msg->msg_name; +first_skb = skb; +namelen = sizeof(sin); +ret = rtnet_put_arg(fd, &msg->msg_namelen, &namelen, sizeof(namelen)); +if (ret) + goto fail; + /* copy the address */ -msg->msg_namelen = sizeof(*sin); -if (sin) { -sin->sin_family = AF_INET; -sin->sin_port= uh->source; -sin->sin_addr.s_addr = skb->nh.iph->saddr; +if (msg->msg_name) { + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port= uh->source; + sin.sin_addr.s_addr = skb->nh.iph->saddr; + ret = rtnet_put_arg(fd, &msg->msg_name, &sin, sizeof(sin)); + if (ret) + goto fail; } +data_len = ntohs(uh->len) - sizeof(struct udphdr); + /* remove the UDP header */ __rtskb_pull(skb, sizeof(struct udphdr)); -first_skb = skb; +flags = msg->msg_flags & ~MSG_TRUNC; +len = rt_iovec_len(iov, msg->msg_iovlen); /* iterate over all IP fragments */ do { @@ -440,25 +468,28 @@ ssize_t rt_udp_recvmsg(struct rtdm_fd *fd, struct user_msghdr *msg, int msg_flag if (copied > len) { block_size -= copied - len; copied = len; -msg->msg_flags |= MSG_TRUNC; - -/* copy the data */ -rt_memcpy_tokerneliovec(msg->msg_iov, skb->data, block_size); - -break; + flags |= MSG_TRUNC; } /* copy the data */ -rt_memcpy_tokerneliovec(msg->msg_iov, skb->data, block_size); + ret = rtnet_write_to_iov(fd, iov, msg->msg_iovlen, skb->data, block_size); + if (ret) + goto fail; /* next fragment */ skb = skb->next; -} while (skb != NULL); +} while (skb && !(flags & MSG_TRUNC)); /* did we copied all bytes? */ if (data_len > 0) -msg->msg_flags |= MSG_TRUNC; + flags |= MSG_TRUNC; +if (flags != msg->msg_flags) { + ret = rtnet_put_arg(fd, &msg->msg_flags, &flags, sizeof(flags)); + if (ret) + goto fail;
[Xenomai-git] Philippe Gerum : net/udp: recvmsg: remove direct references to user memory
Module: xenomai-3 Branch: wip/rtnet-fixes Commit: 81c5c20cc57e12b371ee229cf51b2df1e7defd16 URL: http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=81c5c20cc57e12b371ee229cf51b2df1e7defd16 Author: Philippe Gerum Date: Wed Dec 6 12:45:31 2017 +0100 net/udp: recvmsg: remove direct references to user memory --- kernel/drivers/net/stack/ipv4/udp/udp.c | 95 +-- 1 file changed, 65 insertions(+), 30 deletions(-) diff --git a/kernel/drivers/net/stack/ipv4/udp/udp.c b/kernel/drivers/net/stack/ipv4/udp/udp.c index f8eeadd..8284ff7 100644 --- a/kernel/drivers/net/stack/ipv4/udp/udp.c +++ b/kernel/drivers/net/stack/ipv4/udp/udp.c @@ -377,20 +377,39 @@ int rt_udp_ioctl(struct rtdm_fd *fd, unsigned int request, void __user *arg) /*** * rt_udp_recvmsg */ +/*** + * rt_udp_recvmsg + */ ssize_t rt_udp_recvmsg(struct rtdm_fd *fd, struct user_msghdr *msg, int msg_flags) { struct rtsocket *sock = rtdm_fd_to_private(fd); -size_t len = rt_iovec_len(msg->msg_iov, msg->msg_iovlen); +size_t len; struct rtskb*skb; struct rtskb*first_skb; size_t copied = 0; size_t block_size; size_t data_len; struct udphdr *uh; -struct sockaddr_in *sin; +struct sockaddr_in sin; nanosecs_rel_t timeout = sock->timeout; -int ret; +int ret, flags; +struct user_msghdr _msg; +socklen_t namelen; +struct iovec iov_fast[RTDM_IOV_FASTMAX], *iov; + +msg = rtnet_get_arg(fd, &_msg, msg, sizeof(*msg)); +if (IS_ERR(msg)) + return PTR_ERR(msg); +if (msg->msg_iovlen < 0) + return -EINVAL; + +if (msg->msg_iovlen == 0) + return 0; + +ret = rtdm_get_iovec(fd, &iov, msg, iov_fast); +if (ret) + return ret; /* non-blocking receive? */ if (msg_flags & MSG_DONTWAIT) @@ -398,35 +417,44 @@ ssize_t rt_udp_recvmsg(struct rtdm_fd *fd, struct user_msghdr *msg, int msg_flag ret = rtdm_sem_timeddown(&sock->pending_sem, timeout, NULL); if (unlikely(ret < 0)) -switch (ret) { -case -EWOULDBLOCK: -case -ETIMEDOUT: -case -EINTR: -return ret; - -default: -return -EBADF; /* socket has been closed */ -} + switch (ret) { + default: + ret = -EBADF; /* socket has been closed */ + case -EWOULDBLOCK: + case -ETIMEDOUT: + case -EINTR: + rtdm_drop_iovec(iov, iov_fast); + return ret; + } skb = rtskb_dequeue_chain(&sock->incoming); RTNET_ASSERT(skb != NULL, return -EFAULT;); - uh = skb->h.uh; -data_len = ntohs(uh->len) - sizeof(struct udphdr); -sin = msg->msg_name; +first_skb = skb; +namelen = sizeof(sin); +ret = rtnet_put_arg(fd, &msg->msg_namelen, &namelen, sizeof(namelen)); +if (ret) + goto fail; + /* copy the address */ -msg->msg_namelen = sizeof(*sin); -if (sin) { -sin->sin_family = AF_INET; -sin->sin_port= uh->source; -sin->sin_addr.s_addr = skb->nh.iph->saddr; +if (msg->msg_name) { + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port= uh->source; + sin.sin_addr.s_addr = skb->nh.iph->saddr; + ret = rtnet_put_arg(fd, &msg->msg_name, &sin, sizeof(sin)); + if (ret) + goto fail; } +data_len = ntohs(uh->len) - sizeof(struct udphdr); + /* remove the UDP header */ __rtskb_pull(skb, sizeof(struct udphdr)); -first_skb = skb; +flags = msg->msg_flags & ~MSG_TRUNC; +len = rt_iovec_len(iov, msg->msg_iovlen); /* iterate over all IP fragments */ do { @@ -440,25 +468,28 @@ ssize_t rt_udp_recvmsg(struct rtdm_fd *fd, struct user_msghdr *msg, int msg_flag if (copied > len) { block_size -= copied - len; copied = len; -msg->msg_flags |= MSG_TRUNC; - -/* copy the data */ -rt_memcpy_tokerneliovec(msg->msg_iov, skb->data, block_size); - -break; + flags |= MSG_TRUNC; } /* copy the data */ -rt_memcpy_tokerneliovec(msg->msg_iov, skb->data, block_size); + ret = rtnet_write_to_iov(fd, iov, msg->msg_iovlen, skb->data, block_size); + if (ret) + goto fail; /* next fragment */ skb = skb->next; -} while (skb != NULL); +} while (skb && !(flags & MSG_TRUNC)); /* did we copied all bytes? */ if (data_len > 0) -msg->msg_flags |= MSG_TRUNC; + flags |= MSG_TRUNC; +if (flags != msg->msg_flags) { + ret = rtnet_put_arg(fd, &msg->msg_flags, &flags, sizeof(flags)); + if (ret) + goto fail;
[Xenomai-git] Philippe Gerum : net/udp: recvmsg: remove direct references to user memory
Module: xenomai-3 Branch: wip/rtnet-fixes Commit: 1db36f2b2db10717312da68cb75702c388bd5f90 URL: http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=1db36f2b2db10717312da68cb75702c388bd5f90 Author: Philippe Gerum Date: Wed Dec 6 12:45:31 2017 +0100 net/udp: recvmsg: remove direct references to user memory --- kernel/drivers/net/stack/ipv4/udp/udp.c | 95 +-- 1 file changed, 65 insertions(+), 30 deletions(-) diff --git a/kernel/drivers/net/stack/ipv4/udp/udp.c b/kernel/drivers/net/stack/ipv4/udp/udp.c index f8eeadd..8284ff7 100644 --- a/kernel/drivers/net/stack/ipv4/udp/udp.c +++ b/kernel/drivers/net/stack/ipv4/udp/udp.c @@ -377,20 +377,39 @@ int rt_udp_ioctl(struct rtdm_fd *fd, unsigned int request, void __user *arg) /*** * rt_udp_recvmsg */ +/*** + * rt_udp_recvmsg + */ ssize_t rt_udp_recvmsg(struct rtdm_fd *fd, struct user_msghdr *msg, int msg_flags) { struct rtsocket *sock = rtdm_fd_to_private(fd); -size_t len = rt_iovec_len(msg->msg_iov, msg->msg_iovlen); +size_t len; struct rtskb*skb; struct rtskb*first_skb; size_t copied = 0; size_t block_size; size_t data_len; struct udphdr *uh; -struct sockaddr_in *sin; +struct sockaddr_in sin; nanosecs_rel_t timeout = sock->timeout; -int ret; +int ret, flags; +struct user_msghdr _msg; +socklen_t namelen; +struct iovec iov_fast[RTDM_IOV_FASTMAX], *iov; + +msg = rtnet_get_arg(fd, &_msg, msg, sizeof(*msg)); +if (IS_ERR(msg)) + return PTR_ERR(msg); +if (msg->msg_iovlen < 0) + return -EINVAL; + +if (msg->msg_iovlen == 0) + return 0; + +ret = rtdm_get_iovec(fd, &iov, msg, iov_fast); +if (ret) + return ret; /* non-blocking receive? */ if (msg_flags & MSG_DONTWAIT) @@ -398,35 +417,44 @@ ssize_t rt_udp_recvmsg(struct rtdm_fd *fd, struct user_msghdr *msg, int msg_flag ret = rtdm_sem_timeddown(&sock->pending_sem, timeout, NULL); if (unlikely(ret < 0)) -switch (ret) { -case -EWOULDBLOCK: -case -ETIMEDOUT: -case -EINTR: -return ret; - -default: -return -EBADF; /* socket has been closed */ -} + switch (ret) { + default: + ret = -EBADF; /* socket has been closed */ + case -EWOULDBLOCK: + case -ETIMEDOUT: + case -EINTR: + rtdm_drop_iovec(iov, iov_fast); + return ret; + } skb = rtskb_dequeue_chain(&sock->incoming); RTNET_ASSERT(skb != NULL, return -EFAULT;); - uh = skb->h.uh; -data_len = ntohs(uh->len) - sizeof(struct udphdr); -sin = msg->msg_name; +first_skb = skb; +namelen = sizeof(sin); +ret = rtnet_put_arg(fd, &msg->msg_namelen, &namelen, sizeof(namelen)); +if (ret) + goto fail; + /* copy the address */ -msg->msg_namelen = sizeof(*sin); -if (sin) { -sin->sin_family = AF_INET; -sin->sin_port= uh->source; -sin->sin_addr.s_addr = skb->nh.iph->saddr; +if (msg->msg_name) { + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port= uh->source; + sin.sin_addr.s_addr = skb->nh.iph->saddr; + ret = rtnet_put_arg(fd, &msg->msg_name, &sin, sizeof(sin)); + if (ret) + goto fail; } +data_len = ntohs(uh->len) - sizeof(struct udphdr); + /* remove the UDP header */ __rtskb_pull(skb, sizeof(struct udphdr)); -first_skb = skb; +flags = msg->msg_flags & ~MSG_TRUNC; +len = rt_iovec_len(iov, msg->msg_iovlen); /* iterate over all IP fragments */ do { @@ -440,25 +468,28 @@ ssize_t rt_udp_recvmsg(struct rtdm_fd *fd, struct user_msghdr *msg, int msg_flag if (copied > len) { block_size -= copied - len; copied = len; -msg->msg_flags |= MSG_TRUNC; - -/* copy the data */ -rt_memcpy_tokerneliovec(msg->msg_iov, skb->data, block_size); - -break; + flags |= MSG_TRUNC; } /* copy the data */ -rt_memcpy_tokerneliovec(msg->msg_iov, skb->data, block_size); + ret = rtnet_write_to_iov(fd, iov, msg->msg_iovlen, skb->data, block_size); + if (ret) + goto fail; /* next fragment */ skb = skb->next; -} while (skb != NULL); +} while (skb && !(flags & MSG_TRUNC)); /* did we copied all bytes? */ if (data_len > 0) -msg->msg_flags |= MSG_TRUNC; + flags |= MSG_TRUNC; +if (flags != msg->msg_flags) { + ret = rtnet_put_arg(fd, &msg->msg_flags, &flags, sizeof(flags)); + if (ret) + goto fail;
[Xenomai-git] Philippe Gerum : net/udp: recvmsg: remove direct references to user memory
Module: xenomai-3 Branch: wip/rtnet-fixes Commit: b6dc4754f8fa09ce178fd2aec8f0eb5715a2e900 URL: http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=b6dc4754f8fa09ce178fd2aec8f0eb5715a2e900 Author: Philippe Gerum Date: Wed Dec 6 12:45:31 2017 +0100 net/udp: recvmsg: remove direct references to user memory --- kernel/drivers/net/stack/ipv4/udp/udp.c | 95 +-- 1 file changed, 65 insertions(+), 30 deletions(-) diff --git a/kernel/drivers/net/stack/ipv4/udp/udp.c b/kernel/drivers/net/stack/ipv4/udp/udp.c index f8eeadd..8284ff7 100644 --- a/kernel/drivers/net/stack/ipv4/udp/udp.c +++ b/kernel/drivers/net/stack/ipv4/udp/udp.c @@ -377,20 +377,39 @@ int rt_udp_ioctl(struct rtdm_fd *fd, unsigned int request, void __user *arg) /*** * rt_udp_recvmsg */ +/*** + * rt_udp_recvmsg + */ ssize_t rt_udp_recvmsg(struct rtdm_fd *fd, struct user_msghdr *msg, int msg_flags) { struct rtsocket *sock = rtdm_fd_to_private(fd); -size_t len = rt_iovec_len(msg->msg_iov, msg->msg_iovlen); +size_t len; struct rtskb*skb; struct rtskb*first_skb; size_t copied = 0; size_t block_size; size_t data_len; struct udphdr *uh; -struct sockaddr_in *sin; +struct sockaddr_in sin; nanosecs_rel_t timeout = sock->timeout; -int ret; +int ret, flags; +struct user_msghdr _msg; +socklen_t namelen; +struct iovec iov_fast[RTDM_IOV_FASTMAX], *iov; + +msg = rtnet_get_arg(fd, &_msg, msg, sizeof(*msg)); +if (IS_ERR(msg)) + return PTR_ERR(msg); +if (msg->msg_iovlen < 0) + return -EINVAL; + +if (msg->msg_iovlen == 0) + return 0; + +ret = rtdm_get_iovec(fd, &iov, msg, iov_fast); +if (ret) + return ret; /* non-blocking receive? */ if (msg_flags & MSG_DONTWAIT) @@ -398,35 +417,44 @@ ssize_t rt_udp_recvmsg(struct rtdm_fd *fd, struct user_msghdr *msg, int msg_flag ret = rtdm_sem_timeddown(&sock->pending_sem, timeout, NULL); if (unlikely(ret < 0)) -switch (ret) { -case -EWOULDBLOCK: -case -ETIMEDOUT: -case -EINTR: -return ret; - -default: -return -EBADF; /* socket has been closed */ -} + switch (ret) { + default: + ret = -EBADF; /* socket has been closed */ + case -EWOULDBLOCK: + case -ETIMEDOUT: + case -EINTR: + rtdm_drop_iovec(iov, iov_fast); + return ret; + } skb = rtskb_dequeue_chain(&sock->incoming); RTNET_ASSERT(skb != NULL, return -EFAULT;); - uh = skb->h.uh; -data_len = ntohs(uh->len) - sizeof(struct udphdr); -sin = msg->msg_name; +first_skb = skb; +namelen = sizeof(sin); +ret = rtnet_put_arg(fd, &msg->msg_namelen, &namelen, sizeof(namelen)); +if (ret) + goto fail; + /* copy the address */ -msg->msg_namelen = sizeof(*sin); -if (sin) { -sin->sin_family = AF_INET; -sin->sin_port= uh->source; -sin->sin_addr.s_addr = skb->nh.iph->saddr; +if (msg->msg_name) { + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port= uh->source; + sin.sin_addr.s_addr = skb->nh.iph->saddr; + ret = rtnet_put_arg(fd, &msg->msg_name, &sin, sizeof(sin)); + if (ret) + goto fail; } +data_len = ntohs(uh->len) - sizeof(struct udphdr); + /* remove the UDP header */ __rtskb_pull(skb, sizeof(struct udphdr)); -first_skb = skb; +flags = msg->msg_flags & ~MSG_TRUNC; +len = rt_iovec_len(iov, msg->msg_iovlen); /* iterate over all IP fragments */ do { @@ -440,25 +468,28 @@ ssize_t rt_udp_recvmsg(struct rtdm_fd *fd, struct user_msghdr *msg, int msg_flag if (copied > len) { block_size -= copied - len; copied = len; -msg->msg_flags |= MSG_TRUNC; - -/* copy the data */ -rt_memcpy_tokerneliovec(msg->msg_iov, skb->data, block_size); - -break; + flags |= MSG_TRUNC; } /* copy the data */ -rt_memcpy_tokerneliovec(msg->msg_iov, skb->data, block_size); + ret = rtnet_write_to_iov(fd, iov, msg->msg_iovlen, skb->data, block_size); + if (ret) + goto fail; /* next fragment */ skb = skb->next; -} while (skb != NULL); +} while (skb && !(flags & MSG_TRUNC)); /* did we copied all bytes? */ if (data_len > 0) -msg->msg_flags |= MSG_TRUNC; + flags |= MSG_TRUNC; +if (flags != msg->msg_flags) { + ret = rtnet_put_arg(fd, &msg->msg_flags, &flags, sizeof(flags)); + if (ret) + goto fail;
[Xenomai-git] Philippe Gerum : net/udp: recvmsg: remove direct references to user memory
Module: xenomai-3 Branch: wip/rtnet-fixes Commit: 6670cf25851d474b3ac1b876d7369e15c6468c75 URL: http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=6670cf25851d474b3ac1b876d7369e15c6468c75 Author: Philippe Gerum Date: Wed Dec 6 12:45:31 2017 +0100 net/udp: recvmsg: remove direct references to user memory --- kernel/drivers/net/stack/ipv4/udp/udp.c | 95 +-- 1 file changed, 65 insertions(+), 30 deletions(-) diff --git a/kernel/drivers/net/stack/ipv4/udp/udp.c b/kernel/drivers/net/stack/ipv4/udp/udp.c index f8eeadd..8284ff7 100644 --- a/kernel/drivers/net/stack/ipv4/udp/udp.c +++ b/kernel/drivers/net/stack/ipv4/udp/udp.c @@ -377,20 +377,39 @@ int rt_udp_ioctl(struct rtdm_fd *fd, unsigned int request, void __user *arg) /*** * rt_udp_recvmsg */ +/*** + * rt_udp_recvmsg + */ ssize_t rt_udp_recvmsg(struct rtdm_fd *fd, struct user_msghdr *msg, int msg_flags) { struct rtsocket *sock = rtdm_fd_to_private(fd); -size_t len = rt_iovec_len(msg->msg_iov, msg->msg_iovlen); +size_t len; struct rtskb*skb; struct rtskb*first_skb; size_t copied = 0; size_t block_size; size_t data_len; struct udphdr *uh; -struct sockaddr_in *sin; +struct sockaddr_in sin; nanosecs_rel_t timeout = sock->timeout; -int ret; +int ret, flags; +struct user_msghdr _msg; +socklen_t namelen; +struct iovec iov_fast[RTDM_IOV_FASTMAX], *iov; + +msg = rtnet_get_arg(fd, &_msg, msg, sizeof(*msg)); +if (IS_ERR(msg)) + return PTR_ERR(msg); +if (msg->msg_iovlen < 0) + return -EINVAL; + +if (msg->msg_iovlen == 0) + return 0; + +ret = rtdm_get_iovec(fd, &iov, msg, iov_fast); +if (ret) + return ret; /* non-blocking receive? */ if (msg_flags & MSG_DONTWAIT) @@ -398,35 +417,44 @@ ssize_t rt_udp_recvmsg(struct rtdm_fd *fd, struct user_msghdr *msg, int msg_flag ret = rtdm_sem_timeddown(&sock->pending_sem, timeout, NULL); if (unlikely(ret < 0)) -switch (ret) { -case -EWOULDBLOCK: -case -ETIMEDOUT: -case -EINTR: -return ret; - -default: -return -EBADF; /* socket has been closed */ -} + switch (ret) { + default: + ret = -EBADF; /* socket has been closed */ + case -EWOULDBLOCK: + case -ETIMEDOUT: + case -EINTR: + rtdm_drop_iovec(iov, iov_fast); + return ret; + } skb = rtskb_dequeue_chain(&sock->incoming); RTNET_ASSERT(skb != NULL, return -EFAULT;); - uh = skb->h.uh; -data_len = ntohs(uh->len) - sizeof(struct udphdr); -sin = msg->msg_name; +first_skb = skb; +namelen = sizeof(sin); +ret = rtnet_put_arg(fd, &msg->msg_namelen, &namelen, sizeof(namelen)); +if (ret) + goto fail; + /* copy the address */ -msg->msg_namelen = sizeof(*sin); -if (sin) { -sin->sin_family = AF_INET; -sin->sin_port= uh->source; -sin->sin_addr.s_addr = skb->nh.iph->saddr; +if (msg->msg_name) { + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port= uh->source; + sin.sin_addr.s_addr = skb->nh.iph->saddr; + ret = rtnet_put_arg(fd, &msg->msg_name, &sin, sizeof(sin)); + if (ret) + goto fail; } +data_len = ntohs(uh->len) - sizeof(struct udphdr); + /* remove the UDP header */ __rtskb_pull(skb, sizeof(struct udphdr)); -first_skb = skb; +flags = msg->msg_flags & ~MSG_TRUNC; +len = rt_iovec_len(iov, msg->msg_iovlen); /* iterate over all IP fragments */ do { @@ -440,25 +468,28 @@ ssize_t rt_udp_recvmsg(struct rtdm_fd *fd, struct user_msghdr *msg, int msg_flag if (copied > len) { block_size -= copied - len; copied = len; -msg->msg_flags |= MSG_TRUNC; - -/* copy the data */ -rt_memcpy_tokerneliovec(msg->msg_iov, skb->data, block_size); - -break; + flags |= MSG_TRUNC; } /* copy the data */ -rt_memcpy_tokerneliovec(msg->msg_iov, skb->data, block_size); + ret = rtnet_write_to_iov(fd, iov, msg->msg_iovlen, skb->data, block_size); + if (ret) + goto fail; /* next fragment */ skb = skb->next; -} while (skb != NULL); +} while (skb && !(flags & MSG_TRUNC)); /* did we copied all bytes? */ if (data_len > 0) -msg->msg_flags |= MSG_TRUNC; + flags |= MSG_TRUNC; +if (flags != msg->msg_flags) { + ret = rtnet_put_arg(fd, &msg->msg_flags, &flags, sizeof(flags)); + if (ret) + goto fail;