Revert "fs: remove ksys_dup()"
authorDominik Brodowski <linux@dominikbrodowski.net>
Wed, 1 Jan 2020 19:05:03 +0000 (20:05 +0100)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 3 Jan 2020 00:15:33 +0000 (16:15 -0800)
This reverts commit 8243186f0cc7 ("fs: remove ksys_dup()") and the
subsequent fix for it in commit 2d3145f8d280 ("early init: fix error
handling when opening /dev/console").

Trying to use filp_open() and f_dupfd() instead of pseudo-syscalls
caused more trouble than what is worth it: it requires accessing vfs
internals and it turns out there were other bugs in it too.

In particular, the file reference counting was wrong - because unlike
the original "open+2*dup" sequence it used "filp_open+3*f_dupfd" and
thus had an extra leaked file reference.

That in turn then caused odd problems with Androidx86 long after boot
becaue of how the extra reference to the console kept the session active
even after all file descriptors had been closed.

Reported-by: youling 257 <youling257@gmail.com>
Cc: Arvind Sankar <nivedita@alum.mit.edu>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
fs/file.c
include/linux/syscalls.h
init/main.c

index 2f4fcf985079d52400e7d58b732b7b189133b36c..3da91a112babe874af392635a32e971d8885937f 100644 (file)
--- a/fs/file.c
+++ b/fs/file.c
@@ -960,7 +960,7 @@ SYSCALL_DEFINE2(dup2, unsigned int, oldfd, unsigned int, newfd)
        return ksys_dup3(oldfd, newfd, 0);
 }
 
-SYSCALL_DEFINE1(dup, unsigned int, fildes)
+int ksys_dup(unsigned int fildes)
 {
        int ret = -EBADF;
        struct file *file = fget_raw(fildes);
@@ -975,6 +975,11 @@ SYSCALL_DEFINE1(dup, unsigned int, fildes)
        return ret;
 }
 
+SYSCALL_DEFINE1(dup, unsigned int, fildes)
+{
+       return ksys_dup(fildes);
+}
+
 int f_dupfd(unsigned int from, struct file *file, unsigned flags)
 {
        int err;
index 2960dedcfde8a25ad53ed7f15d133d7c9fdb4757..5262b7a76d392b60769a93dde860a30e4b23481f 100644 (file)
@@ -1232,6 +1232,7 @@ asmlinkage long sys_ni_syscall(void);
  */
 
 int ksys_umount(char __user *name, int flags);
+int ksys_dup(unsigned int fildes);
 int ksys_chroot(const char __user *filename);
 ssize_t ksys_write(unsigned int fd, const char __user *buf, size_t count);
 int ksys_chdir(const char __user *filename);
index 1ecfd43ed4643461af60bb47f5d4f61aad9b12af..2cd736059416f90e5347a3f965d1b6c3e25434fa 100644 (file)
@@ -93,7 +93,6 @@
 #include <linux/rodata_test.h>
 #include <linux/jump_label.h>
 #include <linux/mem_encrypt.h>
-#include <linux/file.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -1158,26 +1157,13 @@ static int __ref kernel_init(void *unused)
 
 void console_on_rootfs(void)
 {
-       struct file *file;
-       unsigned int i;
-
-       /* Open /dev/console in kernelspace, this should never fail */
-       file = filp_open("/dev/console", O_RDWR, 0);
-       if (IS_ERR(file))
-               goto err_out;
-
-       /* create stdin/stdout/stderr, this should never fail */
-       for (i = 0; i < 3; i++) {
-               if (f_dupfd(i, file, 0) != i)
-                       goto err_out;
-       }
-
-       return;
+       /* Open the /dev/console as stdin, this should never fail */
+       if (ksys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
+               pr_err("Warning: unable to open an initial console.\n");
 
-err_out:
-       /* no panic -- this might not be fatal */
-       pr_err("Warning: unable to open an initial console.\n");
-       return;
+       /* create stdout/stderr */
+       (void) ksys_dup(0);
+       (void) ksys_dup(0);
 }
 
 static noinline void __init kernel_init_freeable(void)