From: Josef Bacik <josef@toxicpanda.com>
To: Christian Brauner <brauner@kernel.org>,
James Bottomley <James.Bottomley@HansenPartnership.com>,
Andrew Halaney <andrew@amutable.com>,
Jeremy Bingham <jbingham@gmail.com>,
Tahera Fahimi <taherafahimi@linux.microsoft.com>,
Serge Hallyn <sergeh@kernel.org>
Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org,
Josef Bacik <josef@toxicpanda.com>
Subject: [PATCH RFC v3 75/90] net: add net_may()
Date: Thu, 05 Nov 2026 15:03:07 +0000 [thread overview]
Message-ID: <20261105-b4-cells-v3-75-bc9095937a84@toxicpanda.com> (raw)
In-Reply-To: <20261105-b4-cells-v3-0-bc9095937a84@toxicpanda.com>
Almost every operation that changes a network namespace is guarded by the
same check: ns_capable(net->user_ns, CAP_NET_ADMIN). There are well over a
hundred of these checks. They cover devices, addresses, routes, netfilter,
traffic control, tunnels, IPsec, socket options and more.
The check does not say which of these it is guarding. So there is no way
to allow one kind of operation without allowing all of them. A program
that only needs to add a netfilter rule must be given the power to create
tunnels as well.
Add net_may(net, right). It asks whether the caller may do one particular
kind of thing to a network namespace, and enum net_right names the kinds.
For now the answer is the same as before: NET_RIGHT_RAW requires
CAP_NET_RAW over the owner of the namespace, and every other right
requires CAP_NET_ADMIN. A single function, net_right_ns(), makes that
decision, so a later patch can change it in one place.
Add a variant for each form the existing checks take:
net_may_noaudit() like ns_capable_noaudit()
file_net_may() like file_ns_capable(), for the opener of a file
sockopt_net_may() like sockopt_ns_capable(), which lets BPF set options
netlink_net_may() like netlink_ns_capable(), which checks both the
opener of the socket and the sender of the message
The rights follow the entry points, because most of the code in question
sits behind a handful of them. A right can be split later if its entry
point learns to distinguish more cases.
There are no users yet.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
include/linux/netlink.h | 2 ++
include/net/net_namespace.h | 25 +++++++++++++++++++
include/net/sock.h | 1 +
net/core/net_namespace.c | 58 +++++++++++++++++++++++++++++++++++++++++++++
net/core/sock.c | 13 ++++++++++
net/netlink/af_netlink.c | 21 ++++++++++++++++
6 files changed, 120 insertions(+)
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index 882e9c1b6c1d..16ecb55e9f12 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -10,6 +10,7 @@
#include <uapi/linux/netlink.h>
struct net;
+enum net_right;
void do_trace_netlink_extack(const char *msg);
@@ -356,6 +357,7 @@ bool netlink_ns_capable(const struct sk_buff *skb,
struct user_namespace *ns, int cap);
bool netlink_capable(const struct sk_buff *skb, int cap);
bool netlink_net_capable(const struct sk_buff *skb, int cap);
+bool netlink_net_may(const struct sk_buff *skb, const struct net *net, enum net_right right);
struct sk_buff *netlink_alloc_large_skb(unsigned int size, int broadcast);
#endif /* __LINUX_NETLINK_H */
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index c29a22ca178f..badee0bbc567 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -459,6 +459,31 @@ static inline struct net *read_pnet_rcu(const possible_net_t *pnet)
#define __net_initconst __initconst
#endif
+/**
+ * enum net_right - what somebody wants to do to a network namespace
+ *
+ * Changing anything about a network namespace takes a capability over the user
+ * namespace that owns it, and nearly always that is CAP_NET_ADMIN, whatever it is
+ * that is to be changed. A check that goes by way of net_may() says what it is for.
+ */
+enum net_right {
+ NET_RIGHT_LINK, /* change a device: up, down, mtu, name */
+ NET_RIGHT_LINK_NEW, /* make and remove devices */
+ NET_RIGHT_ADDR, /* addresses */
+ NET_RIGHT_ROUTE, /* routes, rules, neighbours */
+ NET_RIGHT_FILTER, /* netfilter */
+ NET_RIGHT_TC, /* queueing disciplines, classes, filters */
+ NET_RIGHT_TUN, /* make tun and tap devices */
+ NET_RIGHT_SYSCTL, /* /proc/sys/net */
+ NET_RIGHT_SOCKOPT, /* socket options that reach beyond the socket */
+ NET_RIGHT_RAW, /* raw and packet sockets. This one is CAP_NET_RAW */
+ NET_RIGHT_NR
+};
+
+bool net_may(const struct net *net, enum net_right right);
+bool net_may_noaudit(const struct net *net, enum net_right right);
+bool file_net_may(const struct file *file, const struct net *net, enum net_right right);
+
int peernet2id_alloc(struct net *net, struct net *peer, gfp_t gfp);
int peernet2id(const struct net *net, struct net *peer);
bool peernet_has_id(const struct net *net, struct net *peer);
diff --git a/include/net/sock.h b/include/net/sock.h
index 173b37b2b8bb..7562a73ac29d 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1781,6 +1781,7 @@ 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_net_may(const struct sock *sk, enum net_right right);
bool sockopt_capable(int cap);
/* Used by processes to "lock" a socket state, so that
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 52c2bd44778a..d211631f8c42 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -362,6 +362,64 @@ int peernet2id(const struct net *net, struct net *peer)
}
EXPORT_SYMBOL(peernet2id);
+static int net_right_cap(enum net_right right)
+{
+ return right == NET_RIGHT_RAW ? CAP_NET_RAW : CAP_NET_ADMIN;
+}
+
+/* The user namespace over which @cred needs the capability. NULL: none will do. */
+static struct user_namespace *net_right_ns(const struct cred *cred, const struct net *net,
+ enum net_right right)
+{
+ return net->user_ns;
+}
+
+/**
+ * net_may - may the caller do this to a network namespace?
+ * @net: the network namespace
+ * @right: what it is that the caller wants to do
+ *
+ * Return: true if it may, which is noted as a use of privilege.
+ */
+bool net_may(const struct net *net, enum net_right right)
+{
+ struct user_namespace *ns = net_right_ns(current_cred(), net, right);
+
+ return ns && ns_capable(ns, net_right_cap(right));
+}
+EXPORT_SYMBOL_GPL(net_may);
+
+/**
+ * net_may_noaudit - the same, where a no is nothing to write home about
+ * @net: the network namespace
+ * @right: what it is that the caller wants to do
+ *
+ * Return: true if it may.
+ */
+bool net_may_noaudit(const struct net *net, enum net_right right)
+{
+ struct user_namespace *ns = net_right_ns(current_cred(), net, right);
+
+ return ns && ns_capable_noaudit(ns, net_right_cap(right));
+}
+EXPORT_SYMBOL_GPL(net_may_noaudit);
+
+/**
+ * file_net_may - might whoever opened a file do this to a network namespace?
+ * @file: the file
+ * @net: the network namespace
+ * @right: what is to be done
+ *
+ * Return: true if it might, going by what it was when it opened @file.
+ */
+bool file_net_may(const struct file *file, const struct net *net, enum net_right right)
+{
+ struct user_namespace *ns = net_right_ns(file->f_cred, net, right);
+
+ return ns && file_ns_capable(file, ns, net_right_cap(right));
+}
+EXPORT_SYMBOL_GPL(file_net_may);
+
/* This function returns true is the peer netns has an id assigned into the
* current netns.
*/
diff --git a/net/core/sock.c b/net/core/sock.c
index cac93cba3c84..352310066e35 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1172,6 +1172,19 @@ bool sockopt_ns_capable(struct user_namespace *ns, int cap)
}
EXPORT_SYMBOL(sockopt_ns_capable);
+/**
+ * sockopt_net_may - net_may() over the network namespace of a socket, for an option
+ * @sk: the socket
+ * @right: what the option comes to
+ *
+ * Return: true if the caller may, or if it is a BPF program that sets the option.
+ */
+bool sockopt_net_may(const struct sock *sk, enum net_right right)
+{
+ return has_current_bpf_ctx() || net_may(sock_net(sk), right);
+}
+EXPORT_SYMBOL(sockopt_net_may);
+
bool sockopt_capable(int cap)
{
return has_current_bpf_ctx() || capable(cap);
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 1281c42a3456..69c92fad0a32 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -899,6 +899,27 @@ bool netlink_net_capable(const struct sk_buff *skb, int cap)
}
EXPORT_SYMBOL(netlink_net_capable);
+/**
+ * netlink_net_may - net_may() for a request that came in by netlink
+ * @skb: socket buffer holding a netlink command from userspace
+ * @net: the network namespace that the command is about
+ * @right: what the command wants to do to it
+ *
+ * As for netlink_ns_capable(), it takes both whoever opened the socket and whoever
+ * sent the message.
+ *
+ * Return: true if both may.
+ */
+bool netlink_net_may(const struct sk_buff *skb, const struct net *net, enum net_right right)
+{
+ const struct netlink_skb_parms *nsp = &NETLINK_CB(skb);
+
+ return ((nsp->flags & NETLINK_SKB_DST) ||
+ file_net_may(nsp->sk->sk_socket->file, net, right)) &&
+ net_may(net, right);
+}
+EXPORT_SYMBOL(netlink_net_may);
+
static inline int netlink_allowed(const struct socket *sock, unsigned int flag)
{
return (nl_table[sock->sk->sk_protocol].flags & flag) ||
--
2.55.0
next prev parent reply other threads:[~2026-11-05 15:27 UTC|newest]
Thread overview: 93+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-05 14:56 [PATCH RFC v3 00/90] cells: a container as one kernel object Josef Bacik
2026-11-05 14:56 ` [PATCH RFC v3 01/90] Documentation: add a design document for cells Josef Bacik
2026-11-05 17:06 ` Serge E. Hallyn
2026-11-05 18:23 ` Josef Bacik
2026-11-05 14:56 ` [PATCH RFC v3 02/90] Documentation: add examples " Josef Bacik
2026-11-05 14:56 ` [PATCH RFC v3 03/90] cells: reserve a window of ids Josef Bacik
2026-11-05 14:56 ` [PATCH RFC v3 04/90] user_namespace: let a cell own a user namespace Josef Bacik
2026-11-05 14:56 ` [PATCH RFC v3 05/90] user_namespace: refuse setns() into a cell Josef Bacik
2026-11-05 14:56 ` [PATCH RFC v3 06/90] capability: give the owner no say over " Josef Bacik
2026-11-05 14:56 ` [PATCH RFC v3 07/90] ucount: count the id blocks a user holds Josef Bacik
2026-11-05 14:56 ` [PATCH RFC v3 08/90] user_namespace: let the kernel map the ids of a cell Josef Bacik
2026-11-05 14:57 ` [PATCH RFC v3 09/90] user_namespace: keep legacy maps out of the window Josef Bacik
2026-11-05 14:57 ` [PATCH RFC v3 10/90] user: add uid_range_in_use() Josef Bacik
2026-11-05 14:57 ` [PATCH RFC v3 11/90] keys: add key_user_range_in_use() Josef Bacik
2026-11-05 14:57 ` [PATCH RFC v3 12/90] fs: add kuid_has_fsmapping() and kgid_has_fsmapping() Josef Bacik
2026-11-05 14:57 ` [PATCH RFC v3 13/90] fs: never store an id that was lent to a cell Josef Bacik
2026-11-05 14:57 ` [PATCH RFC v3 14/90] fs: take no id of a cell for a mount option Josef Bacik
2026-11-05 14:57 ` [PATCH RFC v3 15/90] fs: let an idmapping pin the ids of a cell Josef Bacik
2026-11-05 14:57 ` [PATCH RFC v3 16/90] cgroup: let a cgroup become the budget " Josef Bacik
2026-11-05 14:57 ` [PATCH RFC v3 17/90] cgroup: add cgroup_cell_chown() Josef Bacik
2026-11-05 14:57 ` [PATCH RFC v3 18/90] cgroup: give the budget of a cell back Josef Bacik
2026-11-05 14:57 ` [PATCH RFC v3 19/90] cgroup: add cgroup_cell_kill() Josef Bacik
2026-11-05 14:57 ` [PATCH RFC v3 20/90] cgroup: root a cgroup namespace at a given cgroup Josef Bacik
2026-11-05 14:57 ` [PATCH RFC v3 21/90] fs: seal a mount namespace for a cell Josef Bacik
2026-11-05 14:57 ` [PATCH RFC v3 22/90] nsfs: make open_namespace() available outside of fs/ Josef Bacik
2026-11-05 14:57 ` [PATCH RFC v3 23/90] nsproxy: build the nsproxy the tasks of a cell share Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 24/90] cells: add the cell object and cell_create() Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 25/90] cells: add cell_kill() Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 26/90] cells: add cell_configure() Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 27/90] cells: add the "budget" slot Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 28/90] cells: add the "root" slot Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 29/90] cells: add the "ids" slot, for a single id Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 30/90] cells: lend a cell a block of ids Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 31/90] cells: reserve the "spawn" slot Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 32/90] cells: add CELL_CMD_SEAL Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 33/90] cells: add cell_open() Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 34/90] pid: allocate a struct pid ahead of its numbers Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 35/90] fork: let copy_process() place a task in a cell Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 36/90] cgroup: fork a task of a cell into the budget Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 37/90] x86: give a task without an mm no user state Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 38/90] uprobes: cope with a new task that has no mm Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 39/90] fork: add tasks that start out with nothing Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 40/90] pidfd: add PIDFD_EMPTY Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 41/90] pidfd: add pidfd_configure() Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 42/90] pidfd: let pidfd_configure() place files Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 43/90] pidfd: let pidfd_configure() set credentials Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 44/90] pidfd: let pidfd_configure() name a cgroup to start in Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 45/90] ptrace: keep everybody off an embryo Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 46/90] cells: end a cell when its init exits Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 47/90] cells: refuse a task of a cell a change of namespaces Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 48/90] fs: refuse a task of a cell a new mount namespace Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 49/90] nsproxy: refuse to enter a namespace of a cell Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 50/90] cgroup: keep a task of a cell within the budget Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 51/90] cgroup: let nothing but a spawn into a budget Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 52/90] kernfs: let a filesystem refuse a change to a node Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 53/90] cgroup: let a cell change nothing outside its budget Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 54/90] cgroup: leave the limits of a budget to who is above Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 55/90] fs: let a filesystem hold ids that go with the cell Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 56/90] cgroup: let a cell make cgroups below its budget Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 57/90] resctrl: let a cell change nothing Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 58/90] cred: let no id count across cells Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 59/90] ptrace: refuse PTRACE_TRACEME " Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 60/90] keys: ignore an equal uid or gid " Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 61/90] fs: accept a cellfd for MOUNT_ATTR_IDMAP Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 62/90] fs: let a cell set no set-id bits Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 63/90] fs: drop privileges from what a cell may write to Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 64/90] cells: add the "caps" slot Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 65/90] capabilities: take nothing from a file in a cell Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 66/90] capabilities: let a cell shrink its bounding sets Josef Bacik
2026-11-05 15:02 ` [PATCH RFC v3 67/90] af_unix: deliver ancillary data only within a cell Josef Bacik
2026-11-05 15:03 ` [PATCH RFC v3 68/90] af_unix: tell a sender that control data will not cross Josef Bacik
2026-11-05 15:03 ` [PATCH RFC v3 69/90] net: do not identify a peer in another cell Josef Bacik
2026-11-05 15:03 ` [PATCH RFC v3 70/90] seccomp: let a listener put no file into a cell Josef Bacik
2026-11-05 15:03 ` [PATCH RFC v3 71/90] umh: run no program for a task of " Josef Bacik
2026-11-05 15:03 ` [PATCH RFC v3 72/90] coredump: let no core dump leave " Josef Bacik
2026-11-05 15:03 ` [PATCH RFC v3 73/90] cells: add the "net" slot Josef Bacik
2026-11-05 15:03 ` [PATCH RFC v3 74/90] net: give a cell without a network no sockets Josef Bacik
2026-11-05 15:03 ` Josef Bacik [this message]
2026-11-05 15:03 ` [PATCH RFC v3 76/90] rtnetlink: use net_may() for requests that change state Josef Bacik
2026-11-05 15:03 ` [PATCH RFC v3 77/90] net: use net_may() in the configuration ioctls Josef Bacik
2026-11-05 15:03 ` [PATCH RFC v3 78/90] netfilter: use net_may() for configuration Josef Bacik
2026-11-05 15:03 ` [PATCH RFC v3 79/90] tun: use net_may() to create and attach to devices Josef Bacik
2026-11-05 15:03 ` [PATCH RFC v3 80/90] net: use net_may() for the net sysctls Josef Bacik
2026-11-05 15:03 ` [PATCH RFC v3 81/90] net: use net_may() for privileged socket options Josef Bacik
2026-11-05 15:03 ` [PATCH RFC v3 82/90] net: use net_may() for raw and packet sockets Josef Bacik
2026-11-05 15:03 ` [PATCH RFC v3 83/90] cells: add the "net-rights" slot Josef Bacik
2026-11-05 15:03 ` [PATCH RFC v3 84/90] net: honour the rights of a cell in net_may() Josef Bacik
2026-11-05 15:03 ` [PATCH RFC v3 85/90] tun: ignore an equal uid or gid across cells Josef Bacik
2026-11-05 15:03 ` [PATCH RFC v3 86/90] cells: add cell_info() Josef Bacik
2026-11-05 15:03 ` [PATCH RFC v3 87/90] cells: add CONFIG_CELLS Josef Bacik
2026-11-05 15:03 ` [PATCH RFC v3 88/90] arch: wire up the cell system calls Josef Bacik
2026-11-05 15:03 ` [PATCH RFC v3 89/90] MAINTAINERS: add an entry for cells Josef Bacik
2026-11-05 15:03 ` [PATCH RFC v3 90/90] selftests: add tests " Josef Bacik
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=20261105-b4-cells-v3-75-bc9095937a84@toxicpanda.com \
--to=josef@toxicpanda.com \
--cc=James.Bottomley@HansenPartnership.com \
--cc=andrew@amutable.com \
--cc=brauner@kernel.org \
--cc=jbingham@gmail.com \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=sergeh@kernel.org \
--cc=taherafahimi@linux.microsoft.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®