@@ -440,5 +440,6 @@
433 i386 fspick sys_fspick
434 i386 pidfd_open sys_pidfd_open
435 i386 clone3 sys_clone3
+436 i386 pidfd_mem sys_pidfd_mem
437 i386 openat2 sys_openat2
438 i386 pidfd_getfd sys_pidfd_getfd
@@ -357,6 +357,7 @@
433 common fspick sys_fspick
434 common pidfd_open sys_pidfd_open
435 common clone3 sys_clone3
+436 common pidfd_mem sys_pidfd_mem
437 common openat2 sys_openat2
438 common pidfd_getfd sys_pidfd_getfd
@@ -76,6 +76,7 @@ extern const struct file_operations pidfd_fops;
struct file;
+extern struct pid *pidfd_get_pid(unsigned int fd);
extern struct pid *pidfd_pid(const struct file *file);
static inline struct pid *get_pid(struct pid *pid)
@@ -934,6 +934,7 @@ asmlinkage long sys_clock_adjtime32(clockid_t which_clock,
asmlinkage long sys_syncfs(int fd);
asmlinkage long sys_setns(int fd, int nstype);
asmlinkage long sys_pidfd_open(pid_t pid, unsigned int flags);
+asmlinkage long sys_pidfd_mem(int pidfd, int __user *fds, unsigned int flags);
asmlinkage long sys_sendmmsg(int fd, struct mmsghdr __user *msg,
unsigned int vlen, unsigned flags);
asmlinkage long sys_process_vm_readv(pid_t pid,
@@ -850,6 +850,8 @@ __SYSCALL(__NR_pidfd_open, sys_pidfd_open)
#define __NR_clone3 435
__SYSCALL(__NR_clone3, sys_clone3)
#endif
+#define __NR_pidfd_mem 436
+__SYSCALL(__NR_pidfd_mem, sys_pidfd_mem)
#define __NR_openat2 437
__SYSCALL(__NR_openat2, sys_openat2)
@@ -1464,7 +1464,7 @@ static long do_wait(struct wait_opts *wo)
return retval;
}
-static struct pid *pidfd_get_pid(unsigned int fd)
+struct pid *pidfd_get_pid(unsigned int fd)
{
struct fd f;
struct pid *pid;
@@ -42,6 +42,7 @@
#include <linux/sched/signal.h>
#include <linux/sched/task.h>
#include <linux/idr.h>
+#include <linux/remote_mapping.h>
struct pid init_struct_pid = {
.count = REFCOUNT_INIT(1),
@@ -565,6 +566,60 @@ SYSCALL_DEFINE2(pidfd_open, pid_t, pid, unsigned int, flags)
return fd;
}
+/**
+ * pidfd_mem() - Allow access to process address space.
+ *
+ * @pidfd: pid file descriptor for the target process
+ * @fds: array where the control and access file descriptors are returned
+ * @flags: flags to pass
+ *
+ * This creates a pair of file descriptors used to gain access to the
+ * target process memory. The control fd is used to establish a linear
+ * mapping between an offset range and a userspace address range.
+ * The access fd is used to mmap(offset range) on the client side.
+ *
+ * Return: On success, 0 is returned.
+ * On error, a negative errno number will be returned.
+ */
+SYSCALL_DEFINE3(pidfd_mem, int, pidfd, int __user *, fds, unsigned int, flags)
+{
+ struct pid *pid;
+ struct task_struct *task;
+ int ret_fds[2];
+ int ret;
+
+ if (pidfd < 0)
+ return -EINVAL;
+ if (!fds)
+ return -EINVAL;
+ if (flags)
+ return -EINVAL;
+
+ pid = pidfd_get_pid(pidfd);
+ if (IS_ERR(pid))
+ return PTR_ERR(pid);
+
+ task = get_pid_task(pid, PIDTYPE_PID);
+ put_pid(pid);
+ if (IS_ERR(task))
+ return PTR_ERR(task);
+
+ ret = -EPERM;
+ if (unlikely(task == current) || capable(CAP_SYS_PTRACE))
+ ret = task_remote_map(task, ret_fds);
+ put_task_struct(task);
+ if (IS_ERR_VALUE((long)ret))
+ return ret;
+
+ if (copy_to_user(fds, ret_fds, sizeof(ret_fds))) {
+ put_unused_fd(ret_fds[0]);
+ put_unused_fd(ret_fds[1]);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
void __init pid_idr_init(void)
{
/* Verify no one has done anything silly: */