aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOvidiu Panait <ovidiu.panait@windriver.com>2018-04-02 15:18:29 +0300
committerBruce Ashfield <bruce.ashfield@windriver.com>2018-04-02 10:09:46 -0400
commite3c2247579b1387ce62e040d215270d9c82971c8 (patch)
tree51abdc4bced8fb1b46bbc4800c093c4ceb3af19b
parent23139524f3ee5d2d65366428b03cbff5541dcd34 (diff)
downloadlinux-yocto-4.8-standard/base.tar.gz
linux-yocto-4.8-standard/base.tar.bz2
linux-yocto-4.8-standard/base.zip
bpf/verifier: Fix states_equal() comparison of pointer and UNKNOWNstandard/base
commit 37435f7e80ef9adc32a69013c18f135e3f434244 upstream commit taken from: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/commit/?id=37435f7e80ef9adc32a69013c18f135e3f434244 An UNKNOWN_VALUE is not supposed to be derived from a pointer, unless pointer leaks are allowed. Therefore, states_equal() must not treat a state with a pointer in a register as "equal" to a state with an UNKNOWN_VALUE in that register. This was fixed differently upstream, but the code around here was largely rewritten in 4.14 by commit f1174f77b50c "bpf/verifier: rework value tracking". The bug can be detected by the bpf/verifier sub-test "pointer/scalar confusion in state equality check (way 1)". Signed-off-by: Ben Hutchings <ben@decadent.org.uk> Cc: Edward Cree <ecree@solarflare.com> Cc: Jann Horn <jannh@google.com> Cc: Alexei Starovoitov <ast@kernel.org> Cc: Daniel Borkmann <daniel@iogearbox.net> [OP: adjusted context for kernel version 4.8] Signed-off-by: Ovidiu Panait <ovidiu.panait@windriver.com> Signed-off-by: Bruce Ashfield <bruce.ashfield@windriver.com>
-rw-r--r--kernel/bpf/verifier.c17
1 files changed, 12 insertions, 5 deletions
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 48fe5d4da143..d2e228eeb733 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -706,12 +706,13 @@ static int check_ctx_access(struct verifier_env *env, int off, int size,
return -EACCES;
}
-static bool is_pointer_value(struct verifier_env *env, int regno)
+static bool __is_pointer_value(bool allow_ptr_leaks,
+ const struct reg_state *reg)
{
- if (env->allow_ptr_leaks)
+ if (allow_ptr_leaks)
return false;
- switch (env->cur_state.regs[regno].type) {
+ switch (reg->type) {
case UNKNOWN_VALUE:
case CONST_IMM:
return false;
@@ -720,6 +721,12 @@ static bool is_pointer_value(struct verifier_env *env, int regno)
}
}
+static bool is_pointer_value(struct verifier_env *env, int regno)
+{
+ return __is_pointer_value(env->allow_ptr_leaks, &env->cur_state.regs[regno]);
+}
+
+
static int check_ptr_alignment(struct verifier_env *env, struct reg_state *reg,
int off, int size)
{
@@ -2147,9 +2154,9 @@ static bool states_equal(struct verifier_state *old, struct verifier_state *cur)
if (memcmp(rold, rcur, sizeof(*rold)) == 0)
continue;
-
if (rold->type == NOT_INIT ||
- (rold->type == UNKNOWN_VALUE && rcur->type != NOT_INIT))
+ (rold->type == UNKNOWN_VALUE && rcur->type != NOT_INIT &&
+ !__is_pointer_value(capable(CAP_SYS_ADMIN), rcur)))
continue;
if (rold->type == PTR_TO_PACKET && rcur->type == PTR_TO_PACKET &&