Skip to content

Commit ce1219c

Browse files
jk-ozlabsPaolo Abeni
authored andcommitted
net: mctp: handle skb cleanup on sock_queue failures
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: 4a992bb ("mctp: Implement message fragmentation & reassembly") Cc: [email protected] Signed-off-by: Jeremy Kerr <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
1 parent 572af9f commit ce1219c

File tree

2 files changed

+112
-10
lines changed

2 files changed

+112
-10
lines changed

net/mctp/route.c

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -374,8 +374,13 @@ static int mctp_route_input(struct mctp_route *route, struct sk_buff *skb)
374374
msk = NULL;
375375
rc = -EINVAL;
376376

377-
/* we may be receiving a locally-routed packet; drop source sk
378-
* accounting
377+
/* We may be receiving a locally-routed packet; drop source sk
378+
* accounting.
379+
*
380+
* From here, we will either queue the skb - either to a frag_queue, or
381+
* to a receiving socket. When that succeeds, we clear the skb pointer;
382+
* a non-NULL skb on exit will be otherwise unowned, and hence
383+
* kfree_skb()-ed.
379384
*/
380385
skb_orphan(skb);
381386

@@ -434,7 +439,9 @@ static int mctp_route_input(struct mctp_route *route, struct sk_buff *skb)
434439
* pending key.
435440
*/
436441
if (flags & MCTP_HDR_FLAG_EOM) {
437-
sock_queue_rcv_skb(&msk->sk, skb);
442+
rc = sock_queue_rcv_skb(&msk->sk, skb);
443+
if (!rc)
444+
skb = NULL;
438445
if (key) {
439446
/* we've hit a pending reassembly; not much we
440447
* can do but drop it
@@ -443,7 +450,6 @@ static int mctp_route_input(struct mctp_route *route, struct sk_buff *skb)
443450
MCTP_TRACE_KEY_REPLIED);
444451
key = NULL;
445452
}
446-
rc = 0;
447453
goto out_unlock;
448454
}
449455

@@ -470,8 +476,10 @@ static int mctp_route_input(struct mctp_route *route, struct sk_buff *skb)
470476
* this function.
471477
*/
472478
rc = mctp_key_add(key, msk);
473-
if (!rc)
479+
if (!rc) {
474480
trace_mctp_key_acquire(key);
481+
skb = NULL;
482+
}
475483

476484
/* we don't need to release key->lock on exit, so
477485
* clean up here and suppress the unlock via
@@ -489,6 +497,8 @@ static int mctp_route_input(struct mctp_route *route, struct sk_buff *skb)
489497
key = NULL;
490498
} else {
491499
rc = mctp_frag_queue(key, skb);
500+
if (!rc)
501+
skb = NULL;
492502
}
493503
}
494504

@@ -503,12 +513,19 @@ static int mctp_route_input(struct mctp_route *route, struct sk_buff *skb)
503513
else
504514
rc = mctp_frag_queue(key, skb);
505515

516+
if (rc)
517+
goto out_unlock;
518+
519+
/* we've queued; the queue owns the skb now */
520+
skb = NULL;
521+
506522
/* end of message? deliver to socket, and we're done with
507523
* the reassembly/response key
508524
*/
509-
if (!rc && flags & MCTP_HDR_FLAG_EOM) {
510-
sock_queue_rcv_skb(key->sk, key->reasm_head);
511-
key->reasm_head = NULL;
525+
if (flags & MCTP_HDR_FLAG_EOM) {
526+
rc = sock_queue_rcv_skb(key->sk, key->reasm_head);
527+
if (!rc)
528+
key->reasm_head = NULL;
512529
__mctp_key_done_in(key, net, f, MCTP_TRACE_KEY_REPLIED);
513530
key = NULL;
514531
}
@@ -527,8 +544,7 @@ static int mctp_route_input(struct mctp_route *route, struct sk_buff *skb)
527544
if (any_key)
528545
mctp_key_unref(any_key);
529546
out:
530-
if (rc)
531-
kfree_skb(skb);
547+
kfree_skb(skb);
532548
return rc;
533549
}
534550

net/mctp/test/route-test.c

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -837,6 +837,90 @@ static void mctp_test_route_input_multiple_nets_key(struct kunit *test)
837837
mctp_test_route_input_multiple_nets_key_fini(test, &t2);
838838
}
839839

840+
/* Input route to socket, using a single-packet message, where sock delivery
841+
* fails. Ensure we're handling the failure appropriately.
842+
*/
843+
static void mctp_test_route_input_sk_fail_single(struct kunit *test)
844+
{
845+
const struct mctp_hdr hdr = RX_HDR(1, 10, 8, FL_S | FL_E | FL_TO);
846+
struct mctp_test_route *rt;
847+
struct mctp_test_dev *dev;
848+
struct socket *sock;
849+
struct sk_buff *skb;
850+
int rc;
851+
852+
__mctp_route_test_init(test, &dev, &rt, &sock, MCTP_NET_ANY);
853+
854+
/* No rcvbuf space, so delivery should fail. __sock_set_rcvbuf will
855+
* clamp the minimum to SOCK_MIN_RCVBUF, so we open-code this.
856+
*/
857+
lock_sock(sock->sk);
858+
WRITE_ONCE(sock->sk->sk_rcvbuf, 0);
859+
release_sock(sock->sk);
860+
861+
skb = mctp_test_create_skb(&hdr, 10);
862+
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, skb);
863+
skb_get(skb);
864+
865+
mctp_test_skb_set_dev(skb, dev);
866+
867+
/* do route input, which should fail */
868+
rc = mctp_route_input(&rt->rt, skb);
869+
KUNIT_EXPECT_NE(test, rc, 0);
870+
871+
/* we should hold the only reference to skb */
872+
KUNIT_EXPECT_EQ(test, refcount_read(&skb->users), 1);
873+
kfree_skb(skb);
874+
875+
__mctp_route_test_fini(test, dev, rt, sock);
876+
}
877+
878+
/* Input route to socket, using a fragmented message, where sock delivery fails.
879+
*/
880+
static void mctp_test_route_input_sk_fail_frag(struct kunit *test)
881+
{
882+
const struct mctp_hdr hdrs[2] = { RX_FRAG(FL_S, 0), RX_FRAG(FL_E, 1) };
883+
struct mctp_test_route *rt;
884+
struct mctp_test_dev *dev;
885+
struct sk_buff *skbs[2];
886+
struct socket *sock;
887+
unsigned int i;
888+
int rc;
889+
890+
__mctp_route_test_init(test, &dev, &rt, &sock, MCTP_NET_ANY);
891+
892+
lock_sock(sock->sk);
893+
WRITE_ONCE(sock->sk->sk_rcvbuf, 0);
894+
release_sock(sock->sk);
895+
896+
for (i = 0; i < ARRAY_SIZE(skbs); i++) {
897+
skbs[i] = mctp_test_create_skb(&hdrs[i], 10);
898+
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, skbs[i]);
899+
skb_get(skbs[i]);
900+
901+
mctp_test_skb_set_dev(skbs[i], dev);
902+
}
903+
904+
/* first route input should succeed, we're only queueing to the
905+
* frag list
906+
*/
907+
rc = mctp_route_input(&rt->rt, skbs[0]);
908+
KUNIT_EXPECT_EQ(test, rc, 0);
909+
910+
/* final route input should fail to deliver to the socket */
911+
rc = mctp_route_input(&rt->rt, skbs[1]);
912+
KUNIT_EXPECT_NE(test, rc, 0);
913+
914+
/* we should hold the only reference to both skbs */
915+
KUNIT_EXPECT_EQ(test, refcount_read(&skbs[0]->users), 1);
916+
kfree_skb(skbs[0]);
917+
918+
KUNIT_EXPECT_EQ(test, refcount_read(&skbs[1]->users), 1);
919+
kfree_skb(skbs[1]);
920+
921+
__mctp_route_test_fini(test, dev, rt, sock);
922+
}
923+
840924
#if IS_ENABLED(CONFIG_MCTP_FLOWS)
841925

842926
static void mctp_test_flow_init(struct kunit *test,
@@ -1053,6 +1137,8 @@ static struct kunit_case mctp_test_cases[] = {
10531137
mctp_route_input_sk_reasm_gen_params),
10541138
KUNIT_CASE_PARAM(mctp_test_route_input_sk_keys,
10551139
mctp_route_input_sk_keys_gen_params),
1140+
KUNIT_CASE(mctp_test_route_input_sk_fail_single),
1141+
KUNIT_CASE(mctp_test_route_input_sk_fail_frag),
10561142
KUNIT_CASE(mctp_test_route_input_multiple_nets_bind),
10571143
KUNIT_CASE(mctp_test_route_input_multiple_nets_key),
10581144
KUNIT_CASE(mctp_test_packet_flow),

0 commit comments

Comments
 (0)