* [PATCH net v4] net/packet: account user-triggered allocations to memcg
@ 2026-11-01 9:48 Ahmad AG
0 siblings, 0 replies; only message in thread
From: Ahmad AG @ 2026-11-01 9:48 UTC (permalink / raw)
To: Willem de Bruijn
Cc: kuba, davem, edumazet, pabeni, horms, netdev, linux-kernel,
stable+noautosel, Ahmad AG
A packet socket makes allocations whose size or count its user chooses
without charging them to the user's memory cgroup: the blocks and block
array of a PACKET_RX_RING or PACKET_TX_RING ring and the rx_owner_map
of a TPACKET_V1/V2 RX ring, the PACKET_FANOUT group (about 1 MB with
max_num_members = 65536), and one packet_mclist per
PACKET_ADD_MEMBERSHIP entry. CAP_NET_RAW in a user namespace is enough
to pin memory far beyond memory.max this way.
Allocate them with GFP_KERNEL_ACCOUNT, as the AF_XDP rings do since
commit b0057c68df71 ("xsk: account ring allocations to memcg"), and with
__GFP_NOWARN where the size comes from user space, so that a ring or
group that does not fit prints no allocation warning. Fixed-size
per-socket state is left unaccounted.
Reproducer, as uid 1000 in a memory cgroup with memory.max 16M, after
unshare(CLONE_NEWUSER | CLONE_NEWNET): open 64 AF_PACKET sockets, give
each a TPACKET_V2 RX ring of 8 blocks of 1 MB, mmap the rings and touch
every block. MemFree drops by 526052 KB while memory.current grows by
1280 KB. 256 fanout groups with max_num_members = 65536 (265144 KB used,
512 KB charged) and 100 sockets with 2000 PACKET_MR_PROMISC entries each
on lo (45220 KB used, 124 KB charged) behave the same. With this change
all three are stopped by the cgroup's OOM killer. psock_fanout,
psock_tpacket and psock_snd.sh pass before and after. Found by code
inspection with the help of an LLM and reproduced on an unmodified
kernel without error injection; tested in a QEMU guest with KASAN on
net.
The ring pages and rx_owner_map were never charged, the rest not since
commit a9bb7e620efd ("memcg: only account kmem allocations marked as
__GFP_ACCOUNT"). The Fixes commit let the user size the fanout array.
Fixes: 9c661b0b8544 ("net/packet: make packet_fanout.arr size configurable up to 64K")
Cc: <stable+noautosel@kernel.org> # changes memcg charging of existing packet rings; not stable material
Signed-off-by: Ahmad AG <ahmadag1001@gmail.com>
---
Tool use: an LLM coding assistant (Claude Code) found the missing
charges by code inspection, drafted the patch, the test program and this
message, and ran the tests in the QEMU guest; I reviewed every hunk, the
results and this message before sending.
v4:
- trim the commit message
- add __GFP_NOWARN to the fanout group allocation
- use __vcalloc() for the vmalloc fallback and bitmap_zalloc() for
rx_owner_map
v3: https://lore.kernel.org/netdev/20261031084316.387533-1-ahmadag1001@gmail.com/
- Fixes 9c661b0b8544; stable+noautosel; drop Assisted-by; leave fixed-size
allocations unaccounted; __GFP_NOWARN on the vmalloc fallback
v2: https://lore.kernel.org/netdev/20261030100504.23498-1-ahmadag1001@gmail.com/
- cover all user-triggered allocations in one patch
v1: https://lore.kernel.org/netdev/CAASqGyZ-9hqZGWNJShxnrSiXDO==51SVsQW_x_mk993y1pNO8A@mail.gmail.com/
net/packet/af_packet.c | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index cf6429f0947..ec6ab96c4f8 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 | __GFP_NOWARN);
if (!match)
goto out;
write_pnet(&match->net, sock_net(sk));
@@ -3773,7 +3774,7 @@ static int packet_mc_add(struct sock *sk, struct packet_mreq_max *mreq)
goto done;
err = -ENOBUFS;
- i = kmalloc_obj(*i);
+ i = kmalloc_obj(*i, GFP_KERNEL_ACCOUNT);
if (i == NULL)
goto done;
@@ -4494,7 +4495,7 @@ static void packet_free_tx_ring(struct sock *sk, struct pgv *pg_vec,
static char *alloc_one_pg_vec_page(unsigned long order)
{
char *buffer;
- gfp_t gfp_flags = GFP_KERNEL | __GFP_COMP |
+ gfp_t gfp_flags = GFP_KERNEL_ACCOUNT | __GFP_COMP |
__GFP_ZERO | __GFP_NOWARN | __GFP_NORETRY;
buffer = (char *) __get_free_pages(gfp_flags, order);
@@ -4502,7 +4503,8 @@ static char *alloc_one_pg_vec_page(unsigned long order)
return buffer;
/* __get_free_pages failed, fall back to vmalloc */
- buffer = vzalloc(array_size((1 << order), PAGE_SIZE));
+ buffer = __vcalloc(1 << order, PAGE_SIZE,
+ GFP_KERNEL_ACCOUNT | __GFP_NOWARN);
if (buffer)
return buffer;
@@ -4523,7 +4525,8 @@ static struct pgv *alloc_pg_vec(struct tpacket_req *req, int order, bool tx_ring
struct pgv *pg_vec;
int i;
- vec = kzalloc_flex(*vec, pg_vec, block_nr, GFP_KERNEL | __GFP_NOWARN);
+ vec = kzalloc_flex(*vec, pg_vec, block_nr,
+ GFP_KERNEL_ACCOUNT | __GFP_NOWARN);
if (unlikely(!vec))
return NULL;
vec->order = order;
@@ -4647,8 +4650,10 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
break;
default:
if (!tx_ring) {
- rx_owner_map = bitmap_alloc(req->tp_frame_nr,
- GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO);
+ rx_owner_map =
+ bitmap_zalloc(req->tp_frame_nr,
+ GFP_KERNEL_ACCOUNT |
+ __GFP_NOWARN);
if (!rx_owner_map)
goto out_free_pg_vec;
}
base-commit: cb284914e749388eef402938bdb3115fe1f6d337
--
2.43.0
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2026-11-01 9:50 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-01 9:48 [PATCH net v4] net/packet: account user-triggered allocations to memcg Ahmad AG
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox