Skip to content

Commit b3698c3

Browse files
eddyz87Alexei Starovoitov
authored andcommitted
bpf: callchain sensitive stack liveness tracking using CFG
This commit adds a flow-sensitive, context-sensitive, path-insensitive data flow analysis for live stack slots: - flow-sensitive: uses program control flow graph to compute data flow values; - context-sensitive: collects data flow values for each possible call chain in a program; - path-insensitive: does not distinguish between separate control flow graph paths reaching the same instruction. Compared to the current path-sensitive analysis, this approach trades some precision for not having to enumerate every path in the program. This gives a theoretical capability to run the analysis before main verification pass. See cover letter for motivation. The basic idea is as follows: - Data flow values indicate stack slots that might be read and stack slots that are definitely written. - Data flow values are collected for each (call chain, instruction number) combination in the program. - Within a subprogram, data flow values are propagated using control flow graph. - Data flow values are transferred from entry instructions of callee subprograms to call sites in caller subprograms. In other words, a tree of all possible call chains is constructed. Each node of this tree represents a subprogram. Read and write marks are collected for each instruction of each node. Live stack slots are first computed for lower level nodes. Then, information about outer stack slots that might be read or are definitely written by a subprogram is propagated one level up, to the corresponding call instructions of the upper nodes. Procedure repeats until root node is processed. In the absence of value range analysis, stack read/write marks are collected during main verification pass, and data flow computation is triggered each time verifier.c:states_equal() needs to query the information. Implementation details are documented in kernel/bpf/liveness.c. Quantitative data about verification performance changes and memory consumption is in the cover letter. Signed-off-by: Eduard Zingerman <eddyz87@gmail.com> Link: https://lore.kernel.org/r/20250918-callchain-sensitive-liveness-v3-6-c3cd27bacc60@gmail.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
1 parent efcda22 commit b3698c3

File tree

3 files changed

+692
-1
lines changed

3 files changed

+692
-1
lines changed

include/linux/bpf_verifier.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,8 @@ struct bpf_scc_info {
745745
struct bpf_scc_visit visits[];
746746
};
747747

748+
struct bpf_liveness;
749+
748750
/* single container for all structs
749751
* one verifier_env per bpf_check() call
750752
*/
@@ -846,6 +848,7 @@ struct bpf_verifier_env {
846848
struct bpf_insn insn_buf[INSN_BUF_SIZE];
847849
struct bpf_insn epilogue_buf[INSN_BUF_SIZE];
848850
struct bpf_scc_callchain callchain_buf;
851+
struct bpf_liveness *liveness;
849852
/* array of pointers to bpf_scc_info indexed by SCC id */
850853
struct bpf_scc_info **scc_info;
851854
u32 scc_cnt;
@@ -1074,4 +1077,15 @@ int bpf_insn_successors(struct bpf_prog *prog, u32 idx, u32 succ[2]);
10741077
void bpf_fmt_stack_mask(char *buf, ssize_t buf_sz, u64 stack_mask);
10751078
bool bpf_calls_callback(struct bpf_verifier_env *env, int insn_idx);
10761079

1080+
int bpf_stack_liveness_init(struct bpf_verifier_env *env);
1081+
void bpf_stack_liveness_free(struct bpf_verifier_env *env);
1082+
int bpf_update_live_stack(struct bpf_verifier_env *env);
1083+
int bpf_mark_stack_read(struct bpf_verifier_env *env, u32 frameno, u32 insn_idx, u64 mask);
1084+
void bpf_mark_stack_write(struct bpf_verifier_env *env, u32 frameno, u64 mask);
1085+
int bpf_reset_stack_write_marks(struct bpf_verifier_env *env, u32 insn_idx);
1086+
int bpf_commit_stack_write_marks(struct bpf_verifier_env *env);
1087+
int bpf_live_stack_query_init(struct bpf_verifier_env *env, struct bpf_verifier_state *st);
1088+
bool bpf_stack_slot_alive(struct bpf_verifier_env *env, u32 frameno, u32 spi);
1089+
void bpf_reset_live_stack_callchain(struct bpf_verifier_env *env);
1090+
10771091
#endif /* _LINUX_BPF_VERIFIER_H */

kernel/bpf/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ cflags-nogcse-$(CONFIG_X86)$(CONFIG_CC_IS_GCC) := -fno-gcse
66
endif
77
CFLAGS_core.o += -Wno-override-init $(cflags-nogcse-yy)
88

9-
obj-$(CONFIG_BPF_SYSCALL) += syscall.o verifier.o inode.o helpers.o tnum.o log.o token.o
9+
obj-$(CONFIG_BPF_SYSCALL) += syscall.o verifier.o inode.o helpers.o tnum.o log.o token.o liveness.o
1010
obj-$(CONFIG_BPF_SYSCALL) += bpf_iter.o map_iter.o task_iter.o prog_iter.o link_iter.o
1111
obj-$(CONFIG_BPF_SYSCALL) += hashtab.o arraymap.o percpu_freelist.o bpf_lru_list.o lpm_trie.o map_in_map.o bloom_filter.o
1212
obj-$(CONFIG_BPF_SYSCALL) += local_storage.o queue_stack_maps.o ringbuf.o

0 commit comments

Comments
 (0)