This patch tries to partially prevent speculative code motion for BPF.
First, some use cases on why we want to prevent speculative code motion.
Use case 1: bpf map value or some other data with a range.
data = bpf_map_lookup_elem(&map, &key); if (!data) return 0; payload = data->payload; len = bpf_probe_read_kernel_str(payload, 16, &task->comm); if (len <= 16) payload += len; ...
The compiler may generate code like:
data = bpf_map_lookup_elem(&map, &key); if (!data) return 0; payload = data->payload; len = bpf_probe_read_kernel_str(payload, 16, &task->comm); new_payload = payload + len; if (len > 16) new_payload = payload ...
The "payload + len" may cause kernel verifier failure as
the "len" can be anything at this moment.
Use case 2: CO-RE relocatons
field_exist = ... if (field_exist) { offset = non-memory-access-builtin-expr1; } else { offset = non-memory-access-builtin-expr2; } use "offset" to read kernel memory
The compiler may generate code like:
field_exist = ... offset = non-memory-access-builtin-expr1; if (!field_exist) offset = non-memory-access-builtin-expr2; use "offset" to read kernel memory
This may cause failures since if field_exist is false and
libbpf is not able to perform relation
for "offset = non-memory-access-builtin-expr1".
The instruction itself will be rewritten as
an illegal instruction and this will cause
program load failures.
To address the above issues, people use
. inline assembly . artificial complex control flow
to prevent the above optimizations.
This patch tries to do with a more user friendly way.
BPF backend TargetTransformInfo implements getUserCost()
to return UserCost INT_MAX for TCK_SizeAndLatency
to prevent compiler moving codes speculatively.
An option "adjustopt", false by default, is added to
enable this adjustment.