[PATCH bpf] bpf: Fix packet length loads into X in bpf_dbg

From: yanxia

Date: Thu Oct 15 2026 - 23:28:33 EST


bpf_single_step() handles BPF_LDX | BPF_W | BPF_LEN by assigning the
packet length to A instead of X. This leaves X unchanged and clobbers A,
so bpf_dbg can report the opposite verdict from the kernel for a valid
classic BPF filter.

For example, load the following filter and run it on a nonempty pcap:

load bpf 3,0 0 0 0,129 0 0 0,22 0 0 0

The filter initializes A to zero, loads the packet length into X and
returns A. The kernel rejects the packet, but bpf_dbg reports it as
passing because the length load overwrites A.

Write the length to X, as required by the instruction, preserving A.

The issue was found by reviewing the load cases in bpf_single_step()
and comparing them with bpf_convert_filter(). Tested the complete
bpf_dbg executable before and after the fix with GCC 12.3.1 on x86-64
Linux 6.6. The fixed tool agrees with SO_ATTACH_FILTER on 21 cases
covering X updates, preservation of A, and LD LEN, LDX IMM and LDX MEM
controls, including a truncated capture with a larger original length.
The original tool disagrees on 12 cases; the nine controls pass with
both versions.

Fixes: fd981e3c321a ("filter: bpf_dbg: add minimal bpf debugger")
Signed-off-by: yanxia <yanxia@xxxxxxxxxxxxxxxxxxxx>
---
tools/bpf/bpf_dbg.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/bpf/bpf_dbg.c b/tools/bpf/bpf_dbg.c
index 00e560a..51af4c2 100644
--- a/tools/bpf/bpf_dbg.c
+++ b/tools/bpf/bpf_dbg.c
@@ -713,7 +713,7 @@ static void bpf_single_step(struct bpf_regs *r, struct sock_filter *f,
r->A = pkt_len;
break;
case BPF_LDX_W | BPF_LEN:
- r->A = pkt_len;
+ r->X = pkt_len;
break;
case BPF_LD | BPF_IMM:
r->A = K;

base-commit: ff47652a4b66c067c765a7ad464d930b5a9367cc