]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.19-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 19 Mar 2021 08:35:16 +0000 (09:35 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 19 Mar 2021 08:35:16 +0000 (09:35 +0100)
added patches:
bpf-add-sanity-check-for-upper-ptr_limit.patch
bpf-fix-off-by-one-for-area-size-in-creating-mask-to-left.patch
bpf-prohibit-alu-ops-for-pointer-types-not-defining-ptr_limit.patch
bpf-simplify-alu_limit-masking-for-pointer-arithmetic.patch

queue-4.19/bpf-add-sanity-check-for-upper-ptr_limit.patch [new file with mode: 0644]
queue-4.19/bpf-fix-off-by-one-for-area-size-in-creating-mask-to-left.patch [new file with mode: 0644]
queue-4.19/bpf-prohibit-alu-ops-for-pointer-types-not-defining-ptr_limit.patch [new file with mode: 0644]
queue-4.19/bpf-simplify-alu_limit-masking-for-pointer-arithmetic.patch [new file with mode: 0644]
queue-4.19/series

diff --git a/queue-4.19/bpf-add-sanity-check-for-upper-ptr_limit.patch b/queue-4.19/bpf-add-sanity-check-for-upper-ptr_limit.patch
new file mode 100644 (file)
index 0000000..5a04130
--- /dev/null
@@ -0,0 +1,58 @@
+From 1b1597e64e1a610c7a96710fc4717158e98a08b3 Mon Sep 17 00:00:00 2001
+From: Piotr Krysiuk <piotras@gmail.com>
+Date: Tue, 16 Mar 2021 09:47:02 +0100
+Subject: bpf: Add sanity check for upper ptr_limit
+
+From: Piotr Krysiuk <piotras@gmail.com>
+
+commit 1b1597e64e1a610c7a96710fc4717158e98a08b3 upstream.
+
+Given we know the max possible value of ptr_limit at the time of retrieving
+the latter, add basic assertions, so that the verifier can bail out if
+anything looks odd and reject the program. Nothing triggered this so far,
+but it also does not hurt to have these.
+
+Signed-off-by: Piotr Krysiuk <piotras@gmail.com>
+Co-developed-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Acked-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/bpf/verifier.c |   11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -2734,24 +2734,29 @@ static int retrieve_ptr_limit(const stru
+ {
+       bool mask_to_left = (opcode == BPF_ADD &&  off_is_neg) ||
+                           (opcode == BPF_SUB && !off_is_neg);
+-      u32 off;
++      u32 off, max;
+       switch (ptr_reg->type) {
+       case PTR_TO_STACK:
++              /* Offset 0 is out-of-bounds, but acceptable start for the
++               * left direction, see BPF_REG_FP.
++               */
++              max = MAX_BPF_STACK + mask_to_left;
+               off = ptr_reg->off + ptr_reg->var_off.value;
+               if (mask_to_left)
+                       *ptr_limit = MAX_BPF_STACK + off;
+               else
+                       *ptr_limit = -off - 1;
+-              return 0;
++              return *ptr_limit >= max ? -ERANGE : 0;
+       case PTR_TO_MAP_VALUE:
++              max = ptr_reg->map_ptr->value_size;
+               if (mask_to_left) {
+                       *ptr_limit = ptr_reg->umax_value + ptr_reg->off;
+               } else {
+                       off = ptr_reg->smin_value + ptr_reg->off;
+                       *ptr_limit = ptr_reg->map_ptr->value_size - off - 1;
+               }
+-              return 0;
++              return *ptr_limit >= max ? -ERANGE : 0;
+       default:
+               return -EINVAL;
+       }
diff --git a/queue-4.19/bpf-fix-off-by-one-for-area-size-in-creating-mask-to-left.patch b/queue-4.19/bpf-fix-off-by-one-for-area-size-in-creating-mask-to-left.patch
new file mode 100644 (file)
index 0000000..ad6ff9c
--- /dev/null
@@ -0,0 +1,54 @@
+From 10d2bb2e6b1d8c4576c56a748f697dbeb8388899 Mon Sep 17 00:00:00 2001
+From: Piotr Krysiuk <piotras@gmail.com>
+Date: Tue, 16 Mar 2021 08:20:16 +0100
+Subject: bpf: Fix off-by-one for area size in creating mask to left
+
+From: Piotr Krysiuk <piotras@gmail.com>
+
+commit 10d2bb2e6b1d8c4576c56a748f697dbeb8388899 upstream.
+
+retrieve_ptr_limit() computes the ptr_limit for registers with stack and
+map_value type. ptr_limit is the size of the memory area that is still
+valid / in-bounds from the point of the current position and direction
+of the operation (add / sub). This size will later be used for masking
+the operation such that attempting out-of-bounds access in the speculative
+domain is redirected to remain within the bounds of the current map value.
+
+When masking to the right the size is correct, however, when masking to
+the left, the size is off-by-one which would lead to an incorrect mask
+and thus incorrect arithmetic operation in the non-speculative domain.
+Piotr found that if the resulting alu_limit value is zero, then the
+BPF_MOV32_IMM() from the fixup_bpf_calls() rewrite will end up loading
+0xffffffff into AX instead of sign-extending to the full 64 bit range,
+and as a result, this allows abuse for executing speculatively out-of-
+bounds loads against 4GB window of address space and thus extracting the
+contents of kernel memory via side-channel.
+
+Fixes: 979d63d50c0c ("bpf: prevent out of bounds speculation on pointer arithmetic")
+Signed-off-by: Piotr Krysiuk <piotras@gmail.com>
+Co-developed-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Acked-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/bpf/verifier.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -2740,13 +2740,13 @@ static int retrieve_ptr_limit(const stru
+       case PTR_TO_STACK:
+               off = ptr_reg->off + ptr_reg->var_off.value;
+               if (mask_to_left)
+-                      *ptr_limit = MAX_BPF_STACK + off;
++                      *ptr_limit = MAX_BPF_STACK + off + 1;
+               else
+                       *ptr_limit = -off;
+               return 0;
+       case PTR_TO_MAP_VALUE:
+               if (mask_to_left) {
+-                      *ptr_limit = ptr_reg->umax_value + ptr_reg->off;
++                      *ptr_limit = ptr_reg->umax_value + ptr_reg->off + 1;
+               } else {
+                       off = ptr_reg->smin_value + ptr_reg->off;
+                       *ptr_limit = ptr_reg->map_ptr->value_size - off;
diff --git a/queue-4.19/bpf-prohibit-alu-ops-for-pointer-types-not-defining-ptr_limit.patch b/queue-4.19/bpf-prohibit-alu-ops-for-pointer-types-not-defining-ptr_limit.patch
new file mode 100644 (file)
index 0000000..b154e47
--- /dev/null
@@ -0,0 +1,83 @@
+From f232326f6966cf2a1d1db7bc917a4ce5f9f55f76 Mon Sep 17 00:00:00 2001
+From: Piotr Krysiuk <piotras@gmail.com>
+Date: Tue, 16 Mar 2021 09:47:02 +0100
+Subject: bpf: Prohibit alu ops for pointer types not defining ptr_limit
+
+From: Piotr Krysiuk <piotras@gmail.com>
+
+commit f232326f6966cf2a1d1db7bc917a4ce5f9f55f76 upstream.
+
+The purpose of this patch is to streamline error propagation and in particular
+to propagate retrieve_ptr_limit() errors for pointer types that are not defining
+a ptr_limit such that register-based alu ops against these types can be rejected.
+
+The main rationale is that a gap has been identified by Piotr in the existing
+protection against speculatively out-of-bounds loads, for example, in case of
+ctx pointers, unprivileged programs can still perform pointer arithmetic. This
+can be abused to execute speculatively out-of-bounds loads without restrictions
+and thus extract contents of kernel memory.
+
+Fix this by rejecting unprivileged programs that attempt any pointer arithmetic
+on unprotected pointer types. The two affected ones are pointer to ctx as well
+as pointer to map. Field access to a modified ctx' pointer is rejected at a
+later point in time in the verifier, and 7c6967326267 ("bpf: Permit map_ptr
+arithmetic with opcode add and offset 0") only relevant for root-only use cases.
+Risk of unprivileged program breakage is considered very low.
+
+Fixes: 7c6967326267 ("bpf: Permit map_ptr arithmetic with opcode add and offset 0")
+Fixes: b2157399cc98 ("bpf: prevent out-of-bounds speculation")
+Signed-off-by: Piotr Krysiuk <piotras@gmail.com>
+Co-developed-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Acked-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/bpf/verifier.c |   16 ++++++++++------
+ 1 file changed, 10 insertions(+), 6 deletions(-)
+
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -2804,6 +2804,7 @@ static int sanitize_ptr_alu(struct bpf_v
+       u32 alu_state, alu_limit;
+       struct bpf_reg_state tmp;
+       bool ret;
++      int err;
+       if (can_skip_alu_sanitation(env, insn))
+               return 0;
+@@ -2819,10 +2820,13 @@ static int sanitize_ptr_alu(struct bpf_v
+       alu_state |= ptr_is_dst_reg ?
+                    BPF_ALU_SANITIZE_SRC : BPF_ALU_SANITIZE_DST;
+-      if (retrieve_ptr_limit(ptr_reg, &alu_limit, opcode, off_is_neg))
+-              return 0;
+-      if (update_alu_sanitation_state(aux, alu_state, alu_limit))
+-              return -EACCES;
++      err = retrieve_ptr_limit(ptr_reg, &alu_limit, opcode, off_is_neg);
++      if (err < 0)
++              return err;
++
++      err = update_alu_sanitation_state(aux, alu_state, alu_limit);
++      if (err < 0)
++              return err;
+ do_sim:
+       /* Simulate and find potential out-of-bounds access under
+        * speculative execution from truncation as a result of
+@@ -2920,7 +2924,7 @@ static int adjust_ptr_min_max_vals(struc
+       case BPF_ADD:
+               ret = sanitize_ptr_alu(env, insn, ptr_reg, dst_reg, smin_val < 0);
+               if (ret < 0) {
+-                      verbose(env, "R%d tried to add from different maps or paths\n", dst);
++                      verbose(env, "R%d tried to add from different maps, paths, or prohibited types\n", dst);
+                       return ret;
+               }
+               /* We can take a fixed offset as long as it doesn't overflow
+@@ -2975,7 +2979,7 @@ static int adjust_ptr_min_max_vals(struc
+       case BPF_SUB:
+               ret = sanitize_ptr_alu(env, insn, ptr_reg, dst_reg, smin_val < 0);
+               if (ret < 0) {
+-                      verbose(env, "R%d tried to sub from different maps or paths\n", dst);
++                      verbose(env, "R%d tried to sub from different maps, paths, or prohibited types\n", dst);
+                       return ret;
+               }
+               if (dst_reg == off_reg) {
diff --git a/queue-4.19/bpf-simplify-alu_limit-masking-for-pointer-arithmetic.patch b/queue-4.19/bpf-simplify-alu_limit-masking-for-pointer-arithmetic.patch
new file mode 100644 (file)
index 0000000..2e89f5d
--- /dev/null
@@ -0,0 +1,57 @@
+From b5871dca250cd391885218b99cc015aca1a51aea Mon Sep 17 00:00:00 2001
+From: Piotr Krysiuk <piotras@gmail.com>
+Date: Tue, 16 Mar 2021 08:26:25 +0100
+Subject: bpf: Simplify alu_limit masking for pointer arithmetic
+
+From: Piotr Krysiuk <piotras@gmail.com>
+
+commit b5871dca250cd391885218b99cc015aca1a51aea upstream.
+
+Instead of having the mov32 with aux->alu_limit - 1 immediate, move this
+operation to retrieve_ptr_limit() instead to simplify the logic and to
+allow for subsequent sanity boundary checks inside retrieve_ptr_limit().
+This avoids in future that at the time of the verifier masking rewrite
+we'd run into an underflow which would not sign extend due to the nature
+of mov32 instruction.
+
+Signed-off-by: Piotr Krysiuk <piotras@gmail.com>
+Co-developed-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Acked-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/bpf/verifier.c |   10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -2740,16 +2740,16 @@ static int retrieve_ptr_limit(const stru
+       case PTR_TO_STACK:
+               off = ptr_reg->off + ptr_reg->var_off.value;
+               if (mask_to_left)
+-                      *ptr_limit = MAX_BPF_STACK + off + 1;
++                      *ptr_limit = MAX_BPF_STACK + off;
+               else
+-                      *ptr_limit = -off;
++                      *ptr_limit = -off - 1;
+               return 0;
+       case PTR_TO_MAP_VALUE:
+               if (mask_to_left) {
+-                      *ptr_limit = ptr_reg->umax_value + ptr_reg->off + 1;
++                      *ptr_limit = ptr_reg->umax_value + ptr_reg->off;
+               } else {
+                       off = ptr_reg->smin_value + ptr_reg->off;
+-                      *ptr_limit = ptr_reg->map_ptr->value_size - off;
++                      *ptr_limit = ptr_reg->map_ptr->value_size - off - 1;
+               }
+               return 0;
+       default:
+@@ -6089,7 +6089,7 @@ static int fixup_bpf_calls(struct bpf_ve
+                       off_reg = issrc ? insn->src_reg : insn->dst_reg;
+                       if (isneg)
+                               *patch++ = BPF_ALU64_IMM(BPF_MUL, off_reg, -1);
+-                      *patch++ = BPF_MOV32_IMM(BPF_REG_AX, aux->alu_limit - 1);
++                      *patch++ = BPF_MOV32_IMM(BPF_REG_AX, aux->alu_limit);
+                       *patch++ = BPF_ALU64_REG(BPF_SUB, BPF_REG_AX, off_reg);
+                       *patch++ = BPF_ALU64_REG(BPF_OR, BPF_REG_AX, off_reg);
+                       *patch++ = BPF_ALU64_IMM(BPF_NEG, BPF_REG_AX, 0);
index b0415901e7b076f37dad464cbdf2fb17ae5e21c0..342c993c7bbf165c959c4cb828408765caa76fc7 100644 (file)
@@ -1,2 +1,6 @@
 ext4-check-journal-inode-extents-more-carefully.patch
 kvm-arm64-nvhe-save-the-spe-context-early.patch
+bpf-prohibit-alu-ops-for-pointer-types-not-defining-ptr_limit.patch
+bpf-fix-off-by-one-for-area-size-in-creating-mask-to-left.patch
+bpf-simplify-alu_limit-masking-for-pointer-arithmetic.patch
+bpf-add-sanity-check-for-upper-ptr_limit.patch