History

bpf: Track verifier context diagnostic events

Record verifier context transitions in the diagnostic history so later reports can anchor causal paths to the critical section that made an operation invalid. This covers lock, IRQ, RCU, and preempt regions without adding any new verifier error reports. Category-specific commits decide where those recorded events should be rendered. Use context depth when selecting scoped history so nested regions anchor at the outer active region, and fall back to the earliest retained event when the matching entry was pruned.

Kumar Kartikeya Dwivedi committed 2 months ago

Commit 956a66e1 parent 9ecd7033 files · +74 −5Browse files

Showing the changes to kernel (3 of 3 files). Show all

Unified · Split

3 files
  1. kernel/bpf/diagnostics.c +39 −0
  2. kernel/bpf/diagnostics.h +12 −0
  3. kernel/bpf/verifier.c +23 −5
kernel/bpf/diagnostics.c+39−0
@@ -104,6 +104,7 @@ enum bpf_diag_history_kind { · 103 unmodified lines
104104 BPF_DIAG_HISTORY_MOD,
105105 BPF_DIAG_HISTORY_REF_ACQUIRE,
106106 BPF_DIAG_HISTORY_REF_RELEASE,
107+ BPF_DIAG_HISTORY_CONTEXT,
107108 };
108109
109110 struct bpf_diag_history_event {
@@ -124,6 +125,11 @@ struct bpf_diag_history_event { · 14 unmodified lines
124125 struct {
125126 u32 ref_id;
126127 } ref;
128+ struct {
129+ u32 depth;
130+ u8 kind;
131+ bool enter;
132+ } ctx;
127133 };
128134 };
129135
@@ -388,6 +394,19 @@ void bpf_diag_event_log_restore(struct bpf_verifier_env *env, u64 log_pos) · 258 unmodified lines
388394 log->cnt = log_pos - log->first_seq;
389395 }
390396
397+u32 bpf_diag_irq_depth(const struct bpf_verifier_state *state)
398+{
399+ u32 depth = 0;
400+ int i;
401+
402+ for (i = 0; i < state->acquired_refs; i++) {
403+ if (state->refs[i].type == REF_TYPE_IRQ)
404+ depth++;
405+ }
406+
407+ return depth;
408+}
409+
391410 static void diag_append_history(struct bpf_verifier_env *env,
392411 const struct bpf_diag_history_event *event)
393412 {
@@ -1049,3 +1068,23 @@ void bpf_diag_record_ref_release(struct bpf_verifier_env *env, u32 insn_idx, u32 · 655 unmodified lines
10491068 {
10501069 diag_record_ref(env, insn_idx, BPF_DIAG_HISTORY_REF_RELEASE, ref_id);
10511070 }
1071+
1072+void bpf_diag_record_context(struct bpf_verifier_env *env, u32 insn_idx,
1073+ enum bpf_diag_context_kind ctx_kind, bool enter, u32 depth)
1074+{
1075+ /*
1076+ * Keep leave events so context rendering can stop at a depth-zero exit
1077+ * and show nested-region depth accurately for the active path.
1078+ */
1079+ struct bpf_diag_history_event event = {
1080+ .insn_idx = insn_idx,
1081+ .kind = BPF_DIAG_HISTORY_CONTEXT,
1082+ .ctx = {
1083+ .kind = ctx_kind,
1084+ .enter = enter,
1085+ .depth = depth,
1086+ },
1087+ };
1088+
1089+ diag_append_history(env, &event);
1090+}
kernel/bpf/diagnostics.h+12−0
@@ -11,6 +11,7 @@ · 10 unmodified lines
1111 struct bpf_func_state;
1212 struct bpf_reg_state;
1313 struct bpf_verifier_env;
14+struct bpf_verifier_state;
1415 struct btf;
1516
1617 enum bpf_diag_mod_reason {
@@ -23,6 +24,14 @@ enum bpf_diag_mod_reason { · 6 unmodified lines
2324 BPF_DIAG_MOD_CALLER_SAVED,
2425 };
2526
27+enum bpf_diag_context_kind {
28+ BPF_DIAG_CONTEXT_NONE,
29+ BPF_DIAG_CONTEXT_RCU,
30+ BPF_DIAG_CONTEXT_PREEMPT,
31+ BPF_DIAG_CONTEXT_IRQ,
32+ BPF_DIAG_CONTEXT_LOCK,
33+};
34+
2635 bool bpf_diag_enabled(const struct bpf_verifier_env *env);
2736 int bpf_diag_init(struct bpf_verifier_env *env);
2837 void bpf_diag_init_frame(struct bpf_verifier_env *env, struct bpf_func_state *state);
@@ -33,6 +42,7 @@ const char *bpf_diag_fmt(struct bpf_verifier_env *env, const char *fmt, ...) __p · 4 unmodified lines
3342 const char *bpf_diag_fmt_btf_type(struct bpf_verifier_env *env, const struct btf *btf, u32 type_id);
3443 u64 bpf_diag_event_log_save(struct bpf_verifier_env *env);
3544 void bpf_diag_event_log_restore(struct bpf_verifier_env *env, u64 log_pos);
45+u32 bpf_diag_irq_depth(const struct bpf_verifier_state *state);
3646 void bpf_diag_free(struct bpf_verifier_env *env);
3747 void bpf_diag_record_branch(struct bpf_verifier_env *env, u32 insn_idx, bool cond_true);
3848 void bpf_diag_mod_begin(struct bpf_verifier_env *env, const struct bpf_reg_state *reg,
@@ -45,5 +55,7 @@ void bpf_diag_record_scrub_stack(struct bpf_verifier_env *env, · 6 unmodified lines
4555 enum bpf_diag_mod_reason reason);
4656 void bpf_diag_record_ref_acquire(struct bpf_verifier_env *env, u32 insn_idx, u32 ref_id);
4757 void bpf_diag_record_ref_release(struct bpf_verifier_env *env, u32 insn_idx, u32 ref_id);
58+void bpf_diag_record_context(struct bpf_verifier_env *env, u32 insn_idx,
59+ enum bpf_diag_context_kind ctx_kind, bool enter, u32 depth);
4860
4961 #endif /* __BPF_DIAGNOSTICS_H */
kernel/bpf/verifier.c+23−5
@@ -1045,7 +1045,7 @@ static int is_iter_reg_valid_init(struct bpf_verifier_env *env, struct bpf_reg_s · 1044 unmodified lines
10451045 }
10461046
10471047 static int acquire_irq_state(struct bpf_verifier_env *env, int insn_idx);
1048−static int release_irq_state(struct bpf_verifier_state *state, int id);
1048+static int release_irq_state(struct bpf_verifier_env *env, int id);
10491049
10501050 static int mark_stack_slot_irq_flag(struct bpf_verifier_env *env,
10511051 struct bpf_call_arg_meta *meta,
@@ -1104,7 +1104,7 @@ static int unmark_stack_slot_irq_flag(struct bpf_verifier_env *env, struct bpf_r · 52 unmodified lines
11041104 return -EINVAL;
11051105 }
11061106
1107− err = release_irq_state(env->cur_state, st->id);
1107+ err = release_irq_state(env, st->id);
11081108 WARN_ON_ONCE(err && err != -EACCES);
11091109 if (err) {
11101110 int insn_idx = 0;
@@ -1439,6 +1439,8 @@ static int acquire_lock_state(struct bpf_verifier_env *env, int insn_idx, enum r · 328 unmodified lines
14391439 state->active_locks++;
14401440 state->active_lock_id = id;
14411441 state->active_lock_ptr = ptr;
1442+ bpf_diag_record_context(env, insn_idx, BPF_DIAG_CONTEXT_LOCK, true,
1443+ state->active_locks);
14421444 return 0;
14431445 }
14441446
@@ -1454,6 +1456,8 @@ static int acquire_irq_state(struct bpf_verifier_env *env, int insn_idx) · 9 unmodified lines
14541456 s->id = ++env->id_gen;
14551457
14561458 state->active_irq_id = s->id;
1459+ bpf_diag_record_context(env, insn_idx, BPF_DIAG_CONTEXT_IRQ, true,
1460+ bpf_diag_irq_depth(state));
14571461 return s->id;
14581462 }
14591463
@@ -1495,8 +1499,9 @@ static bool reg_is_referenced(struct bpf_verifier_env *env, const struct bpf_reg · 35 unmodified lines
14951499 return find_reference_state(env->cur_state, reg->id);
14961500 }
14971501
1498−static int release_lock_state(struct bpf_verifier_state *state, int type, int id, void *ptr)
1502+static int release_lock_state(struct bpf_verifier_env *env, int type, int id, void *ptr)
14991503 {
1504+ struct bpf_verifier_state *state = env->cur_state;
15001505 void *prev_ptr = NULL;
15011506 u32 prev_id = 0;
15021507 int i;
@@ -1509,6 +1514,8 @@ static int release_lock_state(struct bpf_verifier_state *state, int type, int id · 6 unmodified lines
15091514 /* Reassign active lock (id, ptr). */
15101515 state->active_lock_id = prev_id;
15111516 state->active_lock_ptr = prev_ptr;
1517+ bpf_diag_record_context(env, env->insn_idx, BPF_DIAG_CONTEXT_LOCK,
1518+ false, state->active_locks);
15121519 return 0;
15131520 }
15141521 if (state->refs[i].type & REF_TYPE_LOCK_MASK) {
@@ -1519,8 +1526,9 @@ static int release_lock_state(struct bpf_verifier_state *state, int type, int id · 4 unmodified lines
15191526 return -EINVAL;
15201527 }
15211528
1522−static int release_irq_state(struct bpf_verifier_state *state, int id)
1529+static int release_irq_state(struct bpf_verifier_env *env, int id)
15231530 {
1531+ struct bpf_verifier_state *state = env->cur_state;
15241532 u32 prev_id = 0;
15251533 int i;
15261534
@@ -1533,6 +1541,8 @@ static int release_irq_state(struct bpf_verifier_state *state, int id) · 6 unmodified lines
15331541 if (state->refs[i].id == id) {
15341542 release_reference_state(state, i);
15351543 state->active_irq_id = prev_id;
1544+ bpf_diag_record_context(env, env->insn_idx, BPF_DIAG_CONTEXT_IRQ,
1545+ false, bpf_diag_irq_depth(state));
15361546 return 0;
15371547 } else {
15381548 prev_id = state->refs[i].id;
@@ -7181,7 +7191,7 @@ static int process_spin_lock(struct bpf_verifier_env *env, struct bpf_reg_state · 5642 unmodified lines
71817191 verbose(env, "%s_unlock cannot be out of order\n", lock_str);
71827192 return -EINVAL;
71837193 }
7184− if (release_lock_state(cur, type, reg->id, ptr)) {
7194+ if (release_lock_state(env, type, reg->id, ptr)) {
71857195 verbose(env, "%s_unlock of different lock\n", lock_str);
71867196 return -EINVAL;
71877197 }
@@ -13242,22 +13252,30 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn, · 6054 unmodified lines
1324213252
1324313253 if (rcu_lock) {
1324413254 env->cur_state->active_rcu_locks++;
13255+ bpf_diag_record_context(env, insn_idx, BPF_DIAG_CONTEXT_RCU, true,
13256+ env->cur_state->active_rcu_locks);
1324513257 } else if (rcu_unlock) {
1324613258 if (env->cur_state->active_rcu_locks == 0) {
1324713259 verbose(env, "unmatched rcu read unlock (kernel function %s)\n", func_name);
1324813260 return -EINVAL;
1324913261 }
1325013262 env->cur_state->active_rcu_locks--;
13263+ bpf_diag_record_context(env, insn_idx, BPF_DIAG_CONTEXT_RCU, false,
13264+ env->cur_state->active_rcu_locks);
1325113265 if (!in_rcu_cs(env))
1325213266 invalidate_rcu_protected_refs(env);
1325313267 } else if (preempt_disable) {
1325413268 env->cur_state->active_preempt_locks++;
13269+ bpf_diag_record_context(env, insn_idx, BPF_DIAG_CONTEXT_PREEMPT, true,
13270+ env->cur_state->active_preempt_locks);
1325513271 } else if (preempt_enable) {
1325613272 if (env->cur_state->active_preempt_locks == 0) {
1325713273 verbose(env, "unmatched attempt to enable preemption (kernel function %s)\n", func_name);
1325813274 return -EINVAL;
1325913275 }
1326013276 env->cur_state->active_preempt_locks--;
13277+ bpf_diag_record_context(env, insn_idx, BPF_DIAG_CONTEXT_PREEMPT, false,
13278+ env->cur_state->active_preempt_locks);
1326113279 if (!in_rcu_cs(env))
1326213280 invalidate_rcu_protected_refs(env);
1326313281 }