]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.9-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 22 Dec 2017 15:58:01 +0000 (16:58 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 22 Dec 2017 15:58:01 +0000 (16:58 +0100)
added patches:
bpf-adjust-insn_aux_data-when-patching-insns.patch
bpf-fix-branch-pruning-logic.patch
bpf-fix-incorrect-sign-extension-in-check_alu_op.patch
bpf-reject-out-of-bounds-stack-pointer-calculation.patch

queue-4.9/bpf-adjust-insn_aux_data-when-patching-insns.patch [new file with mode: 0644]
queue-4.9/bpf-fix-branch-pruning-logic.patch [new file with mode: 0644]
queue-4.9/bpf-fix-incorrect-sign-extension-in-check_alu_op.patch [new file with mode: 0644]
queue-4.9/bpf-reject-out-of-bounds-stack-pointer-calculation.patch [new file with mode: 0644]
queue-4.9/series

diff --git a/queue-4.9/bpf-adjust-insn_aux_data-when-patching-insns.patch b/queue-4.9/bpf-adjust-insn_aux_data-when-patching-insns.patch
new file mode 100644 (file)
index 0000000..e0817ec
--- /dev/null
@@ -0,0 +1,104 @@
+From foo@baz Fri Dec 22 16:57:35 CET 2017
+From: Daniel Borkmann <daniel@iogearbox.net>
+Date: Fri, 22 Dec 2017 16:29:02 +0100
+Subject: bpf: adjust insn_aux_data when patching insns
+To: gregkh@linuxfoundation.org
+Cc: ast@kernel.org, daniel@iogearbox.net, jannh@google.com, stable@vger.kernel.org, Alexei Starovoitov <ast@fb.com>, "David S . Miller" <davem@davemloft.net>
+Message-ID: <20171222152905.3455-2-daniel@iogearbox.net>
+
+From: Daniel Borkmann <daniel@iogearbox.net>
+
+
+From: Alexei Starovoitov <ast@fb.com>
+
+[ Upstream commit 8041902dae5299c1f194ba42d14383f734631009 ]
+
+convert_ctx_accesses() replaces single bpf instruction with a set of
+instructions. Adjust corresponding insn_aux_data while patching.
+It's needed to make sure subsequent 'for(all insn)' loops
+have matching insn and insn_aux_data.
+
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Acked-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/bpf/verifier.c |   44 +++++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 39 insertions(+), 5 deletions(-)
+
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -3210,6 +3210,41 @@ static void convert_pseudo_ld_imm64(stru
+                       insn->src_reg = 0;
+ }
++/* single env->prog->insni[off] instruction was replaced with the range
++ * insni[off, off + cnt).  Adjust corresponding insn_aux_data by copying
++ * [0, off) and [off, end) to new locations, so the patched range stays zero
++ */
++static int adjust_insn_aux_data(struct bpf_verifier_env *env, u32 prog_len,
++                              u32 off, u32 cnt)
++{
++      struct bpf_insn_aux_data *new_data, *old_data = env->insn_aux_data;
++
++      if (cnt == 1)
++              return 0;
++      new_data = vzalloc(sizeof(struct bpf_insn_aux_data) * prog_len);
++      if (!new_data)
++              return -ENOMEM;
++      memcpy(new_data, old_data, sizeof(struct bpf_insn_aux_data) * off);
++      memcpy(new_data + off + cnt - 1, old_data + off,
++             sizeof(struct bpf_insn_aux_data) * (prog_len - off - cnt + 1));
++      env->insn_aux_data = new_data;
++      vfree(old_data);
++      return 0;
++}
++
++static struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 off,
++                                          const struct bpf_insn *patch, u32 len)
++{
++      struct bpf_prog *new_prog;
++
++      new_prog = bpf_patch_insn_single(env->prog, off, patch, len);
++      if (!new_prog)
++              return NULL;
++      if (adjust_insn_aux_data(env, new_prog->len, off, len))
++              return NULL;
++      return new_prog;
++}
++
+ /* convert load instructions that access fields of 'struct __sk_buff'
+  * into sequence of instructions that access fields of 'struct sk_buff'
+  */
+@@ -3229,10 +3264,10 @@ static int convert_ctx_accesses(struct b
+                       verbose("bpf verifier is misconfigured\n");
+                       return -EINVAL;
+               } else if (cnt) {
+-                      new_prog = bpf_patch_insn_single(env->prog, 0,
+-                                                       insn_buf, cnt);
++                      new_prog = bpf_patch_insn_data(env, 0, insn_buf, cnt);
+                       if (!new_prog)
+                               return -ENOMEM;
++
+                       env->prog = new_prog;
+                       delta += cnt - 1;
+               }
+@@ -3253,7 +3288,7 @@ static int convert_ctx_accesses(struct b
+               else
+                       continue;
+-              if (env->insn_aux_data[i].ptr_type != PTR_TO_CTX)
++              if (env->insn_aux_data[i + delta].ptr_type != PTR_TO_CTX)
+                       continue;
+               cnt = ops->convert_ctx_access(type, insn->dst_reg, insn->src_reg,
+@@ -3263,8 +3298,7 @@ static int convert_ctx_accesses(struct b
+                       return -EINVAL;
+               }
+-              new_prog = bpf_patch_insn_single(env->prog, i + delta, insn_buf,
+-                                               cnt);
++              new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
+               if (!new_prog)
+                       return -ENOMEM;
diff --git a/queue-4.9/bpf-fix-branch-pruning-logic.patch b/queue-4.9/bpf-fix-branch-pruning-logic.patch
new file mode 100644 (file)
index 0000000..e26ef71
--- /dev/null
@@ -0,0 +1,122 @@
+From foo@baz Fri Dec 22 16:57:35 CET 2017
+From: Daniel Borkmann <daniel@iogearbox.net>
+Date: Fri, 22 Dec 2017 16:29:03 +0100
+Subject: bpf: fix branch pruning logic
+To: gregkh@linuxfoundation.org
+Cc: ast@kernel.org, daniel@iogearbox.net, jannh@google.com, stable@vger.kernel.org, Alexei Starovoitov <ast@fb.com>
+Message-ID: <20171222152905.3455-3-daniel@iogearbox.net>
+
+From: Daniel Borkmann <daniel@iogearbox.net>
+
+
+From: Alexei Starovoitov <ast@fb.com>
+
+[ Upstream commit c131187db2d3fa2f8bf32fdf4e9a4ef805168467 ]
+
+when the verifier detects that register contains a runtime constant
+and it's compared with another constant it will prune exploration
+of the branch that is guaranteed not to be taken at runtime.
+This is all correct, but malicious program may be constructed
+in such a way that it always has a constant comparison and
+the other branch is never taken under any conditions.
+In this case such path through the program will not be explored
+by the verifier. It won't be taken at run-time either, but since
+all instructions are JITed the malicious program may cause JITs
+to complain about using reserved fields, etc.
+To fix the issue we have to track the instructions explored by
+the verifier and sanitize instructions that are dead at run time
+with NOPs. We cannot reject such dead code, since llvm generates
+it for valid C code, since it doesn't do as much data flow
+analysis as the verifier does.
+
+Fixes: 17a5267067f3 ("bpf: verifier (add verifier core)")
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Acked-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/bpf_verifier.h |    1 +
+ kernel/bpf/verifier.c        |   27 +++++++++++++++++++++++++++
+ 2 files changed, 28 insertions(+)
+
+--- a/include/linux/bpf_verifier.h
++++ b/include/linux/bpf_verifier.h
+@@ -68,6 +68,7 @@ struct bpf_verifier_state_list {
+ struct bpf_insn_aux_data {
+       enum bpf_reg_type ptr_type;     /* pointer type for load/store insns */
++      bool seen; /* this insn was processed by the verifier */
+ };
+ #define MAX_USED_MAPS 64 /* max number of maps accessed by one eBPF program */
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -2862,6 +2862,7 @@ static int do_check(struct bpf_verifier_
+               if (err)
+                       return err;
++              env->insn_aux_data[insn_idx].seen = true;
+               if (class == BPF_ALU || class == BPF_ALU64) {
+                       err = check_alu_op(env, insn);
+                       if (err)
+@@ -3059,6 +3060,7 @@ process_bpf_exit:
+                                       return err;
+                               insn_idx++;
++                              env->insn_aux_data[insn_idx].seen = true;
+                       } else {
+                               verbose("invalid BPF_LD mode\n");
+                               return -EINVAL;
+@@ -3218,6 +3220,7 @@ static int adjust_insn_aux_data(struct b
+                               u32 off, u32 cnt)
+ {
+       struct bpf_insn_aux_data *new_data, *old_data = env->insn_aux_data;
++      int i;
+       if (cnt == 1)
+               return 0;
+@@ -3227,6 +3230,8 @@ static int adjust_insn_aux_data(struct b
+       memcpy(new_data, old_data, sizeof(struct bpf_insn_aux_data) * off);
+       memcpy(new_data + off + cnt - 1, old_data + off,
+              sizeof(struct bpf_insn_aux_data) * (prog_len - off - cnt + 1));
++      for (i = off; i < off + cnt - 1; i++)
++              new_data[i].seen = true;
+       env->insn_aux_data = new_data;
+       vfree(old_data);
+       return 0;
+@@ -3245,6 +3250,25 @@ static struct bpf_prog *bpf_patch_insn_d
+       return new_prog;
+ }
++/* The verifier does more data flow analysis than llvm and will not explore
++ * branches that are dead at run time. Malicious programs can have dead code
++ * too. Therefore replace all dead at-run-time code with nops.
++ */
++static void sanitize_dead_code(struct bpf_verifier_env *env)
++{
++      struct bpf_insn_aux_data *aux_data = env->insn_aux_data;
++      struct bpf_insn nop = BPF_MOV64_REG(BPF_REG_0, BPF_REG_0);
++      struct bpf_insn *insn = env->prog->insnsi;
++      const int insn_cnt = env->prog->len;
++      int i;
++
++      for (i = 0; i < insn_cnt; i++) {
++              if (aux_data[i].seen)
++                      continue;
++              memcpy(insn + i, &nop, sizeof(nop));
++      }
++}
++
+ /* convert load instructions that access fields of 'struct __sk_buff'
+  * into sequence of instructions that access fields of 'struct sk_buff'
+  */
+@@ -3407,6 +3431,9 @@ skip_full_check:
+       free_states(env);
+       if (ret == 0)
++              sanitize_dead_code(env);
++
++      if (ret == 0)
+               /* program is valid, convert *(u32*)(ctx + off) accesses */
+               ret = convert_ctx_accesses(env);
diff --git a/queue-4.9/bpf-fix-incorrect-sign-extension-in-check_alu_op.patch b/queue-4.9/bpf-fix-incorrect-sign-extension-in-check_alu_op.patch
new file mode 100644 (file)
index 0000000..bafa97f
--- /dev/null
@@ -0,0 +1,61 @@
+From foo@baz Fri Dec 22 16:57:35 CET 2017
+From: Daniel Borkmann <daniel@iogearbox.net>
+Date: Fri, 22 Dec 2017 16:29:05 +0100
+Subject: bpf: fix incorrect sign extension in check_alu_op()
+To: gregkh@linuxfoundation.org
+Cc: ast@kernel.org, daniel@iogearbox.net, jannh@google.com, stable@vger.kernel.org
+Message-ID: <20171222152905.3455-5-daniel@iogearbox.net>
+
+From: Daniel Borkmann <daniel@iogearbox.net>
+
+
+From: Jann Horn <jannh@google.com>
+
+[ Upstream commit 95a762e2c8c942780948091f8f2a4f32fce1ac6f ]
+
+Distinguish between
+BPF_ALU64|BPF_MOV|BPF_K (load 32-bit immediate, sign-extended to 64-bit)
+and BPF_ALU|BPF_MOV|BPF_K (load 32-bit immediate, zero-padded to 64-bit);
+only perform sign extension in the first case.
+
+Starting with v4.14, this is exploitable by unprivileged users as long as
+the unprivileged_bpf_disabled sysctl isn't set.
+
+Debian assigned CVE-2017-16995 for this issue.
+
+v3:
+ - add CVE number (Ben Hutchings)
+
+Fixes: 484611357c19 ("bpf: allow access into map value arrays")
+Signed-off-by: Jann Horn <jannh@google.com>
+Acked-by: Edward Cree <ecree@solarflare.com>
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/bpf/verifier.c |   13 ++++++++++---
+ 1 file changed, 10 insertions(+), 3 deletions(-)
+
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -1790,10 +1790,17 @@ static int check_alu_op(struct bpf_verif
+                       /* case: R = imm
+                        * remember the value we stored into this reg
+                        */
++                      u64 imm;
++
++                      if (BPF_CLASS(insn->code) == BPF_ALU64)
++                              imm = insn->imm;
++                      else
++                              imm = (u32)insn->imm;
++
+                       regs[insn->dst_reg].type = CONST_IMM;
+-                      regs[insn->dst_reg].imm = insn->imm;
+-                      regs[insn->dst_reg].max_value = insn->imm;
+-                      regs[insn->dst_reg].min_value = insn->imm;
++                      regs[insn->dst_reg].imm = imm;
++                      regs[insn->dst_reg].max_value = imm;
++                      regs[insn->dst_reg].min_value = imm;
+               }
+       } else if (opcode > BPF_END) {
diff --git a/queue-4.9/bpf-reject-out-of-bounds-stack-pointer-calculation.patch b/queue-4.9/bpf-reject-out-of-bounds-stack-pointer-calculation.patch
new file mode 100644 (file)
index 0000000..e83b5bd
--- /dev/null
@@ -0,0 +1,62 @@
+From foo@baz Fri Dec 22 16:57:35 CET 2017
+From: Daniel Borkmann <daniel@iogearbox.net>
+Date: Fri, 22 Dec 2017 16:29:04 +0100
+Subject: bpf: reject out-of-bounds stack pointer calculation
+To: gregkh@linuxfoundation.org
+Cc: ast@kernel.org, daniel@iogearbox.net, jannh@google.com, stable@vger.kernel.org
+Message-ID: <20171222152905.3455-4-daniel@iogearbox.net>
+
+From: Daniel Borkmann <daniel@iogearbox.net>
+
+
+From: Jann Horn <jannh@google.com>
+
+Reject programs that compute wildly out-of-bounds stack pointers.
+Otherwise, pointers can be computed with an offset that doesn't fit into an
+`int`, causing security issues in the stack memory access check (as well as
+signed integer overflow during offset addition).
+
+This is a fix specifically for the v4.9 stable tree because the mainline
+code looks very different at this point.
+
+Fixes: 7bca0a9702edf ("bpf: enhance verifier to understand stack pointer arithmetic")
+Signed-off-by: Jann Horn <jannh@google.com>
+Acked-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/bpf/verifier.c |   22 ++++++++++++++++++++--
+ 1 file changed, 20 insertions(+), 2 deletions(-)
+
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -1861,10 +1861,28 @@ static int check_alu_op(struct bpf_verif
+                          ((BPF_SRC(insn->code) == BPF_X &&
+                            regs[insn->src_reg].type == CONST_IMM) ||
+                           BPF_SRC(insn->code) == BPF_K)) {
+-                      if (BPF_SRC(insn->code) == BPF_X)
++                      if (BPF_SRC(insn->code) == BPF_X) {
++                              /* check in case the register contains a big
++                               * 64-bit value
++                               */
++                              if (regs[insn->src_reg].imm < -MAX_BPF_STACK ||
++                                  regs[insn->src_reg].imm > MAX_BPF_STACK) {
++                                      verbose("R%d value too big in R%d pointer arithmetic\n",
++                                              insn->src_reg, insn->dst_reg);
++                                      return -EACCES;
++                              }
+                               dst_reg->imm += regs[insn->src_reg].imm;
+-                      else
++                      } else {
++                              /* safe against overflow: addition of 32-bit
++                               * numbers in 64-bit representation
++                               */
+                               dst_reg->imm += insn->imm;
++                      }
++                      if (dst_reg->imm > 0 || dst_reg->imm < -MAX_BPF_STACK) {
++                              verbose("R%d out-of-bounds pointer arithmetic\n",
++                                      insn->dst_reg);
++                              return -EACCES;
++                      }
+                       return 0;
+               } else if (opcode == BPF_ADD &&
+                          BPF_CLASS(insn->code) == BPF_ALU64 &&
index 14a69767bef8c54d890ec546c1c3a9712eb0d052..b455b3a46e5b2bd8c4383c599ee74ba3601a8167 100644 (file)
@@ -101,3 +101,7 @@ thermal-drivers-hisi-fix-multiple-alarm-interrupts-firing.patch
 mips-math-emu-fix-final-emulation-phase-for-certain-instructions.patch
 platform-x86-asus-wireless-send-an-ev_syn-syn_report-between-state-changes.patch
 revert-bluetooth-btusb-driver-to-enable-the-usb-wakeup.patch
+bpf-adjust-insn_aux_data-when-patching-insns.patch
+bpf-fix-branch-pruning-logic.patch
+bpf-reject-out-of-bounds-stack-pointer-calculation.patch
+bpf-fix-incorrect-sign-extension-in-check_alu_op.patch