"Program too large" 阈值大于实际指令数
"Program too large" threshold greater than actual instruction count
我已经编写了几个生产 BPF 代理,但我的方法是非常迭代,直到我取悦验证者并可以继续前进。我又达到了我的极限。
这是一个程序,如果我的 &&
条件少一个就可以运行,否则就会中断。令人困惑的部分是警告暗示 103 insns
大于 at most 4096 insns
。很明显我对这一切是如何串在一起的有些误解。
我的最终目标是根据进程的环境进行日志记录——因此欢迎使用其他方法。 :)
错误:
$ sudo python foo.py
bpf: Argument list too long. Program too large (103 insns), at most 4096 insns
Failed to load BPF program b'tracepoint__sched__sched_process_exec': Argument list too long
BPF 来源:
#include <linux/mm_types.h>
#include <linux/sched.h>
#include <linux/version.h>
int tracepoint__sched__sched_process_exec(
struct tracepoint__sched__sched_process_exec* args
) {
struct task_struct* task = (typeof(task))bpf_get_current_task();
const struct mm_struct* mm = task->mm;
unsigned long env_start = mm->env_start;
unsigned long env_end = mm->env_end;
// Read up to 512 environment variables -- only way I could find to "limit"
// the loop to satisfy the verifier.
char var[12];
for (int n = 0; n < 512; n++) {
int result = bpf_probe_read_str(&var, sizeof var, (void*)env_start);
if (result <= 0) {
break;
}
env_start += result;
if (
var[0] == 'H' &&
var[1] == 'I' &&
var[2] == 'S' &&
var[3] == 'T' &&
var[4] == 'S' &&
var[5] == 'I' &&
var[6] == 'Z' &&
var[7] == 'E'
) {
bpf_trace_printk("Got it: %s\n", var);
break;
}
}
return 0;
}
用于复制的基本加载程序:
#!/usr/bin/env python3
import sys
from bcc import BPF
if __name__ == '__main__':
source = open("./foo.c").read()
try:
BPF(text=source.encode("utf-8")).trace_print()
except Exception as e:
error = str(e)
sys.exit(error)
bpf: Argument list too long. Program too large (103 insns), at most 4096 insns
看错误信息,我猜你的程序有 103 条指令,它被拒绝了,因为它太复杂了。即验证者还没有分析完所有路径上的所有指令就放弃了
在 Linux 5.15 上,有特权用户,验证者在读取 100 万条指令后放弃(复杂度 限制)。由于它必须分析通过程序的所有路径,因此指令数量较少的程序可能具有非常高的 复杂度 。当你有循环和许多条件时尤其如此,就像你的情况一样。
为什么错误信息令人困惑?这个错误信息是coming from libbpf.c:
if (ret < 0 && errno == E2BIG) {
fprintf(stderr,
"bpf: %s. Program %s too large (%u insns), at most %d insns\n\n",
strerror(errno), attr->name, insns_cnt, BPF_MAXINSNS);
return -1;
}
由于 bpf(2)
系统调用 returns E2BIG
无论是程序太大还是复杂度太高,libbpf 都会为这两种情况打印相同的错误消息,总是at most 4096 instructions
。我相信上游会接受补丁来改进该错误消息。
我已经编写了几个生产 BPF 代理,但我的方法是非常迭代,直到我取悦验证者并可以继续前进。我又达到了我的极限。
这是一个程序,如果我的 &&
条件少一个就可以运行,否则就会中断。令人困惑的部分是警告暗示 103 insns
大于 at most 4096 insns
。很明显我对这一切是如何串在一起的有些误解。
我的最终目标是根据进程的环境进行日志记录——因此欢迎使用其他方法。 :)
错误:
$ sudo python foo.py
bpf: Argument list too long. Program too large (103 insns), at most 4096 insns
Failed to load BPF program b'tracepoint__sched__sched_process_exec': Argument list too long
BPF 来源:
#include <linux/mm_types.h>
#include <linux/sched.h>
#include <linux/version.h>
int tracepoint__sched__sched_process_exec(
struct tracepoint__sched__sched_process_exec* args
) {
struct task_struct* task = (typeof(task))bpf_get_current_task();
const struct mm_struct* mm = task->mm;
unsigned long env_start = mm->env_start;
unsigned long env_end = mm->env_end;
// Read up to 512 environment variables -- only way I could find to "limit"
// the loop to satisfy the verifier.
char var[12];
for (int n = 0; n < 512; n++) {
int result = bpf_probe_read_str(&var, sizeof var, (void*)env_start);
if (result <= 0) {
break;
}
env_start += result;
if (
var[0] == 'H' &&
var[1] == 'I' &&
var[2] == 'S' &&
var[3] == 'T' &&
var[4] == 'S' &&
var[5] == 'I' &&
var[6] == 'Z' &&
var[7] == 'E'
) {
bpf_trace_printk("Got it: %s\n", var);
break;
}
}
return 0;
}
用于复制的基本加载程序:
#!/usr/bin/env python3
import sys
from bcc import BPF
if __name__ == '__main__':
source = open("./foo.c").read()
try:
BPF(text=source.encode("utf-8")).trace_print()
except Exception as e:
error = str(e)
sys.exit(error)
bpf: Argument list too long. Program too large (103 insns), at most 4096 insns
看错误信息,我猜你的程序有 103 条指令,它被拒绝了,因为它太复杂了。即验证者还没有分析完所有路径上的所有指令就放弃了
在 Linux 5.15 上,有特权用户,验证者在读取 100 万条指令后放弃(复杂度 限制)。由于它必须分析通过程序的所有路径,因此指令数量较少的程序可能具有非常高的 复杂度 。当你有循环和许多条件时尤其如此,就像你的情况一样。
为什么错误信息令人困惑?这个错误信息是coming from libbpf.c:
if (ret < 0 && errno == E2BIG) {
fprintf(stderr,
"bpf: %s. Program %s too large (%u insns), at most %d insns\n\n",
strerror(errno), attr->name, insns_cnt, BPF_MAXINSNS);
return -1;
}
由于 bpf(2)
系统调用 returns E2BIG
无论是程序太大还是复杂度太高,libbpf 都会为这两种情况打印相同的错误消息,总是at most 4096 instructions
。我相信上游会接受补丁来改进该错误消息。