[<prev] [next>] [day] [month] [year] [list]
Message-Id: <20250829-mctp-skb-unshare-v1-1-1c28fe10235a@codeconstruct.com.au>
Date: Fri, 29 Aug 2025 15:28:26 +0800
From: Jeremy Kerr <jk@...econstruct.com.au>
To: Matt Johnston <matt@...econstruct.com.au>,
"David S. Miller" <davem@...emloft.net>, Eric Dumazet <edumazet@...gle.com>,
Jakub Kicinski <kuba@...nel.org>, Paolo Abeni <pabeni@...hat.com>,
Simon Horman <horms@...nel.org>
Cc: netdev@...r.kernel.org
Subject: [PATCH net] net: mctp: mctp_fraq_queue should take ownership of
passed skb
As of commit f5d83cf0eeb9 ("net: mctp: unshare packets when
reassembling"), we skb_unshare() in mctp_frag_queue(). The unshare may
invalidate the original skb pointer, so we need to treat the skb as
entirely owned by the fraq queue, even on failure.
Fixes: f5d83cf0eeb9 ("net: mctp: unshare packets when reassembling")
Signed-off-by: Jeremy Kerr <jk@...econstruct.com.au>
---
net/mctp/route.c | 35 +++++++++++++++++++----------------
1 file changed, 19 insertions(+), 16 deletions(-)
diff --git a/net/mctp/route.c b/net/mctp/route.c
index 2b2b958ef6a37525cc4d3f6a5758bd3880c98e6c..4d314e062ba9c4137f196482880660be67a71b11 100644
--- a/net/mctp/route.c
+++ b/net/mctp/route.c
@@ -378,6 +378,7 @@ static void mctp_skb_set_flow(struct sk_buff *skb, struct mctp_sk_key *key) {}
static void mctp_flow_prepare_output(struct sk_buff *skb, struct mctp_dev *dev) {}
#endif
+/* takes ownership of skb, both in success and failure cases */
static int mctp_frag_queue(struct mctp_sk_key *key, struct sk_buff *skb)
{
struct mctp_hdr *hdr = mctp_hdr(skb);
@@ -387,8 +388,10 @@ static int mctp_frag_queue(struct mctp_sk_key *key, struct sk_buff *skb)
& MCTP_HDR_SEQ_MASK;
if (!key->reasm_head) {
- /* Since we're manipulating the shared frag_list, ensure it isn't
- * shared with any other SKBs.
+ /* Since we're manipulating the shared frag_list, ensure it
+ * isn't shared with any other SKBs. In the cloned case,
+ * this will free the skb; callers can no longer access it
+ * safely.
*/
key->reasm_head = skb_unshare(skb, GFP_ATOMIC);
if (!key->reasm_head)
@@ -402,10 +405,10 @@ static int mctp_frag_queue(struct mctp_sk_key *key, struct sk_buff *skb)
exp_seq = (key->last_seq + 1) & MCTP_HDR_SEQ_MASK;
if (this_seq != exp_seq)
- return -EINVAL;
+ goto err_free;
if (key->reasm_head->len + skb->len > mctp_message_maxlen)
- return -EINVAL;
+ goto err_free;
skb->next = NULL;
skb->sk = NULL;
@@ -419,6 +422,10 @@ static int mctp_frag_queue(struct mctp_sk_key *key, struct sk_buff *skb)
key->reasm_head->truesize += skb->truesize;
return 0;
+
+err_free:
+ kfree_skb(skb);
+ return -EINVAL;
}
static int mctp_dst_input(struct mctp_dst *dst, struct sk_buff *skb)
@@ -532,18 +539,16 @@ static int mctp_dst_input(struct mctp_dst *dst, struct sk_buff *skb)
* key isn't observable yet
*/
mctp_frag_queue(key, skb);
+ skb = NULL;
/* if the key_add fails, we've raced with another
* SOM packet with the same src, dest and tag. There's
* no way to distinguish future packets, so all we
- * can do is drop; we'll free the skb on exit from
- * this function.
+ * can do is drop.
*/
rc = mctp_key_add(key, msk);
- if (!rc) {
+ if (!rc)
trace_mctp_key_acquire(key);
- skb = NULL;
- }
/* we don't need to release key->lock on exit, so
* clean up here and suppress the unlock via
@@ -561,8 +566,7 @@ static int mctp_dst_input(struct mctp_dst *dst, struct sk_buff *skb)
key = NULL;
} else {
rc = mctp_frag_queue(key, skb);
- if (!rc)
- skb = NULL;
+ skb = NULL;
}
}
@@ -572,17 +576,16 @@ static int mctp_dst_input(struct mctp_dst *dst, struct sk_buff *skb)
*/
/* we need to be continuing an existing reassembly... */
- if (!key->reasm_head)
+ if (!key->reasm_head) {
rc = -EINVAL;
- else
+ } else {
rc = mctp_frag_queue(key, skb);
+ skb = NULL;
+ }
if (rc)
goto out_unlock;
- /* we've queued; the queue owns the skb now */
- skb = NULL;
-
/* end of message? deliver to socket, and we're done with
* the reassembly/response key
*/
---
base-commit: 007a5ffadc4fd51739527f1503b7cf048f31c413
change-id: 20250829-mctp-skb-unshare-630a63c9fa37
Best regards,
--
Jeremy Kerr <jk@...econstruct.com.au>
Powered by blists - more mailing lists