summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorEduard Zingerman <eddyz87@gmail.com>2026-10-09 03:47:23 -0700
committerAlexei Starovoitov <ast@kernel.org>2026-10-09 20:29:12 +0000
commit0360ed8655cfe4ed25d5feb46c7f31addc59e63a (patch)
treed01017d6fe704e1c6dd1afc92bcc39f33adc4128 /kernel
parentac43e0393f44931bd2d84ab682e78b1f08f9f1ec (diff)
bpf: Summarize may write stack slots in insn_aux_data
SCEV needs may-write information to invalidate stack expressions after indirect writes. Liveness tracks this per function instance, but SCEV is not callchain-sensitive and needs a summary across calling contexts. For each instruction, union the current-frame may_write masks from all analyzed instances. Represent 8-byte slots as a summary of constituent halves. Store the summary in insn_aux_data and expose it via a helper. Signed-off-by: Eduard Zingerman <eddyz87@gmail.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Link: https://patch.msgid.link/20261009-scev-minimal-rebase-v3-5-bcba9bc53ac9@gmail.com
Diffstat (limited to 'kernel')
-rw-r--r--kernel/bpf/liveness.c41
1 files changed, 41 insertions, 0 deletions
diff --git a/kernel/bpf/liveness.c b/kernel/bpf/liveness.c
index e18d5d86c301..ec9c8beef556 100644
--- a/kernel/bpf/liveness.c
+++ b/kernel/bpf/liveness.c
@@ -718,6 +718,45 @@ static int cmp_instances(const void *pa, const void *pb)
return 0;
}
+/* OR the 8-byte slots touched by a half-slot (4-byte) mask into @slots. */
+static void half_spis_to_slots(unsigned long *slots, const unsigned long *mask, u32 nbits)
+{
+ u32 slot;
+
+ for (slot = 0; slot < MAX_BPF_STACK_SLOTS && slot * 2 + 1 < nbits; slot++)
+ if (test_bit(slot * 2, mask) || test_bit(slot * 2 + 1, mask))
+ __set_bit(slot, slots);
+}
+
+/*
+ * Precompute, for each instruction, the OR of may_write masks over its top
+ * frame across all func_instances reaching it, stash it in the insn_aux_data.
+ */
+static void compute_may_write_masks(struct bpf_verifier_env *env)
+{
+ struct bpf_insn_aux_data *aux = env->insn_aux_data;
+ struct bpf_liveness *liveness = env->liveness;
+ struct func_instance *instance;
+ struct frame_masks *fm;
+ u32 nbits;
+ int bkt, i;
+
+ hash_for_each(liveness->func_instances, bkt, instance, hl_node) {
+ fm = instance->frames[instance->depth];
+ if (!fm)
+ continue;
+ nbits = frame_mask_bits(fm);
+ for (i = 0; i < instance->insn_cnt; i++)
+ half_spis_to_slots(aux[instance->subprog_start + i].may_write_mask,
+ rel_mask(fm, i, FM_MAY_WRITE), nbits);
+ }
+}
+
+const unsigned long *bpf_may_write_mask(struct bpf_verifier_env *env, u32 insn_idx)
+{
+ return env->insn_aux_data[insn_idx].may_write_mask;
+}
+
/* print use/def slots for all instances ordered by callsite first, then by depth */
static int print_instances(struct bpf_verifier_env *env)
{
@@ -2352,6 +2391,8 @@ int bpf_compute_subprog_arg_access(struct bpf_verifier_env *env)
goto out;
}
+ compute_may_write_masks(env);
+
if (env->log.level & BPF_LOG_LEVEL2)
err = print_instances(env);