aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJakub Kicinski <jakub.kicinski@netronome.com>2019-03-21 17:34:36 -0400
committerAlexei Starovoitov <ast@kernel.org>2019-03-21 22:57:02 -0400
commit83d163124cf1104cca5b668d5fe6325715a60855 (patch)
tree0efb88a71d45a495137c28f26eb94575bf28ff2c
parent0803278b0b4d8eeb2b461fb698785df65a725d9e (diff)
bpf: verifier: propagate liveness on all frames
Commit 7640ead93924 ("bpf: verifier: make sure callees don't prune with caller differences") connected up parentage chains of all frames of the stack. It didn't, however, ensure propagate_liveness() propagates all liveness information along those chains. This means pruning happening in the callee may generate explored states with incomplete liveness for the chains in lower frames of the stack. The included selftest is similar to the prior one from commit 7640ead93924 ("bpf: verifier: make sure callees don't prune with caller differences"), where callee would prune regardless of the difference in r8 state. Now we also initialize r9 to 0 or 1 based on a result from get_random(). r9 is never read so the walk with r9 = 0 gets pruned (correctly) after the walk with r9 = 1 completes. The selftest is so arranged that the pruning will happen in the callee. Since callee does not propagate read marks of r8, the explored state at the pruning point prior to the callee will now ignore r8. Propagate liveness on all frames of the stack when pruning. Fixes: f4d7e40a5b71 ("bpf: introduce function calls (verification)") Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
-rw-r--r--kernel/bpf/verifier.c20
-rw-r--r--tools/testing/selftests/bpf/verifier/calls.c25
2 files changed, 36 insertions, 9 deletions
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index f19d5e04c69d..fd502c1f71eb 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -6078,15 +6078,17 @@ static int propagate_liveness(struct bpf_verifier_env *env,
6078 } 6078 }
6079 /* Propagate read liveness of registers... */ 6079 /* Propagate read liveness of registers... */
6080 BUILD_BUG_ON(BPF_REG_FP + 1 != MAX_BPF_REG); 6080 BUILD_BUG_ON(BPF_REG_FP + 1 != MAX_BPF_REG);
6081 /* We don't need to worry about FP liveness because it's read-only */ 6081 for (frame = 0; frame <= vstate->curframe; frame++) {
6082 for (i = 0; i < BPF_REG_FP; i++) { 6082 /* We don't need to worry about FP liveness, it's read-only */
6083 if (vparent->frame[vparent->curframe]->regs[i].live & REG_LIVE_READ) 6083 for (i = frame < vstate->curframe ? BPF_REG_6 : 0; i < BPF_REG_FP; i++) {
6084 continue; 6084 if (vparent->frame[frame]->regs[i].live & REG_LIVE_READ)
6085 if (vstate->frame[vstate->curframe]->regs[i].live & REG_LIVE_READ) { 6085 continue;
6086 err = mark_reg_read(env, &vstate->frame[vstate->curframe]->regs[i], 6086 if (vstate->frame[frame]->regs[i].live & REG_LIVE_READ) {
6087 &vparent->frame[vstate->curframe]->regs[i]); 6087 err = mark_reg_read(env, &vstate->frame[frame]->regs[i],
6088 if (err) 6088 &vparent->frame[frame]->regs[i]);
6089 return err; 6089 if (err)
6090 return err;
6091 }
6090 } 6092 }
6091 } 6093 }
6092 6094
diff --git a/tools/testing/selftests/bpf/verifier/calls.c b/tools/testing/selftests/bpf/verifier/calls.c
index 4004891afa9c..f2ccae39ee66 100644
--- a/tools/testing/selftests/bpf/verifier/calls.c
+++ b/tools/testing/selftests/bpf/verifier/calls.c
@@ -1940,3 +1940,28 @@
1940 .errstr = "!read_ok", 1940 .errstr = "!read_ok",
1941 .result = REJECT, 1941 .result = REJECT,
1942}, 1942},
1943{
1944 "calls: cross frame pruning - liveness propagation",
1945 .insns = {
1946 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_prandom_u32),
1947 BPF_MOV64_IMM(BPF_REG_8, 0),
1948 BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
1949 BPF_MOV64_IMM(BPF_REG_8, 1),
1950 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_prandom_u32),
1951 BPF_MOV64_IMM(BPF_REG_9, 0),
1952 BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
1953 BPF_MOV64_IMM(BPF_REG_9, 1),
1954 BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
1955 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 4),
1956 BPF_JMP_IMM(BPF_JEQ, BPF_REG_8, 1, 1),
1957 BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_2, 0),
1958 BPF_MOV64_IMM(BPF_REG_0, 0),
1959 BPF_EXIT_INSN(),
1960 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 0),
1961 BPF_EXIT_INSN(),
1962 },
1963 .prog_type = BPF_PROG_TYPE_SOCKET_FILTER,
1964 .errstr_unpriv = "function calls to other bpf functions are allowed for root only",
1965 .errstr = "!read_ok",
1966 .result = REJECT,
1967},