bpf: Add arm64 JIT support for bpf_addr_space_cast instruction.
authorPuranjay Mohan <puranjay12@gmail.com>
Mon, 25 Mar 2024 15:07:16 +0000 (15:07 +0000)
committerAlexei Starovoitov <ast@kernel.org>
Wed, 3 Apr 2024 02:45:50 +0000 (19:45 -0700)
LLVM generates bpf_addr_space_cast instruction while translating
pointers between native (zero) address space and
__attribute__((address_space(N))). The addr_space=0 is reserved as
bpf_arena address space.

rY = addr_space_cast(rX, 0, 1) is processed by the verifier and
converted to normal 32-bit move: wX = wY.

rY = addr_space_cast(rX, 1, 0) : used to convert a bpf arena pointer to
a pointer in the userspace vma. This has to be converted by the JIT.

Signed-off-by: Puranjay Mohan <puranjay12@gmail.com>
Link: https://lore.kernel.org/r/20240325150716.4387-3-puranjay12@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
arch/arm64/net/bpf_jit_comp.c
tools/testing/selftests/bpf/DENYLIST.aarch64

index c6210b1..76b91f3 100644 (file)
@@ -82,6 +82,7 @@ struct jit_ctx {
        __le32 *ro_image;
        u32 stack_size;
        int fpb_offset;
+       u64 user_vm_start;
 };
 
 struct bpf_plt {
@@ -868,6 +869,15 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
        /* dst = src */
        case BPF_ALU | BPF_MOV | BPF_X:
        case BPF_ALU64 | BPF_MOV | BPF_X:
+               if (insn_is_cast_user(insn)) {
+                       emit(A64_MOV(0, tmp, src), ctx); // 32-bit mov clears the upper 32 bits
+                       emit_a64_mov_i(0, dst, ctx->user_vm_start >> 32, ctx);
+                       emit(A64_LSL(1, dst, dst, 32), ctx);
+                       emit(A64_CBZ(1, tmp, 2), ctx);
+                       emit(A64_ORR(1, tmp, dst, tmp), ctx);
+                       emit(A64_MOV(1, dst, tmp), ctx);
+                       break;
+               }
                switch (insn->off) {
                case 0:
                        emit(A64_MOV(is64, dst, src), ctx);
@@ -1690,6 +1700,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
        }
 
        ctx.fpb_offset = find_fpb_offset(prog);
+       ctx.user_vm_start = bpf_arena_get_user_vm_start(prog->aux->arena);
 
        /*
         * 1. Initial fake pass to compute ctx->idx and ctx->offset.
@@ -2511,6 +2522,11 @@ bool bpf_jit_supports_exceptions(void)
        return true;
 }
 
+bool bpf_jit_supports_arena(void)
+{
+       return true;
+}
+
 void bpf_jit_free(struct bpf_prog *prog)
 {
        if (prog->jited) {
index d8ade15..0445ac3 100644 (file)
@@ -10,5 +10,3 @@ fill_link_info/kprobe_multi_link_info            # bpf_program__attach_kprobe_mu
 fill_link_info/kretprobe_multi_link_info         # bpf_program__attach_kprobe_multi_opts unexpected error: -95
 fill_link_info/kprobe_multi_invalid_ubuff        # bpf_program__attach_kprobe_multi_opts unexpected error: -95
 missed/kprobe_recursion                          # missed_kprobe_recursion__attach unexpected error: -95 (errno 95)
-verifier_arena                                   # JIT does not support arena
-arena_htab                                       # JIT does not support arena