forked from Minki/linux
ax25: Fix refcount leaks caused by ax25_cb_del()
The previous commitd01ffb9eee
("ax25: add refcount in ax25_dev to avoid UAF bugs") and commitfeef318c85
("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:d01ffb9eee
("ax25: add refcount in ax25_dev to avoid UAF bugs") Fixes:87563a043c
("ax25: fix reference count leaks of ax25_dev") Fixes:feef318c85
("ax25: fix UAF bugs of net_device caused by rebinding operation") Reported-by: Thomas Osterried <thomas@osterried.de> Signed-off-by: Duoming Zhou <duoming@zju.edu.cn> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
0caf6d9922
commit
9fd75b66b8
@ -98,8 +98,10 @@ again:
|
||||
spin_unlock_bh(&ax25_list_lock);
|
||||
lock_sock(sk);
|
||||
s->ax25_dev = NULL;
|
||||
dev_put_track(ax25_dev->dev, &ax25_dev->dev_tracker);
|
||||
ax25_dev_put(ax25_dev);
|
||||
if (sk->sk_socket) {
|
||||
dev_put_track(ax25_dev->dev, &ax25_dev->dev_tracker);
|
||||
ax25_dev_put(ax25_dev);
|
||||
}
|
||||
ax25_disconnect(s, ENETUNREACH);
|
||||
release_sock(sk);
|
||||
spin_lock_bh(&ax25_list_lock);
|
||||
@ -979,14 +981,20 @@ static int ax25_release(struct socket *sock)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
ax25_cb *ax25;
|
||||
ax25_dev *ax25_dev;
|
||||
|
||||
if (sk == NULL)
|
||||
return 0;
|
||||
|
||||
sock_hold(sk);
|
||||
sock_orphan(sk);
|
||||
lock_sock(sk);
|
||||
sock_orphan(sk);
|
||||
ax25 = sk_to_ax25(sk);
|
||||
ax25_dev = ax25->ax25_dev;
|
||||
if (ax25_dev) {
|
||||
dev_put_track(ax25_dev->dev, &ax25_dev->dev_tracker);
|
||||
ax25_dev_put(ax25_dev);
|
||||
}
|
||||
|
||||
if (sk->sk_type == SOCK_SEQPACKET) {
|
||||
switch (ax25->state) {
|
||||
|
Loading…
Reference in New Issue
Block a user