调用bpf_probe_write_user返回错误-14的技术求助
sys_enter_execve中bpf_probe_write_user返回-14失败排查
我正在进行一个eBPF实验,目标是在sys_enter_execve的tracepoint中修改第一个参数(被执行程序的文件路径),但调用bpf_probe_write_user时返回-14,修改失败。
环境信息
- 内核版本:Linux cjh 5.15.0-152-generic #162-Ubuntu SMP Wed Jul 23 09:48:42 UTC 2025 x86_64
- libbpf:由内核源码编译而来
相关代码
eBPF代码(exechijack.bpf.c)
// SPDX-License-Identifier: BSD-3-Clause #include "vmlinux.h" #include <bpf/bpf_helpers.h> #include <bpf/bpf_tracing.h> #include <bpf/bpf_core_read.h> #include "exechijack.h" char LICENSE[] SEC("license") = "Dual BSD/GPL"; // Ringbuffer Map to pass messages from kernel to user struct { __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 256 * 1024); } rb SEC(".maps"); struct TASK_COMM { char comm[8]; }; // Optional Target Parent PID const volatile int target_ppid = 340126; SEC("tp/syscalls/sys_enter_execve") int handle_execve_enter(struct trace_event_raw_sys_enter *ctx) { size_t pid_tgid = bpf_get_current_pid_tgid(); // Check if we're a process of interest if (target_ppid != 0) { struct task_struct *task = (struct task_struct *)bpf_get_current_task(); int ppid = BPF_CORE_READ(task, real_parent, tgid); if (ppid != target_ppid) { return 0; } } char prog_name[TASK_COMM_LEN]; // Read in program from first arg of execve char prog_name_orig[TASK_COMM_LEN]; __builtin_memset(prog_name, '\x00', TASK_COMM_LEN); bpf_probe_read_user(&prog_name, TASK_COMM_LEN, (void*)ctx->args[0]); // Program can't be less than out two-char name if (prog_name[1] == '\x00') { bpf_printk("[EXECVE_HIJACK] program name too small\n"); return 0; } prog_name[0] = '/'; prog_name[1] = 'a'; for (int i = 2; i < TASK_COMM_LEN ; i++) { prog_name[i] = '\x00'; } long ret = bpf_probe_write_user((void*)ctx->args[0], prog_name, 3); bpf_printk("[EXECVE_HIJACK] ret: %d, %s\n", ret, (void*)ctx->args[0]); return 0; }
用户态加载代码(exechijack.c)
#include <stdio.h> // #include <bpf/bpf.h> #include "exechijack.skel.h" int main() { //int zero = 0; struct exechijack_bpf *_obj = exechijack_bpf__open_and_load(); exechijack_bpf__attach(_obj); printf("attach ...\n"); while (1); return 0; }
被劫持的用户程序(victim2.c)
#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <sys/wait.h> // const char *proga = "./proga"; int main() { int pid = getpid(); printf("current pid: %d\n", pid); while (1) { pid = fork(); if (pid == 0) { char *args[] = {"a", NULL}; printf("./proga"); execv("./proga", args); usleep(1000 * 3000); } else { // waitpid wait(NULL); } usleep(1000 * 3000); } return 0; }
构建脚本
clang -g -O2 -target bpf -D__TARGET_ARCH_x86 -I/usr/local/include/ -c exechijack.bpf.c -o exechijack.bpf.o bpftool gen skeleton exechijack.bpf.o > exechijack.skel.h gcc -g -Wall -I/usr/local/include/ exechijack.c -lelf -lz -lbpf -o exechijack gcc -O0 victim2.c -o victim2
trace_pipe输出
<...>-339834 [002] ....1 87540.993130: bpf_trace_printk: [EXECVE_HIJACK] ret: -14, ./proga <...>-340159 [002] ....1 88515.102412: bpf_trace_printk: [EXECVE_HIJACK] ret: -14, ./proga <...>-340160 [002] ....1 88518.103038: bpf_trace_printk: [EXECVE_HIJACK] ret: -14, ./proga <...>-340161 [000] ....1 88521.103815: bpf_trace_printk: [EXECVE_HIJACK] ret: -14, ./proga victim2-340162 [003] ....1 88524.104488: bpf_trace_printk: [EXECVE_HIJACK] ret: -14, ./proga victim2-340163 [003] ....1 88527.105239: bpf_trace_printk: [EXECVE_HIJACK] ret: -14, ./proga victim2-340164 [003] ....1 88530.105970: bpf_trace_printk: [EXECVE_HIJACK] ret: -14, ./proga victim2-340165 [003] ....1 88533.106663: bpf_trace_printk: [EXECVE_HIJACK] ret: -14, ./proga victim2-340166 [003] ....1 88536.107434: bpf_trace_printk: [EXECVE_HIJACK] ret: -14, ./proga victim2-340167 [003] ....1 88539.108153: bpf_trace_printk: [EXECVE_HIJACK] ret: -14, ./proga
排查情况
已确认失败并非权限问题(如缺少CAP_SYS_ADMIN),且在其他测试BPF程序中bpf_probe_write_user可以正常工作,无法定位当前场景下的失败原因,寻求帮助。
内容的提问来源于stack exchange,提问作者C JH
相关产品推荐
相关产品推荐

