Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: Revert "net: optimize the sockptr_t for unified kernel/user address spaces"

This reverts commits 6d04fe15f78acdf8e32329e208552e226f7a8ae6 and
a31edb2059ed4e498f9aa8230c734b59d0ad797a.

It turns out the idea to share a single pointer for both kernel and user
space address causes various kinds of problems. So use the slightly less
optimal version that uses an extra bit, but which is guaranteed to be safe
everywhere.

Fixes: 6d04fe15f78a ("net: optimize the sockptr_t for unified kernel/user address spaces")
Reported-by: Eric Dumazet <edumazet@google.com>
Reported-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Christoph Hellwig and committed by
David S. Miller
519a8a6c 7c7ab580

+9 -37
+2 -24
include/linux/sockptr.h
··· 8 8 #ifndef _LINUX_SOCKPTR_H 9 9 #define _LINUX_SOCKPTR_H 10 10 11 - #include <linux/compiler.h> 12 11 #include <linux/slab.h> 13 12 #include <linux/uaccess.h> 14 13 15 - #ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE 16 - typedef union { 17 - void *kernel; 18 - void __user *user; 19 - } sockptr_t; 20 - 21 - static inline bool sockptr_is_kernel(sockptr_t sockptr) 22 - { 23 - return (unsigned long)sockptr.kernel >= TASK_SIZE; 24 - } 25 - 26 - static inline sockptr_t KERNEL_SOCKPTR(void *p) 27 - { 28 - return (sockptr_t) { .kernel = p }; 29 - } 30 - #else /* CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE */ 31 14 typedef struct { 32 15 union { 33 16 void *kernel; ··· 28 45 { 29 46 return (sockptr_t) { .kernel = p, .is_kernel = true }; 30 47 } 31 - #endif /* CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE */ 32 48 33 - static inline int __must_check init_user_sockptr(sockptr_t *sp, void __user *p, 34 - size_t size) 49 + static inline sockptr_t USER_SOCKPTR(void __user *p) 35 50 { 36 - if (!access_ok(p, size)) 37 - return -EFAULT; 38 - *sp = (sockptr_t) { .user = p }; 39 - return 0; 51 + return (sockptr_t) { .user = p }; 40 52 } 41 53 42 54 static inline bool sockptr_is_null(sockptr_t sockptr)
+6 -8
net/ipv4/bpfilter/sockopt.c
··· 57 57 return bpfilter_mbox_request(sk, optname, optval, optlen, true); 58 58 } 59 59 60 - int bpfilter_ip_get_sockopt(struct sock *sk, int optname, 61 - char __user *user_optval, int __user *optlen) 60 + int bpfilter_ip_get_sockopt(struct sock *sk, int optname, char __user *optval, 61 + int __user *optlen) 62 62 { 63 - sockptr_t optval; 64 - int err, len; 63 + int len; 65 64 66 65 if (get_user(len, optlen)) 67 66 return -EFAULT; 68 - err = init_user_sockptr(&optval, user_optval, len); 69 - if (err) 70 - return err; 71 - return bpfilter_mbox_request(sk, optname, optval, len, false); 67 + 68 + return bpfilter_mbox_request(sk, optname, USER_SOCKPTR(optval), len, 69 + false); 72 70 } 73 71 74 72 static int __init bpfilter_sockopt_init(void)
+1 -5
net/socket.c
··· 2095 2095 int __sys_setsockopt(int fd, int level, int optname, char __user *user_optval, 2096 2096 int optlen) 2097 2097 { 2098 - sockptr_t optval; 2098 + sockptr_t optval = USER_SOCKPTR(user_optval); 2099 2099 char *kernel_optval = NULL; 2100 2100 int err, fput_needed; 2101 2101 struct socket *sock; 2102 2102 2103 2103 if (optlen < 0) 2104 2104 return -EINVAL; 2105 - 2106 - err = init_user_sockptr(&optval, user_optval, optlen); 2107 - if (err) 2108 - return err; 2109 2105 2110 2106 sock = sockfd_lookup_light(fd, &err, &fput_needed); 2111 2107 if (!sock)