Skip to content

Commit 475d145

Browse files
mcgrofgregkh
authored andcommitted
cfg80211: fix possible circular lock on reg_regdb_search()
commit a85d0d7 upstream. When call_crda() is called we kick off a witch hunt search for the same regulatory domain on our internal regulatory database and that work gets kicked off on a workqueue, this is done while the cfg80211_mutex is held. If that workqueue kicks off it will first lock reg_regdb_search_mutex and later cfg80211_mutex but to ensure two CPUs will not contend against cfg80211_mutex the right thing to do is to have the reg_regdb_search() wait until the cfg80211_mutex is let go. The lockdep report is pasted below. cfg80211: Calling CRDA to update world regulatory domain ====================================================== [ INFO: possible circular locking dependency detected ] 3.3.8 #3 Tainted: G O ------------------------------------------------------- kworker/0:1/235 is trying to acquire lock: (cfg80211_mutex){+.+...}, at: [<816468a4>] set_regdom+0x78c/0x808 [cfg80211] but task is already holding lock: (reg_regdb_search_mutex){+.+...}, at: [<81646828>] set_regdom+0x710/0x808 [cfg80211] which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #2 (reg_regdb_search_mutex){+.+...}: [<800a8384>] lock_acquire+0x60/0x88 [<802950a8>] mutex_lock_nested+0x54/0x31c [<81645778>] is_world_regdom+0x9f8/0xc74 [cfg80211] -> #1 (reg_mutex#2){+.+...}: [<800a8384>] lock_acquire+0x60/0x88 [<802950a8>] mutex_lock_nested+0x54/0x31c [<8164539c>] is_world_regdom+0x61c/0xc74 [cfg80211] -> #0 (cfg80211_mutex){+.+...}: [<800a77b8>] __lock_acquire+0x10d4/0x17bc [<800a8384>] lock_acquire+0x60/0x88 [<802950a8>] mutex_lock_nested+0x54/0x31c [<816468a4>] set_regdom+0x78c/0x808 [cfg80211] other info that might help us debug this: Chain exists of: cfg80211_mutex --> reg_mutex#2 --> reg_regdb_search_mutex Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock(reg_regdb_search_mutex); lock(reg_mutex#2); lock(reg_regdb_search_mutex); lock(cfg80211_mutex); *** DEADLOCK *** 3 locks held by kworker/0:1/235: #0: (events){.+.+..}, at: [<80089a00>] process_one_work+0x230/0x460 #1: (reg_regdb_work){+.+...}, at: [<80089a00>] process_one_work+0x230/0x460 #2: (reg_regdb_search_mutex){+.+...}, at: [<81646828>] set_regdom+0x710/0x808 [cfg80211] stack backtrace: Call Trace: [<80290fd4>] dump_stack+0x8/0x34 [<80291bc4>] print_circular_bug+0x2ac/0x2d8 [<800a77b8>] __lock_acquire+0x10d4/0x17bc [<800a8384>] lock_acquire+0x60/0x88 [<802950a8>] mutex_lock_nested+0x54/0x31c [<816468a4>] set_regdom+0x78c/0x808 [cfg80211] Reported-by: Felix Fietkau <nbd@openwrt.org> Tested-by: Felix Fietkau <nbd@openwrt.org> Signed-off-by: Luis R. Rodriguez <mcgrof@do-not-panic.com> Reviewed-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 8c1d6b7 commit 475d145

File tree

1 file changed

+9
-3
lines changed

1 file changed

+9
-3
lines changed

net/wireless/reg.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,9 @@ static void reg_regdb_search(struct work_struct *work)
340340
struct reg_regdb_search_request *request;
341341
const struct ieee80211_regdomain *curdom, *regdom;
342342
int i, r;
343+
bool set_reg = false;
344+
345+
mutex_lock(&cfg80211_mutex);
343346

344347
mutex_lock(&reg_regdb_search_mutex);
345348
while (!list_empty(&reg_regdb_search_list)) {
@@ -355,16 +358,19 @@ static void reg_regdb_search(struct work_struct *work)
355358
r = reg_copy_regd(&regdom, curdom);
356359
if (r)
357360
break;
358-
mutex_lock(&cfg80211_mutex);
359-
set_regdom(regdom);
360-
mutex_unlock(&cfg80211_mutex);
361+
set_reg = true;
361362
break;
362363
}
363364
}
364365

365366
kfree(request);
366367
}
367368
mutex_unlock(&reg_regdb_search_mutex);
369+
370+
if (set_reg)
371+
set_regdom(regdom);
372+
373+
mutex_unlock(&cfg80211_mutex);
368374
}
369375

370376
static DECLARE_WORK(reg_regdb_work, reg_regdb_search);

0 commit comments

Comments
 (0)