* [PATCH net 0/2] Fix refcount leak and NPD bugs in ax25
@ 2022-03-11 7:03 Duoming Zhou
2022-03-11 7:03 ` [PATCH net 1/2] ax25: Fix refcount leaks caused by ax25_cb_del() Duoming Zhou
2022-03-11 7:03 ` [PATCH net 2/2] ax25: Fix NULL pointer dereferences in ax25 timers Duoming Zhou
0 siblings, 2 replies; 3+ messages in thread
From: Duoming Zhou @ 2022-03-11 7:03 UTC (permalink / raw)
To: linux-hams
Cc: netdev, linux-kernel, jreuter, kuba, davem, ralf, thomas,
Duoming Zhou
The first patch fixes refcount leak in ax25 that could cause
ax25-ex-connected-session-now-listening-state-bug.
The second patch fixes NPD bugs in ax25 timers.
Duoming Zhou (2):
ax25: Fix refcount leaks caused by ax25_cb_del()
ax25: Fix NULL pointer dereferences in ax25 timers
include/net/ax25.h | 5 +++++
net/ax25/af_ax25.c | 13 ++++++++++---
net/ax25/ax25_dev.c | 1 +
net/ax25/ax25_timer.c | 10 +++++-----
4 files changed, 21 insertions(+), 8 deletions(-)
--
2.17.1
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH net 1/2] ax25: Fix refcount leaks caused by ax25_cb_del()
2022-03-11 7:03 [PATCH net 0/2] Fix refcount leak and NPD bugs in ax25 Duoming Zhou
@ 2022-03-11 7:03 ` Duoming Zhou
2022-03-11 7:03 ` [PATCH net 2/2] ax25: Fix NULL pointer dereferences in ax25 timers Duoming Zhou
1 sibling, 0 replies; 3+ messages in thread
From: Duoming Zhou @ 2022-03-11 7:03 UTC (permalink / raw)
To: linux-hams
Cc: netdev, linux-kernel, jreuter, kuba, davem, ralf, thomas,
Duoming Zhou
The previous commit d01ffb9eee4a ("ax25: add refcount in ax25_dev to avoid
UAF bugs") and commit feef318c855a ("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 a flag in ax25_dev in order to prevent reference count
leaks. If the above condition happens, the "test_bit" condition check
in ax25_kill_by_device() could pass and the refcounts could be
decreased properly.
Fixes: d01ffb9eee4a ("ax25: add refcount in ax25_dev to avoid UAF bugs")
Fixes: feef318c855a ("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>
---
include/net/ax25.h | 5 +++++
net/ax25/af_ax25.c | 6 ++++++
net/ax25/ax25_dev.c | 1 +
3 files changed, 12 insertions(+)
diff --git a/include/net/ax25.h b/include/net/ax25.h
index 8221af1811d..ea6ca385190 100644
--- a/include/net/ax25.h
+++ b/include/net/ax25.h
@@ -158,6 +158,10 @@ enum {
#define AX25_DEF_PROTOCOL AX25_PROTO_STD_SIMPLEX /* Standard AX.25 */
#define AX25_DEF_DS_TIMEOUT 180000 /* DAMA timeout 3 minutes */
+#define AX25_DEV_INIT 0
+#define AX25_DEV_KILL 0
+#define AX25_DEV_BIND 1
+
typedef struct ax25_uid_assoc {
struct hlist_node uid_node;
refcount_t refcount;
@@ -240,6 +244,7 @@ typedef struct ax25_dev {
ax25_dama_info dama;
#endif
refcount_t refcount;
+ unsigned long flag;
} ax25_dev;
typedef struct ax25_cb {
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index 6bd09718077..fc564b87acc 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -86,6 +86,7 @@ static void ax25_kill_by_device(struct net_device *dev)
again:
ax25_for_each(s, &ax25_list) {
if (s->ax25_dev == ax25_dev) {
+ set_bit(AX25_DEV_KILL, &ax25_dev->flag);
sk = s->sk;
if (!sk) {
spin_unlock_bh(&ax25_list_lock);
@@ -115,6 +116,10 @@ static void ax25_kill_by_device(struct net_device *dev)
}
}
spin_unlock_bh(&ax25_list_lock);
+ if (!test_bit(AX25_DEV_KILL, &ax25_dev->flag) && test_bit(AX25_DEV_BIND, &ax25_dev->flag)) {
+ dev_put_track(ax25_dev->dev, &ax25_dev->dev_tracker);
+ ax25_dev_put(ax25_dev);
+ }
}
/*
@@ -1132,6 +1137,7 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
done:
ax25_cb_add(ax25);
sock_reset_flag(sk, SOCK_ZAPPED);
+ set_bit(AX25_DEV_BIND, &ax25_dev->flag);
out:
release_sock(sk);
diff --git a/net/ax25/ax25_dev.c b/net/ax25/ax25_dev.c
index d2a244e1c26..9b04d74a1be 100644
--- a/net/ax25/ax25_dev.c
+++ b/net/ax25/ax25_dev.c
@@ -77,6 +77,7 @@ void ax25_dev_device_up(struct net_device *dev)
ax25_dev->values[AX25_VALUES_PACLEN] = AX25_DEF_PACLEN;
ax25_dev->values[AX25_VALUES_PROTOCOL] = AX25_DEF_PROTOCOL;
ax25_dev->values[AX25_VALUES_DS_TIMEOUT]= AX25_DEF_DS_TIMEOUT;
+ ax25_dev->flag = AX25_DEV_INIT;
#if defined(CONFIG_AX25_DAMA_SLAVE) || defined(CONFIG_AX25_DAMA_MASTER)
ax25_ds_setup_timer(ax25_dev);
--
2.17.1
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH net 2/2] ax25: Fix NULL pointer dereferences in ax25 timers
2022-03-11 7:03 [PATCH net 0/2] Fix refcount leak and NPD bugs in ax25 Duoming Zhou
2022-03-11 7:03 ` [PATCH net 1/2] ax25: Fix refcount leaks caused by ax25_cb_del() Duoming Zhou
@ 2022-03-11 7:03 ` Duoming Zhou
1 sibling, 0 replies; 3+ messages in thread
From: Duoming Zhou @ 2022-03-11 7:03 UTC (permalink / raw)
To: linux-hams
Cc: netdev, linux-kernel, jreuter, kuba, davem, ralf, thomas,
Duoming Zhou
There are race conditions that may lead to null pointer dereferences in
ax25_heartbeat_expiry(), ax25_t1timer_expiry(), ax25_t2timer_expiry(),
ax25_t3timer_expiry() and ax25_idletimer_expiry(), when we use
ax25_kill_by_device() to detach the ax25 device.
One of the race conditions that cause null pointer dereferences can be
shown as below:
(Thread 1) | (Thread 2)
ax25_connect() |
ax25_std_establish_data_link() |
ax25_start_t1timer() |
mod_timer(&ax25->t1timer,..) |
| ax25_kill_by_device()
(wait a time) | ...
| s->ax25_dev = NULL; //(1)
ax25_t1timer_expiry() |
ax25->ax25_dev->values[..] //(2)| ...
... |
We set null to ax25_cb->ax25_dev in position (1) and dereference
the null pointer in position (2).
The corresponding fail log is shown below:
===============================================================
BUG: kernel NULL pointer dereference, address: 0000000000000050
CPU: 1 PID: 0 Comm: swapper/1 Not tainted 5.17.0-rc6-00794-g45690b7d0
RIP: 0010:ax25_t1timer_expiry+0x12/0x40
...
Call Trace:
call_timer_fn+0x21/0x120
__run_timers.part.0+0x1ca/0x250
run_timer_softirq+0x2c/0x60
__do_softirq+0xef/0x2f3
irq_exit_rcu+0xb6/0x100
sysvec_apic_timer_interrupt+0xa2/0xd0
...
This patch uses ax25_disconnect() to delete timers before we set null to
ax25_cb->ax25_dev in ax25_kill_by_device(). Function ax25_disconnect()
will not return until all timers are stopped, because we have changed
del_timer() to del_timer_sync(). What`s more, we add condition check in
ax25_destroy_socket(), because ax25_stop_heartbeat() will not return,
if there is still heartbeat.
Signed-off-by: Duoming Zhou <duoming@zju.edu.cn>
---
net/ax25/af_ax25.c | 7 ++++---
net/ax25/ax25_timer.c | 10 +++++-----
2 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index fc564b87acc..46e4d0cc878 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -90,18 +90,18 @@ static void ax25_kill_by_device(struct net_device *dev)
sk = s->sk;
if (!sk) {
spin_unlock_bh(&ax25_list_lock);
- s->ax25_dev = NULL;
ax25_disconnect(s, ENETUNREACH);
+ s->ax25_dev = NULL;
spin_lock_bh(&ax25_list_lock);
goto again;
}
sock_hold(sk);
spin_unlock_bh(&ax25_list_lock);
lock_sock(sk);
+ ax25_disconnect(s, ENETUNREACH);
s->ax25_dev = NULL;
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);
sock_put(sk);
@@ -310,7 +310,8 @@ void ax25_destroy_socket(ax25_cb *ax25)
ax25_cb_del(ax25);
- ax25_stop_heartbeat(ax25);
+ if (!ax25->sk || !sock_flag(ax25->sk, SOCK_DESTROY))
+ ax25_stop_heartbeat(ax25);
ax25_stop_t1timer(ax25);
ax25_stop_t2timer(ax25);
ax25_stop_t3timer(ax25);
diff --git a/net/ax25/ax25_timer.c b/net/ax25/ax25_timer.c
index 85865ebfdfa..99af3d1aeec 100644
--- a/net/ax25/ax25_timer.c
+++ b/net/ax25/ax25_timer.c
@@ -78,27 +78,27 @@ void ax25_start_idletimer(ax25_cb *ax25)
void ax25_stop_heartbeat(ax25_cb *ax25)
{
- del_timer(&ax25->timer);
+ del_timer_sync(&ax25->timer);
}
void ax25_stop_t1timer(ax25_cb *ax25)
{
- del_timer(&ax25->t1timer);
+ del_timer_sync(&ax25->t1timer);
}
void ax25_stop_t2timer(ax25_cb *ax25)
{
- del_timer(&ax25->t2timer);
+ del_timer_sync(&ax25->t2timer);
}
void ax25_stop_t3timer(ax25_cb *ax25)
{
- del_timer(&ax25->t3timer);
+ del_timer_sync(&ax25->t3timer);
}
void ax25_stop_idletimer(ax25_cb *ax25)
{
- del_timer(&ax25->idletimer);
+ del_timer_sync(&ax25->idletimer);
}
int ax25_t1timer_running(ax25_cb *ax25)
--
2.17.1
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2022-03-11 7:03 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-03-11 7:03 [PATCH net 0/2] Fix refcount leak and NPD bugs in ax25 Duoming Zhou
2022-03-11 7:03 ` [PATCH net 1/2] ax25: Fix refcount leaks caused by ax25_cb_del() Duoming Zhou
2022-03-11 7:03 ` [PATCH net 2/2] ax25: Fix NULL pointer dereferences in ax25 timers Duoming Zhou
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).