嗨,我正在尝试为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
(,这将在映射值结束后进行读取,从而导致无限制的内存访问。因此,验证者拒绝它。