summaryrefslogtreecommitdiffstats
path: root/fs/efivarfs/inode.c
diff options
context:
space:
mode:
authorArd Biesheuvel <ardb@kernel.org>2023-12-08 17:39:29 +0100
committerArd Biesheuvel <ardb@kernel.org>2023-12-11 11:19:18 +0100
commitcdb46a8aefbf7fd36772bb206aaaf7e45d7cf8f6 (patch)
treeb0eb3387296b811d060af9ce3e5f57b2b9d392ae /fs/efivarfs/inode.c
parent547713d502f7b4b8efccd409cff84d731a23853b (diff)
downloadlinux-cdb46a8aefbf7fd36772bb206aaaf7e45d7cf8f6.tar.gz
linux-cdb46a8aefbf7fd36772bb206aaaf7e45d7cf8f6.tar.bz2
linux-cdb46a8aefbf7fd36772bb206aaaf7e45d7cf8f6.zip
efivarfs: Move efivarfs list into superblock s_fs_info
syzbot reports issues with concurrent fsopen()/fsconfig() invocations on efivarfs, which are the result of the fact that the efivarfs list (which caches the names and GUIDs of existing EFI variables) is a global structure. In normal use, these issues are unlikely to trigger, even in the presence of multiple mounts of efivarfs, but the execution pattern used by the syzkaller reproducer may result in multiple instances of the superblock that share the global efivarfs list, and this causes list corruption when the list is reinitialized by one user while another is traversing it. So let's move the list head into the superblock s_fs_info field, so that it will never be shared between distinct instances of the superblock. In the common case, there will still be a single instance of this list, but in the artificial syzkaller case, no list corruption can occur any longer. Reported-by: syzbot+1902c359bfcaf39c46f2@syzkaller.appspotmail.com Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Diffstat (limited to 'fs/efivarfs/inode.c')
-rw-r--r--fs/efivarfs/inode.c3
1 files changed, 2 insertions, 1 deletions
diff --git a/fs/efivarfs/inode.c b/fs/efivarfs/inode.c
index 91290fe4a70b..586446e02ef7 100644
--- a/fs/efivarfs/inode.c
+++ b/fs/efivarfs/inode.c
@@ -77,6 +77,7 @@ bool efivarfs_valid_name(const char *str, int len)
static int efivarfs_create(struct mnt_idmap *idmap, struct inode *dir,
struct dentry *dentry, umode_t mode, bool excl)
{
+ struct efivarfs_fs_info *info = dir->i_sb->s_fs_info;
struct inode *inode = NULL;
struct efivar_entry *var;
int namelen, i = 0, err = 0;
@@ -118,7 +119,7 @@ static int efivarfs_create(struct mnt_idmap *idmap, struct inode *dir,
inode->i_private = var;
kmemleak_ignore(var);
- err = efivar_entry_add(var, &efivarfs_list);
+ err = efivar_entry_add(var, &info->efivarfs_list);
if (err)
goto out;