bpf: Allow SO_BINDTODEVICE opt in bpf_setsockopt

Extending the supported sockopts in bpf_setsockopt with
SO_BINDTODEVICE. We call sock_bindtoindex with parameter
lock_sk = false in this context because we already owning
the socket.

Signed-off-by: Ferenc Fejes <fejes@inf.elte.hu>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/4149e304867b8d5a606a305bc59e29b063e51f49.1590871065.git.fejes@inf.elte.hu
This commit is contained in:
Ferenc Fejes 2020-05-30 23:09:01 +02:00 committed by Alexei Starovoitov
parent 8ea204c2b6
commit 70c58997c1

View File

@ -4248,6 +4248,9 @@ static const struct bpf_func_proto bpf_get_socket_uid_proto = {
static int _bpf_setsockopt(struct sock *sk, int level, int optname, static int _bpf_setsockopt(struct sock *sk, int level, int optname,
char *optval, int optlen, u32 flags) char *optval, int optlen, u32 flags)
{ {
char devname[IFNAMSIZ];
struct net *net;
int ifindex;
int ret = 0; int ret = 0;
int val; int val;
@ -4257,7 +4260,7 @@ static int _bpf_setsockopt(struct sock *sk, int level, int optname,
sock_owned_by_me(sk); sock_owned_by_me(sk);
if (level == SOL_SOCKET) { if (level == SOL_SOCKET) {
if (optlen != sizeof(int)) if (optlen != sizeof(int) && optname != SO_BINDTODEVICE)
return -EINVAL; return -EINVAL;
val = *((int *)optval); val = *((int *)optval);
@ -4298,6 +4301,29 @@ static int _bpf_setsockopt(struct sock *sk, int level, int optname,
sk_dst_reset(sk); sk_dst_reset(sk);
} }
break; break;
case SO_BINDTODEVICE:
ret = -ENOPROTOOPT;
#ifdef CONFIG_NETDEVICES
optlen = min_t(long, optlen, IFNAMSIZ - 1);
strncpy(devname, optval, optlen);
devname[optlen] = 0;
ifindex = 0;
if (devname[0] != '\0') {
struct net_device *dev;
ret = -ENODEV;
net = sock_net(sk);
dev = dev_get_by_name(net, devname);
if (!dev)
break;
ifindex = dev->ifindex;
dev_put(dev);
}
ret = sock_bindtoindex(sk, ifindex, false);
#endif
break;
default: default:
ret = -EINVAL; ret = -EINVAL;
} }