net: improve the user pointer check in init_user_sockptr
Make sure not just the pointer itself but the whole range lies in
the user address space. For that pass the length and then use
the access_ok helper to do the check.
Fixes: 6d04fe15f7
("net: optimize the sockptr_t for unified kernel/user address spaces")
Reported-by: David Laight <David.Laight@ACULAB.COM>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:

committed by
David S. Miller

parent
d3c4815151
commit
a31edb2059
@@ -27,14 +27,6 @@ static inline sockptr_t KERNEL_SOCKPTR(void *p)
|
|||||||
{
|
{
|
||||||
return (sockptr_t) { .kernel = 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 */
|
#else /* CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
union {
|
union {
|
||||||
@@ -53,14 +45,16 @@ static inline sockptr_t KERNEL_SOCKPTR(void *p)
|
|||||||
{
|
{
|
||||||
return (sockptr_t) { .kernel = p, .is_kernel = true };
|
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;
|
if (!access_ok(p, size))
|
||||||
sp->is_kernel = false;
|
return -EFAULT;
|
||||||
|
*sp = (sockptr_t) { .user = p };
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE */
|
|
||||||
|
|
||||||
static inline bool sockptr_is_null(sockptr_t sockptr)
|
static inline bool sockptr_is_null(sockptr_t sockptr)
|
||||||
{
|
{
|
||||||
|
@@ -65,7 +65,7 @@ int bpfilter_ip_get_sockopt(struct sock *sk, int optname,
|
|||||||
|
|
||||||
if (get_user(len, optlen))
|
if (get_user(len, optlen))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
err = init_user_sockptr(&optval, user_optval);
|
err = init_user_sockptr(&optval, user_optval, len);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
return bpfilter_mbox_request(sk, optname, optval, len, false);
|
return bpfilter_mbox_request(sk, optname, optval, len, false);
|
||||||
|
@@ -2105,7 +2105,7 @@ int __sys_setsockopt(int fd, int level, int optname, char __user *user_optval,
|
|||||||
if (optlen < 0)
|
if (optlen < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
err = init_user_sockptr(&optval, user_optval);
|
err = init_user_sockptr(&optval, user_optval, optlen);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user