Skip to content

Commit 9fd75b6

Browse files
stonezdmdavem330
authored andcommitted
ax25: Fix refcount leaks caused by ax25_cb_del()
The previous commit d01ffb9 ("ax25: add refcount in ax25_dev to avoid UAF bugs") and commit feef318 ("ax25: fix UAF bugs of net_device caused by rebinding operation") increase the refcounts of ax25_dev and net_device in ax25_bind() and decrease the matching refcounts in ax25_kill_by_device() in order to prevent UAF bugs, but there are reference count leaks. The root cause of refcount leaks is shown below: (Thread 1) | (Thread 2) ax25_bind() | ... | ax25_addr_ax25dev() | ax25_dev_hold() //(1) | ... | dev_hold_track() //(2) | ... | ax25_destroy_socket() | ax25_cb_del() | ... | hlist_del_init() //(3) | | (Thread 3) | ax25_kill_by_device() | ... | ax25_for_each(s, &ax25_list) { | if (s->ax25_dev == ax25_dev) //(4) | ... | Firstly, we use ax25_bind() to increase the refcount of ax25_dev in position (1) and increase the refcount of net_device in position (2). Then, we use ax25_cb_del() invoked by ax25_destroy_socket() to delete ax25_cb in hlist in position (3) before calling ax25_kill_by_device(). Finally, the decrements of refcounts in ax25_kill_by_device() will not be executed, because no s->ax25_dev equals to ax25_dev in position (4). This patch adds decrements of refcounts in ax25_release() and use lock_sock() to do synchronization. If refcounts decrease in ax25_release(), the decrements of refcounts in ax25_kill_by_device() will not be executed and vice versa. Fixes: d01ffb9 ("ax25: add refcount in ax25_dev to avoid UAF bugs") Fixes: 87563a0 ("ax25: fix reference count leaks of ax25_dev") Fixes: feef318 ("ax25: fix UAF bugs of net_device caused by rebinding operation") Reported-by: Thomas Osterried <[email protected]> Signed-off-by: Duoming Zhou <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 0caf6d9 commit 9fd75b6

File tree

1 file changed

+11
-3
lines changed

1 file changed

+11
-3
lines changed

net/ax25/af_ax25.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,10 @@ static void ax25_kill_by_device(struct net_device *dev)
9898
spin_unlock_bh(&ax25_list_lock);
9999
lock_sock(sk);
100100
s->ax25_dev = NULL;
101-
dev_put_track(ax25_dev->dev, &ax25_dev->dev_tracker);
102-
ax25_dev_put(ax25_dev);
101+
if (sk->sk_socket) {
102+
dev_put_track(ax25_dev->dev, &ax25_dev->dev_tracker);
103+
ax25_dev_put(ax25_dev);
104+
}
103105
ax25_disconnect(s, ENETUNREACH);
104106
release_sock(sk);
105107
spin_lock_bh(&ax25_list_lock);
@@ -979,14 +981,20 @@ static int ax25_release(struct socket *sock)
979981
{
980982
struct sock *sk = sock->sk;
981983
ax25_cb *ax25;
984+
ax25_dev *ax25_dev;
982985

983986
if (sk == NULL)
984987
return 0;
985988

986989
sock_hold(sk);
987-
sock_orphan(sk);
988990
lock_sock(sk);
991+
sock_orphan(sk);
989992
ax25 = sk_to_ax25(sk);
993+
ax25_dev = ax25->ax25_dev;
994+
if (ax25_dev) {
995+
dev_put_track(ax25_dev->dev, &ax25_dev->dev_tracker);
996+
ax25_dev_put(ax25_dev);
997+
}
990998

991999
if (sk->sk_type == SOCK_SEQPACKET) {
9921000
switch (ax25->state) {

0 commit comments

Comments
 (0)