From: Luxiao Xu <[email protected]>

batadv_tp_sender_shutdown() unconditionally decrements the "sending"
atomic counter. If multiple paths (e.g. timeout, user cancel, and
normal finish) call this function, the counter can underflow to -1.

Since the sender logic treats any non-zero value as "still sending",
a negative value causes the sender kthread to loop indefinitely.
This leads to a use-after-free when the interface is removed while
the zombie thread is still active.

Fix this by using atomic_xchg() to ensure the counter only transitions
from 1 to 0 once.

Fixes: 33a3bb4a3345 ("batman-adv: throughput meter implementation")
Cc: [email protected]
Reported-by: Yuan Tan <[email protected]>
Reported-by: Yifan Wu <[email protected]>
Reported-by: Juefei Pu <[email protected]>
Reported-by: Xin Liu <[email protected]>
Signed-off-by: Luxiao Xu <[email protected]>
Signed-off-by: Ren Wei <[email protected]>
[sven: added missing change in batadv_tp_send]
Signed-off-by: Sven Eckelmann <[email protected]>
Signed-off-by: Simon Wunderlich <[email protected]>
---
 net/batman-adv/tp_meter.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/net/batman-adv/tp_meter.c b/net/batman-adv/tp_meter.c
index 066c76113fc43..a4397aa881dd4 100644
--- a/net/batman-adv/tp_meter.c
+++ b/net/batman-adv/tp_meter.c
@@ -451,7 +451,7 @@ static void batadv_tp_sender_end(struct batadv_priv 
*bat_priv,
 static void batadv_tp_sender_shutdown(struct batadv_tp_vars *tp_vars,
                                      enum batadv_tp_meter_reason reason)
 {
-       if (!atomic_dec_and_test(&tp_vars->sending))
+       if (atomic_xchg(&tp_vars->sending, 0) != 1)
                return;
 
        tp_vars->reason = reason;
@@ -885,7 +885,7 @@ static int batadv_tp_send(void *arg)
                                   "Meter: %s() cannot send packets (%d)\n",
                                   __func__, err);
                        /* ensure nobody else tries to stop the thread now */
-                       if (atomic_dec_and_test(&tp_vars->sending))
+                       if (atomic_xchg(&tp_vars->sending, 0) == 1)
                                tp_vars->reason = err;
                        break;
                }
-- 
2.47.3

Reply via email to