summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2023-10-11 16:55:10 +0200
committerJohannes Berg <johannes.berg@intel.com>2023-10-11 16:55:10 +0200
commitf2ac54ebf85615a6d78f5eb213a8bbeeb17ebe5d (patch)
tree2a05651d3033d9195c20ad0176464a4fdc43447e
parentb2f750c3a80b285cd60c9346f8c96bd0a2a66cde (diff)
downloadlinux-f2ac54ebf85615a6d78f5eb213a8bbeeb17ebe5d.tar.gz
linux-f2ac54ebf85615a6d78f5eb213a8bbeeb17ebe5d.tar.bz2
linux-f2ac54ebf85615a6d78f5eb213a8bbeeb17ebe5d.zip
net: rfkill: reduce data->mtx scope in rfkill_fop_open
In syzbot runs, lockdep reports that there's a (potential) deadlock here of data->mtx being locked recursively. This isn't really a deadlock since they are different instances, but lockdep cannot know, and teaching it would be far more difficult than other fixes. At the same time we don't even really _need_ the mutex to be locked in rfkill_fop_open(), since we're modifying only a completely fresh instance of 'data' (struct rfkill_data) that's not yet added to the global list. However, to avoid any reordering etc. within the globally locked section, and to make the code look more symmetric, we should still lock the data->events list manipulation, but also need to lock _only_ that. So do that. Reported-by: syzbot+509238e523e032442b80@syzkaller.appspotmail.com Fixes: 2c3dfba4cf84 ("rfkill: sync before userspace visibility/changes") Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--net/rfkill/core.c5
1 files changed, 2 insertions, 3 deletions
diff --git a/net/rfkill/core.c b/net/rfkill/core.c
index 08630896b6c8..14cc8fe8584b 100644
--- a/net/rfkill/core.c
+++ b/net/rfkill/core.c
@@ -1180,7 +1180,6 @@ static int rfkill_fop_open(struct inode *inode, struct file *file)
init_waitqueue_head(&data->read_wait);
mutex_lock(&rfkill_global_mutex);
- mutex_lock(&data->mtx);
/*
* start getting events from elsewhere but hold mtx to get
* startup events added first
@@ -1192,10 +1191,11 @@ static int rfkill_fop_open(struct inode *inode, struct file *file)
goto free;
rfkill_sync(rfkill);
rfkill_fill_event(&ev->ev, rfkill, RFKILL_OP_ADD);
+ mutex_lock(&data->mtx);
list_add_tail(&ev->list, &data->events);
+ mutex_unlock(&data->mtx);
}
list_add(&data->list, &rfkill_fds);
- mutex_unlock(&data->mtx);
mutex_unlock(&rfkill_global_mutex);
file->private_data = data;
@@ -1203,7 +1203,6 @@ static int rfkill_fop_open(struct inode *inode, struct file *file)
return stream_open(inode, file);
free:
- mutex_unlock(&data->mtx);
mutex_unlock(&rfkill_global_mutex);
mutex_destroy(&data->mtx);
list_for_each_entry_safe(ev, tmp, &data->events, list)