Thread (11 messages) flat view 11 messages, 7 authors, 2019-12-06

Re: [RFC PATCH] ptrace: add PTRACE_GETFD request

From: Andy Lutomirski <luto@amacapital.net>
Date: 2019-12-06 20:45:45
Also in: lkml

On Dec 5, 2019, at 3:44 PM, Sargun Dhillon [off-list ref] wrote:

PTRACE_GETFD is a generic ptrace API that allows the tracer to
get file descriptors from the traceee.

The primary reason to use this syscall is to allow sandboxers to
take action on an FD on behalf of the tracee. For example, this
can be combined with seccomp's user notification feature to extract
a file descriptor and call privileged syscalls, like binding
a socket to a privileged port.
Can you document the circumstances under which you can call this?

Does it require that you be attached as a tracer?  Does the tracee need to be stopped?  Does it work equivalently if the tracee is ptrace-stopped vs stopped by seccomp?

If the tracee is running and is single-threaded, is the locking correct?
quoted hunk ↗ jump to hunk
Signed-off-by: Sargun Dhillon <redacted>
---
include/uapi/linux/ptrace.h |  5 +++++
kernel/ptrace.c             | 39 +++++++++++++++++++++++++++++++++++--
2 files changed, 42 insertions(+), 2 deletions(-)
diff --git a/include/uapi/linux/ptrace.h b/include/uapi/linux/ptrace.h
index a71b6e3b03eb..2b69f759826a 100644
--- a/include/uapi/linux/ptrace.h
+++ b/include/uapi/linux/ptrace.h
@@ -101,6 +101,11 @@ struct ptrace_syscall_info {
   };
};

+/* This gets a file descriptor from a running process. It doesn't require the
+ * process to be stopped.
+ */
+#define PTRACE_GETFD    0x420f
+
/*
 * These values are stored in task->ptrace_message
 * by tracehook_report_syscall_* to describe the current syscall-stop.
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index cb9ddcc08119..a1d7b289fe8e 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -31,6 +31,7 @@
#include <linux/cn_proc.h>
#include <linux/compat.h>
#include <linux/sched/signal.h>
+#include <linux/fdtable.h>

#include <asm/syscall.h>    /* for syscall_get_* */
@@ -994,6 +995,37 @@ ptrace_get_syscall_info(struct task_struct *child, unsigned long user_size,
}
#endif /* CONFIG_HAVE_ARCH_TRACEHOOK */

+static int ptrace_getfd(struct task_struct *child, unsigned long fd)
+{
+    struct files_struct *files;
+    struct file *file;
+    int ret = 0;
+
+    files = get_files_struct(child);
+    if (!files)
+        return -ENOENT;
+
+    spin_lock(&files->file_lock);
+    file = fcheck_files(files, fd);
+    if (!file)
+        ret = -EBADF;
+    else
+        get_file(file);
+    spin_unlock(&files->file_lock);
+    put_files_struct(files);
+
+    if (ret)
+        goto out;
+
+    ret = get_unused_fd_flags(0);
+    if (ret >= 0)
+        fd_install(ret, file);
+
+    fput(file);
+out:
+    return ret;
+}
+
int ptrace_request(struct task_struct *child, long request,
          unsigned long addr, unsigned long data)
{
@@ -1222,7 +1254,9 @@ int ptrace_request(struct task_struct *child, long request,
   case PTRACE_SECCOMP_GET_METADATA:
       ret = seccomp_get_metadata(child, addr, datavp);
       break;
-
+    case PTRACE_GETFD:
+        ret = ptrace_getfd(child, data);
+        break;
   default:
       break;
   }
@@ -1265,7 +1299,8 @@ SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr,
   }

   ret = ptrace_check_attach(child, request == PTRACE_KILL ||
-                  request == PTRACE_INTERRUPT);
+                  request == PTRACE_INTERRUPT ||
+                  request == PTRACE_GETFD);
   if (ret < 0)
       goto out_put_task_struct;
-- 
2.20.1
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help