diff options
| -rw-r--r-- | include/net/compat.h | 1 | ||||
| -rw-r--r-- | net/compat.c | 17 | ||||
| -rw-r--r-- | net/packet/af_packet.c | 25 |
3 files changed, 41 insertions, 2 deletions
diff --git a/include/net/compat.h b/include/net/compat.h index 48103cf94e97..13de0ccaa059 100644 --- a/include/net/compat.h +++ b/include/net/compat.h | |||
| @@ -42,6 +42,7 @@ int compat_sock_get_timestampns(struct sock *, struct timespec __user *); | |||
| 42 | 42 | ||
| 43 | int get_compat_msghdr(struct msghdr *, struct compat_msghdr __user *, | 43 | int get_compat_msghdr(struct msghdr *, struct compat_msghdr __user *, |
| 44 | struct sockaddr __user **, struct iovec **); | 44 | struct sockaddr __user **, struct iovec **); |
| 45 | struct sock_fprog __user *get_compat_bpf_fprog(char __user *optval); | ||
| 45 | asmlinkage long compat_sys_sendmsg(int, struct compat_msghdr __user *, | 46 | asmlinkage long compat_sys_sendmsg(int, struct compat_msghdr __user *, |
| 46 | unsigned int); | 47 | unsigned int); |
| 47 | asmlinkage long compat_sys_sendmmsg(int, struct compat_mmsghdr __user *, | 48 | asmlinkage long compat_sys_sendmmsg(int, struct compat_mmsghdr __user *, |
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, |
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 4040eb92d9c9..9bff6ef16fa7 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c | |||
| @@ -93,6 +93,7 @@ | |||
| 93 | #include <net/inet_common.h> | 93 | #include <net/inet_common.h> |
| 94 | #endif | 94 | #endif |
| 95 | #include <linux/bpf.h> | 95 | #include <linux/bpf.h> |
| 96 | #include <net/compat.h> | ||
| 96 | 97 | ||
| 97 | #include "internal.h" | 98 | #include "internal.h" |
| 98 | 99 | ||
| @@ -3940,6 +3941,27 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, | |||
| 3940 | } | 3941 | } |
| 3941 | 3942 | ||
| 3942 | 3943 | ||
| 3944 | #ifdef CONFIG_COMPAT | ||
| 3945 | static int compat_packet_setsockopt(struct socket *sock, int level, int optname, | ||
| 3946 | char __user *optval, unsigned int optlen) | ||
| 3947 | { | ||
| 3948 | struct packet_sock *po = pkt_sk(sock->sk); | ||
| 3949 | |||
| 3950 | if (level != SOL_PACKET) | ||
| 3951 | return -ENOPROTOOPT; | ||
| 3952 | |||
| 3953 | if (optname == PACKET_FANOUT_DATA && | ||
| 3954 | po->fanout && po->fanout->type == PACKET_FANOUT_CBPF) { | ||
| 3955 | optval = (char __user *)get_compat_bpf_fprog(optval); | ||
| 3956 | if (!optval) | ||
| 3957 | return -EFAULT; | ||
| 3958 | optlen = sizeof(struct sock_fprog); | ||
| 3959 | } | ||
| 3960 | |||
| 3961 | return packet_setsockopt(sock, level, optname, optval, optlen); | ||
| 3962 | } | ||
| 3963 | #endif | ||
| 3964 | |||
| 3943 | static int packet_notifier(struct notifier_block *this, | 3965 | static int packet_notifier(struct notifier_block *this, |
| 3944 | unsigned long msg, void *ptr) | 3966 | unsigned long msg, void *ptr) |
| 3945 | { | 3967 | { |
| @@ -4416,6 +4438,9 @@ static const struct proto_ops packet_ops = { | |||
| 4416 | .shutdown = sock_no_shutdown, | 4438 | .shutdown = sock_no_shutdown, |
| 4417 | .setsockopt = packet_setsockopt, | 4439 | .setsockopt = packet_setsockopt, |
| 4418 | .getsockopt = packet_getsockopt, | 4440 | .getsockopt = packet_getsockopt, |
| 4441 | #ifdef CONFIG_COMPAT | ||
| 4442 | .compat_setsockopt = compat_packet_setsockopt, | ||
| 4443 | #endif | ||
| 4419 | .sendmsg = packet_sendmsg, | 4444 | .sendmsg = packet_sendmsg, |
| 4420 | .recvmsg = packet_recvmsg, | 4445 | .recvmsg = packet_recvmsg, |
| 4421 | .mmap = packet_mmap, | 4446 | .mmap = packet_mmap, |
