When skb_orphan_frags() throws -ENOMEM, skb_copy_ubufs() may have already reallocated and replaced 'from->head'. Accessing from->head to drop the old refcount leaks the original head page, and erroneously puts an unrelated new buffer. Use the local 'page' tracker variable instead to drop the reference properly. Fixes: 36d5fe6a0007 ("core, nfqueue, openvswitch: Orphan frags in skb_zerocopy and handle errors") Signed-off-by: Mina Almasry --- Note to sashiko: if you find pre-existing issues, mark them clearly as pre-existing. --- net/core/skbuff.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 201c9ec1519c7..92aad6f0b0e14 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -3907,7 +3907,7 @@ skb_zerocopy(struct sk_buff *to, struct sk_buff *from, int len, int hlen) } if (!skb_frags_readable(from) && j > 0 && len) { - put_page(virt_to_head_page(from->head)); + put_page(page); return -EFAULT; } @@ -3916,7 +3916,7 @@ skb_zerocopy(struct sk_buff *to, struct sk_buff *from, int len, int hlen) if (unlikely(skb_orphan_frags(from, GFP_ATOMIC))) { skb_tx_error(from); if (j > 0) - put_page(virt_to_head_page(from->head)); + put_page(page); return -ENOMEM; } skb_zerocopy_clone(to, from, GFP_ATOMIC); -- 2.55.0.766.g2966f0265a-goog