Skip to content

Commit

Permalink
Merge branch 'do-not-leave-dangling-sk-pointers-in-pf-create-functions'
Browse files Browse the repository at this point in the history
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 6310831
("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: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
Jakub Kicinski committed Oct 16, 2024
2 parents 397006b + 18429e6 commit 2d859af
Show file tree
Hide file tree
Showing 9 changed files with 42 additions and 45 deletions.
1 change: 1 addition & 0 deletions net/bluetooth/l2cap_sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
10 changes: 5 additions & 5 deletions net/bluetooth/rfcomm/sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
1 change: 1 addition & 0 deletions net/can/af_can.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
3 changes: 0 additions & 3 deletions net/core/sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 7 additions & 5 deletions net/ieee802154/socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
22 changes: 10 additions & 12 deletions net/ipv4/af_inet.c
Original file line number Diff line number Diff line change
Expand Up @@ -376,32 +376,30 @@ static int inet_create(struct net *net, struct socket *sock, int protocol,
inet->inet_sport = htons(inet->inet_num);
/* Add to protocol hash chains. */
err = sk->sk_prot->hash(sk);
if (err) {
sk_common_release(sk);
goto out;
}
if (err)
goto out_sk_release;
}

if (sk->sk_prot->init) {
err = sk->sk_prot->init(sk);
if (err) {
sk_common_release(sk);
goto out;
}
if (err)
goto out_sk_release;
}

if (!kern) {
err = BPF_CGROUP_RUN_PROG_INET_SOCK(sk);
if (err) {
sk_common_release(sk);
goto out;
}
if (err)
goto out_sk_release;
}
out:
return err;
out_rcu_unlock:
rcu_read_unlock();
goto out;
out_sk_release:
sk_common_release(sk);
sock->sk = NULL;
goto out;
}


Expand Down
22 changes: 10 additions & 12 deletions net/ipv6/af_inet6.c
Original file line number Diff line number Diff line change
Expand Up @@ -252,31 +252,29 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol,
*/
inet->inet_sport = htons(inet->inet_num);
err = sk->sk_prot->hash(sk);
if (err) {
sk_common_release(sk);
goto out;
}
if (err)
goto out_sk_release;
}
if (sk->sk_prot->init) {
err = sk->sk_prot->init(sk);
if (err) {
sk_common_release(sk);
goto out;
}
if (err)
goto out_sk_release;
}

if (!kern) {
err = BPF_CGROUP_RUN_PROG_INET_SOCK(sk);
if (err) {
sk_common_release(sk);
goto out;
}
if (err)
goto out_sk_release;
}
out:
return err;
out_rcu_unlock:
rcu_read_unlock();
goto out;
out_sk_release:
sk_common_release(sk);
sock->sk = NULL;
goto out;
}

static int __inet6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len,
Expand Down
12 changes: 6 additions & 6 deletions net/packet/af_packet.c
Original file line number Diff line number Diff line change
Expand Up @@ -3422,17 +3422,17 @@ static int packet_create(struct net *net, struct socket *sock, int protocol,
if (sock->type == SOCK_PACKET)
sock->ops = &packet_ops_spkt;

po = pkt_sk(sk);
err = packet_alloc_pending(po);
if (err)
goto out_sk_free;

sock_init_data(sock, sk);

po = pkt_sk(sk);
init_completion(&po->skb_completion);
sk->sk_family = PF_PACKET;
po->num = proto;

err = packet_alloc_pending(po);
if (err)
goto out2;

packet_cached_dev_reset(po);

sk->sk_destruct = packet_sock_destruct;
Expand Down Expand Up @@ -3464,7 +3464,7 @@ static int packet_create(struct net *net, struct socket *sock, int protocol,
sock_prot_inuse_add(net, &packet_proto, 1);

return 0;
out2:
out_sk_free:
sk_free(sk);
out:
return err;
Expand Down
4 changes: 2 additions & 2 deletions net/socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -1576,9 +1576,9 @@ int __sock_create(struct net *net, int family, int type, int protocol,
err = pf->create(net, sock, protocol, kern);
if (err < 0) {
/* ->create should release the allocated sock->sk object on error
* but it may leave the dangling pointer
* and make sure sock->sk is set to NULL to avoid use-after-free
*/
sock->sk = NULL;
DEBUG_NET_WARN_ON_ONCE(sock->sk);
goto out_module_put;
}

Expand Down

0 comments on commit 2d859af

Please sign in to comment.