From: Martin KaFai Lau <kafai@fb.com>
To: <bpf@vger.kernel.org>, <netdev@vger.kernel.org>
Cc: Alexei Starovoitov <ast@kernel.org>,
Andrii Nakryiko <andrii@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
David Miller <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, <kernel-team@fb.com>,
Paolo Abeni <pabeni@redhat.com>,
Stanislav Fomichev <sdf@google.com>
Subject: [PATCH v3 bpf-next 03/15] bpf: net: Consider has_current_bpf_ctx() when testing capable() in sk_setsockopt()
Date: Wed, 10 Aug 2022 12:07:44 -0700 [thread overview]
Message-ID: <20220810190744.2694835-1-kafai@fb.com> (raw)
In-Reply-To: <20220810190724.2692127-1-kafai@fb.com>
When bpf program calling bpf_setsockopt(SOL_SOCKET),
it could be run in softirq and doesn't make sense to do the capable
check. There was a similar situation in bpf_setsockopt(TCP_CONGESTION).
In commit 8d650cdedaab ("tcp: fix tcp_set_congestion_control() use from bpf hook"),
tcp_set_congestion_control(..., cap_net_admin) was added to skip
the cap check for bpf prog.
This patch adds sockopt_ns_capable() and sockopt_capable() for
the sk_setsockopt() to use. They will consider the
has_current_bpf_ctx() before doing the ns_capable() and capable() test.
They are in EXPORT_SYMBOL for the ipv6 module to use in a latter patch.
Suggested-by: Stanislav Fomichev <sdf@google.com>
Signed-off-by: Martin KaFai Lau <kafai@fb.com>
---
include/net/sock.h | 2 ++
net/core/sock.c | 38 +++++++++++++++++++++++++-------------
2 files changed, 27 insertions(+), 13 deletions(-)
diff --git a/include/net/sock.h b/include/net/sock.h
index b2ff230860c6..72b78c2b6f83 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1723,6 +1723,8 @@ static inline void unlock_sock_fast(struct sock *sk, bool slow)
void sockopt_lock_sock(struct sock *sk);
void sockopt_release_sock(struct sock *sk);
+bool sockopt_ns_capable(struct user_namespace *ns, int cap);
+bool sockopt_capable(int cap);
/* Used by processes to "lock" a socket state, so that
* interrupts and bottom half handlers won't change it
diff --git a/net/core/sock.c b/net/core/sock.c
index d3683228376f..7ea46e4700fd 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1060,6 +1060,18 @@ void sockopt_release_sock(struct sock *sk)
}
EXPORT_SYMBOL(sockopt_release_sock);
+bool sockopt_ns_capable(struct user_namespace *ns, int cap)
+{
+ return has_current_bpf_ctx() || ns_capable(ns, cap);
+}
+EXPORT_SYMBOL(sockopt_ns_capable);
+
+bool sockopt_capable(int cap)
+{
+ return has_current_bpf_ctx() || capable(cap);
+}
+EXPORT_SYMBOL(sockopt_capable);
+
/*
* This is meant for all protocols to use and covers goings on
* at the socket level. Everything here is generic.
@@ -1095,7 +1107,7 @@ static int sk_setsockopt(struct sock *sk, int level, int optname,
switch (optname) {
case SO_DEBUG:
- if (val && !capable(CAP_NET_ADMIN))
+ if (val && !sockopt_capable(CAP_NET_ADMIN))
ret = -EACCES;
else
sock_valbool_flag(sk, SOCK_DBG, valbool);
@@ -1139,7 +1151,7 @@ static int sk_setsockopt(struct sock *sk, int level, int optname,
break;
case SO_SNDBUFFORCE:
- if (!capable(CAP_NET_ADMIN)) {
+ if (!sockopt_capable(CAP_NET_ADMIN)) {
ret = -EPERM;
break;
}
@@ -1161,7 +1173,7 @@ static int sk_setsockopt(struct sock *sk, int level, int optname,
break;
case SO_RCVBUFFORCE:
- if (!capable(CAP_NET_ADMIN)) {
+ if (!sockopt_capable(CAP_NET_ADMIN)) {
ret = -EPERM;
break;
}
@@ -1188,8 +1200,8 @@ static int sk_setsockopt(struct sock *sk, int level, int optname,
case SO_PRIORITY:
if ((val >= 0 && val <= 6) ||
- ns_capable(sock_net(sk)->user_ns, CAP_NET_RAW) ||
- ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
+ sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_RAW) ||
+ sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
sk->sk_priority = val;
else
ret = -EPERM;
@@ -1334,8 +1346,8 @@ static int sk_setsockopt(struct sock *sk, int level, int optname,
clear_bit(SOCK_PASSSEC, &sock->flags);
break;
case SO_MARK:
- if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_RAW) &&
- !ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) {
+ if (!sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_RAW) &&
+ !sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) {
ret = -EPERM;
break;
}
@@ -1343,8 +1355,8 @@ static int sk_setsockopt(struct sock *sk, int level, int optname,
__sock_set_mark(sk, val);
break;
case SO_RCVMARK:
- if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_RAW) &&
- !ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) {
+ if (!sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_RAW) &&
+ !sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) {
ret = -EPERM;
break;
}
@@ -1378,7 +1390,7 @@ static int sk_setsockopt(struct sock *sk, int level, int optname,
#ifdef CONFIG_NET_RX_BUSY_POLL
case SO_BUSY_POLL:
/* allow unprivileged users to decrease the value */
- if ((val > sk->sk_ll_usec) && !capable(CAP_NET_ADMIN))
+ if ((val > sk->sk_ll_usec) && !sockopt_capable(CAP_NET_ADMIN))
ret = -EPERM;
else {
if (val < 0)
@@ -1388,13 +1400,13 @@ static int sk_setsockopt(struct sock *sk, int level, int optname,
}
break;
case SO_PREFER_BUSY_POLL:
- if (valbool && !capable(CAP_NET_ADMIN))
+ if (valbool && !sockopt_capable(CAP_NET_ADMIN))
ret = -EPERM;
else
WRITE_ONCE(sk->sk_prefer_busy_poll, valbool);
break;
case SO_BUSY_POLL_BUDGET:
- if (val > READ_ONCE(sk->sk_busy_poll_budget) && !capable(CAP_NET_ADMIN)) {
+ if (val > READ_ONCE(sk->sk_busy_poll_budget) && !sockopt_capable(CAP_NET_ADMIN)) {
ret = -EPERM;
} else {
if (val < 0 || val > U16_MAX)
@@ -1465,7 +1477,7 @@ static int sk_setsockopt(struct sock *sk, int level, int optname,
* scheduler has enough safe guards.
*/
if (sk_txtime.clockid != CLOCK_MONOTONIC &&
- !ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) {
+ !sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) {
ret = -EPERM;
break;
}
--
2.30.2
next prev parent reply other threads:[~2022-08-10 19:10 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-08-10 19:07 [PATCH v3 bpf-next 00/15] bpf: net: Remove duplicated code from bpf_setsockopt() Martin KaFai Lau
2022-08-10 19:07 ` [PATCH v3 bpf-next 01/15] net: Add sk_setsockopt() to take the sk ptr instead of the sock ptr Martin KaFai Lau
2022-08-10 19:07 ` [PATCH v3 bpf-next 02/15] bpf: net: Avoid sk_setsockopt() taking sk lock when called from bpf Martin KaFai Lau
2022-08-16 3:32 ` Andrii Nakryiko
2022-08-10 19:07 ` Martin KaFai Lau [this message]
2022-08-10 19:07 ` [PATCH v3 bpf-next 04/15] bpf: net: Change do_tcp_setsockopt() to use the sockopt's lock_sock() and capable() Martin KaFai Lau
2022-08-10 19:07 ` [PATCH v3 bpf-next 05/15] bpf: net: Change do_ip_setsockopt() " Martin KaFai Lau
2022-08-10 19:08 ` [PATCH v3 bpf-next 06/15] bpf: net: Change do_ipv6_setsockopt() " Martin KaFai Lau
2022-08-10 19:08 ` [PATCH v3 bpf-next 07/15] bpf: Initialize the bpf_run_ctx in bpf_iter_run_prog() Martin KaFai Lau
2022-08-16 3:33 ` Andrii Nakryiko
2022-08-10 19:08 ` [PATCH v3 bpf-next 08/15] bpf: Embed kernel CONFIG check into the if statement in bpf_setsockopt Martin KaFai Lau
2022-08-10 19:08 ` [PATCH v3 bpf-next 09/15] bpf: Change bpf_setsockopt(SOL_SOCKET) to reuse sk_setsockopt() Martin KaFai Lau
2022-08-10 19:08 ` [PATCH v3 bpf-next 10/15] bpf: Refactor bpf specific tcp optnames to a new function Martin KaFai Lau
2022-08-10 19:08 ` [PATCH v3 bpf-next 11/15] bpf: Change bpf_setsockopt(SOL_TCP) to reuse do_tcp_setsockopt() Martin KaFai Lau
2022-08-10 19:08 ` [PATCH v3 bpf-next 12/15] bpf: Change bpf_setsockopt(SOL_IP) to reuse do_ip_setsockopt() Martin KaFai Lau
2022-08-10 19:08 ` [PATCH v3 bpf-next 13/15] bpf: Change bpf_setsockopt(SOL_IPV6) to reuse do_ipv6_setsockopt() Martin KaFai Lau
2022-08-10 19:08 ` [PATCH v3 bpf-next 14/15] bpf: Add a few optnames to bpf_setsockopt Martin KaFai Lau
2022-08-10 19:09 ` [PATCH v3 bpf-next 15/15] selftests/bpf: bpf_setsockopt tests Martin KaFai Lau
2022-08-11 17:04 ` [PATCH v3 bpf-next 00/15] bpf: net: Remove duplicated code from bpf_setsockopt() sdf
2022-08-15 22:04 ` Daniel Borkmann
2022-08-17 5:23 ` Martin KaFai Lau
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220810190744.2694835-1-kafai@fb.com \
--to=kafai@fb.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=kernel-team@fb.com \
--cc=kuba@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=sdf@google.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.