I am writing a bpf program in which i need to match prefix of filename in openat
syscall.
Since we cannot link libc
, and there is no such builtin function, i wrote one myself.
#define MAX_FILE_NAME_LENGTH 128
#define LOG_DIR "/my/prefix"
#define LEN_LOG_DIR sizeof(LOG_DIR)
int matchPrefix(char str[MAX_FILE_NAME_LENGTH]) {
for (int i = 0; i < LEN_LOG_DIR; i++) {
char ch1 = LOG_DIR[i];
if (ch1 == '\0') {
return 0;
}
char ch2 = str[i];
if (ch2 == '\0') {
return -1;
}
if (ch1 != ch2) {
return -2;
}
}
return (-3);
}
i am getting invalid mem access 'mem_or_null'
error when i try to load this program.
libbpf: load bpf program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
Validating matchPrefix() func#1...
38: R1=mem_or_null(id=2,off=0,imm=0) R10=fp0
; int matchPrefix(char str[MAX_FILE_NAME_LENGTH]) {
38: (18) r0 = 0xffffffff ; R0_w=P4294967295
; char ch2 = str[i];
40: (71) r2 = *(u8 *)(r1 +0)
R1 invalid mem access 'mem_or_null'
processed 2 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
libbpf: -- END LOG --
libbpf: failed to load program 'syscall_enter_open'
R1
is the register for first argument. which is a char array on stack. Do i need to pass length of array separately?
the function is called this way
char filename[MAX_FILE_NAME_LENGTH];
bpf_probe_read_user(filename, sizeof(filename), args->filename);
if (matchPrefix(filename) != 0) {
return 0;
}
Even if i change the function signature to accept a char *
, there is some other error R1 invalid mem access 'scalar'
.
Can someone help in understanding why am i getting this error in function verification?
TL;DR. Making your
matchPrefix
function astatic inline
one should work around the verifier issue.I believe this is happening because the BPF verifier recognizes your function as a global one (vs. inlined) and therefore verifies it independently. That means it won't assume anything for the arguments. Thus, the
str
argument is recognized asmem_or_null
and verification fails because you didn't check that pointer isn't null.Inlining the function will work around this issue because the verifier won't see a function anymore. It will be able to preserve the inferred type of
filename
when verifying the code that corresponds to the body ofmatchPrefix
.