diff mbox series

linux-user: Emulate CLONE_PIDFD flag in clone()

Message ID Y4XoJCpvUA1JD7Sj@p100 (mailing list archive)
State New, archived
Headers show
Series linux-user: Emulate CLONE_PIDFD flag in clone() | expand

Commit Message

Helge Deller Nov. 29, 2022, 11:08 a.m. UTC
Add emulation for the CLONE_PIDFD flag of the clone() syscall.
This flag was added in Linux kernel 5.2.

Successfully tested on a x86-64 Linux host with hppa-linux target.
Can be verified by running the testsuite of the qcoro debian package,
which breaks hard and kills the currently logged-in user without this
patch.

Signed-off-by: Helge Deller <deller@gmx.de>

Comments

Laurent Vivier March 7, 2023, 4:27 p.m. UTC | #1
Le 29/11/2022 à 12:08, Helge Deller a écrit :
> Add emulation for the CLONE_PIDFD flag of the clone() syscall.
> This flag was added in Linux kernel 5.2.
> 
> Successfully tested on a x86-64 Linux host with hppa-linux target.
> Can be verified by running the testsuite of the qcoro debian package,
> which breaks hard and kills the currently logged-in user without this
> patch.
> 
> Signed-off-by: Helge Deller <deller@gmx.de>
> 
> diff --git a/linux-user/strace.c b/linux-user/strace.c
> index 9ae5a812cd..8fa5c1ec3d 100644
> --- a/linux-user/strace.c
> +++ b/linux-user/strace.c
> @@ -1097,6 +1097,7 @@ UNUSED static struct flags clone_flags[] = {
>       FLAG_GENERIC(CLONE_FS),
>       FLAG_GENERIC(CLONE_FILES),
>       FLAG_GENERIC(CLONE_SIGHAND),
> +    FLAG_GENERIC(CLONE_PIDFD),
>       FLAG_GENERIC(CLONE_PTRACE),
>       FLAG_GENERIC(CLONE_VFORK),
>       FLAG_GENERIC(CLONE_PARENT),
> diff --git a/linux-user/syscall.c b/linux-user/syscall.c
> index 24b25759be..0468a1bad7 100644
> --- a/linux-user/syscall.c
> +++ b/linux-user/syscall.c
> @@ -213,7 +213,7 @@ struct file_clone_range {
> 
>   /* Flags for fork which we can implement within QEMU itself */
>   #define CLONE_OPTIONAL_FORK_FLAGS               \
> -    (CLONE_SETTLS | CLONE_PARENT_SETTID |       \
> +    (CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_PIDFD | \
>        CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID)
> 
>   /* Flags for thread creation which we can implement within QEMU itself */
> @@ -6747,6 +6747,17 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
>               return -TARGET_EINVAL;
>           }
> 
> +#if !defined(__NR_pidfd_open) || !defined(TARGET_NR_pidfd_open)
> +        if (flags & CLONE_PIDFD) {
> +            return -TARGET_EINVAL;
> +        }
> +#endif
> +
> +        /* Can not allow CLONE_PIDFD with CLONE_PARENT_SETTID */
> +        if ((flags & CLONE_PIDFD) && (flags & CLONE_PARENT_SETTID)) {
> +            return -TARGET_EINVAL;
> +        }
> +
>           if (block_signals()) {
>               return -QEMU_ERESTARTSYS;
>           }
> @@ -6774,6 +6785,20 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
>                   ts->child_tidptr = child_tidptr;
>           } else {
>               cpu_clone_regs_parent(env, flags);
> +            if (flags & CLONE_PIDFD) {
> +                int pid_fd = 0;
> +#if defined(__NR_pidfd_open) && defined(TARGET_NR_pidfd_open)
> +                int pid_child = ret;
> +                pid_fd = pidfd_open(pid_child, 0);
> +                if (pid_fd >= 0) {
> +                        fcntl(pid_fd, F_SETFD, fcntl(pid_fd, F_GETFL)
> +                                               | FD_CLOEXEC);
> +                } else {
> +                        pid_fd = 0;
> +                }
> +#endif
> +                put_user_u32(pid_fd, parent_tidptr);
> +                }
>               fork_end(0);
>           }
>       }
> 

Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Laurent Vivier March 7, 2023, 4:32 p.m. UTC | #2
Le 29/11/2022 à 12:08, Helge Deller a écrit :
> Add emulation for the CLONE_PIDFD flag of the clone() syscall.
> This flag was added in Linux kernel 5.2.
> 
> Successfully tested on a x86-64 Linux host with hppa-linux target.
> Can be verified by running the testsuite of the qcoro debian package,
> which breaks hard and kills the currently logged-in user without this
> patch.
> 
> Signed-off-by: Helge Deller <deller@gmx.de>
> 
> diff --git a/linux-user/strace.c b/linux-user/strace.c
> index 9ae5a812cd..8fa5c1ec3d 100644
> --- a/linux-user/strace.c
> +++ b/linux-user/strace.c
> @@ -1097,6 +1097,7 @@ UNUSED static struct flags clone_flags[] = {
>       FLAG_GENERIC(CLONE_FS),
>       FLAG_GENERIC(CLONE_FILES),
>       FLAG_GENERIC(CLONE_SIGHAND),
> +    FLAG_GENERIC(CLONE_PIDFD),
>       FLAG_GENERIC(CLONE_PTRACE),
>       FLAG_GENERIC(CLONE_VFORK),
>       FLAG_GENERIC(CLONE_PARENT),
> diff --git a/linux-user/syscall.c b/linux-user/syscall.c
> index 24b25759be..0468a1bad7 100644
> --- a/linux-user/syscall.c
> +++ b/linux-user/syscall.c
> @@ -213,7 +213,7 @@ struct file_clone_range {
> 
>   /* Flags for fork which we can implement within QEMU itself */
>   #define CLONE_OPTIONAL_FORK_FLAGS               \
> -    (CLONE_SETTLS | CLONE_PARENT_SETTID |       \
> +    (CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_PIDFD | \
>        CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID)
> 
>   /* Flags for thread creation which we can implement within QEMU itself */
> @@ -6747,6 +6747,17 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
>               return -TARGET_EINVAL;
>           }
> 
> +#if !defined(__NR_pidfd_open) || !defined(TARGET_NR_pidfd_open)
> +        if (flags & CLONE_PIDFD) {
> +            return -TARGET_EINVAL;
> +        }
> +#endif
> +
> +        /* Can not allow CLONE_PIDFD with CLONE_PARENT_SETTID */
> +        if ((flags & CLONE_PIDFD) && (flags & CLONE_PARENT_SETTID)) {
> +            return -TARGET_EINVAL;
> +        }
> +
>           if (block_signals()) {
>               return -QEMU_ERESTARTSYS;
>           }
> @@ -6774,6 +6785,20 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
>                   ts->child_tidptr = child_tidptr;
>           } else {
>               cpu_clone_regs_parent(env, flags);
> +            if (flags & CLONE_PIDFD) {
> +                int pid_fd = 0;
> +#if defined(__NR_pidfd_open) && defined(TARGET_NR_pidfd_open)
> +                int pid_child = ret;
> +                pid_fd = pidfd_open(pid_child, 0);
> +                if (pid_fd >= 0) {
> +                        fcntl(pid_fd, F_SETFD, fcntl(pid_fd, F_GETFL)
> +                                               | FD_CLOEXEC);
> +                } else {
> +                        pid_fd = 0;
> +                }
> +#endif
> +                put_user_u32(pid_fd, parent_tidptr);
> +                }
>               fork_end(0);
>           }
>       }
> 

Applied to my linux-user-for-8.0 branch.

Thanks,
Laurent
diff mbox series

Patch

diff --git a/linux-user/strace.c b/linux-user/strace.c
index 9ae5a812cd..8fa5c1ec3d 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -1097,6 +1097,7 @@  UNUSED static struct flags clone_flags[] = {
     FLAG_GENERIC(CLONE_FS),
     FLAG_GENERIC(CLONE_FILES),
     FLAG_GENERIC(CLONE_SIGHAND),
+    FLAG_GENERIC(CLONE_PIDFD),
     FLAG_GENERIC(CLONE_PTRACE),
     FLAG_GENERIC(CLONE_VFORK),
     FLAG_GENERIC(CLONE_PARENT),
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 24b25759be..0468a1bad7 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -213,7 +213,7 @@  struct file_clone_range {

 /* Flags for fork which we can implement within QEMU itself */
 #define CLONE_OPTIONAL_FORK_FLAGS               \
-    (CLONE_SETTLS | CLONE_PARENT_SETTID |       \
+    (CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_PIDFD | \
      CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID)

 /* Flags for thread creation which we can implement within QEMU itself */
@@ -6747,6 +6747,17 @@  static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
             return -TARGET_EINVAL;
         }

+#if !defined(__NR_pidfd_open) || !defined(TARGET_NR_pidfd_open)
+        if (flags & CLONE_PIDFD) {
+            return -TARGET_EINVAL;
+        }
+#endif
+
+        /* Can not allow CLONE_PIDFD with CLONE_PARENT_SETTID */
+        if ((flags & CLONE_PIDFD) && (flags & CLONE_PARENT_SETTID)) {
+            return -TARGET_EINVAL;
+        }
+
         if (block_signals()) {
             return -QEMU_ERESTARTSYS;
         }
@@ -6774,6 +6785,20 @@  static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
                 ts->child_tidptr = child_tidptr;
         } else {
             cpu_clone_regs_parent(env, flags);
+            if (flags & CLONE_PIDFD) {
+                int pid_fd = 0;
+#if defined(__NR_pidfd_open) && defined(TARGET_NR_pidfd_open)
+                int pid_child = ret;
+                pid_fd = pidfd_open(pid_child, 0);
+                if (pid_fd >= 0) {
+                        fcntl(pid_fd, F_SETFD, fcntl(pid_fd, F_GETFL)
+                                               | FD_CLOEXEC);
+                } else {
+                        pid_fd = 0;
+                }
+#endif
+                put_user_u32(pid_fd, parent_tidptr);
+                }
             fork_end(0);
         }
     }