Skip to content

Commit 8c2c844

Browse files
Phil Suttergregkh
Phil Sutter
authored andcommitted
netfilter: IDLETIMER: Fix for possible ABBA deadlock
[ Upstream commit f36b019 ] Deletion of the last rule referencing a given idletimer may happen at the same time as a read of its file in sysfs: | ====================================================== | WARNING: possible circular locking dependency detected | 6.12.0-rc7-01692-g5e9a28f41134-dirty #594 Not tainted | ------------------------------------------------------ | iptables/3303 is trying to acquire lock: | ffff8881057e04b8 (kn->active#48){++++}-{0:0}, at: __kernfs_remove+0x20 | | but task is already holding lock: | ffffffffa0249068 (list_mutex){+.+.}-{3:3}, at: idletimer_tg_destroy_v] | | which lock already depends on the new lock. A simple reproducer is: | #!/bin/bash | | while true; do | iptables -A INPUT -i foo -j IDLETIMER --timeout 10 --label "testme" | iptables -D INPUT -i foo -j IDLETIMER --timeout 10 --label "testme" | done & | while true; do | cat /sys/class/xt_idletimer/timers/testme >/dev/null | done Avoid this by freeing list_mutex right after deleting the element from the list, then continuing with the teardown. Fixes: 0902b46 ("netfilter: xtables: idletimer target implementation") Signed-off-by: Phil Sutter <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent 01b2c76 commit 8c2c844

File tree

1 file changed

+28
-24
lines changed

1 file changed

+28
-24
lines changed

net/netfilter/xt_IDLETIMER.c

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -409,21 +409,23 @@ static void idletimer_tg_destroy(const struct xt_tgdtor_param *par)
409409

410410
mutex_lock(&list_mutex);
411411

412-
if (--info->timer->refcnt == 0) {
413-
pr_debug("deleting timer %s\n", info->label);
414-
415-
list_del(&info->timer->entry);
416-
timer_shutdown_sync(&info->timer->timer);
417-
cancel_work_sync(&info->timer->work);
418-
sysfs_remove_file(idletimer_tg_kobj, &info->timer->attr.attr);
419-
kfree(info->timer->attr.attr.name);
420-
kfree(info->timer);
421-
} else {
412+
if (--info->timer->refcnt > 0) {
422413
pr_debug("decreased refcnt of timer %s to %u\n",
423414
info->label, info->timer->refcnt);
415+
mutex_unlock(&list_mutex);
416+
return;
424417
}
425418

419+
pr_debug("deleting timer %s\n", info->label);
420+
421+
list_del(&info->timer->entry);
426422
mutex_unlock(&list_mutex);
423+
424+
timer_shutdown_sync(&info->timer->timer);
425+
cancel_work_sync(&info->timer->work);
426+
sysfs_remove_file(idletimer_tg_kobj, &info->timer->attr.attr);
427+
kfree(info->timer->attr.attr.name);
428+
kfree(info->timer);
427429
}
428430

429431
static void idletimer_tg_destroy_v1(const struct xt_tgdtor_param *par)
@@ -434,25 +436,27 @@ static void idletimer_tg_destroy_v1(const struct xt_tgdtor_param *par)
434436

435437
mutex_lock(&list_mutex);
436438

437-
if (--info->timer->refcnt == 0) {
438-
pr_debug("deleting timer %s\n", info->label);
439-
440-
list_del(&info->timer->entry);
441-
if (info->timer->timer_type & XT_IDLETIMER_ALARM) {
442-
alarm_cancel(&info->timer->alarm);
443-
} else {
444-
timer_shutdown_sync(&info->timer->timer);
445-
}
446-
cancel_work_sync(&info->timer->work);
447-
sysfs_remove_file(idletimer_tg_kobj, &info->timer->attr.attr);
448-
kfree(info->timer->attr.attr.name);
449-
kfree(info->timer);
450-
} else {
439+
if (--info->timer->refcnt > 0) {
451440
pr_debug("decreased refcnt of timer %s to %u\n",
452441
info->label, info->timer->refcnt);
442+
mutex_unlock(&list_mutex);
443+
return;
453444
}
454445

446+
pr_debug("deleting timer %s\n", info->label);
447+
448+
list_del(&info->timer->entry);
455449
mutex_unlock(&list_mutex);
450+
451+
if (info->timer->timer_type & XT_IDLETIMER_ALARM) {
452+
alarm_cancel(&info->timer->alarm);
453+
} else {
454+
timer_shutdown_sync(&info->timer->timer);
455+
}
456+
cancel_work_sync(&info->timer->work);
457+
sysfs_remove_file(idletimer_tg_kobj, &info->timer->attr.attr);
458+
kfree(info->timer->attr.attr.name);
459+
kfree(info->timer);
456460
}
457461

458462

0 commit comments

Comments
 (0)