]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
net: mctp: handle skb cleanup on sock_queue failures
authorJeremy Kerr <jk@codeconstruct.com.au>
Wed, 18 Dec 2024 03:53:01 +0000 (11:53 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 9 Jan 2025 12:29:57 +0000 (13:29 +0100)
[ Upstream commit ce1219c3f76bb131d095e90521506d3c6ccfa086 ]

Currently, we don't use the return value from sock_queue_rcv_skb, which
means we may leak skbs if a message is not successfully queued to a
socket.

Instead, ensure that we're freeing the skb where the sock hasn't
otherwise taken ownership of the skb by adding checks on the
sock_queue_rcv_skb() to invoke a kfree on failure.

In doing so, rather than using the 'rc' value to trigger the
kfree_skb(), use the skb pointer itself, which is more explicit.

Also, add a kunit test for the sock delivery failure cases.

Fixes: 4a992bbd3650 ("mctp: Implement message fragmentation & reassembly")
Cc: stable@vger.kernel.org
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Link: https://patch.msgid.link/20241218-mctp-next-v2-1-1c1729645eaa@codeconstruct.com.au
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
net/mctp/route.c

index ea7cb9973128d13295bdf11ff97d1e7a50a21606..e72cdd4ce588fd5ff2f1452b007693748da8b9b2 100644 (file)
@@ -334,8 +334,13 @@ static int mctp_route_input(struct mctp_route *route, struct sk_buff *skb)
        msk = NULL;
        rc = -EINVAL;
 
-       /* we may be receiving a locally-routed packet; drop source sk
-        * accounting
+       /* We may be receiving a locally-routed packet; drop source sk
+        * accounting.
+        *
+        * From here, we will either queue the skb - either to a frag_queue, or
+        * to a receiving socket. When that succeeds, we clear the skb pointer;
+        * a non-NULL skb on exit will be otherwise unowned, and hence
+        * kfree_skb()-ed.
         */
        skb_orphan(skb);
 
@@ -389,7 +394,9 @@ static int mctp_route_input(struct mctp_route *route, struct sk_buff *skb)
                 * pending key.
                 */
                if (flags & MCTP_HDR_FLAG_EOM) {
-                       sock_queue_rcv_skb(&msk->sk, skb);
+                       rc = sock_queue_rcv_skb(&msk->sk, skb);
+                       if (!rc)
+                               skb = NULL;
                        if (key) {
                                /* we've hit a pending reassembly; not much we
                                 * can do but drop it
@@ -398,7 +405,6 @@ static int mctp_route_input(struct mctp_route *route, struct sk_buff *skb)
                                                   MCTP_TRACE_KEY_REPLIED);
                                key = NULL;
                        }
-                       rc = 0;
                        goto out_unlock;
                }
 
@@ -425,8 +431,10 @@ static int mctp_route_input(struct mctp_route *route, struct sk_buff *skb)
                         * this function.
                         */
                        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
@@ -444,6 +452,8 @@ static int mctp_route_input(struct mctp_route *route, struct sk_buff *skb)
                                key = NULL;
                        } else {
                                rc = mctp_frag_queue(key, skb);
+                               if (!rc)
+                                       skb = NULL;
                        }
                }
 
@@ -458,12 +468,19 @@ static int mctp_route_input(struct mctp_route *route, struct sk_buff *skb)
                else
                        rc = mctp_frag_queue(key, skb);
 
+               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
                 */
-               if (!rc && flags & MCTP_HDR_FLAG_EOM) {
-                       sock_queue_rcv_skb(key->sk, key->reasm_head);
-                       key->reasm_head = NULL;
+               if (flags & MCTP_HDR_FLAG_EOM) {
+                       rc = sock_queue_rcv_skb(key->sk, key->reasm_head);
+                       if (!rc)
+                               key->reasm_head = NULL;
                        __mctp_key_done_in(key, net, f, MCTP_TRACE_KEY_REPLIED);
                        key = NULL;
                }
@@ -482,8 +499,7 @@ out_unlock:
        if (any_key)
                mctp_key_unref(any_key);
 out:
-       if (rc)
-               kfree_skb(skb);
+       kfree_skb(skb);
        return rc;
 }