尝试散列字符串(进程名称)时eBPF验证错误



嗨,我正在尝试为ebpf中的完整进程名称生成一个32位哈希。这些进程名称可能很长,并且将不适合堆栈;堆";每个cpu阵列。我目前正在使用libbpf引导程序作为原型:https://github.com/libbpf/libbpf-bootstrap.git我遇到了验证器未验证哈希函数的问题。这里有什么问题?我被难住了。

代码的核心是:

uint32_t map_id = 0;
char *map_val = bpf_map_lookup_elem(&heap, &map_id);
if (!map_val)
return 0;
int bytes_read = bpf_probe_read_str(map_val, sizeof(e->filename), (void *)ctx + fname_off);
if (bytes_read > 0) {
map_val[ (bytes_read - 1) & (4096 -1) ] = 0;
uint32_t key = hash( (unsigned char*)map_val);
bpf_printk("process_exec count: %u, hash: %lu, full path: %sn", bytes_read -1, key, map_val); 
}

散列函数是:

uint32_t hash(unsigned char *str)
{
int c;
uint32_t hash = 5381;
while ( c = *str++ )
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
return hash;
}

我收到一个验证器错误:

; hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
91: (27) r4 *= 33
; hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
92: (0f) r4 += r1
; while ( c = *str++ )
93: (71) r1 = *(u8 *)(r2 +0)
R0=inv(id=6,smin_value=-4096,smax_value=4095) R1_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R2_w=map_value(id=0,off=4096,ks=4,vs=4096,imm=0) R4_w=inv(id=0) R6=ctx(id=0,off=0,umax_value=65535,var_off=(0x0; 0xffff)) R7=map_value(id=0,off=0,ks=4,vs=4096,imm=0) R8=invP0 R10=fp0 fp-8=mmmm???? fp-16=mmmmmmmm fp-24=mmmm???? fp-32=mmmmmmmm
invalid access to map value, value_size=4096 off=4096 size=1
R2 min value is outside of the allowed memory range
processed 32861 insns (limit 1000000) max_states_per_insn 4 total_states 337 peak_states 337 mark_read 4
-- END PROG LOAD LOG --
libbpf: prog 'handle_exec': failed to load: -13
libbpf: failed to load object 'bootstrap_bpf'
libbpf: failed to load BPF skeleton 'bootstrap_bpf': -13
Failed to load and verify BPF skeleton

以下是我的用例的完整差异:

diff --git a/examples/c/bootstrap.bpf.c b/examples/c/bootstrap.bpf.c
index d0860c0..c93ed58 100644
--- a/examples/c/bootstrap.bpf.c
+++ b/examples/c/bootstrap.bpf.c
@@ -20,6 +20,13 @@ struct {
__uint(max_entries, 256 * 1024);
} rb SEC(".maps");
+struct {
+       __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+       __uint(key_size, sizeof(u32));
+       __uint(max_entries, 1);
+       __uint(value_size, 4096);
+} heap SEC(".maps");
+
const volatile unsigned long long min_duration_ns = 0;
SEC("tp/sched/sched_process_exec")
@@ -58,6 +65,22 @@ int handle_exec(struct trace_event_raw_sched_process_exec *ctx)
/* successfully submit it to user-space for post-processing */
bpf_ringbuf_submit(e, 0);
+
+
+  uint32_t map_id = 0;
+  char *map_val = bpf_map_lookup_elem(&heap, &map_id);
+  if (!map_val)
+    return 0;
+
+  int bytes_read = bpf_probe_read_str(map_val, sizeof(e->filename), (void *)ctx + fname_off);
+  if (bytes_read > 0) {
+      // tell the validator bytes ready is between 0 and 4095
+      map_val[ (bytes_read - 1) & (4096 -1) ] = 0;
+
+      uint32_t key = hash( (unsigned char*)map_val);
+      bpf_printk("process_exec count: %u, hash: %u, full path: %sn", bytes_read -1, key, map_val);
+  }
+
return 0;
}
@@ -109,4 +132,3 @@ int handle_exit(struct trace_event_raw_sched_process_template* ctx)
bpf_ringbuf_submit(e, 0);
return 0;
}
-
diff --git a/examples/c/bootstrap.h b/examples/c/bootstrap.h
index b49e022..d268e56 100644
--- a/examples/c/bootstrap.h
+++ b/examples/c/bootstrap.h
@@ -4,7 +4,7 @@
#define __BOOTSTRAP_H
#define TASK_COMM_LEN 16
-#define MAX_FILENAME_LEN 127
+#define MAX_FILENAME_LEN 4096
struct event {
int pid;
@@ -16,4 +16,15 @@ struct event {
bool exit_event;
};
+static inline
+uint32_t hash(unsigned char *str)
+{
+    int c;
+    uint32_t hash = 5381;
+    while ( c = *str++ )
+        hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
+
+    return hash;
+}
+
#endif /* __BOOTSTRAP_H */

TL;DR。您需要确保您的读数没有超过映射值的末尾。因此,您需要检查str从未超过初始str值+4095。


验证程序错误解释

; while ( c = *str++ )
93: (71) r1 = *(u8 *)(r2 +0)
R0=inv(id=6,smin_value=-4096,smax_value=4095) R1_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R2_w=map_value(id=0,off=4096,ks=4,vs=4096,imm=0) R4_w=inv(id=0) R6=ctx(id=0,off=0,umax_value=65535,var_off=(0x0; 0xffff)) R7=map_value(id=0,off=0,ks=4,vs=4096,imm=0) R8=invP0 R10=fp0 fp-8=mmmm???? fp-16=mmmmmmmm fp-24=mmmm???? fp-32=mmmmmmmm
invalid access to map value, value_size=4096 off=4096 size=1
R2 min value is outside of the allowed memory range

这里的验证器告诉您,您的代码可能会尝试从映射值中读取一个字节(size=1(,偏移量为4096(off=4096(。由于映射值的大小为4096(value_size=4096(,这将在映射值结束后进行读取,从而导致无限制的内存访问。因此,验证者拒绝它。

相关内容

  • 没有找到相关文章

最新更新