mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
bpf: Change bpf_setsockopt(SOL_IP) to reuse do_ip_setsockopt()
After the prep work in the previous patches, this patch removes the dup code from bpf_setsockopt(SOL_IP) and reuses the implementation in do_ip_setsockopt(). The existing optname white-list is refactored into a new function sol_ip_setsockopt(). NOTE, the current bpf_setsockopt(IP_TOS) is quite different from the the do_ip_setsockopt(IP_TOS). For example, it does not take the INET_ECN_MASK into the account for tcp and also does not adjust sk->sk_priority. It looks like the current bpf_setsockopt(IP_TOS) was referencing the IPV6_TCLASS implementation instead of IP_TOS. This patch tries to rectify that by using the do_ip_setsockopt(IP_TOS). While this is a behavior change, the do_ip_setsockopt(IP_TOS) behavior is arguably what the user is expecting. At least, the INET_ECN_MASK bits should be masked out for tcp. Reviewed-by: Stanislav Fomichev <sdf@google.com> Signed-off-by: Martin KaFai Lau <kafai@fb.com> Link: https://lore.kernel.org/r/20220817061826.4180990-1-kafai@fb.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
parent
0c751f7071
commit
ee7f1e1302
@ -743,6 +743,8 @@ void ip_cmsg_recv_offset(struct msghdr *msg, struct sock *sk,
|
|||||||
int ip_cmsg_send(struct sock *sk, struct msghdr *msg,
|
int ip_cmsg_send(struct sock *sk, struct msghdr *msg,
|
||||||
struct ipcm_cookie *ipc, bool allow_ipv6);
|
struct ipcm_cookie *ipc, bool allow_ipv6);
|
||||||
DECLARE_STATIC_KEY_FALSE(ip4_min_ttl);
|
DECLARE_STATIC_KEY_FALSE(ip4_min_ttl);
|
||||||
|
int do_ip_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,
|
||||||
|
unsigned int optlen);
|
||||||
int ip_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,
|
int ip_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,
|
||||||
unsigned int optlen);
|
unsigned int optlen);
|
||||||
int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
|
int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
|
||||||
|
@ -5114,6 +5114,25 @@ static int sol_tcp_setsockopt(struct sock *sk, int optname,
|
|||||||
KERNEL_SOCKPTR(optval), optlen);
|
KERNEL_SOCKPTR(optval), optlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int sol_ip_setsockopt(struct sock *sk, int optname,
|
||||||
|
char *optval, int optlen)
|
||||||
|
{
|
||||||
|
if (sk->sk_family != AF_INET)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
switch (optname) {
|
||||||
|
case IP_TOS:
|
||||||
|
if (optlen != sizeof(int))
|
||||||
|
return -EINVAL;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return do_ip_setsockopt(sk, SOL_IP, optname,
|
||||||
|
KERNEL_SOCKPTR(optval), optlen);
|
||||||
|
}
|
||||||
|
|
||||||
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)
|
char *optval, int optlen)
|
||||||
{
|
{
|
||||||
@ -5125,26 +5144,7 @@ static int __bpf_setsockopt(struct sock *sk, int level, int optname,
|
|||||||
if (level == SOL_SOCKET) {
|
if (level == SOL_SOCKET) {
|
||||||
return sol_socket_setsockopt(sk, optname, optval, optlen);
|
return sol_socket_setsockopt(sk, optname, optval, optlen);
|
||||||
} else if (IS_ENABLED(CONFIG_INET) && level == SOL_IP) {
|
} else if (IS_ENABLED(CONFIG_INET) && level == SOL_IP) {
|
||||||
if (optlen != sizeof(int) || sk->sk_family != AF_INET)
|
return sol_ip_setsockopt(sk, optname, optval, optlen);
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
val = *((int *)optval);
|
|
||||||
/* Only some options are supported */
|
|
||||||
switch (optname) {
|
|
||||||
case IP_TOS:
|
|
||||||
if (val < -1 || val > 0xff) {
|
|
||||||
ret = -EINVAL;
|
|
||||||
} else {
|
|
||||||
struct inet_sock *inet = inet_sk(sk);
|
|
||||||
|
|
||||||
if (val == -1)
|
|
||||||
val = 0;
|
|
||||||
inet->tos = val;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ret = -EINVAL;
|
|
||||||
}
|
|
||||||
} else if (IS_ENABLED(CONFIG_IPV6) && level == SOL_IPV6) {
|
} else if (IS_ENABLED(CONFIG_IPV6) && level == SOL_IPV6) {
|
||||||
if (optlen != sizeof(int) || sk->sk_family != AF_INET6)
|
if (optlen != sizeof(int) || sk->sk_family != AF_INET6)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -888,8 +888,8 @@ static int compat_ip_mcast_join_leave(struct sock *sk, int optname,
|
|||||||
|
|
||||||
DEFINE_STATIC_KEY_FALSE(ip4_min_ttl);
|
DEFINE_STATIC_KEY_FALSE(ip4_min_ttl);
|
||||||
|
|
||||||
static int do_ip_setsockopt(struct sock *sk, int level, int optname,
|
int do_ip_setsockopt(struct sock *sk, int level, int optname,
|
||||||
sockptr_t optval, unsigned int optlen)
|
sockptr_t optval, unsigned int optlen)
|
||||||
{
|
{
|
||||||
struct inet_sock *inet = inet_sk(sk);
|
struct inet_sock *inet = inet_sk(sk);
|
||||||
struct net *net = sock_net(sk);
|
struct net *net = sock_net(sk);
|
||||||
|
Loading…
Reference in New Issue
Block a user