Skip to content

Commit c8e2ee1

Browse files
kkdwivediAlexei Starovoitov
authored andcommitted
bpf: Introduce support for bpf_local_irq_{save,restore}
Teach the verifier about IRQ-disabled sections through the introduction of two new kfuncs, bpf_local_irq_save, to save IRQ state and disable them, and bpf_local_irq_restore, to restore IRQ state and enable them back again. For the purposes of tracking the saved IRQ state, the verifier is taught about a new special object on the stack of type STACK_IRQ_FLAG. This is a 8 byte value which saves the IRQ flags which are to be passed back to the IRQ restore kfunc. Renumber the enums for REF_TYPE_* to simplify the check in find_lock_state, filtering out non-lock types as they grow will become cumbersome and is unecessary. To track a dynamic number of IRQ-disabled regions and their associated saved states, a new resource type RES_TYPE_IRQ is introduced, which its state management functions: acquire_irq_state and release_irq_state, taking advantage of the refactoring and clean ups made in earlier commits. One notable requirement of the kernel's IRQ save and restore API is that they cannot happen out of order. For this purpose, when releasing reference we keep track of the prev_id we saw with REF_TYPE_IRQ. Since reference states are inserted in increasing order of the index, this is used to remember the ordering of acquisitions of IRQ saved states, so that we maintain a logical stack in acquisition order of resource identities, and can enforce LIFO ordering when restoring IRQ state. The top of the stack is maintained using bpf_verifier_state's active_irq_id. To maintain the stack property when releasing reference states, we need to modify release_reference_state to instead shift the remaining array left using memmove instead of swapping deleted element with last that might break the ordering. A selftest to test this subtle behavior is added in late patches. The logic to detect initialized and unitialized irq flag slots, marking and unmarking is similar to how it's done for iterators. No additional checks are needed in refsafe for REF_TYPE_IRQ, apart from the usual check_id satisfiability check on the ref[i].id. We have to perform the same check_ids check on state->active_irq_id as well. To ensure we don't get assigned REF_TYPE_PTR by default after acquire_reference_state, if someone forgets to assign the type, let's also renumber the enum ref_state_type. This way any unassigned types get caught by refsafe's default switch statement, don't assume REF_TYPE_PTR by default. The kfuncs themselves are plain wrappers over local_irq_save and local_irq_restore macros. Acked-by: Eduard Zingerman <[email protected]> Signed-off-by: Kumar Kartikeya Dwivedi <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent b79f5f5 commit c8e2ee1

File tree

4 files changed

+320
-4
lines changed

4 files changed

+320
-4
lines changed

include/linux/bpf_verifier.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ enum bpf_stack_slot_type {
233233
*/
234234
STACK_DYNPTR,
235235
STACK_ITER,
236+
STACK_IRQ_FLAG,
236237
};
237238

238239
#define BPF_REG_SIZE 8 /* size of eBPF register in bytes */
@@ -254,8 +255,9 @@ struct bpf_reference_state {
254255
* default to pointer reference on zero initialization of a state.
255256
*/
256257
enum ref_state_type {
257-
REF_TYPE_PTR = 0,
258-
REF_TYPE_LOCK,
258+
REF_TYPE_PTR = 1,
259+
REF_TYPE_IRQ = 2,
260+
REF_TYPE_LOCK = 3,
259261
} type;
260262
/* Track each reference created with a unique id, even if the same
261263
* instruction creates the reference multiple times (eg, via CALL).
@@ -421,6 +423,7 @@ struct bpf_verifier_state {
421423
u32 acquired_refs;
422424
u32 active_locks;
423425
u32 active_preempt_locks;
426+
u32 active_irq_id;
424427
bool active_rcu_lock;
425428

426429
bool speculative;

kernel/bpf/helpers.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3057,6 +3057,21 @@ __bpf_kfunc int bpf_copy_from_user_str(void *dst, u32 dst__sz, const void __user
30573057
return ret + 1;
30583058
}
30593059

3060+
/* Keep unsinged long in prototype so that kfunc is usable when emitted to
3061+
* vmlinux.h in BPF programs directly, but note that while in BPF prog, the
3062+
* unsigned long always points to 8-byte region on stack, the kernel may only
3063+
* read and write the 4-bytes on 32-bit.
3064+
*/
3065+
__bpf_kfunc void bpf_local_irq_save(unsigned long *flags__irq_flag)
3066+
{
3067+
local_irq_save(*flags__irq_flag);
3068+
}
3069+
3070+
__bpf_kfunc void bpf_local_irq_restore(unsigned long *flags__irq_flag)
3071+
{
3072+
local_irq_restore(*flags__irq_flag);
3073+
}
3074+
30603075
__bpf_kfunc_end_defs();
30613076

30623077
BTF_KFUNCS_START(generic_btf_ids)
@@ -3149,6 +3164,8 @@ BTF_ID_FLAGS(func, bpf_get_kmem_cache)
31493164
BTF_ID_FLAGS(func, bpf_iter_kmem_cache_new, KF_ITER_NEW | KF_SLEEPABLE)
31503165
BTF_ID_FLAGS(func, bpf_iter_kmem_cache_next, KF_ITER_NEXT | KF_RET_NULL | KF_SLEEPABLE)
31513166
BTF_ID_FLAGS(func, bpf_iter_kmem_cache_destroy, KF_ITER_DESTROY | KF_SLEEPABLE)
3167+
BTF_ID_FLAGS(func, bpf_local_irq_save)
3168+
BTF_ID_FLAGS(func, bpf_local_irq_restore)
31523169
BTF_KFUNCS_END(common_btf_ids)
31533170

31543171
static const struct btf_kfunc_id_set common_kfunc_set = {

kernel/bpf/log.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,7 @@ static char slot_type_char[] = {
537537
[STACK_ZERO] = '0',
538538
[STACK_DYNPTR] = 'd',
539539
[STACK_ITER] = 'i',
540+
[STACK_IRQ_FLAG] = 'f'
540541
};
541542

542543
static void print_liveness(struct bpf_verifier_env *env,

0 commit comments

Comments
 (0)