bpf_probe_read_user() is throwing `permission denied: invalid access to map value` in an ebpf program

131 views Asked by At

In the kretprobe/sys_read probe, I am trying to read the request buffer (user space) in a BPF_MAP_TYPE_ARRAY. The eBPF verifier is throwing the following error:

{"error": "field SyscallProbeRetRead: program syscall__probe_ret_read: load program: permission denied: invalid access to map value, value_size=70 off=0 size=16383: R1 min value is outside of the allowed memory range (truncated, 73 line(s) omitted)"}

LOGIC: If the buf_size is greater than MAX_MSG_SIZE, then we will read TRACE_PARENT_SIZE or less (depending on the size of the buffer) into seventy_bytes_array->data, otherwise, we will not read anything.

#define MAX_MSG_SIZE 16383 
#define TRACE_PARENT_SIZE 70

SEC("kretprobe/sys_read")
int syscall__probe_ret_read(struct pt_regs *ctx)
{
    size_t buf_size = PT_REGS_RC(ctx);
    u64 id = bpf_get_current_pid_tgid();
    struct data_args_t *read_args = bpf_map_lookup_elem(&active_read_args_map, &id);

    if (read_args)
    {
        char *buf = read_args->buf;

        const u32 keyOne = 0;
        struct char_array_value *seventy_bytes_array = bpf_map_lookup_elem(&leftover_buf, &keyOne);

        unsigned int overrided_bytes = (buf_size - MAX_MSG_SIZE) > TRACE_PARENT_SIZE ? TRACE_PARENT_SIZE : ((buf_size - MAX_MSG_SIZE) > 0 ? (buf_size - MAX_MSG_SIZE) : 0);

        if (overrided_bytes > 0 && buf + MAX_MSG_SIZE && seventy_bytes_array)
        {
             asm volatile("%[overrided_bytes] &= 0x3fff;\n" ::[overrided_bytes] "+r"(overrided_bytes) :);
             bpf_probe_read_user(&seventy_bytes_array, overrided_bytes & 0x3fff, buf + MAX_MSG_SIZE);
        }
    }

    return 0;
}

Declaration of leftover_buf:

struct 
{
    __uint(type, BPF_MAP_TYPE_ARRAY);
    __type(key, u32);
    __type(value, struct char_array_value);
    __uint(max_entries, 1);
} leftover_buf SEC(".maps");

Declaration of char_array_value:

struct char_array_value {
    char data[TRACE_PARENT_SIZE];  // Replace SIZE with the desired size of your char array
};

Here are the full verifier logs:

599: frame1: R0=map_value_or_null(id=13,off=0,ks=4,vs=70,imm=0) R2=scalar(id=4,umin=16,umax=4294967295,var_off=(0x0; 0xffffffff)) R6=scalar(umin=16384,umax=16453,var_off=(0x4000; 0x7f)) R8=map_value(off=0,ks=8,vs=40,imm=0) R9=map_value(off=0,ks=4,vs=16448,imm=0) R10=fp0 fp-80=mmmm???? fp-88= fp-96=mmmmmmmm fp-104=1
:; unsigned int overrided_bytes = (buf_size - MAX_MSG_SIZE) > TRACE_PARENT_SIZE ? TRACE_PARENT_SIZE : ((buf_size - MAX_MSG_SIZE) > 0 ? (buf_size - MAX_MSG_SIZE) : 0);
:599: (07) r2 += -16383                ; frame1: R2_w=scalar(smin=-16367,smax=4294950912)
:; if (overrided_bytes > 0 && buf + MAX_MSG_SIZE && seventy_bytes_array)
:600: (bf) r1 = r2                     ; frame1: R1_w=scalar(id=255,smin=-16367,smax=4294950912) R2_w=scalar(id=255,smin=-16367,smax=4294950912)
:601: (67) r1 <<= 32                   ; frame1: R1_w=scalar(smax=9223372032559808512,umax=18446744069414584320,var_off=(0x0; 0xffffffff00000000),s32_min=0,s32_max=0,u32_max=0)
:602: (77) r1 >>= 32                   ; frame1: R1_w=scalar(umax=4294967295,var_off=(0x0; 0xffffffff))
:; if (overrided_bytes > 0 && buf + MAX_MSG_SIZE && seventy_bytes_array)
:603: (15) if r1 == 0x0 goto pc+6      ; frame1: R1_w=scalar(umax=4294967295,var_off=(0x0; 0xffffffff))
:604: (15) if r0 == 0x0 goto pc+5      ; frame1: R0=map_value(off=0,ks=4,vs=70,imm=0)
:; asm volatile("%[overrided_bytes] &= 0x3fff;\n" ::[overrided_bytes] "+r"(overrided_bytes) :);
:605: (57) r2 &= 16383                 ; frame1: R2_w=scalar(umax=16383,var_off=(0x0; 0x3fff))
:606: (79) r3 = *(u64 *)(r10 -96)      ; frame1: R3_w=scalar() R10=fp0 fp-96=mmmmmmmm
:607: (07) r3 += 16383                 ; frame1: R3_w=scalar()
:; bpf_probe_read_user(&seventy_bytes_array->data, overrided_bytes & 0x3fff, buf + MAX_MSG_SIZE);
:608: (bf) r1 = r0                     ; frame1: R0=map_value(off=0,ks=4,vs=70,imm=0) R1_w=map_value(off=0,ks=4,vs=70,imm=0)
:609: (85) call bpf_probe_read_user#112
:invalid access to map value, value_size=70 off=0 size=16383
:R1 min value is outside of the allowed memory range
:processed 7704 insns (limit 1000000) max_states_per_insn 1 total_states 336 peak_states 336 mark_read 253
0

There are 0 answers