2020static __noinline bool pcap_stub_l3 (void * _ctx , void * __ctx , void * ___ctx ,
2121 void * data , void * data_end )
2222{
23- /* 512 × 8-byte NOP insns; must equal stubReservedInsns in internal/pcapfilter/elfpatch.go */
23+ /*
24+ * Bind the five parameters to R1..R5 and route them through the NOP
25+ * region as "+r" in/out operands. This creates a real data dependency
26+ * that forces clang to (1) emit the comparison below AFTER the region
27+ * and (2) read its operands from R1..R5 — exactly the registers the
28+ * spliced filter leaves set (R4=verdict, R5=0, R1=R2=R3=0 via the
29+ * fall-through epilogue in internal/pcapfilter/bpf_filter.go).
30+ *
31+ * Without these constraints clang is free to schedule the comparison
32+ * before the region: clang-12 does, stashing the result in callee-saved
33+ * registers and then letting the region's `r0 = 0` NOPs clobber the
34+ * return value, so the filter verdict is silently dropped. Do not
35+ * "simplify" the register pinning away.
36+ *
37+ */
38+ register void * a1 asm("r1" ) = _ctx ;
39+ register void * a2 asm("r2" ) = __ctx ;
40+ register void * a3 asm("r3" ) = ___ctx ;
41+ register void * a4 asm("r4" ) = data ;
42+ register void * a5 asm("r5" ) = data_end ;
2443 asm volatile (".rept 512\n\t"
2544 ".byte 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n\t"
26- ".endr\n\t" );
27- return data != data_end && _ctx == __ctx && __ctx == ___ctx ;
45+ ".endr\n\t"
46+ : "+r" (a1 ), "+r" (a2 ), "+r" (a3 ), "+r" (a4 ), "+r" (a5 )
47+ :: "r0" );
48+ return a4 != a5 && a1 == a2 && a2 == a3 ;
2849}
2950
3051static __noinline bool pcap_stub_l2 (void * _ctx , void * __ctx , void * ___ctx ,
3152 void * data , void * data_end )
3253{
33- /* 512 × 8-byte NOP insns; must equal stubReservedInsns in internal/pcapfilter/elfpatch.go */
54+ /*
55+ * Register-pinned NOP region; see pcap_stub_l3 above for why the
56+ * parameters are bound to R1..R5 and fed through the asm as "+r"
57+ * operands. Do not "simplify" the register pinning away.
58+ *
59+ */
60+ register void * a1 asm("r1" ) = _ctx ;
61+ register void * a2 asm("r2" ) = __ctx ;
62+ register void * a3 asm("r3" ) = ___ctx ;
63+ register void * a4 asm("r4" ) = data ;
64+ register void * a5 asm("r5" ) = data_end ;
3465 asm volatile (".rept 512\n\t"
3566 ".byte 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n\t"
36- ".endr\n\t" );
37- return data != data_end && _ctx == __ctx && __ctx == ___ctx ;
67+ ".endr\n\t"
68+ : "+r" (a1 ), "+r" (a2 ), "+r" (a3 ), "+r" (a4 ), "+r" (a5 )
69+ :: "r0" );
70+ return a4 != a5 && a1 == a2 && a2 == a3 ;
3871}
3972
4073/*
@@ -48,10 +81,10 @@ static __noinline bool pcap_stub_l2(void *_ctx, void *__ctx, void *___ctx,
4881 */
4982#define PCAP_STUB_PASS_SKB (skb ) ({ \
5083 void *__head = BPF_CORE_READ((skb), head); \
51- void *__pkt_end = __head + (u64)BPF_CORE_READ((skb), tail); \
52- void *__l3 = skb_network_header(skb); \
53- void *__l2 = skb_mac_header(skb); \
54- bool __pass; \
84+ void *__pkt_end = __head + (u64)BPF_CORE_READ((skb), tail); \
85+ void *__l3 = skb_network_header(skb); \
86+ void *__l2 = skb_mac_header(skb); \
87+ bool __pass; \
5588 if (BPF_CORE_READ((skb), mac_len) == 0) \
5689 __pass = pcap_stub_l3((skb), (skb), (skb), __l3, __pkt_end);\
5790 else \
0 commit comments