aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexei Starovoitov <ast@fb.com>2017-10-05 19:20:56 -0400
committerDavid S. Miller <davem@davemloft.net>2017-10-07 18:25:17 -0400
commit8fe2d6ccd52b086268f2f36e5e2fc0fe3aeffa80 (patch)
tree66dd8b086aefb8cdf320ef53b5a6d98540fa6f9f
parent00a534e5ea5c21b95f58cbb2f7918cc9fa82dd47 (diff)
bpf: fix liveness marking
while processing Rx = Ry instruction the verifier does regs[insn->dst_reg] = regs[insn->src_reg] which often clears write mark (when Ry doesn't have it) that was just set by check_reg_arg(Rx) prior to the assignment. That causes mark_reg_read() to keep marking Rx in this block as REG_LIVE_READ (since the logic incorrectly misses that it's screened by the write) and in many of its parents (until lucky write into the same Rx or beginning of the program). That causes is_state_visited() logic to miss many pruning opportunities. Furthermore mark_reg_read() logic propagates the read mark for BPF_REG_FP as well (though it's readonly) which causes harmless but unnecssary work during is_state_visited(). Note that do_propagate_liveness() skips FP correctly, so do the same in mark_reg_read() as well. It saves 0.2 seconds for the test below program before after bpf_lb-DLB_L3.o 2604 2304 bpf_lb-DLB_L4.o 11159 3723 bpf_lb-DUNKNOWN.o 1116 1110 bpf_lxc-DDROP_ALL.o 34566 28004 bpf_lxc-DUNKNOWN.o 53267 39026 bpf_netdev.o 17843 16943 bpf_overlay.o 8672 7929 time ~11 sec ~4 sec Fixes: dc503a8ad984 ("bpf/verifier: track liveness for pruning") Signed-off-by: Alexei Starovoitov <ast@kernel.org> Acked-by: Edward Cree <ecree@solarflare.com> Acked-by: Daniel Borkmann <daniel@iogearbox.net> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--kernel/bpf/verifier.c5
1 files changed, 5 insertions, 0 deletions
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index b914fbe1383e..8b8d6ba39e23 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -653,6 +653,10 @@ static void mark_reg_read(const struct bpf_verifier_state *state, u32 regno)
653{ 653{
654 struct bpf_verifier_state *parent = state->parent; 654 struct bpf_verifier_state *parent = state->parent;
655 655
656 if (regno == BPF_REG_FP)
657 /* We don't need to worry about FP liveness because it's read-only */
658 return;
659
656 while (parent) { 660 while (parent) {
657 /* if read wasn't screened by an earlier write ... */ 661 /* if read wasn't screened by an earlier write ... */
658 if (state->regs[regno].live & REG_LIVE_WRITTEN) 662 if (state->regs[regno].live & REG_LIVE_WRITTEN)
@@ -2345,6 +2349,7 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)
2345 * copy register state to dest reg 2349 * copy register state to dest reg
2346 */ 2350 */
2347 regs[insn->dst_reg] = regs[insn->src_reg]; 2351 regs[insn->dst_reg] = regs[insn->src_reg];
2352 regs[insn->dst_reg].live |= REG_LIVE_WRITTEN;
2348 } else { 2353 } else {
2349 /* R1 = (u32) R2 */ 2354 /* R1 = (u32) R2 */
2350 if (is_pointer_value(env, insn->src_reg)) { 2355 if (is_pointer_value(env, insn->src_reg)) {