diff options
author | Willem de Bruijn <willemb@google.com> | 2016-06-07 12:06:34 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-06-10 02:41:03 -0400 |
commit | 719c44d340beeecd22cbda91b00ef55585b3c1a0 (patch) | |
tree | 5e53d5a92c7548ee9464b2133ad4651c23871297 /net/compat.c | |
parent | ca8bdaf13abbdcbb12ff12164aa2d5b522ec524d (diff) |
packet: compat support for sock_fprog
Socket option PACKET_FANOUT_DATA takes a struct sock_fprog as argument
if PACKET_FANOUT has mode PACKET_FANOUT_CBPF. This structure contains
a pointer into user memory. If userland is 32-bit and kernel is 64-bit
the two disagree about the layout of struct sock_fprog.
Add compat setsockopt support to convert a 32-bit compat_sock_fprog to
a 64-bit sock_fprog. This is analogous to compat_sock_fprog support for
SO_REUSEPORT added in commit 1957598840f4 ("soreuseport: add compat
case for setsockopt SO_ATTACH_REUSEPORT_CBPF").
Reported-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: Willem de Bruijn <willemb@google.com>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/compat.c')
-rw-r--r-- | net/compat.c | 17 |
1 files changed, 15 insertions, 2 deletions
diff --git a/net/compat.c b/net/compat.c index 1373947efb50..1cd2ec046164 100644 --- a/net/compat.c +++ b/net/compat.c | |||
@@ -309,8 +309,8 @@ void scm_detach_fds_compat(struct msghdr *kmsg, struct scm_cookie *scm) | |||
309 | __scm_destroy(scm); | 309 | __scm_destroy(scm); |
310 | } | 310 | } |
311 | 311 | ||
312 | static int do_set_attach_filter(struct socket *sock, int level, int optname, | 312 | /* allocate a 64-bit sock_fprog on the user stack for duration of syscall. */ |
313 | char __user *optval, unsigned int optlen) | 313 | struct sock_fprog __user *get_compat_bpf_fprog(char __user *optval) |
314 | { | 314 | { |
315 | struct compat_sock_fprog __user *fprog32 = (struct compat_sock_fprog __user *)optval; | 315 | struct compat_sock_fprog __user *fprog32 = (struct compat_sock_fprog __user *)optval; |
316 | struct sock_fprog __user *kfprog = compat_alloc_user_space(sizeof(struct sock_fprog)); | 316 | struct sock_fprog __user *kfprog = compat_alloc_user_space(sizeof(struct sock_fprog)); |
@@ -323,6 +323,19 @@ static int do_set_attach_filter(struct socket *sock, int level, int optname, | |||
323 | __get_user(ptr, &fprog32->filter) || | 323 | __get_user(ptr, &fprog32->filter) || |
324 | __put_user(len, &kfprog->len) || | 324 | __put_user(len, &kfprog->len) || |
325 | __put_user(compat_ptr(ptr), &kfprog->filter)) | 325 | __put_user(compat_ptr(ptr), &kfprog->filter)) |
326 | return NULL; | ||
327 | |||
328 | return kfprog; | ||
329 | } | ||
330 | EXPORT_SYMBOL_GPL(get_compat_bpf_fprog); | ||
331 | |||
332 | static int do_set_attach_filter(struct socket *sock, int level, int optname, | ||
333 | char __user *optval, unsigned int optlen) | ||
334 | { | ||
335 | struct sock_fprog __user *kfprog; | ||
336 | |||
337 | kfprog = get_compat_bpf_fprog(optval); | ||
338 | if (!kfprog) | ||
326 | return -EFAULT; | 339 | return -EFAULT; |
327 | 340 | ||
328 | return sock_setsockopt(sock, level, optname, (char __user *)kfprog, | 341 | return sock_setsockopt(sock, level, optname, (char __user *)kfprog, |