Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'mptcp-fixes'

Jeremy Kerr says:

====================
net: mctp: struct sock lifetime fixes

This series is a set of fixes for the sock lifetime handling in the
AF_MCTP code, fixing a uaf reported by Noam Rathaus
<noamr@ssd-disclosure.com>.

The Fixes: tags indicate the original patches affected, but some
tweaking to backport to those commits may be needed; I have a separate
branch with backports to 5.15 if that helps with stable trees.

Of course, any comments/queries most welcome.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+28 -16
+7 -3
net/mctp/af_mctp.c
··· 544 544 545 545 static void mctp_sk_close(struct sock *sk, long timeout) 546 546 { 547 - struct mctp_sock *msk = container_of(sk, struct mctp_sock, sk); 548 - 549 - del_timer_sync(&msk->key_expiry); 550 547 sk_common_release(sk); 551 548 } 552 549 ··· 577 580 spin_lock_irqsave(&key->lock, fl2); 578 581 __mctp_key_remove(key, net, fl2, MCTP_TRACE_KEY_CLOSED); 579 582 } 583 + sock_set_flag(sk, SOCK_DEAD); 580 584 spin_unlock_irqrestore(&net->mctp.keys_lock, flags); 585 + 586 + /* Since there are no more tag allocations (we have removed all of the 587 + * keys), stop any pending expiry events. the timer cannot be re-queued 588 + * as the sk is no longer observable 589 + */ 590 + del_timer_sync(&msk->key_expiry); 581 591 } 582 592 583 593 static struct proto mctp_proto = {
+21 -13
net/mctp/route.c
··· 147 147 key->valid = true; 148 148 spin_lock_init(&key->lock); 149 149 refcount_set(&key->refs, 1); 150 + sock_hold(key->sk); 150 151 151 152 return key; 152 153 } ··· 166 165 mctp_dev_release_key(key->dev, key); 167 166 spin_unlock_irqrestore(&key->lock, flags); 168 167 168 + sock_put(key->sk); 169 169 kfree(key); 170 170 } 171 171 ··· 178 176 int rc = 0; 179 177 180 178 spin_lock_irqsave(&net->mctp.keys_lock, flags); 179 + 180 + if (sock_flag(&msk->sk, SOCK_DEAD)) { 181 + rc = -EINVAL; 182 + goto out_unlock; 183 + } 181 184 182 185 hlist_for_each_entry(tmp, &net->mctp.keys, hlist) { 183 186 if (mctp_key_match(tmp, key->local_addr, key->peer_addr, ··· 205 198 hlist_add_head(&key->sklist, &msk->keys); 206 199 } 207 200 201 + out_unlock: 208 202 spin_unlock_irqrestore(&net->mctp.keys_lock, flags); 209 203 210 204 return rc; ··· 323 315 324 316 static int mctp_route_input(struct mctp_route *route, struct sk_buff *skb) 325 317 { 318 + struct mctp_sk_key *key, *any_key = NULL; 326 319 struct net *net = dev_net(skb->dev); 327 - struct mctp_sk_key *key; 328 320 struct mctp_sock *msk; 329 321 struct mctp_hdr *mh; 330 322 unsigned long f; ··· 369 361 * key for reassembly - we'll create a more specific 370 362 * one for future packets if required (ie, !EOM). 371 363 */ 372 - key = mctp_lookup_key(net, skb, MCTP_ADDR_ANY, &f); 373 - if (key) { 374 - msk = container_of(key->sk, 364 + any_key = mctp_lookup_key(net, skb, MCTP_ADDR_ANY, &f); 365 + if (any_key) { 366 + msk = container_of(any_key->sk, 375 367 struct mctp_sock, sk); 376 - spin_unlock_irqrestore(&key->lock, f); 377 - mctp_key_unref(key); 378 - key = NULL; 368 + spin_unlock_irqrestore(&any_key->lock, f); 379 369 } 380 370 } 381 371 ··· 425 419 * this function. 426 420 */ 427 421 rc = mctp_key_add(key, msk); 428 - if (rc) { 429 - kfree(key); 430 - } else { 422 + if (!rc) 431 423 trace_mctp_key_acquire(key); 432 424 433 - /* we don't need to release key->lock on exit */ 434 - mctp_key_unref(key); 435 - } 425 + /* we don't need to release key->lock on exit, so 426 + * clean up here and suppress the unlock via 427 + * setting to NULL 428 + */ 429 + mctp_key_unref(key); 436 430 key = NULL; 437 431 438 432 } else { ··· 479 473 spin_unlock_irqrestore(&key->lock, f); 480 474 mctp_key_unref(key); 481 475 } 476 + if (any_key) 477 + mctp_key_unref(any_key); 482 478 out: 483 479 if (rc) 484 480 kfree_skb(skb);