mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 01:53:29 +02:00
net: skbuff: fix pskb_carve leaking zcopy pages
When SKBFL_MANAGED_FRAG_REFS is set, frag pages are not refcounted but
their lifetime is controlled by the attached ubuf_info. To make a copy
of the skb_shared_info, we either should clear the flag and reference
the frags, or keep the flag and have frags unreferenced.
pskb_carve_inside_header() and pskb_carve_inside_nonlinear() don't
follow the rule and thus can leak page references. Let's clear
SKBFL_MANAGED_FRAG_REFS from the original skb to fix it. It's the
simplest way to address it, but there are more performant ways to do
that if it ever becomes a problem.
Link: https://lore.kernel.org/all/20260523085809.26331-1-nvminh232@clc.fitus.edu.vn/
Fixes: 753f1ca4e1 ("net: introduce managed frags infrastructure")
Reported-by: Minh Nguyen <minhnguyen.080505@gmail.com>
Reported-by: Willem de Bruijn <willemdebruijn.kernel@gmail.com>
Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Link: https://patch.msgid.link/1e2086aa69217d7f9c8da3d38f5be7160f1b4cd1.1779993185.git.asml.silence@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
9c7da87c2d
commit
ff6e798c2e
|
|
@ -6823,6 +6823,11 @@ static int pskb_carve_inside_header(struct sk_buff *skb, const u32 off,
|
|||
skb_copy_from_linear_data_offset(skb, off, data, new_hlen);
|
||||
skb->len -= off;
|
||||
|
||||
/* Remove SKBFL_MANAGED_FRAG_REFS instead of trying to honour it
|
||||
* while refcounting frags below.
|
||||
*/
|
||||
skb_zcopy_downgrade_managed(skb);
|
||||
|
||||
memcpy((struct skb_shared_info *)(data + size),
|
||||
skb_shinfo(skb),
|
||||
offsetof(struct skb_shared_info,
|
||||
|
|
@ -6936,6 +6941,11 @@ static int pskb_carve_inside_nonlinear(struct sk_buff *skb, const u32 off,
|
|||
return -ENOMEM;
|
||||
size = SKB_WITH_OVERHEAD(size);
|
||||
|
||||
/* Remove SKBFL_MANAGED_FRAG_REFS instead of trying to honour it
|
||||
* while refcounting frags below.
|
||||
*/
|
||||
skb_zcopy_downgrade_managed(skb);
|
||||
|
||||
memcpy((struct skb_shared_info *)(data + size),
|
||||
skb_shinfo(skb), offsetof(struct skb_shared_info, frags[0]));
|
||||
if (skb_orphan_frags(skb, gfp_mask)) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user