3

我已经编写了几个生产 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)

4

1 回答 1

1

bpf:参数列表太长。程序太大(103个insns),最多4096个insns

查看错误消息,我的猜测是您的程序有 103 条指令,它被拒绝了,因为它太复杂了。也就是说,验证者在分析所有路径上的所有指令之前就放弃了。

在具有特权用户的 Linux 5.15 上,验证者在阅读 100 万条指令(复杂性限制)后放弃。由于它必须分析通过程序的所有路径,因此具有少量指令的程序可能具有非常高的复杂性。当您有循环和许多条件时尤其如此,就像您的情况一样。


为什么错误信息令人困惑?此错误消息来自 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)系统调用E2BIG在程序太大和复杂度太高时都返回,所以 libbpf 会为这两种情况打印相同的错误消息,总是带有at most 4096 instructions. 我相信上游会接受补丁来改进该错误消息。

于 2021-11-29T09:40:44.433 回答