Skip to content

Commit 2d859af

Browse files
committed
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 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/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents 397006b + 18429e6 commit 2d859af

File tree

9 files changed

+42
-45
lines changed

9 files changed

+42
-45
lines changed

net/bluetooth/l2cap_sock.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1886,6 +1886,7 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
18861886
chan = l2cap_chan_create();
18871887
if (!chan) {
18881888
sk_free(sk);
1889+
sock->sk = NULL;
18891890
return NULL;
18901891
}
18911892

net/bluetooth/rfcomm/sock.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -274,13 +274,13 @@ static struct sock *rfcomm_sock_alloc(struct net *net, struct socket *sock,
274274
struct rfcomm_dlc *d;
275275
struct sock *sk;
276276

277-
sk = bt_sock_alloc(net, sock, &rfcomm_proto, proto, prio, kern);
278-
if (!sk)
277+
d = rfcomm_dlc_alloc(prio);
278+
if (!d)
279279
return NULL;
280280

281-
d = rfcomm_dlc_alloc(prio);
282-
if (!d) {
283-
sk_free(sk);
281+
sk = bt_sock_alloc(net, sock, &rfcomm_proto, proto, prio, kern);
282+
if (!sk) {
283+
rfcomm_dlc_free(d);
284284
return NULL;
285285
}
286286

net/can/af_can.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ static int can_create(struct net *net, struct socket *sock, int protocol,
171171
/* release sk on errors */
172172
sock_orphan(sk);
173173
sock_put(sk);
174+
sock->sk = NULL;
174175
}
175176

176177
errout:

net/core/sock.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3827,9 +3827,6 @@ void sk_common_release(struct sock *sk)
38273827

38283828
sk->sk_prot->unhash(sk);
38293829

3830-
if (sk->sk_socket)
3831-
sk->sk_socket->sk = NULL;
3832-
38333830
/*
38343831
* In this point socket cannot receive new packets, but it is possible
38353832
* that some packets are in flight because some CPU runs receiver and

net/ieee802154/socket.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,19 +1043,21 @@ static int ieee802154_create(struct net *net, struct socket *sock,
10431043

10441044
if (sk->sk_prot->hash) {
10451045
rc = sk->sk_prot->hash(sk);
1046-
if (rc) {
1047-
sk_common_release(sk);
1048-
goto out;
1049-
}
1046+
if (rc)
1047+
goto out_sk_release;
10501048
}
10511049

10521050
if (sk->sk_prot->init) {
10531051
rc = sk->sk_prot->init(sk);
10541052
if (rc)
1055-
sk_common_release(sk);
1053+
goto out_sk_release;
10561054
}
10571055
out:
10581056
return rc;
1057+
out_sk_release:
1058+
sk_common_release(sk);
1059+
sock->sk = NULL;
1060+
goto out;
10591061
}
10601062

10611063
static const struct net_proto_family ieee802154_family_ops = {

net/ipv4/af_inet.c

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -376,32 +376,30 @@ static int inet_create(struct net *net, struct socket *sock, int protocol,
376376
inet->inet_sport = htons(inet->inet_num);
377377
/* Add to protocol hash chains. */
378378
err = sk->sk_prot->hash(sk);
379-
if (err) {
380-
sk_common_release(sk);
381-
goto out;
382-
}
379+
if (err)
380+
goto out_sk_release;
383381
}
384382

385383
if (sk->sk_prot->init) {
386384
err = sk->sk_prot->init(sk);
387-
if (err) {
388-
sk_common_release(sk);
389-
goto out;
390-
}
385+
if (err)
386+
goto out_sk_release;
391387
}
392388

393389
if (!kern) {
394390
err = BPF_CGROUP_RUN_PROG_INET_SOCK(sk);
395-
if (err) {
396-
sk_common_release(sk);
397-
goto out;
398-
}
391+
if (err)
392+
goto out_sk_release;
399393
}
400394
out:
401395
return err;
402396
out_rcu_unlock:
403397
rcu_read_unlock();
404398
goto out;
399+
out_sk_release:
400+
sk_common_release(sk);
401+
sock->sk = NULL;
402+
goto out;
405403
}
406404

407405

net/ipv6/af_inet6.c

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -252,31 +252,29 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol,
252252
*/
253253
inet->inet_sport = htons(inet->inet_num);
254254
err = sk->sk_prot->hash(sk);
255-
if (err) {
256-
sk_common_release(sk);
257-
goto out;
258-
}
255+
if (err)
256+
goto out_sk_release;
259257
}
260258
if (sk->sk_prot->init) {
261259
err = sk->sk_prot->init(sk);
262-
if (err) {
263-
sk_common_release(sk);
264-
goto out;
265-
}
260+
if (err)
261+
goto out_sk_release;
266262
}
267263

268264
if (!kern) {
269265
err = BPF_CGROUP_RUN_PROG_INET_SOCK(sk);
270-
if (err) {
271-
sk_common_release(sk);
272-
goto out;
273-
}
266+
if (err)
267+
goto out_sk_release;
274268
}
275269
out:
276270
return err;
277271
out_rcu_unlock:
278272
rcu_read_unlock();
279273
goto out;
274+
out_sk_release:
275+
sk_common_release(sk);
276+
sock->sk = NULL;
277+
goto out;
280278
}
281279

282280
static int __inet6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len,

net/packet/af_packet.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3422,17 +3422,17 @@ static int packet_create(struct net *net, struct socket *sock, int protocol,
34223422
if (sock->type == SOCK_PACKET)
34233423
sock->ops = &packet_ops_spkt;
34243424

3425+
po = pkt_sk(sk);
3426+
err = packet_alloc_pending(po);
3427+
if (err)
3428+
goto out_sk_free;
3429+
34253430
sock_init_data(sock, sk);
34263431

3427-
po = pkt_sk(sk);
34283432
init_completion(&po->skb_completion);
34293433
sk->sk_family = PF_PACKET;
34303434
po->num = proto;
34313435

3432-
err = packet_alloc_pending(po);
3433-
if (err)
3434-
goto out2;
3435-
34363436
packet_cached_dev_reset(po);
34373437

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

34663466
return 0;
3467-
out2:
3467+
out_sk_free:
34683468
sk_free(sk);
34693469
out:
34703470
return err;

net/socket.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1576,9 +1576,9 @@ int __sock_create(struct net *net, int family, int type, int protocol,
15761576
err = pf->create(net, sock, protocol, kern);
15771577
if (err < 0) {
15781578
/* ->create should release the allocated sock->sk object on error
1579-
* but it may leave the dangling pointer
1579+
* and make sure sock->sk is set to NULL to avoid use-after-free
15801580
*/
1581-
sock->sk = NULL;
1581+
DEBUG_NET_WARN_ON_ONCE(sock->sk);
15821582
goto out_module_put;
15831583
}
15841584

0 commit comments

Comments
 (0)