bpf: Introduce bpf_per_cpu_ptr()
[linux-2.6-microblaze.git] / kernel / trace / bpf_trace.c
index a8d4f25..364a322 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/slab.h>
 #include <linux/bpf.h>
 #include <linux/bpf_perf_event.h>
+#include <linux/btf.h>
 #include <linux/filter.h>
 #include <linux/uaccess.h>
 #include <linux/ctype.h>
@@ -16,6 +17,9 @@
 #include <linux/error-injection.h>
 #include <linux/btf_ids.h>
 
+#include <uapi/linux/bpf.h>
+#include <uapi/linux/btf.h>
+
 #include <asm/tlb.h>
 
 #include "trace_probe.h"
@@ -67,6 +71,10 @@ static struct bpf_raw_event_map *bpf_get_raw_tracepoint_module(const char *name)
 u64 bpf_get_stackid(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5);
 u64 bpf_get_stack(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5);
 
+static int bpf_btf_printf_prepare(struct btf_ptr *ptr, u32 btf_ptr_size,
+                                 u64 flags, const struct btf **btf,
+                                 s32 *btf_id);
+
 /**
  * trace_call_bpf - invoke BPF program
  * @call: tracepoint event
@@ -743,19 +751,18 @@ out:
        return err;
 }
 
-BTF_ID_LIST(bpf_seq_printf_btf_ids)
-BTF_ID(struct, seq_file)
+BTF_ID_LIST_SINGLE(btf_seq_file_ids, struct, seq_file)
 
 static const struct bpf_func_proto bpf_seq_printf_proto = {
        .func           = bpf_seq_printf,
        .gpl_only       = true,
        .ret_type       = RET_INTEGER,
        .arg1_type      = ARG_PTR_TO_BTF_ID,
+       .arg1_btf_id    = &btf_seq_file_ids[0],
        .arg2_type      = ARG_PTR_TO_MEM,
        .arg3_type      = ARG_CONST_SIZE,
        .arg4_type      = ARG_PTR_TO_MEM_OR_NULL,
        .arg5_type      = ARG_CONST_SIZE_OR_ZERO,
-       .btf_id         = bpf_seq_printf_btf_ids,
 };
 
 BPF_CALL_3(bpf_seq_write, struct seq_file *, m, const void *, data, u32, len)
@@ -763,17 +770,39 @@ BPF_CALL_3(bpf_seq_write, struct seq_file *, m, const void *, data, u32, len)
        return seq_write(m, data, len) ? -EOVERFLOW : 0;
 }
 
-BTF_ID_LIST(bpf_seq_write_btf_ids)
-BTF_ID(struct, seq_file)
-
 static const struct bpf_func_proto bpf_seq_write_proto = {
        .func           = bpf_seq_write,
        .gpl_only       = true,
        .ret_type       = RET_INTEGER,
        .arg1_type      = ARG_PTR_TO_BTF_ID,
+       .arg1_btf_id    = &btf_seq_file_ids[0],
+       .arg2_type      = ARG_PTR_TO_MEM,
+       .arg3_type      = ARG_CONST_SIZE_OR_ZERO,
+};
+
+BPF_CALL_4(bpf_seq_printf_btf, struct seq_file *, m, struct btf_ptr *, ptr,
+          u32, btf_ptr_size, u64, flags)
+{
+       const struct btf *btf;
+       s32 btf_id;
+       int ret;
+
+       ret = bpf_btf_printf_prepare(ptr, btf_ptr_size, flags, &btf, &btf_id);
+       if (ret)
+               return ret;
+
+       return btf_type_seq_show_flags(btf, btf_id, ptr->ptr, m, flags);
+}
+
+static const struct bpf_func_proto bpf_seq_printf_btf_proto = {
+       .func           = bpf_seq_printf_btf,
+       .gpl_only       = true,
+       .ret_type       = RET_INTEGER,
+       .arg1_type      = ARG_PTR_TO_BTF_ID,
+       .arg1_btf_id    = &btf_seq_file_ids[0],
        .arg2_type      = ARG_PTR_TO_MEM,
        .arg3_type      = ARG_CONST_SIZE_OR_ZERO,
-       .btf_id         = bpf_seq_write_btf_ids,
+       .arg4_type      = ARG_ANYTHING,
 };
 
 static __always_inline int
@@ -1098,6 +1127,118 @@ static const struct bpf_func_proto bpf_send_signal_thread_proto = {
        .arg1_type      = ARG_ANYTHING,
 };
 
+BPF_CALL_3(bpf_d_path, struct path *, path, char *, buf, u32, sz)
+{
+       long len;
+       char *p;
+
+       if (!sz)
+               return 0;
+
+       p = d_path(path, buf, sz);
+       if (IS_ERR(p)) {
+               len = PTR_ERR(p);
+       } else {
+               len = buf + sz - p;
+               memmove(buf, p, len);
+       }
+
+       return len;
+}
+
+BTF_SET_START(btf_allowlist_d_path)
+#ifdef CONFIG_SECURITY
+BTF_ID(func, security_file_permission)
+BTF_ID(func, security_inode_getattr)
+BTF_ID(func, security_file_open)
+#endif
+#ifdef CONFIG_SECURITY_PATH
+BTF_ID(func, security_path_truncate)
+#endif
+BTF_ID(func, vfs_truncate)
+BTF_ID(func, vfs_fallocate)
+BTF_ID(func, dentry_open)
+BTF_ID(func, vfs_getattr)
+BTF_ID(func, filp_close)
+BTF_SET_END(btf_allowlist_d_path)
+
+static bool bpf_d_path_allowed(const struct bpf_prog *prog)
+{
+       return btf_id_set_contains(&btf_allowlist_d_path, prog->aux->attach_btf_id);
+}
+
+BTF_ID_LIST_SINGLE(bpf_d_path_btf_ids, struct, path)
+
+static const struct bpf_func_proto bpf_d_path_proto = {
+       .func           = bpf_d_path,
+       .gpl_only       = false,
+       .ret_type       = RET_INTEGER,
+       .arg1_type      = ARG_PTR_TO_BTF_ID,
+       .arg1_btf_id    = &bpf_d_path_btf_ids[0],
+       .arg2_type      = ARG_PTR_TO_MEM,
+       .arg3_type      = ARG_CONST_SIZE_OR_ZERO,
+       .allowed        = bpf_d_path_allowed,
+};
+
+#define BTF_F_ALL      (BTF_F_COMPACT  | BTF_F_NONAME | \
+                        BTF_F_PTR_RAW | BTF_F_ZERO)
+
+static int bpf_btf_printf_prepare(struct btf_ptr *ptr, u32 btf_ptr_size,
+                                 u64 flags, const struct btf **btf,
+                                 s32 *btf_id)
+{
+       const struct btf_type *t;
+
+       if (unlikely(flags & ~(BTF_F_ALL)))
+               return -EINVAL;
+
+       if (btf_ptr_size != sizeof(struct btf_ptr))
+               return -EINVAL;
+
+       *btf = bpf_get_btf_vmlinux();
+
+       if (IS_ERR_OR_NULL(*btf))
+               return PTR_ERR(*btf);
+
+       if (ptr->type_id > 0)
+               *btf_id = ptr->type_id;
+       else
+               return -EINVAL;
+
+       if (*btf_id > 0)
+               t = btf_type_by_id(*btf, *btf_id);
+       if (*btf_id <= 0 || !t)
+               return -ENOENT;
+
+       return 0;
+}
+
+BPF_CALL_5(bpf_snprintf_btf, char *, str, u32, str_size, struct btf_ptr *, ptr,
+          u32, btf_ptr_size, u64, flags)
+{
+       const struct btf *btf;
+       s32 btf_id;
+       int ret;
+
+       ret = bpf_btf_printf_prepare(ptr, btf_ptr_size, flags, &btf, &btf_id);
+       if (ret)
+               return ret;
+
+       return btf_type_snprintf_show(btf, btf_id, ptr->ptr, str, str_size,
+                                     flags);
+}
+
+const struct bpf_func_proto bpf_snprintf_btf_proto = {
+       .func           = bpf_snprintf_btf,
+       .gpl_only       = false,
+       .ret_type       = RET_INTEGER,
+       .arg1_type      = ARG_PTR_TO_MEM,
+       .arg2_type      = ARG_CONST_SIZE,
+       .arg3_type      = ARG_PTR_TO_MEM,
+       .arg4_type      = ARG_CONST_SIZE,
+       .arg5_type      = ARG_ANYTHING,
+};
+
 const struct bpf_func_proto *
 bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
 {
@@ -1182,6 +1323,12 @@ bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
                return &bpf_jiffies64_proto;
        case BPF_FUNC_get_task_stack:
                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_snprintf_btf:
+               return &bpf_snprintf_btf_proto;
+       case BPF_FUNC_bpf_per_cpu_ptr:
+               return &bpf_per_cpu_ptr_proto;
        default:
                return NULL;
        }
@@ -1579,6 +1726,12 @@ tracing_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
                return prog->expected_attach_type == BPF_TRACE_ITER ?
                       &bpf_seq_write_proto :
                       NULL;
+       case BPF_FUNC_seq_printf_btf:
+               return prog->expected_attach_type == BPF_TRACE_ITER ?
+                      &bpf_seq_printf_btf_proto :
+                      NULL;
+       case BPF_FUNC_d_path:
+               return &bpf_d_path_proto;
        default:
                return raw_tp_prog_func_proto(func_id, prog);
        }
@@ -1625,6 +1778,7 @@ const struct bpf_verifier_ops raw_tracepoint_verifier_ops = {
 };
 
 const struct bpf_prog_ops raw_tracepoint_prog_ops = {
+       .test_run = bpf_prog_test_run_raw_tp,
 };
 
 const struct bpf_verifier_ops tracing_verifier_ops = {