Add kfunc/helper <-> program type exceptions#252
Conversation
The helper-ref-gen tool reads a data file which models the C methods used to implement which helpers are allowed for which program types. However, the verifier sometimes also adds exceptions outside of this model, directly in the verifier logic, instead of on the ops of program type definitions. For the user this effectively means the same but for us to model it, we have to be able to exclude certain helpers from program types, even if a helper was included before via a group. Signed-off-by: Dylan Reimerink <dylan.reimerink@isovalent.com>
31b81ec to
481758a
Compare
The verifier asserts that in tracing programs (kprobe, tracepoint, raw_tracepoint, raw_tracepoint_writable, perf_event) you cannot have a map with `struct bpf_res_spin_lock`. When it detects such a map exists, it raises an error as if the helpers are blocked. This nuance can now be modeled by our tooling. So lets update the the data file to match reality so the reference lists are accurate. Co-authored-by: AliGhaffarian <alighaffarian9@gmail.com> Signed-off-by: Dylan Reimerink <dylan.reimerink@isovalent.com>
The verifier has logic that excludes certain kfuncs in addition to the normal kfunc <-> program type mapping. This change allows us to specify these exceptions on a per-kfunc basis in the kfunc data file. Signed-off-by: Dylan Reimerink <dylan.reimerink@isovalent.com>
The verifier applies additional restrictions on certain kfuncs when used in combination with specific program types. This commit adds exclusions so the reference lists are accurate. Co-authored-by: AliGhaffarian <alighaffarian9@gmail.com> Signed-off-by: Dylan Reimerink <dylan.reimerink@isovalent.com>
The verifier restricts the use of bpf_timer_* helper functions in certain program types, on top of the normal program type <-> helper function mappings. This commit adds these exceptions to the documentation. Signed-off-by: Dylan Reimerink <dylan.reimerink@isovalent.com>
481758a to
ccb239c
Compare
|
@AliGhaffarian please check if this matches what you had in mind |
| * [`BPF_PROG_TYPE_SOCK_OPS`](../program-type/BPF_PROG_TYPE_SOCK_OPS.md) | ||
| * [`BPF_PROG_TYPE_STRUCT_OPS`](../program-type/BPF_PROG_TYPE_STRUCT_OPS.md) | ||
| * [`BPF_PROG_TYPE_SYSCALL`](../program-type/BPF_PROG_TYPE_SYSCALL.md) | ||
| * [`BPF_PROG_TYPE_TRACING`](../program-type/BPF_PROG_TYPE_TRACING.md) |
There was a problem hiding this comment.
Can we exclude program types from helper functions too?
Currently, BPF_PROG_TYPE_TRACING is still in the bpf_spin_lock.md.
Or instead of having a exclude field for functions themselves, maybe can go through each helper function and for each one, check which program types have the current helper function excluded, this will remove the need to have exclusion for both program types and functions in the data file.
This approach looks something like this
for helper_function in helper_funcs:
exclusions = []
for prog_type in prog_types:
if helper_function in prog_type.exclusions:
exclusions.append(prog_type)I can put the time to implement it, using your patches as reference. it would take some time as i'm not very familiar with golang though.
There was a problem hiding this comment.
Currently,
BPF_PROG_TYPE_TRACINGis still in the bpf_spin_lock.md
Yes. But oddly enough BPF_PROG_TYPE_TRACING is not considered a tracing program according to is_tracing_prog_type and so would be allowed as far as I can see? Unless there is yet another bit of logic somewhere that blocks it.
I have not yet tried using spinlocks in fentry/fexit programs yet to see what happens.
There was a problem hiding this comment.
Just tried it, seems like you can.
#include "vmlinux.h"
#include "bpf_helpers.h"
#include "bpf_tracing.h"
struct data
{
int data;
struct bpf_spin_lock lock;
};
struct
{
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 1024);
__type(key, __u32);
__type(value, struct data);
} test_map SEC(".maps");
SEC("fentry/security_inode_getattr")
int BPF_PROG(d_path_check_rdonly_mem, struct path *path, struct kstat *stat,
__u32 request_mask, unsigned int query_flags)
{
__u32 zero = 0;
struct data *elem = bpf_map_lookup_elem(&test_map, &zero);
if (!elem)
return 0;
bpf_spin_lock(&elem->lock);
bpf_spin_unlock(&elem->lock);
return 0;
}
char __license[] SEC("license") = "GPL";
$ sudo bpftool prog show id 17592
17592: tracing name d_path_check_rdonly_mem tag 7e7ebeefb37c74d9 gpl
loaded_at 2026-02-05T10:41:41+0100 uid 0
xlated 144B jited 89B memlock 4096B map_ids 4639
btf_id 12836
$ sudo bpftool prog dump xlated id 17592
int d_path_check_rdonly_mem(unsigned long long * ctx):
; int BPF_PROG(d_path_check_rdonly_mem, struct path *path, struct kstat *stat,
0: (b7) r1 = 0
; __u32 zero = 0;
1: (63) *(u32 *)(r10 -4) = r1
2: (bf) r2 = r10
;
3: (07) r2 += -4
; struct data *elem = bpf_map_lookup_elem(&test_map, &zero);
4: (18) r1 = map[id:4639]
6: (85) call __htab_map_lookup_elem#294448
7: (15) if r0 == 0x0 goto pc+1
8: (07) r0 += 56
9: (bf) r6 = r0
; if (!elem)
10: (15) if r6 == 0x0 goto pc+5
; bpf_spin_lock(&elem->lock);
11: (07) r6 += 4
; bpf_spin_lock(&elem->lock);
12: (bf) r1 = r6
13: (85) call bpf_spin_lock#253520
; bpf_spin_unlock(&elem->lock);
14: (bf) r1 = r6
15: (85) call bpf_spin_unlock#256064
; int BPF_PROG(d_path_check_rdonly_mem, struct path *path, struct kstat *stat,
16: (b7) r0 = 0
17: (95) exit
$ uname -srv
Linux 6.8.0-52-generic #53~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Wed Jan 15 19:18:46 UTC 2
There was a problem hiding this comment.
Yes. But oddly enough
BPF_PROG_TYPE_TRACINGis not considered a tracing program according tois_tracing_prog_typeand so would be allowed as far as I can see
Oh, that was a misunderstanding on my part, guess they had a hard time naming things.
There was a problem hiding this comment.
There are 2 hard problems in computer science: cache invalidation, naming things, and off-by-1 errors
😄
My suggestion was more complex, it would need to port parts of |
For both helper functions and kfuncs we try to model the kernels approach of which functions can be used from which program types. Usually you start with no functions allowed and gradually add more. However, the verifier can also implement logic to effectively block the usage of helpers / kfuncs for certain program types. This PR add notation to our data files so we can model this same sort of exception on top of the normal mapping and applies this to all cases defined in check_map_prog_compatibility