OSDN Git Service

bpf: Add bpf_copy_from_user_task() helper
authorKenny Yu <kennyyu@fb.com>
Mon, 24 Jan 2022 18:54:01 +0000 (10:54 -0800)
committerAlexei Starovoitov <ast@kernel.org>
Tue, 25 Jan 2022 03:59:27 +0000 (19:59 -0800)
This adds a helper for bpf programs to read the memory of other
tasks.

As an example use case at Meta, we are using a bpf task iterator program
and this new helper to print C++ async stack traces for all threads of
a given process.

Signed-off-by: Kenny Yu <kennyyu@fb.com>
Acked-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/r/20220124185403.468466-3-kennyyu@fb.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
include/linux/bpf.h
include/uapi/linux/bpf.h
kernel/bpf/helpers.c
kernel/trace/bpf_trace.c
tools/include/uapi/linux/bpf.h

index 8c92c97..394305a 100644 (file)
@@ -2243,6 +2243,7 @@ extern const struct bpf_func_proto bpf_kallsyms_lookup_name_proto;
 extern const struct bpf_func_proto bpf_find_vma_proto;
 extern const struct bpf_func_proto bpf_loop_proto;
 extern const struct bpf_func_proto bpf_strncmp_proto;
+extern const struct bpf_func_proto bpf_copy_from_user_task_proto;
 
 const struct bpf_func_proto *tracing_prog_func_proto(
   enum bpf_func_id func_id, const struct bpf_prog *prog);
index 16a7574..4a2f704 100644 (file)
@@ -5076,6 +5076,16 @@ union bpf_attr {
  *             associated to *xdp_md*, at *offset*.
  *     Return
  *             0 on success, or a negative error in case of failure.
+ *
+ * long bpf_copy_from_user_task(void *dst, u32 size, const void *user_ptr, struct task_struct *tsk, u64 flags)
+ *     Description
+ *             Read *size* bytes from user space address *user_ptr* in *tsk*'s
+ *             address space, and stores the data in *dst*. *flags* is not
+ *             used yet and is provided for future extensibility. This helper
+ *             can only be used by sleepable programs.
+ *     Return
+ *             0 on success, or a negative error in case of failure. On error
+ *             *dst* buffer is zeroed out.
  */
 #define __BPF_FUNC_MAPPER(FN)          \
        FN(unspec),                     \
@@ -5269,6 +5279,7 @@ union bpf_attr {
        FN(xdp_get_buff_len),           \
        FN(xdp_load_bytes),             \
        FN(xdp_store_bytes),            \
+       FN(copy_from_user_task),        \
        /* */
 
 /* integer value in 'imm' field of BPF_CALL instruction selects which helper
index 01cfdf4..ed2780b 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/pid_namespace.h>
 #include <linux/proc_ns.h>
 #include <linux/security.h>
+#include <linux/btf_ids.h>
 
 #include "../../lib/kstrtox.h"
 
@@ -671,6 +672,39 @@ const struct bpf_func_proto bpf_copy_from_user_proto = {
        .arg3_type      = ARG_ANYTHING,
 };
 
+BPF_CALL_5(bpf_copy_from_user_task, void *, dst, u32, size,
+          const void __user *, user_ptr, struct task_struct *, tsk, u64, flags)
+{
+       int ret;
+
+       /* flags is not used yet */
+       if (unlikely(flags))
+               return -EINVAL;
+
+       if (unlikely(!size))
+               return 0;
+
+       ret = access_process_vm(tsk, (unsigned long)user_ptr, dst, size, 0);
+       if (ret == size)
+               return 0;
+
+       memset(dst, 0, size);
+       /* Return -EFAULT for partial read */
+       return ret < 0 ? ret : -EFAULT;
+}
+
+const struct bpf_func_proto bpf_copy_from_user_task_proto = {
+       .func           = bpf_copy_from_user_task,
+       .gpl_only       = false,
+       .ret_type       = RET_INTEGER,
+       .arg1_type      = ARG_PTR_TO_UNINIT_MEM,
+       .arg2_type      = ARG_CONST_SIZE_OR_ZERO,
+       .arg3_type      = ARG_ANYTHING,
+       .arg4_type      = ARG_PTR_TO_BTF_ID,
+       .arg4_btf_id    = &btf_tracing_ids[BTF_TRACING_TYPE_TASK],
+       .arg5_type      = ARG_ANYTHING
+};
+
 BPF_CALL_2(bpf_per_cpu_ptr, const void *, ptr, u32, cpu)
 {
        if (cpu >= nr_cpu_ids)
index 06a9e22..a2024ba 100644 (file)
@@ -1235,6 +1235,8 @@ bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
                return &bpf_get_task_stack_proto;
        case BPF_FUNC_copy_from_user:
                return prog->aux->sleepable ? &bpf_copy_from_user_proto : NULL;
+       case BPF_FUNC_copy_from_user_task:
+               return prog->aux->sleepable ? &bpf_copy_from_user_task_proto : NULL;
        case BPF_FUNC_snprintf_btf:
                return &bpf_snprintf_btf_proto;
        case BPF_FUNC_per_cpu_ptr:
index 16a7574..4a2f704 100644 (file)
@@ -5076,6 +5076,16 @@ union bpf_attr {
  *             associated to *xdp_md*, at *offset*.
  *     Return
  *             0 on success, or a negative error in case of failure.
+ *
+ * long bpf_copy_from_user_task(void *dst, u32 size, const void *user_ptr, struct task_struct *tsk, u64 flags)
+ *     Description
+ *             Read *size* bytes from user space address *user_ptr* in *tsk*'s
+ *             address space, and stores the data in *dst*. *flags* is not
+ *             used yet and is provided for future extensibility. This helper
+ *             can only be used by sleepable programs.
+ *     Return
+ *             0 on success, or a negative error in case of failure. On error
+ *             *dst* buffer is zeroed out.
  */
 #define __BPF_FUNC_MAPPER(FN)          \
        FN(unspec),                     \
@@ -5269,6 +5279,7 @@ union bpf_attr {
        FN(xdp_get_buff_len),           \
        FN(xdp_load_bytes),             \
        FN(xdp_store_bytes),            \
+       FN(copy_from_user_task),        \
        /* */
 
 /* integer value in 'imm' field of BPF_CALL instruction selects which helper