On Sat, Apr 03, 2021 at 08:25:38PM +0000, Luis Chamberlain wrote:
> So creating say 1000 random files in /lib/firmware on a freshly created
> btrfs partition helps reproduce:
> 
> mkfs.btrfs /dev/whatever
> mount /dev/wahtever /lib/firmware
> # Put it on /etc/fstab too
> 
> Generate 1000 random files on it:
> 
> ```
> for n in {1..1000}; do                                                        
>   
>     dd if=/dev/urandom of=/lib/firmware/file$( printf %03d "$n" ).bin bs=1 
> count=$((RANDOM + 1024 ))
> done  
> ```
> 
> Then reboot, upon reboot do:
> 
> modprobe test_firmware
> echo 1 > /sys/devices/virtual/misc/test_firmware/config_enable_resume_test
> systemctl suspend

OK this fixes it but this just shows that likely the thaw'ing allows
a race to take place which we didn't expect. I'll do some more digging
for a proper fix.

diff --git a/fs/kernel_read_file.c b/fs/kernel_read_file.c
index 90d255fbdd9b..b9c37eefab35 100644
--- a/fs/kernel_read_file.c
+++ b/fs/kernel_read_file.c
@@ -4,6 +4,7 @@
 #include <linux/kernel_read_file.h>
 #include <linux/security.h>
 #include <linux/vmalloc.h>
+#include <linux/umh.h>
 
 /**
  * kernel_read_file() - read file contents into a kernel buffer
@@ -156,17 +157,25 @@ int kernel_read_file_from_path_initns(const char *path, 
loff_t offset,
        if (!path || !*path)
                return -EINVAL;
 
+       ret = usermodehelper_read_trylock();
+       if (WARN_ON(ret)) {
+               pr_warn_once("Trying to do direct read when not available");
+               return ret;
+       }
        task_lock(&init_task);
        get_fs_root(init_task.fs, &root);
        task_unlock(&init_task);
 
        file = file_open_root(root.dentry, root.mnt, path, O_RDONLY, 0);
        path_put(&root);
-       if (IS_ERR(file))
+       if (IS_ERR(file)) {
+               usermodehelper_read_unlock();
                return PTR_ERR(file);
+       }
 
        ret = kernel_read_file(file, offset, buf, buf_size, file_size, id);
        fput(file);
+       usermodehelper_read_unlock();
        return ret;
 }
 EXPORT_SYMBOL_GPL(kernel_read_file_from_path_initns);

Reply via email to