All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/3] linux user: make execfd global (like exec path) and keep it open
@ 2020-08-17 23:57 Andrew Aladjev
  2020-08-17 23:57 ` [PATCH 2/3] linux user: moving is proc functions to separate file Andrew Aladjev
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Andrew Aladjev @ 2020-08-17 23:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: Andrew Aladjev

User opens /proc/self/exe symlink, than kernel should create /proc/self/fd/<execfd> symlink. We should be able to detect both exe and fd/<execfd> symlinks to provide common behaviour. The easiest solution is to make execfd global and keep it open. This solution looks acceptable because exec_path is already global.

Signed-off-by: Andrew Aladjev <aladjev.andrew@gmail.com>
---
 linux-user/elfload.c |  3 ++-
 linux-user/exit.c    |  7 +++++--
 linux-user/main.c    |  2 +-
 linux-user/qemu.h    |  1 +
 linux-user/syscall.c | 18 ++++++++++++++----
 5 files changed, 23 insertions(+), 8 deletions(-)

diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index fe9dfe795d..dfaf937ab9 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -2363,6 +2363,7 @@ void probe_guest_base(const char *image_name, abi_ulong guest_loaddr,
 
    IMAGE_NAME is the filename of the image, to use in error messages.
    IMAGE_FD is the open file descriptor for the image.
+   WARNING: IMAGE_FD won't be closed.
 
    BPRM_BUF is a copy of the beginning of the file; this of course
    contains the elf file header at offset 0.  It is assumed that this
@@ -2632,7 +2633,6 @@ static void load_elf_image(const char *image_name, int image_fd,
 
     mmap_unlock();
 
-    close(image_fd);
     return;
 
  exit_read:
@@ -2666,6 +2666,7 @@ static void load_elf_interp(const char *filename, struct image_info *info,
     }
 
     load_elf_image(filename, fd, info, NULL, bprm_buf);
+    close(fd);
     return;
 
  exit_perror:
diff --git a/linux-user/exit.c b/linux-user/exit.c
index 1594015444..f0626fc432 100644
--- a/linux-user/exit.c
+++ b/linux-user/exit.c
@@ -28,12 +28,15 @@ extern void __gcov_dump(void);
 
 void preexit_cleanup(CPUArchState *env, int code)
 {
+    close(execfd);
+
 #ifdef CONFIG_GPROF
         _mcleanup();
 #endif
 #ifdef CONFIG_GCOV
         __gcov_dump();
 #endif
-        gdb_exit(env, code);
-        qemu_plugin_atexit_cb();
+
+    gdb_exit(env, code);
+    qemu_plugin_atexit_cb();
 }
diff --git a/linux-user/main.c b/linux-user/main.c
index 75c9785157..27644a831a 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -49,6 +49,7 @@
 #include "crypto/init.h"
 
 char *exec_path;
+int execfd;
 
 int singlestep;
 static const char *argv0;
@@ -629,7 +630,6 @@ int main(int argc, char **argv, char **envp)
     int target_argc;
     int i;
     int ret;
-    int execfd;
     int log_mask;
     unsigned long max_reserved_va;
 
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 5c964389c1..f99be78d42 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -156,6 +156,7 @@ typedef struct TaskState {
 } __attribute__((aligned(16))) TaskState;
 
 extern char *exec_path;
+extern int execfd;
 void init_task_state(TaskState *ts);
 void task_settid(TaskState *);
 void stop_all_tasks(void);
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 945fc25279..5741c72733 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -7613,8 +7613,7 @@ static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags,
     };
 
     if (is_proc_myself(pathname, "exe")) {
-        int execfd = qemu_getauxval(AT_EXECFD);
-        return execfd ? execfd : safe_openat(dirfd, exec_path, flags, mode);
+        return execfd;
     }
 
     for (fake_open = fakes; fake_open->filename; fake_open++) {
@@ -7872,8 +7871,19 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
         return ret;
 #endif
     case TARGET_NR_close:
-        fd_trans_unregister(arg1);
-        return get_errno(close(arg1));
+        {
+            int fd = arg1;
+            if (fd == execfd) {
+                /*
+                 * We don't need to close execfd.
+                 * It will be closed on QEMU exit.
+                 */
+                return 0;
+            }
+
+            fd_trans_unregister(fd);
+            return get_errno(close(fd));
+        }
 
     case TARGET_NR_brk:
         return do_brk(arg1);
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/3] linux user: moving is proc functions to separate file
  2020-08-17 23:57 [PATCH 1/3] linux user: make execfd global (like exec path) and keep it open Andrew Aladjev
@ 2020-08-17 23:57 ` Andrew Aladjev
  2020-08-18 15:56   ` Laurent Vivier
  2020-08-17 23:57 ` [PATCH 3/3] linux user: refactored is proc myself, added support for fd/<execfd> Andrew Aladjev
  2020-08-18 15:23 ` [PATCH 1/3] linux user: make execfd global (like exec path) and keep it open Laurent Vivier
  2 siblings, 1 reply; 7+ messages in thread
From: Andrew Aladjev @ 2020-08-17 23:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: Andrew Aladjev

Signed-off-by: Andrew Aladjev <aladjev.andrew@gmail.com>
---
 linux-user/Makefile.objs  |  5 +++--
 linux-user/syscall.c      | 33 +--------------------------------
 linux-user/syscall_proc.c | 32 ++++++++++++++++++++++++++++++++
 linux-user/syscall_proc.h |  7 +++++++
 4 files changed, 43 insertions(+), 34 deletions(-)
 create mode 100644 linux-user/syscall_proc.c
 create mode 100644 linux-user/syscall_proc.h

diff --git a/linux-user/Makefile.objs b/linux-user/Makefile.objs
index 1940910a73..20f8828b86 100644
--- a/linux-user/Makefile.objs
+++ b/linux-user/Makefile.objs
@@ -1,7 +1,8 @@
 obj-y = main.o syscall.o strace.o mmap.o signal.o \
 	elfload.o linuxload.o uaccess.o uname.o \
-	safe-syscall.o $(TARGET_ABI_DIR)/signal.o \
-        $(TARGET_ABI_DIR)/cpu_loop.o exit.o fd-trans.o
+	safe-syscall.o syscall_proc.o \
+	$(TARGET_ABI_DIR)/cpu_loop.o $(TARGET_ABI_DIR)/signal.o \
+        exit.o fd-trans.o
 
 obj-$(TARGET_HAS_BFLT) += flatload.o
 obj-$(TARGET_I386) += vm86.o
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 5741c72733..01edc9b68d 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -125,6 +125,7 @@
 #include "qapi/error.h"
 #include "fd-trans.h"
 #include "tcg/tcg.h"
+#include "syscall_proc.h"
 
 #ifndef CLONE_IO
 #define CLONE_IO                0x80000000      /* Clone io context */
@@ -7482,38 +7483,6 @@ static int open_self_auxv(void *cpu_env, int fd)
     return 0;
 }
 
-static int is_proc_myself(const char *filename, const char *entry)
-{
-    if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
-        filename += strlen("/proc/");
-        if (!strncmp(filename, "self/", strlen("self/"))) {
-            filename += strlen("self/");
-        } else if (*filename >= '1' && *filename <= '9') {
-            char myself[80];
-            snprintf(myself, sizeof(myself), "%d/", getpid());
-            if (!strncmp(filename, myself, strlen(myself))) {
-                filename += strlen(myself);
-            } else {
-                return 0;
-            }
-        } else {
-            return 0;
-        }
-        if (!strcmp(filename, entry)) {
-            return 1;
-        }
-    }
-    return 0;
-}
-
-#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN) || \
-    defined(TARGET_SPARC) || defined(TARGET_M68K) || defined(TARGET_HPPA)
-static int is_proc(const char *filename, const char *entry)
-{
-    return strcmp(filename, entry) == 0;
-}
-#endif
-
 #if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
 static int open_net_route(void *cpu_env, int fd)
 {
diff --git a/linux-user/syscall_proc.c b/linux-user/syscall_proc.c
new file mode 100644
index 0000000000..34051a8e6b
--- /dev/null
+++ b/linux-user/syscall_proc.c
@@ -0,0 +1,32 @@
+#include "qemu/osdep.h"
+
+#include "syscall_proc.h"
+
+int is_proc_myself(const char *filename, const char *entry)
+{
+    if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
+        filename += strlen("/proc/");
+        if (!strncmp(filename, "self/", strlen("self/"))) {
+            filename += strlen("self/");
+        } else if (*filename >= '1' && *filename <= '9') {
+            char myself[80];
+            snprintf(myself, sizeof(myself), "%d/", getpid());
+            if (!strncmp(filename, myself, strlen(myself))) {
+                filename += strlen(myself);
+            } else {
+                return 0;
+            }
+        } else {
+            return 0;
+        }
+        if (!strcmp(filename, entry)) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+int is_proc(const char *filename, const char *entry)
+{
+    return strcmp(filename, entry) == 0;
+}
diff --git a/linux-user/syscall_proc.h b/linux-user/syscall_proc.h
new file mode 100644
index 0000000000..3098af931f
--- /dev/null
+++ b/linux-user/syscall_proc.h
@@ -0,0 +1,7 @@
+#ifndef SYSCALL_PROC_H
+#define SYSCALL_PROC_H
+
+int is_proc(const char *filename, const char *entry);
+int is_proc_myself(const char *filename, const char *entry);
+
+#endif
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 3/3] linux user: refactored is proc myself, added support for fd/<execfd>
  2020-08-17 23:57 [PATCH 1/3] linux user: make execfd global (like exec path) and keep it open Andrew Aladjev
  2020-08-17 23:57 ` [PATCH 2/3] linux user: moving is proc functions to separate file Andrew Aladjev
@ 2020-08-17 23:57 ` Andrew Aladjev
  2020-08-18 15:23 ` [PATCH 1/3] linux user: make execfd global (like exec path) and keep it open Laurent Vivier
  2 siblings, 0 replies; 7+ messages in thread
From: Andrew Aladjev @ 2020-08-17 23:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: Andrew Aladjev

Signed-off-by: Andrew Aladjev <aladjev.andrew@gmail.com>
---
 linux-user/syscall.c      |  12 ++--
 linux-user/syscall_proc.c | 113 +++++++++++++++++++++++++++++++-------
 linux-user/syscall_proc.h |   5 +-
 3 files changed, 101 insertions(+), 29 deletions(-)

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 01edc9b68d..7f970ccf35 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -7570,18 +7570,18 @@ static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags,
         { "auxv", open_self_auxv, is_proc_myself },
         { "cmdline", open_self_cmdline, is_proc_myself },
 #if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
-        { "/proc/net/route", open_net_route, is_proc },
+        { "net/route", open_net_route, is_proc },
 #endif
 #if defined(TARGET_SPARC) || defined(TARGET_HPPA)
-        { "/proc/cpuinfo", open_cpuinfo, is_proc },
+        { "cpuinfo", open_cpuinfo, is_proc },
 #endif
 #if defined(TARGET_M68K)
-        { "/proc/hardware", open_hardware, is_proc },
+        { "hardware", open_hardware, is_proc },
 #endif
         { NULL, NULL, NULL }
     };
 
-    if (is_proc_myself(pathname, "exe")) {
+    if (is_proc_myself_exe(pathname)) {
         return execfd;
     }
 
@@ -9161,7 +9161,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
             } else if (!arg3) {
                 /* Short circuit this for the magic exe check. */
                 ret = -TARGET_EINVAL;
-            } else if (is_proc_myself((const char *)p, "exe")) {
+            } else if (is_proc_myself_exe((const char *)p)) {
                 char real[PATH_MAX], *temp;
                 temp = realpath(exec_path, real);
                 /* Return value is # of bytes that we wrote to the buffer. */
@@ -9190,7 +9190,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
             p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
             if (!p || !p2) {
                 ret = -TARGET_EFAULT;
-            } else if (is_proc_myself((const char *)p, "exe")) {
+            } else if (is_proc_myself_exe((const char *)p)) {
                 char real[PATH_MAX], *temp;
                 temp = realpath(exec_path, real);
                 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
diff --git a/linux-user/syscall_proc.c b/linux-user/syscall_proc.c
index 34051a8e6b..3cf986b25f 100644
--- a/linux-user/syscall_proc.c
+++ b/linux-user/syscall_proc.c
@@ -1,32 +1,103 @@
 #include "qemu/osdep.h"
+#include "elf.h"
 
 #include "syscall_proc.h"
+#include "qemu.h"
 
-int is_proc_myself(const char *filename, const char *entry)
+#define PROC "/proc/"
+#define SELF "self/"
+#define FD   "fd/"
+
+#define STARTS_WITH(path, CONSTANT) (              \
+    strlen(path) >= strlen(CONSTANT) &&            \
+    strncmp(path, CONSTANT, strlen(CONSTANT)) == 0 \
+)
+
+static inline char *scope_to_proc(const char *path)
 {
-    if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
-        filename += strlen("/proc/");
-        if (!strncmp(filename, "self/", strlen("self/"))) {
-            filename += strlen("self/");
-        } else if (*filename >= '1' && *filename <= '9') {
-            char myself[80];
-            snprintf(myself, sizeof(myself), "%d/", getpid());
-            if (!strncmp(filename, myself, strlen(myself))) {
-                filename += strlen(myself);
-            } else {
-                return 0;
-            }
-        } else {
-            return 0;
-        }
-        if (!strcmp(filename, entry)) {
-            return 1;
+    if (STARTS_WITH(path, PROC)) {
+        return (char *)path + strlen(PROC);
+    }
+
+    return NULL;
+}
+
+static inline char *scope_to_proc_myself(const char *path)
+{
+    char *scope_path = scope_to_proc(path);
+    if (scope_path == NULL) {
+        return NULL;
+    }
+
+    if (STARTS_WITH(scope_path, SELF)) {
+        return scope_path + strlen(SELF);
+    }
+
+    if (strlen(scope_path) >= 1 &&
+        *scope_path >= '1' && *scope_path <= '9') {
+        char pid_path[80];
+        snprintf(pid_path, sizeof(pid_path), "%d/", getpid());
+        if (STARTS_WITH(scope_path, pid_path)) {
+            return scope_path + strlen(pid_path);
         }
     }
-    return 0;
+
+    return NULL;
+}
+
+int is_proc(const char *path, const char *entry)
+{
+    char *scope_path = scope_to_proc(path);
+    if (scope_path == NULL) {
+        return 0;
+    }
+
+    return strcmp(scope_path, entry) == 0;
 }
 
-int is_proc(const char *filename, const char *entry)
+int is_proc_myself(const char *path, const char *entry)
 {
-    return strcmp(filename, entry) == 0;
+    char *scope_path = scope_to_proc_myself(path);
+    if (scope_path == NULL) {
+        return 0;
+    }
+
+    return strcmp(scope_path, entry) == 0;
+}
+
+/*
+ * Kernel creates "fd/#{number}" link after opening "exe" link.
+ * Both "exe" and "fd/#{number}" can be used by application.
+ *
+ * Kernel can provide infinite amount of fd numbers.
+ * QEMU is going to always return single global execfd.
+ *
+ * So we need to check "exe" and "fd/#{execfd}" only.
+ */
+
+int is_proc_myself_exe(const char *path)
+{
+    char *scope_path = scope_to_proc_myself(path);
+    if (scope_path == NULL) {
+        return 0;
+    }
+
+    if (strcmp(scope_path, "exe") == 0) {
+        return 1;
+    }
+
+    if (STARTS_WITH(scope_path, FD)) {
+        scope_path += strlen(FD);
+
+        if (strlen(scope_path) >= 1 &&
+            *scope_path >= '1' && *scope_path <= '9') {
+            char execfd_path[80];
+            snprintf(execfd_path, sizeof(execfd_path), "%d", execfd);
+            if (strcmp(scope_path, execfd_path) == 0) {
+                return 1;
+            }
+        }
+    }
+
+    return 0;
 }
diff --git a/linux-user/syscall_proc.h b/linux-user/syscall_proc.h
index 3098af931f..f0e59c0e96 100644
--- a/linux-user/syscall_proc.h
+++ b/linux-user/syscall_proc.h
@@ -1,7 +1,8 @@
 #ifndef SYSCALL_PROC_H
 #define SYSCALL_PROC_H
 
-int is_proc(const char *filename, const char *entry);
-int is_proc_myself(const char *filename, const char *entry);
+int is_proc(const char *path, const char *entry);
+int is_proc_myself(const char *path, const char *entry);
+int is_proc_myself_exe(const char *path);
 
 #endif
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/3] linux user: make execfd global (like exec path) and keep it open
  2020-08-17 23:57 [PATCH 1/3] linux user: make execfd global (like exec path) and keep it open Andrew Aladjev
  2020-08-17 23:57 ` [PATCH 2/3] linux user: moving is proc functions to separate file Andrew Aladjev
  2020-08-17 23:57 ` [PATCH 3/3] linux user: refactored is proc myself, added support for fd/<execfd> Andrew Aladjev
@ 2020-08-18 15:23 ` Laurent Vivier
  2020-08-18 21:42   ` Андрей Аладьев
  2 siblings, 1 reply; 7+ messages in thread
From: Laurent Vivier @ 2020-08-18 15:23 UTC (permalink / raw)
  To: Andrew Aladjev, qemu-devel

Le 18/08/2020 à 01:57, Andrew Aladjev a écrit :
> User opens /proc/self/exe symlink, than kernel should create /proc/self/fd/<execfd> symlink. We should be able to detect both exe and fd/<execfd> symlinks to provide common behaviour. The easiest solution is to make execfd global and keep it open. This solution looks acceptable because exec_path is already global.
> 
> Signed-off-by: Andrew Aladjev <aladjev.andrew@gmail.com>
> ---
>  linux-user/elfload.c |  3 ++-
>  linux-user/exit.c    |  7 +++++--
>  linux-user/main.c    |  2 +-
>  linux-user/qemu.h    |  1 +
>  linux-user/syscall.c | 18 ++++++++++++++----
>  5 files changed, 23 insertions(+), 8 deletions(-)
> 
> diff --git a/linux-user/elfload.c b/linux-user/elfload.c
> index fe9dfe795d..dfaf937ab9 100644
> --- a/linux-user/elfload.c
> +++ b/linux-user/elfload.c
> @@ -2363,6 +2363,7 @@ void probe_guest_base(const char *image_name, abi_ulong guest_loaddr,
>  
>     IMAGE_NAME is the filename of the image, to use in error messages.
>     IMAGE_FD is the open file descriptor for the image.
> +   WARNING: IMAGE_FD won't be closed.
>  
>     BPRM_BUF is a copy of the beginning of the file; this of course
>     contains the elf file header at offset 0.  It is assumed that this
> @@ -2632,7 +2633,6 @@ static void load_elf_image(const char *image_name, int image_fd,
>  
>      mmap_unlock();
>  
> -    close(image_fd);
>      return;
>  
>   exit_read:
> @@ -2666,6 +2666,7 @@ static void load_elf_interp(const char *filename, struct image_info *info,
>      }
>  
>      load_elf_image(filename, fd, info, NULL, bprm_buf);
> +    close(fd);
>      return;
>  
>   exit_perror:
> diff --git a/linux-user/exit.c b/linux-user/exit.c
> index 1594015444..f0626fc432 100644
> --- a/linux-user/exit.c
> +++ b/linux-user/exit.c
> @@ -28,12 +28,15 @@ extern void __gcov_dump(void);
>  
>  void preexit_cleanup(CPUArchState *env, int code)
>  {
> +    close(execfd);
> +
>  #ifdef CONFIG_GPROF
>          _mcleanup();
>  #endif
>  #ifdef CONFIG_GCOV
>          __gcov_dump();
>  #endif
> -        gdb_exit(env, code);
> -        qemu_plugin_atexit_cb();
> +
> +    gdb_exit(env, code);
> +    qemu_plugin_atexit_cb();
>  }
> diff --git a/linux-user/main.c b/linux-user/main.c
> index 75c9785157..27644a831a 100644
> --- a/linux-user/main.c
> +++ b/linux-user/main.c
> @@ -49,6 +49,7 @@
>  #include "crypto/init.h"
>  
>  char *exec_path;
> +int execfd;
>  
>  int singlestep;
>  static const char *argv0;
> @@ -629,7 +630,6 @@ int main(int argc, char **argv, char **envp)
>      int target_argc;
>      int i;
>      int ret;
> -    int execfd;
>      int log_mask;
>      unsigned long max_reserved_va;
>  
> diff --git a/linux-user/qemu.h b/linux-user/qemu.h
> index 5c964389c1..f99be78d42 100644
> --- a/linux-user/qemu.h
> +++ b/linux-user/qemu.h
> @@ -156,6 +156,7 @@ typedef struct TaskState {
>  } __attribute__((aligned(16))) TaskState;
>  
>  extern char *exec_path;
> +extern int execfd;
>  void init_task_state(TaskState *ts);
>  void task_settid(TaskState *);
>  void stop_all_tasks(void);
> diff --git a/linux-user/syscall.c b/linux-user/syscall.c
> index 945fc25279..5741c72733 100644
> --- a/linux-user/syscall.c
> +++ b/linux-user/syscall.c
> @@ -7613,8 +7613,7 @@ static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags,
>      };
>  
>      if (is_proc_myself(pathname, "exe")) {
> -        int execfd = qemu_getauxval(AT_EXECFD);
> -        return execfd ? execfd : safe_openat(dirfd, exec_path, flags, mode);
> +        return execfd;
>      }
>  
>      for (fake_open = fakes; fake_open->filename; fake_open++) {
> @@ -7872,8 +7871,19 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
>          return ret;
>  #endif
>      case TARGET_NR_close:
> -        fd_trans_unregister(arg1);
> -        return get_errno(close(arg1));
> +        {
> +            int fd = arg1;
> +            if (fd == execfd) {
> +                /*
> +                 * We don't need to close execfd.
> +                 * It will be closed on QEMU exit.
> +                 */
> +                return 0;
> +            }

Why do you prevent the user to close it?

It's his own responsability if he breaks something.

And for instance, doing that breaks a call to dup() if it was done on
purpose.

Except that, the patch looks good.

Thanks,
Laurent


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/3] linux user: moving is proc functions to separate file
  2020-08-17 23:57 ` [PATCH 2/3] linux user: moving is proc functions to separate file Andrew Aladjev
@ 2020-08-18 15:56   ` Laurent Vivier
  2020-08-18 21:55     ` Андрей Аладьев
  0 siblings, 1 reply; 7+ messages in thread
From: Laurent Vivier @ 2020-08-18 15:56 UTC (permalink / raw)
  To: Andrew Aladjev, qemu-devel

Le 18/08/2020 à 01:57, Andrew Aladjev a écrit :
> Signed-off-by: Andrew Aladjev <aladjev.andrew@gmail.com>
> ---
>  linux-user/Makefile.objs  |  5 +++--
>  linux-user/syscall.c      | 33 +--------------------------------
>  linux-user/syscall_proc.c | 32 ++++++++++++++++++++++++++++++++
>  linux-user/syscall_proc.h |  7 +++++++
>  4 files changed, 43 insertions(+), 34 deletions(-)
>  create mode 100644 linux-user/syscall_proc.c
>  create mode 100644 linux-user/syscall_proc.h
> 
> diff --git a/linux-user/Makefile.objs b/linux-user/Makefile.objs
> index 1940910a73..20f8828b86 100644
> --- a/linux-user/Makefile.objs
> +++ b/linux-user/Makefile.objs
> @@ -1,7 +1,8 @@
>  obj-y = main.o syscall.o strace.o mmap.o signal.o \
>  	elfload.o linuxload.o uaccess.o uname.o \
> -	safe-syscall.o $(TARGET_ABI_DIR)/signal.o \
> -        $(TARGET_ABI_DIR)/cpu_loop.o exit.o fd-trans.o
> +	safe-syscall.o syscall_proc.o \
> +	$(TARGET_ABI_DIR)/cpu_loop.o $(TARGET_ABI_DIR)/signal.o \
> +        exit.o fd-trans.o
>  

I think this will collide with Paolo's meson pull request.

>  obj-$(TARGET_HAS_BFLT) += flatload.o
>  obj-$(TARGET_I386) += vm86.o
> diff --git a/linux-user/syscall.c b/linux-user/syscall.c
> index 5741c72733..01edc9b68d 100644
> --- a/linux-user/syscall.c
> +++ b/linux-user/syscall.c
> @@ -125,6 +125,7 @@
>  #include "qapi/error.h"
>  #include "fd-trans.h"
>  #include "tcg/tcg.h"
> +#include "syscall_proc.h"
>  
>  #ifndef CLONE_IO
>  #define CLONE_IO                0x80000000      /* Clone io context */
> @@ -7482,38 +7483,6 @@ static int open_self_auxv(void *cpu_env, int fd)
>      return 0;
>  }
>  
> -static int is_proc_myself(const char *filename, const char *entry)
> -{
> -    if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
> -        filename += strlen("/proc/");
> -        if (!strncmp(filename, "self/", strlen("self/"))) {
> -            filename += strlen("self/");
> -        } else if (*filename >= '1' && *filename <= '9') {
> -            char myself[80];
> -            snprintf(myself, sizeof(myself), "%d/", getpid());
> -            if (!strncmp(filename, myself, strlen(myself))) {
> -                filename += strlen(myself);
> -            } else {
> -                return 0;
> -            }
> -        } else {
> -            return 0;
> -        }
> -        if (!strcmp(filename, entry)) {
> -            return 1;
> -        }
> -    }
> -    return 0;
> -}
> -
> -#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN) || \
> -    defined(TARGET_SPARC) || defined(TARGET_M68K) || defined(TARGET_HPPA)
> -static int is_proc(const char *filename, const char *entry)
> -{
> -    return strcmp(filename, entry) == 0;
> -}
> -#endif
> -
>  #if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
>  static int open_net_route(void *cpu_env, int fd)
>  {
> diff --git a/linux-user/syscall_proc.c b/linux-user/syscall_proc.c
> new file mode 100644
> index 0000000000..34051a8e6b
> --- /dev/null
> +++ b/linux-user/syscall_proc.c
> @@ -0,0 +1,32 @@
> +#include "qemu/osdep.h"
> +
> +#include "syscall_proc.h"
> +
> +int is_proc_myself(const char *filename, const char *entry)
> +{
> +    if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
> +        filename += strlen("/proc/");
> +        if (!strncmp(filename, "self/", strlen("self/"))) {
> +            filename += strlen("self/");
> +        } else if (*filename >= '1' && *filename <= '9') {
> +            char myself[80];
> +            snprintf(myself, sizeof(myself), "%d/", getpid());
> +            if (!strncmp(filename, myself, strlen(myself))) {
> +                filename += strlen(myself);
> +            } else {
> +                return 0;
> +            }
> +        } else {
> +            return 0;
> +        }
> +        if (!strcmp(filename, entry)) {
> +            return 1;
> +        }
> +    }
> +    return 0;
> +}
> +
> +int is_proc(const char *filename, const char *entry)
> +{
> +    return strcmp(filename, entry) == 0;
> +}
> diff --git a/linux-user/syscall_proc.h b/linux-user/syscall_proc.h
> new file mode 100644
> index 0000000000..3098af931f
> --- /dev/null
> +++ b/linux-user/syscall_proc.h
> @@ -0,0 +1,7 @@
> +#ifndef SYSCALL_PROC_H
> +#define SYSCALL_PROC_H
> +
> +int is_proc(const char *filename, const char *entry);
> +int is_proc_myself(const char *filename, const char *entry);
> +
> +#endif
> 

Please add a "SPDX-License-Identifier: GPL-2.0-or-later" header in the
new files.

Thanks,
Laurent






^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/3] linux user: make execfd global (like exec path) and keep it open
  2020-08-18 15:23 ` [PATCH 1/3] linux user: make execfd global (like exec path) and keep it open Laurent Vivier
@ 2020-08-18 21:42   ` Андрей Аладьев
  0 siblings, 0 replies; 7+ messages in thread
From: Андрей Аладьев @ 2020-08-18 21:42 UTC (permalink / raw)
  To: Laurent Vivier; +Cc: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 5959 bytes --]

Hello. I want to explain situation we have in qemu today.
It looks simple, but gives complex problems.

Please open "linux-user/main.c":

execfd = qemu_getauxval(AT_EXECFD);
if (execfd == 0) {
  execfd = open(exec_path, O_RDONLY);
  if (execfd < 0) { ... }
}
...
close(execfd);

We may take AT_EXECFD and than close it.
After that AT_EXECFD will store closed fd.
Kernel doesn't block closing of AT_EXECFD.

Same problem exists in linux-user/syscall.c:

if (is_proc_myself(pathname, "exe")) {
  int execfd = qemu_getauxval(AT_EXECFD);
  return execfd ? execfd : safe_openat(dirfd, exec_path, flags, mode);
}

We are providing AT_EXECFD value for user and he closes it.
Than we are providing same AT_EXECFD value once again.
This fd has already been closed.

I've just re-analyzed patch and agree with you that dup/clone will be
broken.
We shouldn't provide global execfd.
So these patches are wrong.

I am going to create new patches tomorrow.
It will block closing of AT_EXECFD and remove additional AT_EXECFD usage.
I will try to add several tests for this functionality.

Thank you.

вт, 18 авг. 2020 г. в 18:23, Laurent Vivier <laurent@vivier.eu>:

> Le 18/08/2020 à 01:57, Andrew Aladjev a écrit :
> > User opens /proc/self/exe symlink, than kernel should create
> /proc/self/fd/<execfd> symlink. We should be able to detect both exe and
> fd/<execfd> symlinks to provide common behaviour. The easiest solution is
> to make execfd global and keep it open. This solution looks acceptable
> because exec_path is already global.
> >
> > Signed-off-by: Andrew Aladjev <aladjev.andrew@gmail.com>
> > ---
> >  linux-user/elfload.c |  3 ++-
> >  linux-user/exit.c    |  7 +++++--
> >  linux-user/main.c    |  2 +-
> >  linux-user/qemu.h    |  1 +
> >  linux-user/syscall.c | 18 ++++++++++++++----
> >  5 files changed, 23 insertions(+), 8 deletions(-)
> >
> > diff --git a/linux-user/elfload.c b/linux-user/elfload.c
> > index fe9dfe795d..dfaf937ab9 100644
> > --- a/linux-user/elfload.c
> > +++ b/linux-user/elfload.c
> > @@ -2363,6 +2363,7 @@ void probe_guest_base(const char *image_name,
> abi_ulong guest_loaddr,
> >
> >     IMAGE_NAME is the filename of the image, to use in error messages.
> >     IMAGE_FD is the open file descriptor for the image.
> > +   WARNING: IMAGE_FD won't be closed.
> >
> >     BPRM_BUF is a copy of the beginning of the file; this of course
> >     contains the elf file header at offset 0.  It is assumed that this
> > @@ -2632,7 +2633,6 @@ static void load_elf_image(const char *image_name,
> int image_fd,
> >
> >      mmap_unlock();
> >
> > -    close(image_fd);
> >      return;
> >
> >   exit_read:
> > @@ -2666,6 +2666,7 @@ static void load_elf_interp(const char *filename,
> struct image_info *info,
> >      }
> >
> >      load_elf_image(filename, fd, info, NULL, bprm_buf);
> > +    close(fd);
> >      return;
> >
> >   exit_perror:
> > diff --git a/linux-user/exit.c b/linux-user/exit.c
> > index 1594015444..f0626fc432 100644
> > --- a/linux-user/exit.c
> > +++ b/linux-user/exit.c
> > @@ -28,12 +28,15 @@ extern void __gcov_dump(void);
> >
> >  void preexit_cleanup(CPUArchState *env, int code)
> >  {
> > +    close(execfd);
> > +
> >  #ifdef CONFIG_GPROF
> >          _mcleanup();
> >  #endif
> >  #ifdef CONFIG_GCOV
> >          __gcov_dump();
> >  #endif
> > -        gdb_exit(env, code);
> > -        qemu_plugin_atexit_cb();
> > +
> > +    gdb_exit(env, code);
> > +    qemu_plugin_atexit_cb();
> >  }
> > diff --git a/linux-user/main.c b/linux-user/main.c
> > index 75c9785157..27644a831a 100644
> > --- a/linux-user/main.c
> > +++ b/linux-user/main.c
> > @@ -49,6 +49,7 @@
> >  #include "crypto/init.h"
> >
> >  char *exec_path;
> > +int execfd;
> >
> >  int singlestep;
> >  static const char *argv0;
> > @@ -629,7 +630,6 @@ int main(int argc, char **argv, char **envp)
> >      int target_argc;
> >      int i;
> >      int ret;
> > -    int execfd;
> >      int log_mask;
> >      unsigned long max_reserved_va;
> >
> > diff --git a/linux-user/qemu.h b/linux-user/qemu.h
> > index 5c964389c1..f99be78d42 100644
> > --- a/linux-user/qemu.h
> > +++ b/linux-user/qemu.h
> > @@ -156,6 +156,7 @@ typedef struct TaskState {
> >  } __attribute__((aligned(16))) TaskState;
> >
> >  extern char *exec_path;
> > +extern int execfd;
> >  void init_task_state(TaskState *ts);
> >  void task_settid(TaskState *);
> >  void stop_all_tasks(void);
> > diff --git a/linux-user/syscall.c b/linux-user/syscall.c
> > index 945fc25279..5741c72733 100644
> > --- a/linux-user/syscall.c
> > +++ b/linux-user/syscall.c
> > @@ -7613,8 +7613,7 @@ static int do_openat(void *cpu_env, int dirfd,
> const char *pathname, int flags,
> >      };
> >
> >      if (is_proc_myself(pathname, "exe")) {
> > -        int execfd = qemu_getauxval(AT_EXECFD);
> > -        return execfd ? execfd : safe_openat(dirfd, exec_path, flags,
> mode);
> > +        return execfd;
> >      }
> >
> >      for (fake_open = fakes; fake_open->filename; fake_open++) {
> > @@ -7872,8 +7871,19 @@ static abi_long do_syscall1(void *cpu_env, int
> num, abi_long arg1,
> >          return ret;
> >  #endif
> >      case TARGET_NR_close:
> > -        fd_trans_unregister(arg1);
> > -        return get_errno(close(arg1));
> > +        {
> > +            int fd = arg1;
> > +            if (fd == execfd) {
> > +                /*
> > +                 * We don't need to close execfd.
> > +                 * It will be closed on QEMU exit.
> > +                 */
> > +                return 0;
> > +            }
>
> Why do you prevent the user to close it?
>
> It's his own responsability if he breaks something.
>
> And for instance, doing that breaks a call to dup() if it was done on
> purpose.
>
> Except that, the patch looks good.
>
> Thanks,
> Laurent
>

[-- Attachment #2: Type: text/html, Size: 7586 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/3] linux user: moving is proc functions to separate file
  2020-08-18 15:56   ` Laurent Vivier
@ 2020-08-18 21:55     ` Андрей Аладьев
  0 siblings, 0 replies; 7+ messages in thread
From: Андрей Аладьев @ 2020-08-18 21:55 UTC (permalink / raw)
  To: Laurent Vivier; +Cc: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 5047 bytes --]

Ok, we may store these functions in syscall.c.

вт, 18 авг. 2020 г. в 18:56, Laurent Vivier <laurent@vivier.eu>:

> Le 18/08/2020 à 01:57, Andrew Aladjev a écrit :
> > Signed-off-by: Andrew Aladjev <aladjev.andrew@gmail.com>
> > ---
> >  linux-user/Makefile.objs  |  5 +++--
> >  linux-user/syscall.c      | 33 +--------------------------------
> >  linux-user/syscall_proc.c | 32 ++++++++++++++++++++++++++++++++
> >  linux-user/syscall_proc.h |  7 +++++++
> >  4 files changed, 43 insertions(+), 34 deletions(-)
> >  create mode 100644 linux-user/syscall_proc.c
> >  create mode 100644 linux-user/syscall_proc.h
> >
> > diff --git a/linux-user/Makefile.objs b/linux-user/Makefile.objs
> > index 1940910a73..20f8828b86 100644
> > --- a/linux-user/Makefile.objs
> > +++ b/linux-user/Makefile.objs
> > @@ -1,7 +1,8 @@
> >  obj-y = main.o syscall.o strace.o mmap.o signal.o \
> >       elfload.o linuxload.o uaccess.o uname.o \
> > -     safe-syscall.o $(TARGET_ABI_DIR)/signal.o \
> > -        $(TARGET_ABI_DIR)/cpu_loop.o exit.o fd-trans.o
> > +     safe-syscall.o syscall_proc.o \
> > +     $(TARGET_ABI_DIR)/cpu_loop.o $(TARGET_ABI_DIR)/signal.o \
> > +        exit.o fd-trans.o
> >
>
> I think this will collide with Paolo's meson pull request.
>
> >  obj-$(TARGET_HAS_BFLT) += flatload.o
> >  obj-$(TARGET_I386) += vm86.o
> > diff --git a/linux-user/syscall.c b/linux-user/syscall.c
> > index 5741c72733..01edc9b68d 100644
> > --- a/linux-user/syscall.c
> > +++ b/linux-user/syscall.c
> > @@ -125,6 +125,7 @@
> >  #include "qapi/error.h"
> >  #include "fd-trans.h"
> >  #include "tcg/tcg.h"
> > +#include "syscall_proc.h"
> >
> >  #ifndef CLONE_IO
> >  #define CLONE_IO                0x80000000      /* Clone io context */
> > @@ -7482,38 +7483,6 @@ static int open_self_auxv(void *cpu_env, int fd)
> >      return 0;
> >  }
> >
> > -static int is_proc_myself(const char *filename, const char *entry)
> > -{
> > -    if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
> > -        filename += strlen("/proc/");
> > -        if (!strncmp(filename, "self/", strlen("self/"))) {
> > -            filename += strlen("self/");
> > -        } else if (*filename >= '1' && *filename <= '9') {
> > -            char myself[80];
> > -            snprintf(myself, sizeof(myself), "%d/", getpid());
> > -            if (!strncmp(filename, myself, strlen(myself))) {
> > -                filename += strlen(myself);
> > -            } else {
> > -                return 0;
> > -            }
> > -        } else {
> > -            return 0;
> > -        }
> > -        if (!strcmp(filename, entry)) {
> > -            return 1;
> > -        }
> > -    }
> > -    return 0;
> > -}
> > -
> > -#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN) ||
> \
> > -    defined(TARGET_SPARC) || defined(TARGET_M68K) ||
> defined(TARGET_HPPA)
> > -static int is_proc(const char *filename, const char *entry)
> > -{
> > -    return strcmp(filename, entry) == 0;
> > -}
> > -#endif
> > -
> >  #if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
> >  static int open_net_route(void *cpu_env, int fd)
> >  {
> > diff --git a/linux-user/syscall_proc.c b/linux-user/syscall_proc.c
> > new file mode 100644
> > index 0000000000..34051a8e6b
> > --- /dev/null
> > +++ b/linux-user/syscall_proc.c
> > @@ -0,0 +1,32 @@
> > +#include "qemu/osdep.h"
> > +
> > +#include "syscall_proc.h"
> > +
> > +int is_proc_myself(const char *filename, const char *entry)
> > +{
> > +    if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
> > +        filename += strlen("/proc/");
> > +        if (!strncmp(filename, "self/", strlen("self/"))) {
> > +            filename += strlen("self/");
> > +        } else if (*filename >= '1' && *filename <= '9') {
> > +            char myself[80];
> > +            snprintf(myself, sizeof(myself), "%d/", getpid());
> > +            if (!strncmp(filename, myself, strlen(myself))) {
> > +                filename += strlen(myself);
> > +            } else {
> > +                return 0;
> > +            }
> > +        } else {
> > +            return 0;
> > +        }
> > +        if (!strcmp(filename, entry)) {
> > +            return 1;
> > +        }
> > +    }
> > +    return 0;
> > +}
> > +
> > +int is_proc(const char *filename, const char *entry)
> > +{
> > +    return strcmp(filename, entry) == 0;
> > +}
> > diff --git a/linux-user/syscall_proc.h b/linux-user/syscall_proc.h
> > new file mode 100644
> > index 0000000000..3098af931f
> > --- /dev/null
> > +++ b/linux-user/syscall_proc.h
> > @@ -0,0 +1,7 @@
> > +#ifndef SYSCALL_PROC_H
> > +#define SYSCALL_PROC_H
> > +
> > +int is_proc(const char *filename, const char *entry);
> > +int is_proc_myself(const char *filename, const char *entry);
> > +
> > +#endif
> >
>
> Please add a "SPDX-License-Identifier: GPL-2.0-or-later" header in the
> new files.
>
> Thanks,
> Laurent
>
>
>
>
>

[-- Attachment #2: Type: text/html, Size: 6603 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2020-08-18 21:59 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-08-17 23:57 [PATCH 1/3] linux user: make execfd global (like exec path) and keep it open Andrew Aladjev
2020-08-17 23:57 ` [PATCH 2/3] linux user: moving is proc functions to separate file Andrew Aladjev
2020-08-18 15:56   ` Laurent Vivier
2020-08-18 21:55     ` Андрей Аладьев
2020-08-17 23:57 ` [PATCH 3/3] linux user: refactored is proc myself, added support for fd/<execfd> Andrew Aladjev
2020-08-18 15:23 ` [PATCH 1/3] linux user: make execfd global (like exec path) and keep it open Laurent Vivier
2020-08-18 21:42   ` Андрей Аладьев

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.