aboutsummaryrefslogtreecommitdiffstats
path: root/common/recipes-kernel/linux/linux-yocto-4.9.21/0094-bpf-fix-mixed-signed-unsigned-derived-min-max-value-.patch
diff options
context:
space:
mode:
Diffstat (limited to 'common/recipes-kernel/linux/linux-yocto-4.9.21/0094-bpf-fix-mixed-signed-unsigned-derived-min-max-value-.patch')
-rw-r--r--common/recipes-kernel/linux/linux-yocto-4.9.21/0094-bpf-fix-mixed-signed-unsigned-derived-min-max-value-.patch463
1 files changed, 0 insertions, 463 deletions
diff --git a/common/recipes-kernel/linux/linux-yocto-4.9.21/0094-bpf-fix-mixed-signed-unsigned-derived-min-max-value-.patch b/common/recipes-kernel/linux/linux-yocto-4.9.21/0094-bpf-fix-mixed-signed-unsigned-derived-min-max-value-.patch
deleted file mode 100644
index 8b9aea64..00000000
--- a/common/recipes-kernel/linux/linux-yocto-4.9.21/0094-bpf-fix-mixed-signed-unsigned-derived-min-max-value-.patch
+++ /dev/null
@@ -1,463 +0,0 @@
-From 657cf2b4005afd14a566892eb625107d8383487d Mon Sep 17 00:00:00 2001
-From: Daniel Borkmann <daniel@iogearbox.net>
-Date: Fri, 21 Jul 2017 00:00:21 +0200
-Subject: [PATCH 094/103] bpf: fix mixed signed/unsigned derived min/max value
- bounds
-
-[ Upstream commit 4cabc5b186b5427b9ee5a7495172542af105f02b ]
-
-Edward reported that there's an issue in min/max value bounds
-tracking when signed and unsigned compares both provide hints
-on limits when having unknown variables. E.g. a program such
-as the following should have been rejected:
-
- 0: (7a) *(u64 *)(r10 -8) = 0
- 1: (bf) r2 = r10
- 2: (07) r2 += -8
- 3: (18) r1 = 0xffff8a94cda93400
- 5: (85) call bpf_map_lookup_elem#1
- 6: (15) if r0 == 0x0 goto pc+7
- R0=map_value(ks=8,vs=8,id=0),min_value=0,max_value=0 R10=fp
- 7: (7a) *(u64 *)(r10 -16) = -8
- 8: (79) r1 = *(u64 *)(r10 -16)
- 9: (b7) r2 = -1
- 10: (2d) if r1 > r2 goto pc+3
- R0=map_value(ks=8,vs=8,id=0),min_value=0,max_value=0 R1=inv,min_value=0
- R2=imm-1,max_value=18446744073709551615,min_align=1 R10=fp
- 11: (65) if r1 s> 0x1 goto pc+2
- R0=map_value(ks=8,vs=8,id=0),min_value=0,max_value=0 R1=inv,min_value=0,max_value=1
- R2=imm-1,max_value=18446744073709551615,min_align=1 R10=fp
- 12: (0f) r0 += r1
- 13: (72) *(u8 *)(r0 +0) = 0
- R0=map_value_adj(ks=8,vs=8,id=0),min_value=0,max_value=1 R1=inv,min_value=0,max_value=1
- R2=imm-1,max_value=18446744073709551615,min_align=1 R10=fp
- 14: (b7) r0 = 0
- 15: (95) exit
-
-What happens is that in the first part ...
-
- 8: (79) r1 = *(u64 *)(r10 -16)
- 9: (b7) r2 = -1
- 10: (2d) if r1 > r2 goto pc+3
-
-... r1 carries an unsigned value, and is compared as unsigned
-against a register carrying an immediate. Verifier deduces in
-reg_set_min_max() that since the compare is unsigned and operation
-is greater than (>), that in the fall-through/false case, r1's
-minimum bound must be 0 and maximum bound must be r2. Latter is
-larger than the bound and thus max value is reset back to being
-'invalid' aka BPF_REGISTER_MAX_RANGE. Thus, r1 state is now
-'R1=inv,min_value=0'. The subsequent test ...
-
- 11: (65) if r1 s> 0x1 goto pc+2
-
-... is a signed compare of r1 with immediate value 1. Here,
-verifier deduces in reg_set_min_max() that since the compare
-is signed this time and operation is greater than (>), that
-in the fall-through/false case, we can deduce that r1's maximum
-bound must be 1, meaning with prior test, we result in r1 having
-the following state: R1=inv,min_value=0,max_value=1. Given that
-the actual value this holds is -8, the bounds are wrongly deduced.
-When this is being added to r0 which holds the map_value(_adj)
-type, then subsequent store access in above case will go through
-check_mem_access() which invokes check_map_access_adj(), that
-will then probe whether the map memory is in bounds based
-on the min_value and max_value as well as access size since
-the actual unknown value is min_value <= x <= max_value; commit
-fce366a9dd0d ("bpf, verifier: fix alu ops against map_value{,
-_adj} register types") provides some more explanation on the
-semantics.
-
-It's worth to note in this context that in the current code,
-min_value and max_value tracking are used for two things, i)
-dynamic map value access via check_map_access_adj() and since
-commit 06c1c049721a ("bpf: allow helpers access to variable memory")
-ii) also enforced at check_helper_mem_access() when passing a
-memory address (pointer to packet, map value, stack) and length
-pair to a helper and the length in this case is an unknown value
-defining an access range through min_value/max_value in that
-case. The min_value/max_value tracking is /not/ used in the
-direct packet access case to track ranges. However, the issue
-also affects case ii), for example, the following crafted program
-based on the same principle must be rejected as well:
-
- 0: (b7) r2 = 0
- 1: (bf) r3 = r10
- 2: (07) r3 += -512
- 3: (7a) *(u64 *)(r10 -16) = -8
- 4: (79) r4 = *(u64 *)(r10 -16)
- 5: (b7) r6 = -1
- 6: (2d) if r4 > r6 goto pc+5
- R1=ctx R2=imm0,min_value=0,max_value=0,min_align=2147483648 R3=fp-512
- R4=inv,min_value=0 R6=imm-1,max_value=18446744073709551615,min_align=1 R10=fp
- 7: (65) if r4 s> 0x1 goto pc+4
- R1=ctx R2=imm0,min_value=0,max_value=0,min_align=2147483648 R3=fp-512
- R4=inv,min_value=0,max_value=1 R6=imm-1,max_value=18446744073709551615,min_align=1
- R10=fp
- 8: (07) r4 += 1
- 9: (b7) r5 = 0
- 10: (6a) *(u16 *)(r10 -512) = 0
- 11: (85) call bpf_skb_load_bytes#26
- 12: (b7) r0 = 0
- 13: (95) exit
-
-Meaning, while we initialize the max_value stack slot that the
-verifier thinks we access in the [1,2] range, in reality we
-pass -7 as length which is interpreted as u32 in the helper.
-Thus, this issue is relevant also for the case of helper ranges.
-Resetting both bounds in check_reg_overflow() in case only one
-of them exceeds limits is also not enough as similar test can be
-created that uses values which are within range, thus also here
-learned min value in r1 is incorrect when mixed with later signed
-test to create a range:
-
- 0: (7a) *(u64 *)(r10 -8) = 0
- 1: (bf) r2 = r10
- 2: (07) r2 += -8
- 3: (18) r1 = 0xffff880ad081fa00
- 5: (85) call bpf_map_lookup_elem#1
- 6: (15) if r0 == 0x0 goto pc+7
- R0=map_value(ks=8,vs=8,id=0),min_value=0,max_value=0 R10=fp
- 7: (7a) *(u64 *)(r10 -16) = -8
- 8: (79) r1 = *(u64 *)(r10 -16)
- 9: (b7) r2 = 2
- 10: (3d) if r2 >= r1 goto pc+3
- R0=map_value(ks=8,vs=8,id=0),min_value=0,max_value=0 R1=inv,min_value=3
- R2=imm2,min_value=2,max_value=2,min_align=2 R10=fp
- 11: (65) if r1 s> 0x4 goto pc+2
- R0=map_value(ks=8,vs=8,id=0),min_value=0,max_value=0
- R1=inv,min_value=3,max_value=4 R2=imm2,min_value=2,max_value=2,min_align=2 R10=fp
- 12: (0f) r0 += r1
- 13: (72) *(u8 *)(r0 +0) = 0
- R0=map_value_adj(ks=8,vs=8,id=0),min_value=3,max_value=4
- R1=inv,min_value=3,max_value=4 R2=imm2,min_value=2,max_value=2,min_align=2 R10=fp
- 14: (b7) r0 = 0
- 15: (95) exit
-
-This leaves us with two options for fixing this: i) to invalidate
-all prior learned information once we switch signed context, ii)
-to track min/max signed and unsigned boundaries separately as
-done in [0]. (Given latter introduces major changes throughout
-the whole verifier, it's rather net-next material, thus this
-patch follows option i), meaning we can derive bounds either
-from only signed tests or only unsigned tests.) There is still the
-case of adjust_reg_min_max_vals(), where we adjust bounds on ALU
-operations, meaning programs like the following where boundaries
-on the reg get mixed in context later on when bounds are merged
-on the dst reg must get rejected, too:
-
- 0: (7a) *(u64 *)(r10 -8) = 0
- 1: (bf) r2 = r10
- 2: (07) r2 += -8
- 3: (18) r1 = 0xffff89b2bf87ce00
- 5: (85) call bpf_map_lookup_elem#1
- 6: (15) if r0 == 0x0 goto pc+6
- R0=map_value(ks=8,vs=8,id=0),min_value=0,max_value=0 R10=fp
- 7: (7a) *(u64 *)(r10 -16) = -8
- 8: (79) r1 = *(u64 *)(r10 -16)
- 9: (b7) r2 = 2
- 10: (3d) if r2 >= r1 goto pc+2
- R0=map_value(ks=8,vs=8,id=0),min_value=0,max_value=0 R1=inv,min_value=3
- R2=imm2,min_value=2,max_value=2,min_align=2 R10=fp
- 11: (b7) r7 = 1
- 12: (65) if r7 s> 0x0 goto pc+2
- R0=map_value(ks=8,vs=8,id=0),min_value=0,max_value=0 R1=inv,min_value=3
- R2=imm2,min_value=2,max_value=2,min_align=2 R7=imm1,max_value=0 R10=fp
- 13: (b7) r0 = 0
- 14: (95) exit
-
- from 12 to 15: R0=map_value(ks=8,vs=8,id=0),min_value=0,max_value=0
- R1=inv,min_value=3 R2=imm2,min_value=2,max_value=2,min_align=2 R7=imm1,min_value=1 R10=fp
- 15: (0f) r7 += r1
- 16: (65) if r7 s> 0x4 goto pc+2
- R0=map_value(ks=8,vs=8,id=0),min_value=0,max_value=0 R1=inv,min_value=3
- R2=imm2,min_value=2,max_value=2,min_align=2 R7=inv,min_value=4,max_value=4 R10=fp
- 17: (0f) r0 += r7
- 18: (72) *(u8 *)(r0 +0) = 0
- R0=map_value_adj(ks=8,vs=8,id=0),min_value=4,max_value=4 R1=inv,min_value=3
- R2=imm2,min_value=2,max_value=2,min_align=2 R7=inv,min_value=4,max_value=4 R10=fp
- 19: (b7) r0 = 0
- 20: (95) exit
-
-Meaning, in adjust_reg_min_max_vals() we must also reset range
-values on the dst when src/dst registers have mixed signed/
-unsigned derived min/max value bounds with one unbounded value
-as otherwise they can be added together deducing false boundaries.
-Once both boundaries are established from either ALU ops or
-compare operations w/o mixing signed/unsigned insns, then they
-can safely be added to other regs also having both boundaries
-established. Adding regs with one unbounded side to a map value
-where the bounded side has been learned w/o mixing ops is
-possible, but the resulting map value won't recover from that,
-meaning such op is considered invalid on the time of actual
-access. Invalid bounds are set on the dst reg in case i) src reg,
-or ii) in case dst reg already had them. The only way to recover
-would be to perform i) ALU ops but only 'add' is allowed on map
-value types or ii) comparisons, but these are disallowed on
-pointers in case they span a range. This is fine as only BPF_JEQ
-and BPF_JNE may be performed on PTR_TO_MAP_VALUE_OR_NULL registers
-which potentially turn them into PTR_TO_MAP_VALUE type depending
-on the branch, so only here min/max value cannot be invalidated
-for them.
-
-In terms of state pruning, value_from_signed is considered
-as well in states_equal() when dealing with adjusted map values.
-With regards to breaking existing programs, there is a small
-risk, but use-cases are rather quite narrow where this could
-occur and mixing compares probably unlikely.
-
-Joint work with Josef and Edward.
-
- [0] https://lists.iovisor.org/pipermail/iovisor-dev/2017-June/000822.html
-
-Fixes: 484611357c19 ("bpf: allow access into map value arrays")
-Reported-by: Edward Cree <ecree@solarflare.com>
-Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
-Signed-off-by: Edward Cree <ecree@solarflare.com>
-Signed-off-by: Josef Bacik <jbacik@fb.com>
-Signed-off-by: David S. Miller <davem@davemloft.net>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
----
- include/linux/bpf_verifier.h | 1 +
- kernel/bpf/verifier.c | 110 +++++++++++++++++++++++++++++++++++++------
- 2 files changed, 97 insertions(+), 14 deletions(-)
-
-diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
-index 2edf8de..070fc49 100644
---- a/include/linux/bpf_verifier.h
-+++ b/include/linux/bpf_verifier.h
-@@ -40,6 +40,7 @@ struct bpf_reg_state {
- */
- s64 min_value;
- u64 max_value;
-+ bool value_from_signed;
- };
-
- enum bpf_stack_slot_type {
-diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
-index 787b851..bfafb53 100644
---- a/kernel/bpf/verifier.c
-+++ b/kernel/bpf/verifier.c
-@@ -671,12 +671,13 @@ static int check_ctx_access(struct bpf_verifier_env *env, int off, int size,
- return -EACCES;
- }
-
--static bool is_pointer_value(struct bpf_verifier_env *env, int regno)
-+static bool __is_pointer_value(bool allow_ptr_leaks,
-+ const struct bpf_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;
-@@ -685,6 +686,11 @@ static bool is_pointer_value(struct bpf_verifier_env *env, int regno)
- }
- }
-
-+static bool is_pointer_value(struct bpf_verifier_env *env, int regno)
-+{
-+ return __is_pointer_value(env->allow_ptr_leaks, &env->cur_state.regs[regno]);
-+}
-+
- static int check_ptr_alignment(struct bpf_verifier_env *env,
- struct bpf_reg_state *reg, int off, int size)
- {
-@@ -1521,10 +1527,24 @@ static void adjust_reg_min_max_vals(struct bpf_verifier_env *env,
- }
-
- /* We don't know anything about what was done to this register, mark it
-- * as unknown.
-+ * as unknown. Also, if both derived bounds came from signed/unsigned
-+ * mixed compares and one side is unbounded, we cannot really do anything
-+ * with them as boundaries cannot be trusted. Thus, arithmetic of two
-+ * regs of such kind will get invalidated bounds on the dst side.
- */
-- if (min_val == BPF_REGISTER_MIN_RANGE &&
-- max_val == BPF_REGISTER_MAX_RANGE) {
-+ if ((min_val == BPF_REGISTER_MIN_RANGE &&
-+ max_val == BPF_REGISTER_MAX_RANGE) ||
-+ (BPF_SRC(insn->code) == BPF_X &&
-+ ((min_val != BPF_REGISTER_MIN_RANGE &&
-+ max_val == BPF_REGISTER_MAX_RANGE) ||
-+ (min_val == BPF_REGISTER_MIN_RANGE &&
-+ max_val != BPF_REGISTER_MAX_RANGE) ||
-+ (dst_reg->min_value != BPF_REGISTER_MIN_RANGE &&
-+ dst_reg->max_value == BPF_REGISTER_MAX_RANGE) ||
-+ (dst_reg->min_value == BPF_REGISTER_MIN_RANGE &&
-+ dst_reg->max_value != BPF_REGISTER_MAX_RANGE)) &&
-+ regs[insn->dst_reg].value_from_signed !=
-+ regs[insn->src_reg].value_from_signed)) {
- reset_reg_range_values(regs, insn->dst_reg);
- return;
- }
-@@ -1855,38 +1875,63 @@ static void reg_set_min_max(struct bpf_reg_state *true_reg,
- struct bpf_reg_state *false_reg, u64 val,
- u8 opcode)
- {
-+ bool value_from_signed = true;
-+ bool is_range = true;
-+
- switch (opcode) {
- case BPF_JEQ:
- /* If this is false then we know nothing Jon Snow, but if it is
- * true then we know for sure.
- */
- true_reg->max_value = true_reg->min_value = val;
-+ is_range = false;
- break;
- case BPF_JNE:
- /* If this is true we know nothing Jon Snow, but if it is false
- * we know the value for sure;
- */
- false_reg->max_value = false_reg->min_value = val;
-+ is_range = false;
- break;
- case BPF_JGT:
-- /* Unsigned comparison, the minimum value is 0. */
-- false_reg->min_value = 0;
-+ value_from_signed = false;
-+ /* fallthrough */
- case BPF_JSGT:
-+ if (true_reg->value_from_signed != value_from_signed)
-+ reset_reg_range_values(true_reg, 0);
-+ if (false_reg->value_from_signed != value_from_signed)
-+ reset_reg_range_values(false_reg, 0);
-+ if (opcode == BPF_JGT) {
-+ /* Unsigned comparison, the minimum value is 0. */
-+ false_reg->min_value = 0;
-+ }
- /* If this is false then we know the maximum val is val,
- * otherwise we know the min val is val+1.
- */
- false_reg->max_value = val;
-+ false_reg->value_from_signed = value_from_signed;
- true_reg->min_value = val + 1;
-+ true_reg->value_from_signed = value_from_signed;
- break;
- case BPF_JGE:
-- /* Unsigned comparison, the minimum value is 0. */
-- false_reg->min_value = 0;
-+ value_from_signed = false;
-+ /* fallthrough */
- case BPF_JSGE:
-+ if (true_reg->value_from_signed != value_from_signed)
-+ reset_reg_range_values(true_reg, 0);
-+ if (false_reg->value_from_signed != value_from_signed)
-+ reset_reg_range_values(false_reg, 0);
-+ if (opcode == BPF_JGE) {
-+ /* Unsigned comparison, the minimum value is 0. */
-+ false_reg->min_value = 0;
-+ }
- /* If this is false then we know the maximum value is val - 1,
- * otherwise we know the mimimum value is val.
- */
- false_reg->max_value = val - 1;
-+ false_reg->value_from_signed = value_from_signed;
- true_reg->min_value = val;
-+ true_reg->value_from_signed = value_from_signed;
- break;
- default:
- break;
-@@ -1894,6 +1939,12 @@ static void reg_set_min_max(struct bpf_reg_state *true_reg,
-
- check_reg_overflow(false_reg);
- check_reg_overflow(true_reg);
-+ if (is_range) {
-+ if (__is_pointer_value(false, false_reg))
-+ reset_reg_range_values(false_reg, 0);
-+ if (__is_pointer_value(false, true_reg))
-+ reset_reg_range_values(true_reg, 0);
-+ }
- }
-
- /* Same as above, but for the case that dst_reg is a CONST_IMM reg and src_reg
-@@ -1903,39 +1954,64 @@ static void reg_set_min_max_inv(struct bpf_reg_state *true_reg,
- struct bpf_reg_state *false_reg, u64 val,
- u8 opcode)
- {
-+ bool value_from_signed = true;
-+ bool is_range = true;
-+
- switch (opcode) {
- case BPF_JEQ:
- /* If this is false then we know nothing Jon Snow, but if it is
- * true then we know for sure.
- */
- true_reg->max_value = true_reg->min_value = val;
-+ is_range = false;
- break;
- case BPF_JNE:
- /* If this is true we know nothing Jon Snow, but if it is false
- * we know the value for sure;
- */
- false_reg->max_value = false_reg->min_value = val;
-+ is_range = false;
- break;
- case BPF_JGT:
-- /* Unsigned comparison, the minimum value is 0. */
-- true_reg->min_value = 0;
-+ value_from_signed = false;
-+ /* fallthrough */
- case BPF_JSGT:
-+ if (true_reg->value_from_signed != value_from_signed)
-+ reset_reg_range_values(true_reg, 0);
-+ if (false_reg->value_from_signed != value_from_signed)
-+ reset_reg_range_values(false_reg, 0);
-+ if (opcode == BPF_JGT) {
-+ /* Unsigned comparison, the minimum value is 0. */
-+ true_reg->min_value = 0;
-+ }
- /*
- * If this is false, then the val is <= the register, if it is
- * true the register <= to the val.
- */
- false_reg->min_value = val;
-+ false_reg->value_from_signed = value_from_signed;
- true_reg->max_value = val - 1;
-+ true_reg->value_from_signed = value_from_signed;
- break;
- case BPF_JGE:
-- /* Unsigned comparison, the minimum value is 0. */
-- true_reg->min_value = 0;
-+ value_from_signed = false;
-+ /* fallthrough */
- case BPF_JSGE:
-+ if (true_reg->value_from_signed != value_from_signed)
-+ reset_reg_range_values(true_reg, 0);
-+ if (false_reg->value_from_signed != value_from_signed)
-+ reset_reg_range_values(false_reg, 0);
-+ if (opcode == BPF_JGE) {
-+ /* Unsigned comparison, the minimum value is 0. */
-+ true_reg->min_value = 0;
-+ }
- /* If this is false then constant < register, if it is true then
- * the register < constant.
- */
- false_reg->min_value = val + 1;
-+ false_reg->value_from_signed = value_from_signed;
- true_reg->max_value = val;
-+ true_reg->value_from_signed = value_from_signed;
- break;
- default:
- break;
-@@ -1943,6 +2019,12 @@ static void reg_set_min_max_inv(struct bpf_reg_state *true_reg,
-
- check_reg_overflow(false_reg);
- check_reg_overflow(true_reg);
-+ if (is_range) {
-+ if (__is_pointer_value(false, false_reg))
-+ reset_reg_range_values(false_reg, 0);
-+ if (__is_pointer_value(false, true_reg))
-+ reset_reg_range_values(true_reg, 0);
-+ }
- }
-
- static void mark_map_reg(struct bpf_reg_state *regs, u32 regno, u32 id,
---
-2.7.4
-