Skip to content

Commit 6d04fe1

Browse files
Christoph Hellwigdavem330
authored andcommitted
net: optimize the sockptr_t for unified kernel/user address spaces
For architectures like x86 and arm64 we don't need the separate bit to indicate that a pointer is a kernel pointer as the address spaces are unified. That way the sockptr_t can be reduced to a union of two pointers, which leads to nicer calling conventions. The only caveat is that we need to check that users don't pass in kernel address and thus gain access to kernel memory. Thus the USER_SOCKPTR helper is replaced with a init_user_sockptr function that does this check and returns an error if it fails. Signed-off-by: Christoph Hellwig <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent a7b75c5 commit 6d04fe1

File tree

3 files changed

+43
-9
lines changed

3 files changed

+43
-9
lines changed

include/linux/sockptr.h

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,34 @@
88
#ifndef _LINUX_SOCKPTR_H
99
#define _LINUX_SOCKPTR_H
1010

11+
#include <linux/compiler.h>
1112
#include <linux/slab.h>
1213
#include <linux/uaccess.h>
1314

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+
31+
static inline int __must_check init_user_sockptr(sockptr_t *sp, void __user *p)
32+
{
33+
if ((unsigned long)p >= TASK_SIZE)
34+
return -EFAULT;
35+
sp->user = p;
36+
return 0;
37+
}
38+
#else /* CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE */
1439
typedef struct {
1540
union {
1641
void *kernel;
@@ -29,10 +54,13 @@ static inline sockptr_t KERNEL_SOCKPTR(void *p)
2954
return (sockptr_t) { .kernel = p, .is_kernel = true };
3055
}
3156

32-
static inline sockptr_t USER_SOCKPTR(void __user *p)
57+
static inline int __must_check init_user_sockptr(sockptr_t *sp, void __user *p)
3358
{
34-
return (sockptr_t) { .user = p };
59+
sp->user = p;
60+
sp->is_kernel = false;
61+
return 0;
3562
}
63+
#endif /* CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE */
3664

3765
static inline bool sockptr_is_null(sockptr_t sockptr)
3866
{

net/ipv4/bpfilter/sockopt.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,16 +57,18 @@ int bpfilter_ip_set_sockopt(struct sock *sk, int optname, sockptr_t optval,
5757
return bpfilter_mbox_request(sk, optname, optval, optlen, true);
5858
}
5959

60-
int bpfilter_ip_get_sockopt(struct sock *sk, int optname, char __user *optval,
61-
int __user *optlen)
60+
int bpfilter_ip_get_sockopt(struct sock *sk, int optname,
61+
char __user *user_optval, int __user *optlen)
6262
{
63-
int len;
63+
sockptr_t optval;
64+
int err, len;
6465

6566
if (get_user(len, optlen))
6667
return -EFAULT;
67-
68-
return bpfilter_mbox_request(sk, optname, USER_SOCKPTR(optval), len,
69-
false);
68+
err = init_user_sockptr(&optval, user_optval);
69+
if (err)
70+
return err;
71+
return bpfilter_mbox_request(sk, optname, optval, len, false);
7072
}
7173

7274
static int __init bpfilter_sockopt_init(void)

net/socket.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2097,14 +2097,18 @@ static bool sock_use_custom_sol_socket(const struct socket *sock)
20972097
int __sys_setsockopt(int fd, int level, int optname, char __user *user_optval,
20982098
int optlen)
20992099
{
2100-
sockptr_t optval = USER_SOCKPTR(user_optval);
2100+
sockptr_t optval;
21012101
char *kernel_optval = NULL;
21022102
int err, fput_needed;
21032103
struct socket *sock;
21042104

21052105
if (optlen < 0)
21062106
return -EINVAL;
21072107

2108+
err = init_user_sockptr(&optval, user_optval);
2109+
if (err)
2110+
return err;
2111+
21082112
sock = sockfd_lookup_light(fd, &err, &fput_needed);
21092113
if (!sock)
21102114
return err;

0 commit comments

Comments
 (0)