|
3 | 3 | from collections import namedtuple |
4 | 4 | from pathlib import Path |
5 | 5 |
|
| 6 | +Output = namedtuple("Output", ["stdout", "stderr"]) |
6 | 7 |
|
7 | | -def verify_object(obj_path: Path) -> tuple[bool, str]: |
8 | | - """Run bpftool prog load -d to verify a BPF object file against the kernel verifier. |
| 8 | + |
| 9 | +def verify_object(obj_path: Path) -> tuple[bool, Output]: |
| 10 | + """Run bpftool prog load to verify a BPF object file against the kernel verifier. |
9 | 11 |
|
10 | 12 | Pins the program temporarily at /sys/fs/bpf/bpf_prog_test_<uuid>, then removes it. |
11 | | - Returns (success, combined_output). Requires sudo / root. |
| 13 | + Returns (success, Output(stdout, stderr)). Requires sudo / root. |
| 14 | +
|
| 15 | + No -d: it asks the kernel for the full instruction-level log (log level |
| 16 | + 1+2+4) on every load. For a program that makes the verifier walk a loop that |
| 17 | + log outgrows libbpf's buffer, the kernel then fails the load with ENOSPC, and |
| 18 | + libbpf doubles the buffer and verifies the whole program again, until the |
| 19 | + load takes longer than the timeout. A rejection still comes with its log: |
| 20 | + libbpf retries a failed load at log level 1 and prints the log as a warning. |
12 | 21 | """ |
13 | 22 | pin_path = f"/sys/fs/bpf/bpf_prog_test_{uuid.uuid4().hex[:8]}" |
14 | 23 | try: |
15 | 24 | result = subprocess.run( |
16 | | - ["sudo", "bpftool", "prog", "load", "-d", str(obj_path), pin_path], |
| 25 | + ["sudo", "bpftool", "prog", "load", str(obj_path), pin_path], |
17 | 26 | capture_output=True, |
18 | 27 | text=True, |
19 | 28 | timeout=30, |
20 | 29 | ) |
21 | | - Output = namedtuple("Output", ["stdout", "stderr"]) |
22 | | - output = Output(stdout=result.stdout, stderr=result.stderr) |
23 | | - return result.returncode == 0, output |
| 30 | + return result.returncode == 0, Output( |
| 31 | + stdout=result.stdout, stderr=result.stderr |
| 32 | + ) |
24 | 33 | except subprocess.TimeoutExpired: |
25 | | - return False, "bpftool timed out after 30s" |
| 34 | + return False, Output(stdout="", stderr="bpftool timed out after 30s") |
26 | 35 | finally: |
27 | 36 | subprocess.run(["sudo", "rm", "-f", pin_path], check=False, capture_output=True) |
0 commit comments