diff --git a/include/linux/sockptr.h b/include/linux/sockptr.h index 9e6c81d474cb..96840def9d69 100644 --- a/include/linux/sockptr.h +++ b/include/linux/sockptr.h @@ -27,14 +27,6 @@ static inline sockptr_t KERNEL_SOCKPTR(void *p) { return (sockptr_t) { .kernel = p }; } - -static inline int __must_check init_user_sockptr(sockptr_t *sp, void __user *p) -{ - if ((unsigned long)p >= TASK_SIZE) - return -EFAULT; - sp->user = p; - return 0; -} #else /* CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE */ typedef struct { union { @@ -53,14 +45,16 @@ static inline sockptr_t KERNEL_SOCKPTR(void *p) { return (sockptr_t) { .kernel = p, .is_kernel = true }; } +#endif /* CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE */ -static inline int __must_check init_user_sockptr(sockptr_t *sp, void __user *p) +static inline int __must_check init_user_sockptr(sockptr_t *sp, void __user *p, + size_t size) { - sp->user = p; - sp->is_kernel = false; + if (!access_ok(p, size)) + return -EFAULT; + *sp = (sockptr_t) { .user = p }; return 0; } -#endif /* CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE */ static inline bool sockptr_is_null(sockptr_t sockptr) { diff --git a/net/ipv4/bpfilter/sockopt.c b/net/ipv4/bpfilter/sockopt.c index 94f18d2352d0..545b2640f019 100644 --- a/net/ipv4/bpfilter/sockopt.c +++ b/net/ipv4/bpfilter/sockopt.c @@ -65,7 +65,7 @@ int bpfilter_ip_get_sockopt(struct sock *sk, int optname, if (get_user(len, optlen)) return -EFAULT; - err = init_user_sockptr(&optval, user_optval); + err = init_user_sockptr(&optval, user_optval, len); if (err) return err; return bpfilter_mbox_request(sk, optname, optval, len, false); diff --git a/net/socket.c b/net/socket.c index 94ca4547cd7c..aff52e81653c 100644 --- a/net/socket.c +++ b/net/socket.c @@ -2105,7 +2105,7 @@ int __sys_setsockopt(int fd, int level, int optname, char __user *user_optval, if (optlen < 0) return -EINVAL; - err = init_user_sockptr(&optval, user_optval); + err = init_user_sockptr(&optval, user_optval, optlen); if (err) return err;