]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
file: flush delayed work in delayed fput()
authorshao mingyin <shao.mingyin@zte.com.cn>
Wed, 23 Oct 2024 05:58:50 +0000 (13:58 +0800)
committerChristian Brauner <brauner@kernel.org>
Sun, 22 Dec 2024 10:29:52 +0000 (11:29 +0100)
The fput() of file rcS might not have completed causing issues when
executing the file.

rcS is opened in do_populate_rootfs before executed. At the end of
do_populate_rootfs() flush_delayed_fput() is called. Now
do_populate_rootfs() assumes that all fput()s caused by
do_populate_rootfs() have completed.

But flush_delayed_fput() can only ensure that fput() on the current
delayed_fput_list has finished. Any file that has been removed from
delayed_fput_list asynchronously in the meantime might not have
completed causing the exec to fail.

do_populate_rootfs delayed_fput_list delayed_fput execve
fput() a
fput() a->b
fput() a->b->rcS
__fput(a)
fput() c
fput() c->d
__fput(b)
flush_delayed_fput
__fput(c)
__fput(d)
__fput(b)
__fput(b) execve(rcS)

Ensure that all delayed work is done by calling flush_delayed_work() in
flush_delayed_fput() explicitly.

Signed-off-by: Chen Lin <chen.lin5@zte.com.cn>
Signed-off-by: Shao Mingyin <shao.mingyin@zte.com.cn>
Link: https://lore.kernel.org/r/20241023135850067m3w2R0UXESiVCYz_wdAoT@zte.com.cn
Cc: Yang Yang <yang.yang29@zte.com.cn>
Cc: Yang Tao <yang.tao172@zte.com.cn>
Cc: Xu Xin <xu.xin16@zte.com.cn>
[brauner: rewrite commit message]
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/file_table.c

index 502b81f614d9bbbfe3bf38addd0d2f9e60e428a9..a32171d2b83f589459e0306260868aaeda39d78b 100644 (file)
@@ -478,6 +478,8 @@ static void ____fput(struct callback_head *work)
        __fput(container_of(work, struct file, f_task_work));
 }
 
+static DECLARE_DELAYED_WORK(delayed_fput_work, delayed_fput);
+
 /*
  * If kernel thread really needs to have the final fput() it has done
  * to complete, call this.  The only user right now is the boot - we
@@ -491,11 +493,10 @@ static void ____fput(struct callback_head *work)
 void flush_delayed_fput(void)
 {
        delayed_fput(NULL);
+       flush_delayed_work(&delayed_fput_work);
 }
 EXPORT_SYMBOL_GPL(flush_delayed_fput);
 
-static DECLARE_DELAYED_WORK(delayed_fput_work, delayed_fput);
-
 void fput(struct file *file)
 {
        if (file_ref_put(&file->f_ref)) {