Skip to contentSkip to conversation

tcp: Require init_net CAP_NET_ADMIN for tcp_child_ehash_entries

PATCH In review Ren Wei 3 participants 3 messages Jun 28 – Jun 29 1 message not in the archive

Subsystems (2)
lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): [email protected]

Ren Wei

author
#1 lore raw

PATCH 1/1 tcp: Require init_net CAP_NET_ADMIN for tcp_child_ehash_entries

From: Zhiling Zou <[email protected]>

tcp_child_ehash_entries controls the size of the private TCP established hash table allocated for subsequently created child network namespaces. The value is consumed during child netns creation by tcp_set_hashinfo() and passed to inet_pernet_hashinfo_alloc(), which can allocate a large per-netns ehash.

The sysctl is writable in each network namespace, and net sysctl permissions allow a task with CAP_NET_ADMIN in the namespace's owning user namespace to write it. An unprivileged user can therefore create a user and network namespace, set tcp_child_ehash_entries to its maximum value, and repeatedly create nested network namespaces to force large kernel allocations and exhaust host memory.

Require CAP_NET_ADMIN in the initial user namespace before accepting writes to tcp_child_ehash_entries. This keeps the tuning knob available to the host administrator while preventing unprivileged user namespaces from using it to drive host-wide memory consumption.

Fixes d1e5e6408b30 ("tcp: Introduce optional per-netns ehash.")
Assisted-by Codex:gpt-5.4
---
 net/ipv4/sysctl_net_ipv4.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)
net/ipv4/sysctl_net_ipv4.c +12 -1
index ca1180dba1de..1cad1b5cb826 100644
@@ -9,6 +9,7 @@
 #include <linux/sysctl.h>
 #include <linux/seqlock.h>
 #include <linux/init.h>
+#include <linux/capability.h>
 #include <linux/slab.h>
 #include <net/icmp.h>
 #include <net/ip.h>
@@ -415,6 +416,16 @@ static int proc_tcp_ehash_entries(const struct ctl_table *table, int write,
 	return proc_dointvec(&tbl, write, buffer, lenp, ppos);
 }
 
+static int proc_tcp_child_ehash_entries(const struct ctl_table *table, int write,
+					void *buffer, size_t *lenp,
+					loff_t *ppos)
+{
+	if (write && !capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	return proc_douintvec_minmax(table, write, buffer, lenp, ppos);
+}
+
 static int proc_udp_hash_entries(const struct ctl_table *table, int write,
 				 void *buffer, size_t *lenp, loff_t *ppos)
 {
@@ -1524,7 +1535,7 @@ static struct ctl_table ipv4_net_table[] = {
 		.data		= &init_net.ipv4.sysctl_tcp_child_ehash_entries,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= proc_douintvec_minmax,
+		.proc_handler	= proc_tcp_child_ehash_entries,
 		.extra1		= SYSCTL_ZERO,
 		.extra2		= &tcp_child_ehash_entries_max,
 	},
Signature · 1 line
2.43.0
#2 lore raw
Quoted 16 lines · Ren Wei

From: Zhiling Zou <[email protected]>

tcp_child_ehash_entries controls the size of the private TCP established hash table allocated for subsequently created child network namespaces. The value is consumed during child netns creation by tcp_set_hashinfo() and passed to inet_pernet_hashinfo_alloc(), which can allocate a large per-netns ehash.

The sysctl is writable in each network namespace, and net sysctl permissions allow a task with CAP_NET_ADMIN in the namespace's owning user namespace to write it. An unprivileged user can therefore create a user and network namespace, set tcp_child_ehash_entries to its maximum value, and repeatedly create nested network namespaces to force large kernel allocations and exhaust host memory.

Quoted 4 lines

Require CAP_NET_ADMIN in the initial user namespace before accepting writes to tcp_child_ehash_entries. This keeps the tuning knob available to the host administrator while preventing unprivileged user namespaces from using it to drive host-wide memory consumption.

I do not think this patch is desirable.
It breaks nested container use cases.
A container runtime running inside a container (with namespace-local CAP_NET_ADMIN but not global)
would no longer be able to tune tcp_child_ehash_entries for its own nested child namespaces.

inet_pernet_hashinfo_alloc() uses GFP_KERNEL_ACCOUNT for a reason, I suggest you start using memcg :)

Keep in mind the sysctl could be set (by root) in init_net for some reason, so only memcg will protect against OOM.

#3 lore raw
Quoted 30 lines · Eric Dumazet
Quoted 16 lines · Ren Wei

From: Zhiling Zou <[email protected]>

tcp_child_ehash_entries controls the size of the private TCP established hash table allocated for subsequently created child network namespaces. The value is consumed during child netns creation by tcp_set_hashinfo() and passed to inet_pernet_hashinfo_alloc(), which can allocate a large per-netns ehash.

The sysctl is writable in each network namespace, and net sysctl permissions allow a task with CAP_NET_ADMIN in the namespace's owning user namespace to write it. An unprivileged user can therefore create a user and network namespace, set tcp_child_ehash_entries to its maximum value, and repeatedly create nested network namespaces to force large kernel allocations and exhaust host memory.

Quoted 4 lines

Require CAP_NET_ADMIN in the initial user namespace before accepting writes to tcp_child_ehash_entries. This keeps the tuning knob available to the host administrator while preventing unprivileged user namespaces from using it to drive host-wide memory consumption.

I do not think this patch is desirable.
It breaks nested container use cases.
A container runtime running inside a container (with namespace-local CAP_NET_ADMIN but not global)
would no longer be able to tune tcp_child_ehash_entries for its own nested child namespaces.

Quoted 5 lines

inet_pernet_hashinfo_alloc() uses GFP_KERNEL_ACCOUNT for a reason, I suggest you start using memcg :)

Keep in mind the sysctl could be set (by root) in init_net for some reason, so only memcg will protect against OOM.

Thanks for the review.

Agreed, restricting writes to init_user_ns CAP_NET_ADMIN is too broad and would break nested container use cases. We will drop this approach.

We will re-check the memcg accounting/fallback behavior for the per-netns ehash allocation and prepare a different fix if there is still a path to host-wide OOM outside the intended memcg limits.