bpf: don't infer PTR_TO_CTX for programs with unnamed context type
authorAndrii Nakryiko <andrii@kernel.org>
Mon, 12 Feb 2024 23:32:20 +0000 (15:32 -0800)
committerAlexei Starovoitov <ast@kernel.org>
Wed, 14 Feb 2024 02:46:47 +0000 (18:46 -0800)
For program types that don't have named context type name (e.g., BPF
iterator programs or tracepoint programs), ctx_tname will be a non-NULL
empty string. For such programs it shouldn't be possible to have
PTR_TO_CTX argument for global subprogs based on type name alone.
arg:ctx tag is the only way to have PTR_TO_CTX passed into global
subprog for such program types.

Fix this loophole, which currently would assume PTR_TO_CTX whenever
user uses a pointer to anonymous struct as an argument to their global
subprogs. This happens in practice with the following (quite common, in
practice) approach:

typedef struct { /* anonymous */
    int x;
} my_type_t;

int my_subprog(my_type_t *arg) { ... }

User's intent is to have PTR_TO_MEM argument for `arg`, but verifier
will complain about expecting PTR_TO_CTX.

This fix also closes unintended s390x-specific KPROBE handling of
PTR_TO_CTX case. Selftest change is necessary to accommodate this.

Fixes: 91cc1a99740e ("bpf: Annotate context types")
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/r/20240212233221.2575350-4-andrii@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
kernel/bpf/btf.c
tools/testing/selftests/bpf/progs/test_global_func_ctx_args.c

index 26dc0876e4267337516cbeb16c05fa9e51f212ce..6ff0bd1a91d5617fb928e9f6338cb35e0e68b347 100644 (file)
@@ -5746,6 +5746,9 @@ again:
                bpf_log(log, "Please fix kernel include/linux/bpf_types.h\n");
                return false;
        }
+       /* program types without named context types work only with arg:ctx tag */
+       if (ctx_tname[0] == '\0')
+               return false;
        /* only compare that prog's ctx type name is the same as
         * kernel expects. No need to compare field by field.
         * It's ok for bpf prog to do:
index 9a06e5eb1fbef2bfd1f6b1757e23c60e5e9f8ad1..143c8a4852bfe70506253ca880bac91a409b8a9f 100644 (file)
@@ -26,6 +26,23 @@ int kprobe_typedef_ctx(void *ctx)
        return kprobe_typedef_ctx_subprog(ctx);
 }
 
+/* s390x defines:
+ *
+ * typedef user_pt_regs bpf_user_pt_regs_t;
+ * typedef struct { ... } user_pt_regs;
+ *
+ * And so "canonical" underlying struct type is anonymous.
+ * So on s390x only valid ways to have PTR_TO_CTX argument in global subprogs
+ * are:
+ *   - bpf_user_pt_regs_t *ctx (typedef);
+ *   - struct bpf_user_pt_regs_t *ctx (backwards compatible struct hack);
+ *   - void *ctx __arg_ctx (arg:ctx tag)
+ *
+ * Other architectures also allow using underlying struct types (e.g.,
+ * `struct pt_regs *ctx` for x86-64)
+ */
+#ifndef bpf_target_s390
+
 #define pt_regs_struct_t typeof(*(__PT_REGS_CAST((struct pt_regs *)NULL)))
 
 __weak int kprobe_struct_ctx_subprog(pt_regs_struct_t *ctx)
@@ -40,6 +57,8 @@ int kprobe_resolved_ctx(void *ctx)
        return kprobe_struct_ctx_subprog(ctx);
 }
 
+#endif
+
 /* this is current hack to make this work on old kernels */
 struct bpf_user_pt_regs_t {};