History

Merge tag 'threads-v5.6' of git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux

Pull thread management updates from Christian Brauner: "Sargun Dhillon over the last cycle has worked on the pidfd_getfd() syscall. This syscall allows for the retrieval of file descriptors of a process based on its pidfd. A task needs to have ptrace_may_access() permissions with PTRACE_MODE_ATTACH_REALCREDS (suggested by Oleg and Andy) on the target. One of the main use-cases is in combination with seccomp's user notification feature. As a reminder, seccomp's user notification feature was made available in v5.0. It allows a task to retrieve a file descriptor for its seccomp filter. The file descriptor is usually handed of to a more privileged supervising process. The supervisor can then listen for syscall events caught by the seccomp filter of the supervisee and perform actions in lieu of the supervisee, usually emulating syscalls. pidfd_getfd() is needed to expand its uses. There are currently two major users that wait on pidfd_getfd() and one future user: - Netflix, Sargun said, is working on a service mesh where users should be able to connect to a dns-based VIP. When a user connects to e.g. 1.2.3.4:80 that runs e.g. service "foo" they will be redirected to an envoy process. This service mesh uses seccomp user notifications and pidfd to intercept all connect calls and instead of connecting them to 1.2.3.4:80 connects them to e.g. 127.0.0.1:8080. - LXD uses the seccomp notifier heavily to intercept and emulate mknod() and mount() syscalls for unprivileged containers/processes. With pidfd_getfd() more uses-cases e.g. bridging socket connections will be possible. - The patchset has also seen some interest from the browser corner. Right now, Firefox is using a SECCOMP_RET_TRAP sandbox managed by a broker process. In the future glibc will start blocking all signals during dlopen() rendering this type of sandbox impossible. Hence, in the future Firefox will switch to a seccomp-user-nofication based sandbox which also makes use of file descriptor retrieval. The thread for this can be found at https://sourceware.org/ml/libc-alpha/2019-12/msg00079.html With pidfd_getfd() it is e.g. possible to bridge socket connections for the supervisee (binding to a privileged port) and taking actions on file descriptors on behalf of the supervisee in general. Sargun's first version was using an ioctl on pidfds but various people pushed for it to be a proper syscall which he duely implemented as well over various review cycles. Selftests are of course included. I've also added instructions how to deal with merge conflicts below. There's also a small fix coming from the kernel mentee project to correctly annotate struct sighand_struct with __rcu to fix various sparse warnings. We've received a few more such fixes and even though they are mostly trivial I've decided to postpone them until after -rc1 since they came in rather late and I don't want to risk introducing build warnings. Finally, there's a new prctl() command PR_{G,S}ET_IO_FLUSHER which is needed to avoid allocation recursions triggerable by storage drivers that have userspace parts that run in the IO path (e.g. dm-multipath, iscsi, etc). These allocation recursions deadlock the device. The new prctl() allows such privileged userspace components to avoid allocation recursions by setting the PF_MEMALLOC_NOIO and PF_LESS_THROTTLE flags. The patch carries the necessary acks from the relevant maintainers and is routed here as part of prctl() thread-management." * tag 'threads-v5.6' of git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux: prctl: PR_{G,S}ET_IO_FLUSHER to support controlling memory reclaim sched.h: Annotate sighand_struct with __rcu test: Add test for pidfd getfd arch: wire up pidfd_getfd syscall pid: Implement pidfd_getfd syscall vfs, fdtable: Add fget_task helper

Linus Torvalds committed 6 years ago

Commit 83fa8052 parents 896f8d2 8d19f1c32 files · +427 −7Browse files

Unified · Split

32 files
  1. arch/alpha/kernel/syscalls/syscall.tbl +1 −0
  2. arch/arm/tools/syscall.tbl +1 −0
  3. arch/arm64/include/asm/unistd.h +1 −1
  4. arch/arm64/include/asm/unistd32.h +2 −0
  5. arch/ia64/kernel/syscalls/syscall.tbl +1 −0
  6. arch/m68k/kernel/syscalls/syscall.tbl +1 −0
  7. arch/microblaze/kernel/syscalls/syscall.tbl +1 −0
  8. arch/mips/kernel/syscalls/syscall_n32.tbl +1 −0
  9. arch/mips/kernel/syscalls/syscall_n64.tbl +1 −0
  10. arch/mips/kernel/syscalls/syscall_o32.tbl +1 −0
  11. arch/parisc/kernel/syscalls/syscall.tbl +1 −0
  12. arch/powerpc/kernel/syscalls/syscall.tbl +1 −0
  13. arch/s390/kernel/syscalls/syscall.tbl +1 −0
  14. arch/sh/kernel/syscalls/syscall.tbl +1 −0
  15. arch/sparc/kernel/syscalls/syscall.tbl +1 −0
  16. arch/x86/entry/syscalls/syscall_32.tbl +1 −0
  17. arch/x86/entry/syscalls/syscall_64.tbl +1 −0
  18. arch/xtensa/kernel/syscalls/syscall.tbl +1 −0
  19. fs/file.c +20 −2
  20. include/linux/file.h +2 −0
  21. include/linux/sched.h +1 −1
  22. include/linux/syscalls.h +1 −0
  23. include/uapi/asm-generic/unistd.h +3 −1
  24. include/uapi/linux/capability.h +1 −0
  25. include/uapi/linux/prctl.h +4 −0
  26. kernel/pid.c +90 −0
  27. kernel/signal.c +1 −1
  28. kernel/sys.c +25 −0
  29. tools/testing/selftests/pidfd/.gitignore +1 −0
  30. tools/testing/selftests/pidfd/Makefile +1 −1
  31. tools/testing/selftests/pidfd/pidfd.h +9 −0
  32. tools/testing/selftests/pidfd/pidfd_getfd_test.c +249 −0
arch/alpha/kernel/syscalls/syscall.tbl+1−0
@@ -476,3 +476,4 @@ · 475 unmodified lines
476544 common pidfd_open sys_pidfd_open476544 common pidfd_open sys_pidfd_open
477# 545 reserved for clone3477# 545 reserved for clone3
478547 common openat2 sys_openat2478547 common openat2 sys_openat2
479548 common pidfd_getfd sys_pidfd_getfd
arch/arm/tools/syscall.tbl+1−0
@@ -450,3 +450,4 @@ · 449 unmodified lines
450434 common pidfd_open sys_pidfd_open450434 common pidfd_open sys_pidfd_open
451435 common clone3 sys_clone3451435 common clone3 sys_clone3
452437 common openat2 sys_openat2452437 common openat2 sys_openat2
453438 common pidfd_getfd sys_pidfd_getfd
arch/arm64/include/asm/unistd.h+1−1
@@ -38,7 +38,7 @@ · 37 unmodified lines
38#define __ARM_NR_compat_set_tls (__ARM_NR_COMPAT_BASE + 5)38#define __ARM_NR_compat_set_tls (__ARM_NR_COMPAT_BASE + 5)
39#define __ARM_NR_COMPAT_END (__ARM_NR_COMPAT_BASE + 0x800)39#define __ARM_NR_COMPAT_END (__ARM_NR_COMPAT_BASE + 0x800)
40 40
41#define __NR_compat_syscalls 43841#define __NR_compat_syscalls 439
42#endif42#endif
43 43
44#define __ARCH_WANT_SYS_CLONE44#define __ARCH_WANT_SYS_CLONE
arch/arm64/include/asm/unistd32.h+2−0
@@ -881,6 +881,8 @@ __SYSCALL(__NR_pidfd_open, sys_pidfd_open) · 880 unmodified lines
881__SYSCALL(__NR_clone3, sys_clone3)881__SYSCALL(__NR_clone3, sys_clone3)
882#define __NR_openat2 437882#define __NR_openat2 437
883__SYSCALL(__NR_openat2, sys_openat2)883__SYSCALL(__NR_openat2, sys_openat2)
884#define __NR_pidfd_getfd 438
885__SYSCALL(__NR_pidfd_getfd, sys_pidfd_getfd)
884 886
885/*887/*
886 * Please add new compat syscalls above this comment and update888 * Please add new compat syscalls above this comment and update
arch/ia64/kernel/syscalls/syscall.tbl+1−0
@@ -357,3 +357,4 @@ · 356 unmodified lines
357434 common pidfd_open sys_pidfd_open357434 common pidfd_open sys_pidfd_open
358# 435 reserved for clone3358# 435 reserved for clone3
359437 common openat2 sys_openat2359437 common openat2 sys_openat2
360438 common pidfd_getfd sys_pidfd_getfd
arch/m68k/kernel/syscalls/syscall.tbl+1−0
@@ -436,3 +436,4 @@ · 435 unmodified lines
436434 common pidfd_open sys_pidfd_open436434 common pidfd_open sys_pidfd_open
437435 common clone3 __sys_clone3437435 common clone3 __sys_clone3
438437 common openat2 sys_openat2438437 common openat2 sys_openat2
439438 common pidfd_getfd sys_pidfd_getfd
arch/microblaze/kernel/syscalls/syscall.tbl+1−0
@@ -442,3 +442,4 @@ · 441 unmodified lines
442434 common pidfd_open sys_pidfd_open442434 common pidfd_open sys_pidfd_open
443435 common clone3 sys_clone3443435 common clone3 sys_clone3
444437 common openat2 sys_openat2444437 common openat2 sys_openat2
445438 common pidfd_getfd sys_pidfd_getfd
arch/mips/kernel/syscalls/syscall_n32.tbl+1−0
@@ -375,3 +375,4 @@ · 374 unmodified lines
375434 n32 pidfd_open sys_pidfd_open375434 n32 pidfd_open sys_pidfd_open
376435 n32 clone3 __sys_clone3376435 n32 clone3 __sys_clone3
377437 n32 openat2 sys_openat2377437 n32 openat2 sys_openat2
378438 n32 pidfd_getfd sys_pidfd_getfd
arch/mips/kernel/syscalls/syscall_n64.tbl+1−0
@@ -351,3 +351,4 @@ · 350 unmodified lines
351434 n64 pidfd_open sys_pidfd_open351434 n64 pidfd_open sys_pidfd_open
352435 n64 clone3 __sys_clone3352435 n64 clone3 __sys_clone3
353437 n64 openat2 sys_openat2353437 n64 openat2 sys_openat2
354438 n64 pidfd_getfd sys_pidfd_getfd
arch/mips/kernel/syscalls/syscall_o32.tbl+1−0
@@ -424,3 +424,4 @@ · 423 unmodified lines
424434 o32 pidfd_open sys_pidfd_open424434 o32 pidfd_open sys_pidfd_open
425435 o32 clone3 __sys_clone3425435 o32 clone3 __sys_clone3
426437 o32 openat2 sys_openat2426437 o32 openat2 sys_openat2
427438 o32 pidfd_getfd sys_pidfd_getfd
arch/parisc/kernel/syscalls/syscall.tbl+1−0
@@ -434,3 +434,4 @@ · 433 unmodified lines
434434 common pidfd_open sys_pidfd_open434434 common pidfd_open sys_pidfd_open
435435 common clone3 sys_clone3_wrapper435435 common clone3 sys_clone3_wrapper
436437 common openat2 sys_openat2436437 common openat2 sys_openat2
437438 common pidfd_getfd sys_pidfd_getfd
arch/powerpc/kernel/syscalls/syscall.tbl+1−0
@@ -518,3 +518,4 @@ · 517 unmodified lines
518434 common pidfd_open sys_pidfd_open518434 common pidfd_open sys_pidfd_open
519435 nospu clone3 ppc_clone3519435 nospu clone3 ppc_clone3
520437 common openat2 sys_openat2520437 common openat2 sys_openat2
521438 common pidfd_getfd sys_pidfd_getfd
arch/s390/kernel/syscalls/syscall.tbl+1−0
@@ -439,3 +439,4 @@ · 438 unmodified lines
439434 common pidfd_open sys_pidfd_open sys_pidfd_open439434 common pidfd_open sys_pidfd_open sys_pidfd_open
440435 common clone3 sys_clone3 sys_clone3440435 common clone3 sys_clone3 sys_clone3
441437 common openat2 sys_openat2 sys_openat2441437 common openat2 sys_openat2 sys_openat2
442438 common pidfd_getfd sys_pidfd_getfd sys_pidfd_getfd
arch/sh/kernel/syscalls/syscall.tbl+1−0
@@ -439,3 +439,4 @@ · 438 unmodified lines
439434 common pidfd_open sys_pidfd_open439434 common pidfd_open sys_pidfd_open
440# 435 reserved for clone3440# 435 reserved for clone3
441437 common openat2 sys_openat2441437 common openat2 sys_openat2
442438 common pidfd_getfd sys_pidfd_getfd
arch/sparc/kernel/syscalls/syscall.tbl+1−0
@@ -482,3 +482,4 @@ · 481 unmodified lines
482434 common pidfd_open sys_pidfd_open482434 common pidfd_open sys_pidfd_open
483# 435 reserved for clone3483# 435 reserved for clone3
484437 common openat2 sys_openat2484437 common openat2 sys_openat2
485438 common pidfd_getfd sys_pidfd_getfd
arch/x86/entry/syscalls/syscall_32.tbl+1−0
@@ -441,3 +441,4 @@ · 440 unmodified lines
441434 i386 pidfd_open sys_pidfd_open __ia32_sys_pidfd_open441434 i386 pidfd_open sys_pidfd_open __ia32_sys_pidfd_open
442435 i386 clone3 sys_clone3 __ia32_sys_clone3442435 i386 clone3 sys_clone3 __ia32_sys_clone3
443437 i386 openat2 sys_openat2 __ia32_sys_openat2443437 i386 openat2 sys_openat2 __ia32_sys_openat2
444438 i386 pidfd_getfd sys_pidfd_getfd __ia32_sys_pidfd_getfd
arch/x86/entry/syscalls/syscall_64.tbl+1−0
@@ -358,6 +358,7 @@ · 357 unmodified lines
358434 common pidfd_open __x64_sys_pidfd_open358434 common pidfd_open __x64_sys_pidfd_open
359435 common clone3 __x64_sys_clone3/ptregs359435 common clone3 __x64_sys_clone3/ptregs
360437 common openat2 __x64_sys_openat2360437 common openat2 __x64_sys_openat2
361438 common pidfd_getfd __x64_sys_pidfd_getfd
361 362
362#363#
363# x32-specific system call numbers start at 512 to avoid cache impact364# x32-specific system call numbers start at 512 to avoid cache impact
arch/xtensa/kernel/syscalls/syscall.tbl+1−0
@@ -407,3 +407,4 @@ · 406 unmodified lines
407434 common pidfd_open sys_pidfd_open407434 common pidfd_open sys_pidfd_open
408435 common clone3 sys_clone3408435 common clone3 sys_clone3
409437 common openat2 sys_openat2409437 common openat2 sys_openat2
410438 common pidfd_getfd sys_pidfd_getfd
fs/file.c+20−2
@@ -708,9 +708,9 @@ void do_close_on_exec(struct files_struct *files) · 707 unmodified lines
708 spin_unlock(&files->file_lock);708 spin_unlock(&files->file_lock);
709}709}
710 710
711static struct file *__fget(unsigned int fd, fmode_t mask, unsigned int refs)711static struct file *__fget_files(struct files_struct *files, unsigned int fd,
712 fmode_t mask, unsigned int refs)
712{713{
713 struct files_struct *files = current->files;
714 struct file *file;714 struct file *file;
715 715
716 rcu_read_lock();716 rcu_read_lock();
@@ -731,6 +731,12 @@ loop: · 14 unmodified lines
731 return file;731 return file;
732}732}
733 733
734static inline struct file *__fget(unsigned int fd, fmode_t mask,
735 unsigned int refs)
736{
737 return __fget_files(current->files, fd, mask, refs);
738}
739
734struct file *fget_many(unsigned int fd, unsigned int refs)740struct file *fget_many(unsigned int fd, unsigned int refs)
735{741{
736 return __fget(fd, FMODE_PATH, refs);742 return __fget(fd, FMODE_PATH, refs);
@@ -748,6 +754,18 @@ struct file *fget_raw(unsigned int fd) · 11 unmodified lines
748}754}
749EXPORT_SYMBOL(fget_raw);755EXPORT_SYMBOL(fget_raw);
750 756
757struct file *fget_task(struct task_struct *task, unsigned int fd)
758{
759 struct file *file = NULL;
760
761 task_lock(task);
762 if (task->files)
763 file = __fget_files(task->files, fd, 0, 1);
764 task_unlock(task);
765
766 return file;
767}
768
751/*769/*
752 * Lightweight file lookup - no refcnt increment if fd table isn't shared.770 * Lightweight file lookup - no refcnt increment if fd table isn't shared.
753 *771 *
include/linux/file.h+2−0
@@ -16,6 +16,7 @@ extern void fput(struct file *); · 15 unmodified lines
16extern void fput_many(struct file *, unsigned int);16extern void fput_many(struct file *, unsigned int);
17 17
18struct file_operations;18struct file_operations;
19struct task_struct;
19struct vfsmount;20struct vfsmount;
20struct dentry;21struct dentry;
21struct inode;22struct inode;
@@ -47,6 +48,7 @@ static inline void fdput(struct fd fd) · 25 unmodified lines
47extern struct file *fget(unsigned int fd);48extern struct file *fget(unsigned int fd);
48extern struct file *fget_many(unsigned int fd, unsigned int refs);49extern struct file *fget_many(unsigned int fd, unsigned int refs);
49extern struct file *fget_raw(unsigned int fd);50extern struct file *fget_raw(unsigned int fd);
51extern struct file *fget_task(struct task_struct *task, unsigned int fd);
50extern unsigned long __fdget(unsigned int fd);52extern unsigned long __fdget(unsigned int fd);
51extern unsigned long __fdget_raw(unsigned int fd);53extern unsigned long __fdget_raw(unsigned int fd);
52extern unsigned long __fdget_pos(unsigned int fd);54extern unsigned long __fdget_pos(unsigned int fd);
include/linux/sched.h+1−1
@@ -917,7 +917,7 @@ struct task_struct { · 916 unmodified lines
917 917
918 /* Signal handlers: */918 /* Signal handlers: */
919 struct signal_struct *signal;919 struct signal_struct *signal;
920 struct sighand_struct *sighand;920 struct sighand_struct __rcu *sighand;
921 sigset_t blocked;921 sigset_t blocked;
922 sigset_t real_blocked;922 sigset_t real_blocked;
923 /* Restored if set_restore_sigmask() was used: */923 /* Restored if set_restore_sigmask() was used: */
include/linux/syscalls.h+1−0
@@ -1002,6 +1002,7 @@ asmlinkage long sys_fspick(int dfd, const char __user *path, unsigned int flags) · 1001 unmodified lines
1002asmlinkage long sys_pidfd_send_signal(int pidfd, int sig,1002asmlinkage long sys_pidfd_send_signal(int pidfd, int sig,
1003 siginfo_t __user *info,1003 siginfo_t __user *info,
1004 unsigned int flags);1004 unsigned int flags);
1005asmlinkage long sys_pidfd_getfd(int pidfd, int fd, unsigned int flags);
1005 1006
1006/*1007/*
1007 * Architecture-specific system calls1008 * Architecture-specific system calls
include/uapi/asm-generic/unistd.h+3−1
@@ -853,9 +853,11 @@ __SYSCALL(__NR_clone3, sys_clone3) · 852 unmodified lines
853 853
854#define __NR_openat2 437854#define __NR_openat2 437
855__SYSCALL(__NR_openat2, sys_openat2)855__SYSCALL(__NR_openat2, sys_openat2)
856#define __NR_pidfd_getfd 438
857__SYSCALL(__NR_pidfd_getfd, sys_pidfd_getfd)
856 858
857#undef __NR_syscalls859#undef __NR_syscalls
858#define __NR_syscalls 438860#define __NR_syscalls 439
859 861
860/*862/*
861 * 32 bit systems traditionally used different863 * 32 bit systems traditionally used different
include/uapi/linux/capability.h+1−0
@@ -301,6 +301,7 @@ struct vfs_ns_cap_data { · 300 unmodified lines
301/* Allow more than 64hz interrupts from the real-time clock */301/* Allow more than 64hz interrupts from the real-time clock */
302/* Override max number of consoles on console allocation */302/* Override max number of consoles on console allocation */
303/* Override max number of keymaps */303/* Override max number of keymaps */
304/* Control memory reclaim behavior */
304 305
305#define CAP_SYS_RESOURCE 24306#define CAP_SYS_RESOURCE 24
306 307
include/uapi/linux/prctl.h+4−0
@@ -234,4 +234,8 @@ struct prctl_mm_map { · 233 unmodified lines
234#define PR_GET_TAGGED_ADDR_CTRL 56234#define PR_GET_TAGGED_ADDR_CTRL 56
235# define PR_TAGGED_ADDR_ENABLE (1UL << 0)235# define PR_TAGGED_ADDR_ENABLE (1UL << 0)
236 236
237/* Control reclaim behavior when allocating memory */
238#define PR_SET_IO_FLUSHER 57
239#define PR_GET_IO_FLUSHER 58
240
237#endif /* _LINUX_PRCTL_H */241#endif /* _LINUX_PRCTL_H */
kernel/pid.c+90−0
@@ -578,3 +578,93 @@ void __init pid_idr_init(void) · 577 unmodified lines
578 init_pid_ns.pid_cachep = KMEM_CACHE(pid,578 init_pid_ns.pid_cachep = KMEM_CACHE(pid,
579 SLAB_HWCACHE_ALIGN | SLAB_PANIC | SLAB_ACCOUNT);579 SLAB_HWCACHE_ALIGN | SLAB_PANIC | SLAB_ACCOUNT);
580}580}
581
582static struct file *__pidfd_fget(struct task_struct *task, int fd)
583{
584 struct file *file;
585 int ret;
586
587 ret = mutex_lock_killable(&task->signal->cred_guard_mutex);
588 if (ret)
589 return ERR_PTR(ret);
590
591 if (ptrace_may_access(task, PTRACE_MODE_ATTACH_REALCREDS))
592 file = fget_task(task, fd);
593 else
594 file = ERR_PTR(-EPERM);
595
596 mutex_unlock(&task->signal->cred_guard_mutex);
597
598 return file ?: ERR_PTR(-EBADF);
599}
600
601static int pidfd_getfd(struct pid *pid, int fd)
602{
603 struct task_struct *task;
604 struct file *file;
605 int ret;
606
607 task = get_pid_task(pid, PIDTYPE_PID);
608 if (!task)
609 return -ESRCH;
610
611 file = __pidfd_fget(task, fd);
612 put_task_struct(task);
613 if (IS_ERR(file))
614 return PTR_ERR(file);
615
616 ret = security_file_receive(file);
617 if (ret) {
618 fput(file);
619 return ret;
620 }
621
622 ret = get_unused_fd_flags(O_CLOEXEC);
623 if (ret < 0)
624 fput(file);
625 else
626 fd_install(ret, file);
627
628 return ret;
629}
630
631/**
632 * sys_pidfd_getfd() - Get a file descriptor from another process
633 *
634 * @pidfd: the pidfd file descriptor of the process
635 * @fd: the file descriptor number to get
636 * @flags: flags on how to get the fd (reserved)
637 *
638 * This syscall gets a copy of a file descriptor from another process
639 * based on the pidfd, and file descriptor number. It requires that
640 * the calling process has the ability to ptrace the process represented
641 * by the pidfd. The process which is having its file descriptor copied
642 * is otherwise unaffected.
643 *
644 * Return: On success, a cloexec file descriptor is returned.
645 * On error, a negative errno number will be returned.
646 */
647SYSCALL_DEFINE3(pidfd_getfd, int, pidfd, int, fd,
648 unsigned int, flags)
649{
650 struct pid *pid;
651 struct fd f;
652 int ret;
653
654 /* flags is currently unused - make sure it's unset */
655 if (flags)
656 return -EINVAL;
657
658 f = fdget(pidfd);
659 if (!f.file)
660 return -EBADF;
661
662 pid = pidfd_pid(f.file);
663 if (IS_ERR(pid))
664 ret = PTR_ERR(pid);
665 else
666 ret = pidfd_getfd(pid, fd);
667
668 fdput(f);
669 return ret;
670}
kernel/signal.c+1−1
@@ -1383,7 +1383,7 @@ struct sighand_struct *__lock_task_sighand(struct task_struct *tsk, · 1382 unmodified lines
1383 * must see ->sighand == NULL.1383 * must see ->sighand == NULL.
1384 */1384 */
1385 spin_lock_irqsave(&sighand->siglock, *flags);1385 spin_lock_irqsave(&sighand->siglock, *flags);
1386 if (likely(sighand == tsk->sighand))1386 if (likely(sighand == rcu_access_pointer(tsk->sighand)))
1387 break;1387 break;
1388 spin_unlock_irqrestore(&sighand->siglock, *flags);1388 spin_unlock_irqrestore(&sighand->siglock, *flags);
1389 }1389 }
kernel/sys.c+25−0
@@ -2261,6 +2261,8 @@ int __weak arch_prctl_spec_ctrl_set(struct task_struct *t, unsigned long which, · 2260 unmodified lines
2261 return -EINVAL;2261 return -EINVAL;
2262}2262}
2263 2263
2264#define PR_IO_FLUSHER (PF_MEMALLOC_NOIO | PF_LESS_THROTTLE)
2265
2264SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,2266SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
2265 unsigned long, arg4, unsigned long, arg5)2267 unsigned long, arg4, unsigned long, arg5)
2266{2268{
@@ -2488,6 +2490,29 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, · 221 unmodified lines
2488 return -EINVAL;2490 return -EINVAL;
2489 error = GET_TAGGED_ADDR_CTRL();2491 error = GET_TAGGED_ADDR_CTRL();
2490 break;2492 break;
2493 case PR_SET_IO_FLUSHER:
2494 if (!capable(CAP_SYS_RESOURCE))
2495 return -EPERM;
2496
2497 if (arg3 || arg4 || arg5)
2498 return -EINVAL;
2499
2500 if (arg2 == 1)
2501 current->flags |= PR_IO_FLUSHER;
2502 else if (!arg2)
2503 current->flags &= ~PR_IO_FLUSHER;
2504 else
2505 return -EINVAL;
2506 break;
2507 case PR_GET_IO_FLUSHER:
2508 if (!capable(CAP_SYS_RESOURCE))
2509 return -EPERM;
2510
2511 if (arg2 || arg3 || arg4 || arg5)
2512 return -EINVAL;
2513
2514 error = (current->flags & PR_IO_FLUSHER) == PR_IO_FLUSHER;
2515 break;
2491 default:2516 default:
2492 error = -EINVAL;2517 error = -EINVAL;
2493 break;2518 break;
tools/testing/selftests/pidfd/.gitignore+1−0
@@ -2,3 +2,4 @@ pidfd_open_test · 1 unmodified line
2pidfd_poll_test2pidfd_poll_test
3pidfd_test3pidfd_test
4pidfd_wait4pidfd_wait
5pidfd_getfd_test
tools/testing/selftests/pidfd/Makefile+1−1
@@ -1,7 +1,7 @@
1# SPDX-License-Identifier: GPL-2.0-only1# SPDX-License-Identifier: GPL-2.0-only
2CFLAGS += -g -I../../../../usr/include/ -pthread2CFLAGS += -g -I../../../../usr/include/ -pthread
3 3
4TEST_GEN_PROGS := pidfd_test pidfd_fdinfo_test pidfd_open_test pidfd_poll_test pidfd_wait4TEST_GEN_PROGS := pidfd_test pidfd_fdinfo_test pidfd_open_test pidfd_poll_test pidfd_wait pidfd_getfd_test
5 5
6include ../lib.mk6include ../lib.mk
7 7
tools/testing/selftests/pidfd/pidfd.h+9−0
@@ -36,6 +36,10 @@ · 35 unmodified lines
36#define __NR_clone3 -136#define __NR_clone3 -1
37#endif37#endif
38 38
39#ifndef __NR_pidfd_getfd
40#define __NR_pidfd_getfd -1
41#endif
42
39/*43/*
40 * The kernel reserves 300 pids via RESERVED_PIDS in kernel/pid.c44 * The kernel reserves 300 pids via RESERVED_PIDS in kernel/pid.c
41 * That means, when it wraps around any pid < 300 will be skipped.45 * That means, when it wraps around any pid < 300 will be skipped.
@@ -84,4 +88,9 @@ static inline int sys_pidfd_send_signal(int pidfd, int sig, siginfo_t *info, · 42 unmodified lines
84 return syscall(__NR_pidfd_send_signal, pidfd, sig, info, flags);88 return syscall(__NR_pidfd_send_signal, pidfd, sig, info, flags);
85}89}
86 90
91static inline int sys_pidfd_getfd(int pidfd, int fd, int flags)
92{
93 return syscall(__NR_pidfd_getfd, pidfd, fd, flags);
94}
95
87#endif /* __PIDFD_H */96#endif /* __PIDFD_H */
tools/testing/selftests/pidfd/pidfd_getfd_test.c+249−0
@@ -0,0 +1,249 @@
1// SPDX-License-Identifier: GPL-2.0
2
3#define _GNU_SOURCE
4#include <errno.h>
5#include <fcntl.h>
6#include <limits.h>
7#include <linux/types.h>
8#include <sched.h>
9#include <signal.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <syscall.h>
14#include <sys/prctl.h>
15#include <sys/wait.h>
16#include <unistd.h>
17#include <sys/socket.h>
18#include <linux/kcmp.h>
19
20#include "pidfd.h"
21#include "../kselftest.h"
22#include "../kselftest_harness.h"
23
24/*
25 * UNKNOWN_FD is an fd number that should never exist in the child, as it is
26 * used to check the negative case.
27 */
28#define UNKNOWN_FD 111
29#define UID_NOBODY 65535
30
31static int sys_kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1,
32 unsigned long idx2)
33{
34 return syscall(__NR_kcmp, pid1, pid2, type, idx1, idx2);
35}
36
37static int sys_memfd_create(const char *name, unsigned int flags)
38{
39 return syscall(__NR_memfd_create, name, flags);
40}
41
42static int __child(int sk, int memfd)
43{
44 int ret;
45 char buf;
46
47 /*
48 * Ensure we don't leave around a bunch of orphaned children if our
49 * tests fail.
50 */
51 ret = prctl(PR_SET_PDEATHSIG, SIGKILL);
52 if (ret) {
53 fprintf(stderr, "%s: Child could not set DEATHSIG\n",
54 strerror(errno));
55 return -1;
56 }
57
58 ret = send(sk, &memfd, sizeof(memfd), 0);
59 if (ret != sizeof(memfd)) {
60 fprintf(stderr, "%s: Child failed to send fd number\n",
61 strerror(errno));
62 return -1;
63 }
64
65 /*
66 * The fixture setup is completed at this point. The tests will run.
67 *
68 * This blocking recv enables the parent to message the child.
69 * Either we will read 'P' off of the sk, indicating that we need
70 * to disable ptrace, or we will read a 0, indicating that the other
71 * side has closed the sk. This occurs during fixture teardown time,
72 * indicating that the child should exit.
73 */
74 while ((ret = recv(sk, &buf, sizeof(buf), 0)) > 0) {
75 if (buf == 'P') {
76 ret = prctl(PR_SET_DUMPABLE, 0);
77 if (ret < 0) {
78 fprintf(stderr,
79 "%s: Child failed to disable ptrace\n",
80 strerror(errno));
81 return -1;
82 }
83 } else {
84 fprintf(stderr, "Child received unknown command %c\n",
85 buf);
86 return -1;
87 }
88 ret = send(sk, &buf, sizeof(buf), 0);
89 if (ret != 1) {
90 fprintf(stderr, "%s: Child failed to ack\n",
91 strerror(errno));
92 return -1;
93 }
94 }
95 if (ret < 0) {
96 fprintf(stderr, "%s: Child failed to read from socket\n",
97 strerror(errno));
98 return -1;
99 }
100
101 return 0;
102}
103
104static int child(int sk)
105{
106 int memfd, ret;
107
108 memfd = sys_memfd_create("test", 0);
109 if (memfd < 0) {
110 fprintf(stderr, "%s: Child could not create memfd\n",
111 strerror(errno));
112 ret = -1;
113 } else {
114 ret = __child(sk, memfd);
115 close(memfd);
116 }
117
118 close(sk);
119 return ret;
120}
121
122FIXTURE(child)
123{
124 /*
125 * remote_fd is the number of the FD which we are trying to retrieve
126 * from the child.
127 */
128 int remote_fd;
129 /* pid points to the child which we are fetching FDs from */
130 pid_t pid;
131 /* pidfd is the pidfd of the child */
132 int pidfd;
133 /*
134 * sk is our side of the socketpair used to communicate with the child.
135 * When it is closed, the child will exit.
136 */
137 int sk;
138};
139
140FIXTURE_SETUP(child)
141{
142 int ret, sk_pair[2];
143
144 ASSERT_EQ(0, socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sk_pair)) {
145 TH_LOG("%s: failed to create socketpair", strerror(errno));
146 }
147 self->sk = sk_pair[0];
148
149 self->pid = fork();
150 ASSERT_GE(self->pid, 0);
151
152 if (self->pid == 0) {
153 close(sk_pair[0]);
154 if (child(sk_pair[1]))
155 _exit(EXIT_FAILURE);
156 _exit(EXIT_SUCCESS);
157 }
158
159 close(sk_pair[1]);
160
161 self->pidfd = sys_pidfd_open(self->pid, 0);
162 ASSERT_GE(self->pidfd, 0);
163
164 /*
165 * Wait for the child to complete setup. It'll send the remote memfd's
166 * number when ready.
167 */
168 ret = recv(sk_pair[0], &self->remote_fd, sizeof(self->remote_fd), 0);
169 ASSERT_EQ(sizeof(self->remote_fd), ret);
170}
171
172FIXTURE_TEARDOWN(child)
173{
174 EXPECT_EQ(0, close(self->pidfd));
175 EXPECT_EQ(0, close(self->sk));
176
177 EXPECT_EQ(0, wait_for_pid(self->pid));
178}
179
180TEST_F(child, disable_ptrace)
181{
182 int uid, fd;
183 char c;
184
185 /*
186 * Turn into nobody if we're root, to avoid CAP_SYS_PTRACE
187 *
188 * The tests should run in their own process, so even this test fails,
189 * it shouldn't result in subsequent tests failing.
190 */
191 uid = getuid();
192 if (uid == 0)
193 ASSERT_EQ(0, seteuid(UID_NOBODY));
194
195 ASSERT_EQ(1, send(self->sk, "P", 1, 0));
196 ASSERT_EQ(1, recv(self->sk, &c, 1, 0));
197
198 fd = sys_pidfd_getfd(self->pidfd, self->remote_fd, 0);
199 EXPECT_EQ(-1, fd);
200 EXPECT_EQ(EPERM, errno);
201
202 if (uid == 0)
203 ASSERT_EQ(0, seteuid(0));
204}
205
206TEST_F(child, fetch_fd)
207{
208 int fd, ret;
209
210 fd = sys_pidfd_getfd(self->pidfd, self->remote_fd, 0);
211 ASSERT_GE(fd, 0);
212
213 EXPECT_EQ(0, sys_kcmp(getpid(), self->pid, KCMP_FILE, fd, self->remote_fd));
214
215 ret = fcntl(fd, F_GETFD);
216 ASSERT_GE(ret, 0);
217 EXPECT_GE(ret & FD_CLOEXEC, 0);
218
219 close(fd);
220}
221
222TEST_F(child, test_unknown_fd)
223{
224 int fd;
225
226 fd = sys_pidfd_getfd(self->pidfd, UNKNOWN_FD, 0);
227 EXPECT_EQ(-1, fd) {
228 TH_LOG("getfd succeeded while fetching unknown fd");
229 };
230 EXPECT_EQ(EBADF, errno) {
231 TH_LOG("%s: getfd did not get EBADF", strerror(errno));
232 }
233}
234
235TEST(flags_set)
236{
237 ASSERT_EQ(-1, sys_pidfd_getfd(0, 0, 1));
238 EXPECT_EQ(errno, EINVAL);
239}
240
241#if __NR_pidfd_getfd == -1
242int main(void)
243{
244 fprintf(stderr, "__NR_pidfd_getfd undefined. The pidfd_getfd syscall is unavailable. Test aborting\n");
245 return KSFT_SKIP;
246}
247#else
248TEST_HARNESS_MAIN
249#endif