History

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").

Willem de Bruijn committed 10 years ago

Commit 719c44d1 parent ca8bdaf3 files · +41 −2Browse files

Unified · Split

3 files
  1. include/net/compat.h +1 −0
  2. net/compat.c +15 −2
  3. net/packet/af_packet.c +25 −0
include/net/compat.h+1−0
@@ -42,6 +42,7 @@ int compat_sock_get_timestampns(struct sock *, struct timespec __user *); · 41 unmodified lines
42 42
43int get_compat_msghdr(struct msghdr *, struct compat_msghdr __user *,43int get_compat_msghdr(struct msghdr *, struct compat_msghdr __user *,
44 struct sockaddr __user **, struct iovec **);44 struct sockaddr __user **, struct iovec **);
45struct sock_fprog __user *get_compat_bpf_fprog(char __user *optval);
45asmlinkage long compat_sys_sendmsg(int, struct compat_msghdr __user *,46asmlinkage long compat_sys_sendmsg(int, struct compat_msghdr __user *,
46 unsigned int);47 unsigned int);
47asmlinkage long compat_sys_sendmmsg(int, struct compat_mmsghdr __user *,48asmlinkage long compat_sys_sendmmsg(int, struct compat_mmsghdr __user *,
net/compat.c+15−2
@@ -309,8 +309,8 @@ void scm_detach_fds_compat(struct msghdr *kmsg, struct scm_cookie *scm) · 308 unmodified lines
309 __scm_destroy(scm);309 __scm_destroy(scm);
310}310}
311 311
312static 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)313struct 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, · 6 unmodified lines
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}
330EXPORT_SYMBOL_GPL(get_compat_bpf_fprog);
331
332static 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,
net/packet/af_packet.c+25−0
@@ -93,6 +93,7 @@ · 92 unmodified lines
93#include <net/inet_common.h>93#include <net/inet_common.h>
94#endif94#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, · 3841 unmodified lines
3940}3941}
3941 3942
3942 3943
3944#ifdef CONFIG_COMPAT
3945static 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
3943static int packet_notifier(struct notifier_block *this,3965static 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 = { · 470 unmodified lines
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,