From 895ce8bb534e66ca418dea62ae67a92dccafb2e1 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Tue, 29 Nov 2022 12:08:20 +0100 Subject: [PATCH] linux-user: Emulate CLONE_PIDFD flag in clone() 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 Reviewed-by: Laurent Vivier Message-Id: [lv: define CLONE_PIDFD if it is not] Signed-off-by: Laurent Vivier --- linux-user/strace.c | 5 +++++ linux-user/syscall.c | 31 ++++++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/linux-user/strace.c b/linux-user/strace.c index e08bd53afb..aad2b62ca4 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -1111,11 +1111,16 @@ UNUSED static const struct flags mmap_flags[] = { FLAG_END, }; +#ifndef CLONE_PIDFD +# define CLONE_PIDFD 0x00001000 +#endif + UNUSED static const struct flags clone_flags[] = { FLAG_GENERIC(CLONE_VM), 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 dad2c33120..24cea6fb6a 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -169,9 +169,13 @@ #define CLONE_IGNORED_FLAGS \ (CLONE_DETACHED | CLONE_IO) +#ifndef CLONE_PIDFD +# define CLONE_PIDFD 0x00001000 +#endif + /* 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 */ @@ -6730,6 +6734,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; } @@ -6757,6 +6772,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); } g_assert(!cpu_in_exclusive_context(cpu));