Description
Current llvm (17&18) when compiling code with BPF target make transformations that hurt further BPF verification and there are seemingly no real workarounds to this problem at the moment.
The problem is demonstrated by the following example:
Source code
id = ctx->protocol;
if (id < 4 || id > 12)
return 0;
*(u64 *)((void *)v + id) = 0;
is getting translated into something like
/* pseudo IR */
id = ctx->protocol;
tmp = id;
tmp += -13;
if (tmp < 0xfffffff7) goto next; // <- tmp and defined bounds are discarded here
v += id;
*v = 0; // <- BPF verification fails because of unbounded variable
next:
which fails BPF verification and leads to BPF loading/verification failures that typically look like
invalid access to map value, value_size=2052 off=4 size=0
R3 min value is outside of the allowed memory range
or R0 unbounded memory access, make sure to bounds check any such access
.
Rewriting the code with a slightly different structure does NOT solve this issue:
id = ctx->protocol;
if (id >= 5 && id <= 12) // <- this is again done in a separate registry of BPF machine and discarded
*(u64 *)((void *)v + id) = 0; // <- id value is getting loaded here without knowledge of the bounds check just performed above
else
return 0;
Neither volatile
nor asm volatile("" : "+r"(var))
provides a direct workaround too.
This problem and the proposed solution were originally raised by @yonghong-song in
https://reviews.llvm.org/D147078
https://reviews.llvm.org/D147968
but there were seemingly no new developments in almost a year.
This problem was also raised in discussions like
https://lore.kernel.org/all/[email protected]/T/ https://lpc.events/event/17/contributions/1648/attachments/1242/2525/Generating%20BPF%20Verifier%20Friendly%20Code%20with%20Clang.pdf
This presents a major paint point because of the absence of a clear workaround, leading to time-sinking fights against LLVM. Could some workaround be implemented until a solid solution is discussed and introduced? It may take the form of a new pragma that would disable FoldAndOrOfICmpsUsingRanges
transformation that seems to be causing this issue.