I have the next functions:
SEC(...)
int BPF_PROG(...){
...
u16 mount_last_index = get_file_mount_root(file, event_info->mountroot);
...
}
static inline u16 get_file_mount_root(struct file *file, u8 buf[MAX_PATH_LENGTH])
{
struct path f_path = BPF_CORE_READ(file, f_path);
return get_path_mount_root(&f_path, buf);
}
static inline u16 get_path_mount_root(const struct path *path, u8 buf[MAX_PATH_LENGTH])
{
struct mount *mnt = get_mount(path);
struct dentry *mnt_mountpoint = BPF_CORE_READ(mnt, mnt_mountpoint);
return read_dentry_strings(mnt_mountpoint, buf, 0);
}
static inline u16 read_dentry_strings(struct dentry *dentry, u8 buf[MAX_PATH_LENGTH], u16 cur_index)
{
if (!dentry)
return 0;
if (cur_index >= MAX_PATH_LENGTH)
return 0;
struct dentry *curr_dtry = dentry;
struct dentry *lastdtryp = dentry;
for (int capacity = MAX_PATH_LENGTH; capacity > 0; capacity--)
{
if (cur_index + MAX_DIR_NAME_LENGTH >= MAX_PATH_LENGTH)
return cur_index <= MAX_PATH_LENGTH ? cur_index : MAX_PATH_LENGTH;
const unsigned char *name = BPF_CORE_READ(curr_dtry, d_name.name);
long read_len = bpf_core_read_str(&buf[cur_index], MAX_DIR_NAME_LENGTH, name);
if (read_len > 1)
{
capacity -= (read_len - 1);
if (cur_index + read_len >= MAX_PATH_LENGTH)
break;
cur_index += read_len;
struct dentry *parent = BPF_CORE_READ(curr_dtry, d_parent);
if (parent != lastdtryp)
{
lastdtryp = parent;
curr_dtry = parent;
buf[cur_index - 1] = '/';
buf[cur_index] = '\0';
}
else
{
if (buf[cur_index - 2] == '/')
{
buf[cur_index - 2] = '\0';
cur_index = cur_index - 2;
}
break;
}
}
else
{
break;
}
}
return cur_index;
}
When i try to run it i get the error:
=5
341: (c7) r8 s>>= 32 ; frame1: R8_w=scalar(umin=2566,umax=4084,var_off=(0x800; 0x7ff),s32_min=2048,s32_max=4095,u32_min=2048,u32_max=4095) refs=5
; for (int capacity = MAX_PATH_LENGTH; capacity > 0; capacity--)
342: (b7) r2 = 1 ; frame1: R2_w=1 refs=5
343: (6d) if r2 s> r8 goto pc+6 ; frame1: R2_w=1 R8_w=scalar(umin=2566,umax=4084,var_off=(0x800; 0x7ff)) refs=5
344: (bf) r2 = r7 ; frame1: R2_w=scalar(id=31,umin=2,umax=1530,var_off=(0x0; 0x7ff)) R7_w=scalar(id=31,umin=2,umax=1530,var_off=(0x0; 0x7ff)) refs=5
345: (57) r2 &= 65535 ; frame1: R2_w=scalar(umax=1530,var_off=(0x0; 0x7ff)) refs=5
346: (bf) r9 = r7 ; frame1: R7_w=scalar(id=31,umin=2,umax=1530,var_off=(0x0; 0x7ff)) R9_w=scalar(id=31,umin=2,umax=1530,var_off=(0x0; 0x7ff)) refs=5
347: (bf) r6 = r1 ; frame1: R1_w=scalar(id=32) R6_w=scalar(id=32) refs=5
348: (b7) r1 = 3841 ; frame1: R1_w=3841 refs=5
349: (2d) if r1 > r2 goto pc+1 ; frame1: R0_w=scalar() R1_w=3841 R2_w=scalar(umax=1530,var_off=(0x0; 0x7ff)) R3_w=47 R6_w=scalar(id=32) R7_w=scalar(id=31,umin=2,umax=1530,var_off=(0x0; 0x7ff)) R8_w=scalar(umin=2566,umax=4084,var_off=(0x800; 0x7ff)) R9_w=scalar(id=31,umin=2,umax=1530,var_off=(0x0; 0x7ff)) R10=fp0 fp-8=mmmmmmmm fp-16=mmmmmmmm fp-24=mmmmmmmm fp-32=alloc_mem refs=5
; return get_path_mount_root(&f_path, buf);
351: (bf) r3 = r6 ; frame1: R3_w=scalar(id=32) R6_w=scalar(id=32) refs=5
352: (b7) r1 = 40
(truncated)
[06:22:38.693] ERROR [EBPF] failed to load objects: field DoSysOpenat2: program do_sys_openat2: load program: permission denied: 351: (bf) r3 = r6 ; frame1: R3_w=scalar(id=32) R6_w=scalar(id=32) refs=5: 352: (b7) r1 = 40 (truncated, 770 line(s) omitted)
exit status 1
make: *** [Makefile:5: runEbpf] Error 1
The problem solves, when i change any of the function above return type to anything but not u16 even if the type has low/bigger capacity. For example:
static inline u8 get_path_mount_root(const struct path *path, u8 buf[MAX_PATH_LENGTH])
{
struct mount *mnt = get_mount(path);
struct dentry *mnt_mountpoint = BPF_CORE_READ(mnt, mnt_mountpoint);
return read_dentry_strings(mnt_mountpoint, buf, 0);
}
It doesn't matter that the next function expects u16, it allows to run the program. Can you explain me the reasons of this verifier's behavior and how to deal with it please?
Replacing inline
with __always_inline
for every function solved the problem