Commit 2d859aff authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'do-not-leave-dangling-sk-pointers-in-pf-create-functions'

Ignat Korchagin says:

====================
do not leave dangling sk pointers in pf->create functions

Some protocol family create() implementations have an error path after
allocating the sk object and calling sock_init_data(). sock_init_data()
attaches the allocated sk object to the sock object, provided by the
caller.

If the create() implementation errors out after calling sock_init_data(),
it releases the allocated sk object, but the caller ends up having a
dangling sk pointer in its sock object on return. Subsequent manipulations
on this sock object may try to access the sk pointer, because it is not
NULL thus creating a use-after-free scenario.

We have implemented a stable hotfix in commit 63108314
("net: explicitly clear the sk pointer, when pf->create fails"), but this
series aims to fix it properly by going through each of the pf->create()
implementations and making sure they all don't return a sock object with
a dangling pointer on error.
====================

Link: https://patch.msgid.link/20241014153808.51894-1-ignat@cloudflare.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 397006ba 18429e6e
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1886,6 +1886,7 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
	chan = l2cap_chan_create();
	if (!chan) {
		sk_free(sk);
		sock->sk = NULL;
		return NULL;
	}

+5 −5
Original line number Diff line number Diff line
@@ -274,13 +274,13 @@ static struct sock *rfcomm_sock_alloc(struct net *net, struct socket *sock,
	struct rfcomm_dlc *d;
	struct sock *sk;

	sk = bt_sock_alloc(net, sock, &rfcomm_proto, proto, prio, kern);
	if (!sk)
	d = rfcomm_dlc_alloc(prio);
	if (!d)
		return NULL;

	d = rfcomm_dlc_alloc(prio);
	if (!d) {
		sk_free(sk);
	sk = bt_sock_alloc(net, sock, &rfcomm_proto, proto, prio, kern);
	if (!sk) {
		rfcomm_dlc_free(d);
		return NULL;
	}

+1 −0
Original line number Diff line number Diff line
@@ -171,6 +171,7 @@ static int can_create(struct net *net, struct socket *sock, int protocol,
		/* release sk on errors */
		sock_orphan(sk);
		sock_put(sk);
		sock->sk = NULL;
	}

 errout:
+0 −3
Original line number Diff line number Diff line
@@ -3827,9 +3827,6 @@ void sk_common_release(struct sock *sk)

	sk->sk_prot->unhash(sk);

	if (sk->sk_socket)
		sk->sk_socket->sk = NULL;

	/*
	 * In this point socket cannot receive new packets, but it is possible
	 * that some packets are in flight because some CPU runs receiver and
+7 −5
Original line number Diff line number Diff line
@@ -1043,19 +1043,21 @@ static int ieee802154_create(struct net *net, struct socket *sock,

	if (sk->sk_prot->hash) {
		rc = sk->sk_prot->hash(sk);
		if (rc) {
			sk_common_release(sk);
			goto out;
		}
		if (rc)
			goto out_sk_release;
	}

	if (sk->sk_prot->init) {
		rc = sk->sk_prot->init(sk);
		if (rc)
			sk_common_release(sk);
			goto out_sk_release;
	}
out:
	return rc;
out_sk_release:
	sk_common_release(sk);
	sock->sk = NULL;
	goto out;
}

static const struct net_proto_family ieee802154_family_ops = {
Loading