[PATCH net] net/packet: charge fanout groups to the memory cgroup
From: Ahmad AG
Date: Thu Oct 29 2026 - 03:17:31 EST
fanout_add() allocates a new group with room for max_num_members
socket pointers. Since commit 9c661b0b8544 ("net/packet: make
packet_fanout.arr size configurable up to 64K") that is up to 64K
pointers, 512 KB per group, from a single PACKET_FANOUT setsockopt().
The allocation uses GFP_KERNEL, so it is not charged to the caller's
memory cgroup.
Each packet socket can create its own group, so a process with
CAP_NET_RAW in its own user and network namespace holds about 512 KB
of kernel memory per open socket that its memory cgroup never sees.
In a cgroup with memory.max set to 16M, 256 sockets each creating a
group with max_num_members = 65536 took 264 MB of system memory while
memory.current grew by 380 KB.
Allocate the group with GFP_KERNEL_ACCOUNT, as other allocations a
user can make on demand in the networking stack already do. With the
change the same test in the 16M cgroup is stopped by the cgroup's OOM
killer, and with memory.max at 512M the 256 groups charge 262656 KB
for 264640 KB of system memory used.
The missing charge was found by code inspection of net/packet/ with
the help of an LLM and then triggered with a small test program that
creates the sockets and groups and reads memory.current; the numbers
above are from that run. Tested in a QEMU/KVM guest on this tree
(x86_64_defconfig plus kvm_guest.config, KASAN, MEMCG, PACKET),
running the test as uid 1000 in a cgroup v2 memory cgroup.
tools/testing/selftests/net/psock_fanout passes before and after.
Fixes: 9c661b0b8544 ("net/packet: make packet_fanout.arr size
configurable up to 64K")
Cc: stable@xxxxxxxxxxxxxxx
Assisted-by: Claude Code
Signed-off-by: Ahmad AG <ahmadag1001@xxxxxxxxx>
---
net/packet/af_packet.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 823e0911c91..406397acc5c 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -1778,7 +1778,8 @@ static int fanout_add(struct sock *sk, struct
fanout_args *args)
/* legacy PACKET_FANOUT_MAX */
args->max_num_members = 256;
err = -ENOMEM;
- match = kvzalloc_flex(*match, arr, args->max_num_members);
+ match = kvzalloc_flex(*match, arr, args->max_num_members,
+ GFP_KERNEL_ACCOUNT);
if (!match)
goto out;
write_pnet(&match->net, sock_net(sk));
base-commit: c339f4010dea8b0d754f84ace70cd1b089878ef8
--
2.43.0