summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEdward Cree <ecree@solarflare.com>2017-08-23 16:10:03 +0200
committerDavid S. Miller <davem@davemloft.net>2017-08-24 07:38:07 +0200
commit63f45f840634ab5fd71bbc07acff915277764068 (patch)
treecb362e59b70cfb3188d10329713764452009257e
parentselftests/bpf: add a test for a bug in liveness-based pruning (diff)
downloadlinux-63f45f840634ab5fd71bbc07acff915277764068.tar.xz
linux-63f45f840634ab5fd71bbc07acff915277764068.zip
bpf/verifier: when pruning a branch, ignore its write marks
The fact that writes occurred in reaching the continuation state does not screen off its reads from us, because we're not really its parent. So detect 'not really the parent' in do_propagate_liveness, and ignore write marks in that case. Fixes: dc503a8ad984 ("bpf/verifier: track liveness for pruning") Signed-off-by: Edward Cree <ecree@solarflare.com> Acked-by: Alexei Starovoitov <ast@kernel.org> Acked-by: Daniel Borkmann <daniel@iogearbox.net> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--kernel/bpf/verifier.c9
1 files changed, 7 insertions, 2 deletions
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index e42c096ba20d..fdbaa6086559 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -3436,6 +3436,7 @@ out_free:
static bool do_propagate_liveness(const struct bpf_verifier_state *state,
struct bpf_verifier_state *parent)
{
+ bool writes = parent == state->parent; /* Observe write marks */
bool touched = false; /* any changes made? */
int i;
@@ -3447,7 +3448,9 @@ static bool do_propagate_liveness(const struct bpf_verifier_state *state,
for (i = 0; i < BPF_REG_FP; i++) {
if (parent->regs[i].live & REG_LIVE_READ)
continue;
- if (state->regs[i].live == REG_LIVE_READ) {
+ if (writes && (state->regs[i].live & REG_LIVE_WRITTEN))
+ continue;
+ if (state->regs[i].live & REG_LIVE_READ) {
parent->regs[i].live |= REG_LIVE_READ;
touched = true;
}
@@ -3460,7 +3463,9 @@ static bool do_propagate_liveness(const struct bpf_verifier_state *state,
continue;
if (parent->spilled_regs[i].live & REG_LIVE_READ)
continue;
- if (state->spilled_regs[i].live == REG_LIVE_READ) {
+ if (writes && (state->spilled_regs[i].live & REG_LIVE_WRITTEN))
+ continue;
+ if (state->spilled_regs[i].live & REG_LIVE_READ) {
parent->spilled_regs[i].live |= REG_LIVE_READ;
touched = true;
}