]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.14-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 22 Dec 2017 15:47:35 +0000 (16:47 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 22 Dec 2017 15:47:35 +0000 (16:47 +0100)
added patches:
bpf-don-t-prune-branches-when-a-scalar-is-replaced-with-a-pointer.patch
bpf-fix-32-bit-alu-op-verification.patch
bpf-fix-branch-pruning-logic.patch
bpf-fix-corruption-on-concurrent-perf_event_output-calls.patch
bpf-fix-incorrect-sign-extension-in-check_alu_op.patch
bpf-fix-incorrect-tracking-of-register-size-truncation.patch
bpf-fix-integer-overflows.patch
bpf-fix-missing-error-return-in-check_stack_boundary.patch
bpf-force-strict-alignment-checks-for-stack-pointers.patch
bpf-ppc64-do-not-reload-skb-pointers-in-non-skb-context.patch
bpf-s390x-do-not-reload-skb-pointers-in-non-skb-context.patch
bpf-sparc-fix-usage-of-wrong-reg-for-load_skb_regs-after-call.patch
bpf-verifier-fix-bounds-calculation-on-bpf_rsh.patch
selftests-bpf-add-tests-for-recent-bugfixes.patch

15 files changed:
queue-4.14/bpf-don-t-prune-branches-when-a-scalar-is-replaced-with-a-pointer.patch [new file with mode: 0644]
queue-4.14/bpf-fix-32-bit-alu-op-verification.patch [new file with mode: 0644]
queue-4.14/bpf-fix-branch-pruning-logic.patch [new file with mode: 0644]
queue-4.14/bpf-fix-corruption-on-concurrent-perf_event_output-calls.patch [new file with mode: 0644]
queue-4.14/bpf-fix-incorrect-sign-extension-in-check_alu_op.patch [new file with mode: 0644]
queue-4.14/bpf-fix-incorrect-tracking-of-register-size-truncation.patch [new file with mode: 0644]
queue-4.14/bpf-fix-integer-overflows.patch [new file with mode: 0644]
queue-4.14/bpf-fix-missing-error-return-in-check_stack_boundary.patch [new file with mode: 0644]
queue-4.14/bpf-force-strict-alignment-checks-for-stack-pointers.patch [new file with mode: 0644]
queue-4.14/bpf-ppc64-do-not-reload-skb-pointers-in-non-skb-context.patch [new file with mode: 0644]
queue-4.14/bpf-s390x-do-not-reload-skb-pointers-in-non-skb-context.patch [new file with mode: 0644]
queue-4.14/bpf-sparc-fix-usage-of-wrong-reg-for-load_skb_regs-after-call.patch [new file with mode: 0644]
queue-4.14/bpf-verifier-fix-bounds-calculation-on-bpf_rsh.patch [new file with mode: 0644]
queue-4.14/selftests-bpf-add-tests-for-recent-bugfixes.patch [new file with mode: 0644]
queue-4.14/series

diff --git a/queue-4.14/bpf-don-t-prune-branches-when-a-scalar-is-replaced-with-a-pointer.patch b/queue-4.14/bpf-don-t-prune-branches-when-a-scalar-is-replaced-with-a-pointer.patch
new file mode 100644 (file)
index 0000000..f4db8eb
--- /dev/null
@@ -0,0 +1,54 @@
+From foo@baz Fri Dec 22 16:47:02 CET 2017
+From: Daniel Borkmann <daniel@iogearbox.net>
+Date: Fri, 22 Dec 2017 16:23:10 +0100
+Subject: [PATCH stable/4.14 12/14] bpf: don't prune branches when a scalar is replaced with a pointer
+To: gregkh@linuxfoundation.org
+Cc: ast@kernel.org, daniel@iogearbox.net, jannh@google.com, stable@vger.kernel.org
+Message-ID: <20171222152312.2945-13-daniel@iogearbox.net>
+
+From: Daniel Borkmann <daniel@iogearbox.net>
+
+
+From: Jann Horn <jannh@google.com>
+
+[ Upstream commit 179d1c5602997fef5a940c6ddcf31212cbfebd14 ]
+
+This could be made safe by passing through a reference to env and checking
+for env->allow_ptr_leaks, but it would only work one way and is probably
+not worth the hassle - not doing it will not directly lead to program
+rejection.
+
+Fixes: f1174f77b50c ("bpf/verifier: rework value tracking")
+Signed-off-by: Jann Horn <jannh@google.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 |   15 +++++++--------
+ 1 file changed, 7 insertions(+), 8 deletions(-)
+
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -3337,15 +3337,14 @@ static bool regsafe(struct bpf_reg_state
+                       return range_within(rold, rcur) &&
+                              tnum_in(rold->var_off, rcur->var_off);
+               } else {
+-                      /* if we knew anything about the old value, we're not
+-                       * equal, because we can't know anything about the
+-                       * scalar value of the pointer in the new value.
++                      /* We're trying to use a pointer in place of a scalar.
++                       * Even if the scalar was unbounded, this could lead to
++                       * pointer leaks because scalars are allowed to leak
++                       * while pointers are not. We could make this safe in
++                       * special cases if root is calling us, but it's
++                       * probably not worth the hassle.
+                        */
+-                      return rold->umin_value == 0 &&
+-                             rold->umax_value == U64_MAX &&
+-                             rold->smin_value == S64_MIN &&
+-                             rold->smax_value == S64_MAX &&
+-                             tnum_is_unknown(rold->var_off);
++                      return false;
+               }
+       case PTR_TO_MAP_VALUE:
+               /* If the new min/max/var_off satisfy the old ones and
diff --git a/queue-4.14/bpf-fix-32-bit-alu-op-verification.patch b/queue-4.14/bpf-fix-32-bit-alu-op-verification.patch
new file mode 100644 (file)
index 0000000..dc65c40
--- /dev/null
@@ -0,0 +1,93 @@
+From foo@baz Fri Dec 22 16:47:02 CET 2017
+From: Daniel Borkmann <daniel@iogearbox.net>
+Date: Fri, 22 Dec 2017 16:23:07 +0100
+Subject: [PATCH stable/4.14 09/14] bpf: fix 32-bit ALU op verification
+To: gregkh@linuxfoundation.org
+Cc: ast@kernel.org, daniel@iogearbox.net, jannh@google.com, stable@vger.kernel.org
+Message-ID: <20171222152312.2945-10-daniel@iogearbox.net>
+
+From: Daniel Borkmann <daniel@iogearbox.net>
+
+
+From: Jann Horn <jannh@google.com>
+
+[ Upstream commit 468f6eafa6c44cb2c5d8aad35e12f06c240a812a ]
+
+32-bit ALU ops operate on 32-bit values and have 32-bit outputs.
+Adjust the verifier accordingly.
+
+Fixes: f1174f77b50c ("bpf/verifier: rework value tracking")
+Signed-off-by: Jann Horn <jannh@google.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 |   28 +++++++++++++++++-----------
+ 1 file changed, 17 insertions(+), 11 deletions(-)
+
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -1984,6 +1984,10 @@ static int adjust_ptr_min_max_vals(struc
+       return 0;
+ }
++/* WARNING: This function does calculations on 64-bit values, but the actual
++ * execution may occur on 32-bit values. Therefore, things like bitshifts
++ * need extra checks in the 32-bit case.
++ */
+ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env,
+                                     struct bpf_insn *insn,
+                                     struct bpf_reg_state *dst_reg,
+@@ -1994,12 +1998,8 @@ static int adjust_scalar_min_max_vals(st
+       bool src_known, dst_known;
+       s64 smin_val, smax_val;
+       u64 umin_val, umax_val;
++      u64 insn_bitness = (BPF_CLASS(insn->code) == BPF_ALU64) ? 64 : 32;
+-      if (BPF_CLASS(insn->code) != BPF_ALU64) {
+-              /* 32-bit ALU ops are (32,32)->64 */
+-              coerce_reg_to_size(dst_reg, 4);
+-              coerce_reg_to_size(&src_reg, 4);
+-      }
+       smin_val = src_reg.smin_value;
+       smax_val = src_reg.smax_value;
+       umin_val = src_reg.umin_value;
+@@ -2135,9 +2135,9 @@ static int adjust_scalar_min_max_vals(st
+               __update_reg_bounds(dst_reg);
+               break;
+       case BPF_LSH:
+-              if (umax_val > 63) {
+-                      /* Shifts greater than 63 are undefined.  This includes
+-                       * shifts by a negative number.
++              if (umax_val >= insn_bitness) {
++                      /* Shifts greater than 31 or 63 are undefined.
++                       * This includes shifts by a negative number.
+                        */
+                       mark_reg_unknown(regs, insn->dst_reg);
+                       break;
+@@ -2163,9 +2163,9 @@ static int adjust_scalar_min_max_vals(st
+               __update_reg_bounds(dst_reg);
+               break;
+       case BPF_RSH:
+-              if (umax_val > 63) {
+-                      /* Shifts greater than 63 are undefined.  This includes
+-                       * shifts by a negative number.
++              if (umax_val >= insn_bitness) {
++                      /* Shifts greater than 31 or 63 are undefined.
++                       * This includes shifts by a negative number.
+                        */
+                       mark_reg_unknown(regs, insn->dst_reg);
+                       break;
+@@ -2201,6 +2201,12 @@ static int adjust_scalar_min_max_vals(st
+               break;
+       }
++      if (BPF_CLASS(insn->code) != BPF_ALU64) {
++              /* 32-bit ALU ops are (32,32)->32 */
++              coerce_reg_to_size(dst_reg, 4);
++              coerce_reg_to_size(&src_reg, 4);
++      }
++
+       __reg_deduce_bounds(dst_reg);
+       __reg_bound_offset(dst_reg);
+       return 0;
diff --git a/queue-4.14/bpf-fix-branch-pruning-logic.patch b/queue-4.14/bpf-fix-branch-pruning-logic.patch
new file mode 100644 (file)
index 0000000..9ac9143
--- /dev/null
@@ -0,0 +1,123 @@
+From foo@baz Fri Dec 22 16:47:02 CET 2017
+From: Daniel Borkmann <daniel@iogearbox.net>
+Date: Fri, 22 Dec 2017 16:22:59 +0100
+Subject: [PATCH stable/4.14 01/14] 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: <20171222152312.2945-2-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 |    2 +-
+ kernel/bpf/verifier.c        |   27 +++++++++++++++++++++++++++
+ 2 files changed, 28 insertions(+), 1 deletion(-)
+
+--- a/include/linux/bpf_verifier.h
++++ b/include/linux/bpf_verifier.h
+@@ -110,7 +110,7 @@ struct bpf_insn_aux_data {
+               struct bpf_map *map_ptr;        /* pointer for call insn into lookup_elem */
+       };
+       int ctx_field_size; /* the ctx field size for load insn, maybe 0 */
+-      int converted_op_size; /* the valid value width after perceived conversion */
++      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
+@@ -3665,6 +3665,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)
+@@ -3855,6 +3856,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;
+@@ -4035,6 +4037,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;
+@@ -4044,6 +4047,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;
+@@ -4062,6 +4067,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'
+  */
+@@ -4379,6 +4403,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.14/bpf-fix-corruption-on-concurrent-perf_event_output-calls.patch b/queue-4.14/bpf-fix-corruption-on-concurrent-perf_event_output-calls.patch
new file mode 100644 (file)
index 0000000..206534a
--- /dev/null
@@ -0,0 +1,113 @@
+From foo@baz Fri Dec 22 16:47:02 CET 2017
+From: Daniel Borkmann <daniel@iogearbox.net>
+Date: Fri, 22 Dec 2017 16:23:00 +0100
+Subject: [PATCH stable/4.14 02/14] bpf: fix corruption on concurrent perf_event_output calls
+To: gregkh@linuxfoundation.org
+Cc: ast@kernel.org, daniel@iogearbox.net, jannh@google.com, stable@vger.kernel.org
+Message-ID: <20171222152312.2945-3-daniel@iogearbox.net>
+
+From: Daniel Borkmann <daniel@iogearbox.net>
+
+
+[ Upstream commit 283ca526a9bd75aed7350220d7b1f8027d99c3fd ]
+
+When tracing and networking programs are both attached in the
+system and both use event-output helpers that eventually call
+into perf_event_output(), then we could end up in a situation
+where the tracing attached program runs in user context while
+a cls_bpf program is triggered on that same CPU out of softirq
+context.
+
+Since both rely on the same per-cpu perf_sample_data, we could
+potentially corrupt it. This can only ever happen in a combination
+of the two types; all tracing programs use a bpf_prog_active
+counter to bail out in case a program is already running on
+that CPU out of a different context. XDP and cls_bpf programs
+by themselves don't have this issue as they run in the same
+context only. Therefore, split both perf_sample_data so they
+cannot be accessed from each other.
+
+Fixes: 20b9d7ac4852 ("bpf: avoid excessive stack usage for perf_sample_data")
+Reported-by: Alexei Starovoitov <ast@fb.com>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Tested-by: Song Liu <songliubraving@fb.com>
+Acked-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/trace/bpf_trace.c |   19 ++++++++++++-------
+ 1 file changed, 12 insertions(+), 7 deletions(-)
+
+--- a/kernel/trace/bpf_trace.c
++++ b/kernel/trace/bpf_trace.c
+@@ -293,14 +293,13 @@ static const struct bpf_func_proto bpf_p
+       .arg2_type      = ARG_ANYTHING,
+ };
+-static DEFINE_PER_CPU(struct perf_sample_data, bpf_sd);
++static DEFINE_PER_CPU(struct perf_sample_data, bpf_trace_sd);
+ static __always_inline u64
+ __bpf_perf_event_output(struct pt_regs *regs, struct bpf_map *map,
+-                      u64 flags, struct perf_raw_record *raw)
++                      u64 flags, struct perf_sample_data *sd)
+ {
+       struct bpf_array *array = container_of(map, struct bpf_array, map);
+-      struct perf_sample_data *sd = this_cpu_ptr(&bpf_sd);
+       unsigned int cpu = smp_processor_id();
+       u64 index = flags & BPF_F_INDEX_MASK;
+       struct bpf_event_entry *ee;
+@@ -323,8 +322,6 @@ __bpf_perf_event_output(struct pt_regs *
+       if (unlikely(event->oncpu != cpu))
+               return -EOPNOTSUPP;
+-      perf_sample_data_init(sd, 0, 0);
+-      sd->raw = raw;
+       perf_event_output(event, sd, regs);
+       return 0;
+ }
+@@ -332,6 +329,7 @@ __bpf_perf_event_output(struct pt_regs *
+ BPF_CALL_5(bpf_perf_event_output, struct pt_regs *, regs, struct bpf_map *, map,
+          u64, flags, void *, data, u64, size)
+ {
++      struct perf_sample_data *sd = this_cpu_ptr(&bpf_trace_sd);
+       struct perf_raw_record raw = {
+               .frag = {
+                       .size = size,
+@@ -342,7 +340,10 @@ BPF_CALL_5(bpf_perf_event_output, struct
+       if (unlikely(flags & ~(BPF_F_INDEX_MASK)))
+               return -EINVAL;
+-      return __bpf_perf_event_output(regs, map, flags, &raw);
++      perf_sample_data_init(sd, 0, 0);
++      sd->raw = &raw;
++
++      return __bpf_perf_event_output(regs, map, flags, sd);
+ }
+ static const struct bpf_func_proto bpf_perf_event_output_proto = {
+@@ -357,10 +358,12 @@ static const struct bpf_func_proto bpf_p
+ };
+ static DEFINE_PER_CPU(struct pt_regs, bpf_pt_regs);
++static DEFINE_PER_CPU(struct perf_sample_data, bpf_misc_sd);
+ u64 bpf_event_output(struct bpf_map *map, u64 flags, void *meta, u64 meta_size,
+                    void *ctx, u64 ctx_size, bpf_ctx_copy_t ctx_copy)
+ {
++      struct perf_sample_data *sd = this_cpu_ptr(&bpf_misc_sd);
+       struct pt_regs *regs = this_cpu_ptr(&bpf_pt_regs);
+       struct perf_raw_frag frag = {
+               .copy           = ctx_copy,
+@@ -378,8 +381,10 @@ u64 bpf_event_output(struct bpf_map *map
+       };
+       perf_fetch_caller_regs(regs);
++      perf_sample_data_init(sd, 0, 0);
++      sd->raw = &raw;
+-      return __bpf_perf_event_output(regs, map, flags, &raw);
++      return __bpf_perf_event_output(regs, map, flags, sd);
+ }
+ BPF_CALL_0(bpf_get_current_task)
diff --git a/queue-4.14/bpf-fix-incorrect-sign-extension-in-check_alu_op.patch b/queue-4.14/bpf-fix-incorrect-sign-extension-in-check_alu_op.patch
new file mode 100644 (file)
index 0000000..bb2a669
--- /dev/null
@@ -0,0 +1,55 @@
+From foo@baz Fri Dec 22 16:47:02 CET 2017
+From: Daniel Borkmann <daniel@iogearbox.net>
+Date: Fri, 22 Dec 2017 16:23:05 +0100
+Subject: [PATCH stable/4.14 07/14] 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: <20171222152312.2945-8-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 |    8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -2374,7 +2374,13 @@ static int check_alu_op(struct bpf_verif
+                        * remember the value we stored into this reg
+                        */
+                       regs[insn->dst_reg].type = SCALAR_VALUE;
+-                      __mark_reg_known(regs + insn->dst_reg, insn->imm);
++                      if (BPF_CLASS(insn->code) == BPF_ALU64) {
++                              __mark_reg_known(regs + insn->dst_reg,
++                                               insn->imm);
++                      } else {
++                              __mark_reg_known(regs + insn->dst_reg,
++                                               (u32)insn->imm);
++                      }
+               }
+       } else if (opcode > BPF_END) {
diff --git a/queue-4.14/bpf-fix-incorrect-tracking-of-register-size-truncation.patch b/queue-4.14/bpf-fix-incorrect-tracking-of-register-size-truncation.patch
new file mode 100644 (file)
index 0000000..5979059
--- /dev/null
@@ -0,0 +1,129 @@
+From foo@baz Fri Dec 22 16:47:02 CET 2017
+From: Daniel Borkmann <daniel@iogearbox.net>
+Date: Fri, 22 Dec 2017 16:23:06 +0100
+Subject: [PATCH stable/4.14 08/14] bpf: fix incorrect tracking of register size truncation
+To: gregkh@linuxfoundation.org
+Cc: ast@kernel.org, daniel@iogearbox.net, jannh@google.com, stable@vger.kernel.org
+Message-ID: <20171222152312.2945-9-daniel@iogearbox.net>
+
+From: Daniel Borkmann <daniel@iogearbox.net>
+
+
+From: Jann Horn <jannh@google.com>
+
+[ Upstream commit 0c17d1d2c61936401f4702e1846e2c19b200f958 ]
+
+Properly handle register truncation to a smaller size.
+
+The old code first mirrors the clearing of the high 32 bits in the bitwise
+tristate representation, which is correct. But then, it computes the new
+arithmetic bounds as the intersection between the old arithmetic bounds and
+the bounds resulting from the bitwise tristate representation. Therefore,
+when coerce_reg_to_32() is called on a number with bounds
+[0xffff'fff8, 0x1'0000'0007], the verifier computes
+[0xffff'fff8, 0xffff'ffff] as bounds of the truncated number.
+This is incorrect: The truncated number could also be in the range [0, 7],
+and no meaningful arithmetic bounds can be computed in that case apart from
+the obvious [0, 0xffff'ffff].
+
+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-16996 for this issue.
+
+v2:
+ - flip the mask during arithmetic bounds calculation (Ben Hutchings)
+v3:
+ - add CVE number (Ben Hutchings)
+
+Fixes: b03c9f9fdc37 ("bpf/verifier: track signed and unsigned min/max values")
+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 |   44 +++++++++++++++++++++++++++-----------------
+ 1 file changed, 27 insertions(+), 17 deletions(-)
+
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -1068,6 +1068,29 @@ static int check_ptr_alignment(struct bp
+       return check_generic_ptr_alignment(reg, pointer_desc, off, size, strict);
+ }
++/* truncate register to smaller size (in bytes)
++ * must be called with size < BPF_REG_SIZE
++ */
++static void coerce_reg_to_size(struct bpf_reg_state *reg, int size)
++{
++      u64 mask;
++
++      /* clear high bits in bit representation */
++      reg->var_off = tnum_cast(reg->var_off, size);
++
++      /* fix arithmetic bounds */
++      mask = ((u64)1 << (size * 8)) - 1;
++      if ((reg->umin_value & ~mask) == (reg->umax_value & ~mask)) {
++              reg->umin_value &= mask;
++              reg->umax_value &= mask;
++      } else {
++              reg->umin_value = 0;
++              reg->umax_value = mask;
++      }
++      reg->smin_value = reg->umin_value;
++      reg->smax_value = reg->umax_value;
++}
++
+ /* check whether memory at (regno + off) is accessible for t = (read | write)
+  * if t==write, value_regno is a register which value is stored into memory
+  * if t==read, value_regno is a register which will receive the value from memory
+@@ -1200,9 +1223,7 @@ static int check_mem_access(struct bpf_v
+       if (!err && size < BPF_REG_SIZE && value_regno >= 0 && t == BPF_READ &&
+           state->regs[value_regno].type == SCALAR_VALUE) {
+               /* b/h/w load zero-extends, mark upper bits as known 0 */
+-              state->regs[value_regno].var_off = tnum_cast(
+-                                      state->regs[value_regno].var_off, size);
+-              __update_reg_bounds(&state->regs[value_regno]);
++              coerce_reg_to_size(&state->regs[value_regno], size);
+       }
+       return err;
+ }
+@@ -1742,14 +1763,6 @@ static int check_call(struct bpf_verifie
+       return 0;
+ }
+-static void coerce_reg_to_32(struct bpf_reg_state *reg)
+-{
+-      /* clear high 32 bits */
+-      reg->var_off = tnum_cast(reg->var_off, 4);
+-      /* Update bounds */
+-      __update_reg_bounds(reg);
+-}
+-
+ static bool signed_add_overflows(s64 a, s64 b)
+ {
+       /* Do the add in u64, where overflow is well-defined */
+@@ -1984,8 +1997,8 @@ static int adjust_scalar_min_max_vals(st
+       if (BPF_CLASS(insn->code) != BPF_ALU64) {
+               /* 32-bit ALU ops are (32,32)->64 */
+-              coerce_reg_to_32(dst_reg);
+-              coerce_reg_to_32(&src_reg);
++              coerce_reg_to_size(dst_reg, 4);
++              coerce_reg_to_size(&src_reg, 4);
+       }
+       smin_val = src_reg.smin_value;
+       smax_val = src_reg.smax_value;
+@@ -2364,10 +2377,7 @@ static int check_alu_op(struct bpf_verif
+                                       return -EACCES;
+                               }
+                               mark_reg_unknown(regs, insn->dst_reg);
+-                              /* high 32 bits are known zero. */
+-                              regs[insn->dst_reg].var_off = tnum_cast(
+-                                              regs[insn->dst_reg].var_off, 4);
+-                              __update_reg_bounds(&regs[insn->dst_reg]);
++                              coerce_reg_to_size(&regs[insn->dst_reg], 4);
+                       }
+               } else {
+                       /* case: R = imm
diff --git a/queue-4.14/bpf-fix-integer-overflows.patch b/queue-4.14/bpf-fix-integer-overflows.patch
new file mode 100644 (file)
index 0000000..ccd0233
--- /dev/null
@@ -0,0 +1,132 @@
+From foo@baz Fri Dec 22 16:47:02 CET 2017
+From: Daniel Borkmann <daniel@iogearbox.net>
+Date: Fri, 22 Dec 2017 16:23:11 +0100
+Subject: [PATCH stable/4.14 13/14] bpf: fix integer overflows
+To: gregkh@linuxfoundation.org
+Cc: ast@kernel.org, daniel@iogearbox.net, jannh@google.com, stable@vger.kernel.org
+Message-ID: <20171222152312.2945-14-daniel@iogearbox.net>
+
+From: Daniel Borkmann <daniel@iogearbox.net>
+
+
+From: Alexei Starovoitov <ast@kernel.org>
+
+[ Upstream commit bb7f0f989ca7de1153bd128a40a71709e339fa03 ]
+
+There were various issues related to the limited size of integers used in
+the verifier:
+ - `off + size` overflow in __check_map_access()
+ - `off + reg->off` overflow in check_mem_access()
+ - `off + reg->var_off.value` overflow or 32-bit truncation of
+   `reg->var_off.value` in check_mem_access()
+ - 32-bit truncation in check_stack_boundary()
+
+Make sure that any integer math cannot overflow by not allowing
+pointer math with large values.
+
+Also reduce the scope of "scalar op scalar" tracking.
+
+Fixes: f1174f77b50c ("bpf/verifier: rework value tracking")
+Reported-by: Jann Horn <jannh@google.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>
+---
+ include/linux/bpf_verifier.h |    4 +--
+ kernel/bpf/verifier.c        |   48 +++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 50 insertions(+), 2 deletions(-)
+
+--- a/include/linux/bpf_verifier.h
++++ b/include/linux/bpf_verifier.h
+@@ -15,11 +15,11 @@
+  * In practice this is far bigger than any realistic pointer offset; this limit
+  * ensures that umax_value + (int)off + (int)size cannot overflow a u64.
+  */
+-#define BPF_MAX_VAR_OFF       (1ULL << 31)
++#define BPF_MAX_VAR_OFF       (1 << 29)
+ /* Maximum variable size permitted for ARG_CONST_SIZE[_OR_ZERO].  This ensures
+  * that converting umax_value to int cannot overflow.
+  */
+-#define BPF_MAX_VAR_SIZ       INT_MAX
++#define BPF_MAX_VAR_SIZ       (1 << 29)
+ /* Liveness marks, used for registers and spilled-regs (in stack slots).
+  * Read marks propagate upwards until they find a write mark; they record that
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -1789,6 +1789,41 @@ static bool signed_sub_overflows(s64 a,
+       return res > a;
+ }
++static bool check_reg_sane_offset(struct bpf_verifier_env *env,
++                                const struct bpf_reg_state *reg,
++                                enum bpf_reg_type type)
++{
++      bool known = tnum_is_const(reg->var_off);
++      s64 val = reg->var_off.value;
++      s64 smin = reg->smin_value;
++
++      if (known && (val >= BPF_MAX_VAR_OFF || val <= -BPF_MAX_VAR_OFF)) {
++              verbose("math between %s pointer and %lld is not allowed\n",
++                      reg_type_str[type], val);
++              return false;
++      }
++
++      if (reg->off >= BPF_MAX_VAR_OFF || reg->off <= -BPF_MAX_VAR_OFF) {
++              verbose("%s pointer offset %d is not allowed\n",
++                      reg_type_str[type], reg->off);
++              return false;
++      }
++
++      if (smin == S64_MIN) {
++              verbose("math between %s pointer and register with unbounded min value is not allowed\n",
++                      reg_type_str[type]);
++              return false;
++      }
++
++      if (smin >= BPF_MAX_VAR_OFF || smin <= -BPF_MAX_VAR_OFF) {
++              verbose("value %lld makes %s pointer be out of bounds\n",
++                      smin, reg_type_str[type]);
++              return false;
++      }
++
++      return true;
++}
++
+ /* Handles arithmetic on a pointer and a scalar: computes new min/max and var_off.
+  * Caller should also handle BPF_MOV case separately.
+  * If we return -EACCES, caller may want to try again treating pointer as a
+@@ -1854,6 +1889,10 @@ static int adjust_ptr_min_max_vals(struc
+       dst_reg->type = ptr_reg->type;
+       dst_reg->id = ptr_reg->id;
++      if (!check_reg_sane_offset(env, off_reg, ptr_reg->type) ||
++          !check_reg_sane_offset(env, ptr_reg, ptr_reg->type))
++              return -EINVAL;
++
+       switch (opcode) {
+       case BPF_ADD:
+               /* We can take a fixed offset as long as it doesn't overflow
+@@ -1984,6 +2023,9 @@ static int adjust_ptr_min_max_vals(struc
+               return -EACCES;
+       }
++      if (!check_reg_sane_offset(env, dst_reg, ptr_reg->type))
++              return -EINVAL;
++
+       __update_reg_bounds(dst_reg);
+       __reg_deduce_bounds(dst_reg);
+       __reg_bound_offset(dst_reg);
+@@ -2013,6 +2055,12 @@ static int adjust_scalar_min_max_vals(st
+       src_known = tnum_is_const(src_reg.var_off);
+       dst_known = tnum_is_const(dst_reg->var_off);
++      if (!src_known &&
++          opcode != BPF_ADD && opcode != BPF_SUB && opcode != BPF_AND) {
++              __mark_reg_unknown(dst_reg);
++              return 0;
++      }
++
+       switch (opcode) {
+       case BPF_ADD:
+               if (signed_add_overflows(dst_reg->smin_value, smin_val) ||
diff --git a/queue-4.14/bpf-fix-missing-error-return-in-check_stack_boundary.patch b/queue-4.14/bpf-fix-missing-error-return-in-check_stack_boundary.patch
new file mode 100644 (file)
index 0000000..87856fd
--- /dev/null
@@ -0,0 +1,35 @@
+From foo@baz Fri Dec 22 16:47:02 CET 2017
+From: Daniel Borkmann <daniel@iogearbox.net>
+Date: Fri, 22 Dec 2017 16:23:08 +0100
+Subject: [PATCH stable/4.14 10/14] bpf: fix missing error return in check_stack_boundary()
+To: gregkh@linuxfoundation.org
+Cc: ast@kernel.org, daniel@iogearbox.net, jannh@google.com, stable@vger.kernel.org
+Message-ID: <20171222152312.2945-11-daniel@iogearbox.net>
+
+From: Daniel Borkmann <daniel@iogearbox.net>
+
+
+From: Jann Horn <jannh@google.com>
+
+Prevent indirect stack accesses at non-constant addresses, which would
+permit reading and corrupting spilled pointers.
+
+Fixes: f1174f77b50c ("bpf/verifier: rework value tracking")
+Signed-off-by: Jann Horn <jannh@google.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 |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -1303,6 +1303,7 @@ static int check_stack_boundary(struct b
+               tnum_strn(tn_buf, sizeof(tn_buf), regs[regno].var_off);
+               verbose("invalid variable stack read R%d var_off=%s\n",
+                       regno, tn_buf);
++              return -EACCES;
+       }
+       off = regs[regno].off + regs[regno].var_off.value;
+       if (off >= 0 || off < -MAX_BPF_STACK || off + access_size > 0 ||
diff --git a/queue-4.14/bpf-force-strict-alignment-checks-for-stack-pointers.patch b/queue-4.14/bpf-force-strict-alignment-checks-for-stack-pointers.patch
new file mode 100644 (file)
index 0000000..76a7479
--- /dev/null
@@ -0,0 +1,42 @@
+From foo@baz Fri Dec 22 16:47:02 CET 2017
+From: Daniel Borkmann <daniel@iogearbox.net>
+Date: Fri, 22 Dec 2017 16:23:09 +0100
+Subject: [PATCH stable/4.14 11/14] bpf: force strict alignment checks for stack pointers
+To: gregkh@linuxfoundation.org
+Cc: ast@kernel.org, daniel@iogearbox.net, jannh@google.com, stable@vger.kernel.org
+Message-ID: <20171222152312.2945-12-daniel@iogearbox.net>
+
+From: Daniel Borkmann <daniel@iogearbox.net>
+
+
+From: Jann Horn <jannh@google.com>
+
+[ Upstream commit a5ec6ae161d72f01411169a938fa5f8baea16e8f ]
+
+Force strict alignment checks for stack pointers because the tracking of
+stack spills relies on it; unaligned stack accesses can lead to corruption
+of spilled registers, which is exploitable.
+
+Fixes: f1174f77b50c ("bpf/verifier: rework value tracking")
+Signed-off-by: Jann Horn <jannh@google.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 |    5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -1061,6 +1061,11 @@ static int check_ptr_alignment(struct bp
+               break;
+       case PTR_TO_STACK:
+               pointer_desc = "stack ";
++              /* The stack spill tracking logic in check_stack_write()
++               * and check_stack_read() relies on stack accesses being
++               * aligned.
++               */
++              strict = true;
+               break;
+       default:
+               break;
diff --git a/queue-4.14/bpf-ppc64-do-not-reload-skb-pointers-in-non-skb-context.patch b/queue-4.14/bpf-ppc64-do-not-reload-skb-pointers-in-non-skb-context.patch
new file mode 100644 (file)
index 0000000..54039eb
--- /dev/null
@@ -0,0 +1,57 @@
+From foo@baz Fri Dec 22 16:47:02 CET 2017
+From: Daniel Borkmann <daniel@iogearbox.net>
+Date: Fri, 22 Dec 2017 16:23:02 +0100
+Subject: [PATCH stable/4.14 04/14] bpf, ppc64: do not reload skb pointers in non-skb context
+To: gregkh@linuxfoundation.org
+Cc: ast@kernel.org, daniel@iogearbox.net, jannh@google.com, stable@vger.kernel.org
+Message-ID: <20171222152312.2945-5-daniel@iogearbox.net>
+
+From: Daniel Borkmann <daniel@iogearbox.net>
+
+
+[ Upstream commit 87338c8e2cbb317b5f757e6172f94e2e3799cd20 ]
+
+The assumption of unconditionally reloading skb pointers on
+BPF helper calls where bpf_helper_changes_pkt_data() holds
+true is wrong. There can be different contexts where the helper
+would enforce a reload such as in case of XDP. Here, we do
+have a struct xdp_buff instead of struct sk_buff as context,
+thus this will access garbage.
+
+JITs only ever need to deal with cached skb pointer reload
+when ld_abs/ind was seen, therefore guard the reload behind
+SEEN_SKB.
+
+Fixes: 156d0e290e96 ("powerpc/ebpf/jit: Implement JIT compiler for extended BPF")
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Reviewed-by: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>
+Acked-by: Alexei Starovoitov <ast@kernel.org>
+Tested-by: Sandipan Das <sandipan@linux.vnet.ibm.com>
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/powerpc/net/bpf_jit_comp64.c |    6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/arch/powerpc/net/bpf_jit_comp64.c
++++ b/arch/powerpc/net/bpf_jit_comp64.c
+@@ -762,7 +762,8 @@ emit_clear:
+                       func = (u8 *) __bpf_call_base + imm;
+                       /* Save skb pointer if we need to re-cache skb data */
+-                      if (bpf_helper_changes_pkt_data(func))
++                      if ((ctx->seen & SEEN_SKB) &&
++                          bpf_helper_changes_pkt_data(func))
+                               PPC_BPF_STL(3, 1, bpf_jit_stack_local(ctx));
+                       bpf_jit_emit_func_call(image, ctx, (u64)func);
+@@ -771,7 +772,8 @@ emit_clear:
+                       PPC_MR(b2p[BPF_REG_0], 3);
+                       /* refresh skb cache */
+-                      if (bpf_helper_changes_pkt_data(func)) {
++                      if ((ctx->seen & SEEN_SKB) &&
++                          bpf_helper_changes_pkt_data(func)) {
+                               /* reload skb pointer to r3 */
+                               PPC_BPF_LL(3, 1, bpf_jit_stack_local(ctx));
+                               bpf_jit_emit_skb_loads(image, ctx);
diff --git a/queue-4.14/bpf-s390x-do-not-reload-skb-pointers-in-non-skb-context.patch b/queue-4.14/bpf-s390x-do-not-reload-skb-pointers-in-non-skb-context.patch
new file mode 100644 (file)
index 0000000..920caf8
--- /dev/null
@@ -0,0 +1,72 @@
+From foo@baz Fri Dec 22 16:47:02 CET 2017
+From: Daniel Borkmann <daniel@iogearbox.net>
+Date: Fri, 22 Dec 2017 16:23:01 +0100
+Subject: [PATCH stable/4.14 03/14] bpf, s390x: do not reload skb pointers in non-skb context
+To: gregkh@linuxfoundation.org
+Cc: ast@kernel.org, daniel@iogearbox.net, jannh@google.com, stable@vger.kernel.org, Michael Holzheu <holzheu@linux.vnet.ibm.com>
+Message-ID: <20171222152312.2945-4-daniel@iogearbox.net>
+
+From: Daniel Borkmann <daniel@iogearbox.net>
+
+
+[ Upstream commit 6d59b7dbf72ed20d0138e2f9b75ca3d4a9d4faca ]
+
+The assumption of unconditionally reloading skb pointers on
+BPF helper calls where bpf_helper_changes_pkt_data() holds
+true is wrong. There can be different contexts where the
+BPF helper would enforce a reload such as in case of XDP.
+Here, we do have a struct xdp_buff instead of struct sk_buff
+as context, thus this will access garbage.
+
+JITs only ever need to deal with cached skb pointer reload
+when ld_abs/ind was seen, therefore guard the reload behind
+SEEN_SKB only. Tested on s390x.
+
+Fixes: 9db7f2b81880 ("s390/bpf: recache skb->data/hlen for skb_vlan_push/pop")
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Acked-by: Alexei Starovoitov <ast@kernel.org>
+Cc: Michael Holzheu <holzheu@linux.vnet.ibm.com>
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/s390/net/bpf_jit_comp.c |   11 +++++------
+ 1 file changed, 5 insertions(+), 6 deletions(-)
+
+--- a/arch/s390/net/bpf_jit_comp.c
++++ b/arch/s390/net/bpf_jit_comp.c
+@@ -55,8 +55,7 @@ struct bpf_jit {
+ #define SEEN_LITERAL  8       /* code uses literals */
+ #define SEEN_FUNC     16      /* calls C functions */
+ #define SEEN_TAIL_CALL        32      /* code uses tail calls */
+-#define SEEN_SKB_CHANGE       64      /* code changes skb data */
+-#define SEEN_REG_AX   128     /* code uses constant blinding */
++#define SEEN_REG_AX   64      /* code uses constant blinding */
+ #define SEEN_STACK    (SEEN_FUNC | SEEN_MEM | SEEN_SKB)
+ /*
+@@ -448,12 +447,12 @@ static void bpf_jit_prologue(struct bpf_
+                       EMIT6_DISP_LH(0xe3000000, 0x0024, REG_W1, REG_0,
+                                     REG_15, 152);
+       }
+-      if (jit->seen & SEEN_SKB)
++      if (jit->seen & SEEN_SKB) {
+               emit_load_skb_data_hlen(jit);
+-      if (jit->seen & SEEN_SKB_CHANGE)
+               /* stg %b1,ST_OFF_SKBP(%r0,%r15) */
+               EMIT6_DISP_LH(0xe3000000, 0x0024, BPF_REG_1, REG_0, REG_15,
+                             STK_OFF_SKBP);
++      }
+ }
+ /*
+@@ -983,8 +982,8 @@ static noinline int bpf_jit_insn(struct
+               EMIT2(0x0d00, REG_14, REG_W1);
+               /* lgr %b0,%r2: load return value into %b0 */
+               EMIT4(0xb9040000, BPF_REG_0, REG_2);
+-              if (bpf_helper_changes_pkt_data((void *)func)) {
+-                      jit->seen |= SEEN_SKB_CHANGE;
++              if ((jit->seen & SEEN_SKB) &&
++                  bpf_helper_changes_pkt_data((void *)func)) {
+                       /* lg %b1,ST_OFF_SKBP(%r15) */
+                       EMIT6_DISP_LH(0xe3000000, 0x0004, BPF_REG_1, REG_0,
+                                     REG_15, STK_OFF_SKBP);
diff --git a/queue-4.14/bpf-sparc-fix-usage-of-wrong-reg-for-load_skb_regs-after-call.patch b/queue-4.14/bpf-sparc-fix-usage-of-wrong-reg-for-load_skb_regs-after-call.patch
new file mode 100644 (file)
index 0000000..c7df885
--- /dev/null
@@ -0,0 +1,54 @@
+From foo@baz Fri Dec 22 16:47:02 CET 2017
+From: Daniel Borkmann <daniel@iogearbox.net>
+Date: Fri, 22 Dec 2017 16:23:03 +0100
+Subject: [PATCH stable/4.14 05/14] bpf, sparc: fix usage of wrong reg for load_skb_regs after call
+To: gregkh@linuxfoundation.org
+Cc: ast@kernel.org, daniel@iogearbox.net, jannh@google.com, stable@vger.kernel.org
+Message-ID: <20171222152312.2945-6-daniel@iogearbox.net>
+
+From: Daniel Borkmann <daniel@iogearbox.net>
+
+
+[ Upstream commit 07aee94394547721ac168cbf4e1c09c14a5fe671 ]
+
+When LD_ABS/IND is used in the program, and we have a BPF helper
+call that changes packet data (bpf_helper_changes_pkt_data() returns
+true), then in case of sparc JIT, we try to reload cached skb data
+from bpf2sparc[BPF_REG_6]. However, there is no such guarantee or
+assumption that skb sits in R6 at this point, all helpers changing
+skb data only have a guarantee that skb sits in R1. Therefore,
+store BPF R1 in L7 temporarily and after procedure call use L7 to
+reload cached skb data. skb sitting in R6 is only true at the time
+when LD_ABS/IND is executed.
+
+Fixes: 7a12b5031c6b ("sparc64: Add eBPF JIT.")
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Acked-by: David S. Miller <davem@davemloft.net>
+Acked-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/sparc/net/bpf_jit_comp_64.c |    6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/arch/sparc/net/bpf_jit_comp_64.c
++++ b/arch/sparc/net/bpf_jit_comp_64.c
+@@ -1245,14 +1245,16 @@ static int build_insn(const struct bpf_i
+               u8 *func = ((u8 *)__bpf_call_base) + imm;
+               ctx->saw_call = true;
++              if (ctx->saw_ld_abs_ind && bpf_helper_changes_pkt_data(func))
++                      emit_reg_move(bpf2sparc[BPF_REG_1], L7, ctx);
+               emit_call((u32 *)func, ctx);
+               emit_nop(ctx);
+               emit_reg_move(O0, bpf2sparc[BPF_REG_0], ctx);
+-              if (bpf_helper_changes_pkt_data(func) && ctx->saw_ld_abs_ind)
+-                      load_skb_regs(ctx, bpf2sparc[BPF_REG_6]);
++              if (ctx->saw_ld_abs_ind && bpf_helper_changes_pkt_data(func))
++                      load_skb_regs(ctx, L7);
+               break;
+       }
diff --git a/queue-4.14/bpf-verifier-fix-bounds-calculation-on-bpf_rsh.patch b/queue-4.14/bpf-verifier-fix-bounds-calculation-on-bpf_rsh.patch
new file mode 100644 (file)
index 0000000..35a82c3
--- /dev/null
@@ -0,0 +1,72 @@
+From foo@baz Fri Dec 22 16:47:02 CET 2017
+From: Daniel Borkmann <daniel@iogearbox.net>
+Date: Fri, 22 Dec 2017 16:23:04 +0100
+Subject: [PATCH stable/4.14 06/14] bpf/verifier: fix bounds calculation on BPF_RSH
+To: gregkh@linuxfoundation.org
+Cc: ast@kernel.org, daniel@iogearbox.net, jannh@google.com, stable@vger.kernel.org, Edward Cree <ecree@solarflare.com>
+Message-ID: <20171222152312.2945-7-daniel@iogearbox.net>
+
+From: Daniel Borkmann <daniel@iogearbox.net>
+
+
+From: Edward Cree <ecree@solarflare.com>
+
+[ Upstream commit 4374f256ce8182019353c0c639bb8d0695b4c941 ]
+
+Incorrect signed bounds were being computed.
+If the old upper signed bound was positive and the old lower signed bound was
+negative, this could cause the new upper signed bound to be too low,
+leading to security issues.
+
+Fixes: b03c9f9fdc37 ("bpf/verifier: track signed and unsigned min/max values")
+Reported-by: Jann Horn <jannh@google.com>
+Signed-off-by: Edward Cree <ecree@solarflare.com>
+Acked-by: Alexei Starovoitov <ast@kernel.org>
+[jannh@google.com: changed description to reflect bug impact]
+Signed-off-by: Jann Horn <jannh@google.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 |   30 ++++++++++++++++--------------
+ 1 file changed, 16 insertions(+), 14 deletions(-)
+
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -2157,20 +2157,22 @@ static int adjust_scalar_min_max_vals(st
+                       mark_reg_unknown(regs, insn->dst_reg);
+                       break;
+               }
+-              /* BPF_RSH is an unsigned shift, so make the appropriate casts */
+-              if (dst_reg->smin_value < 0) {
+-                      if (umin_val) {
+-                              /* Sign bit will be cleared */
+-                              dst_reg->smin_value = 0;
+-                      } else {
+-                              /* Lost sign bit information */
+-                              dst_reg->smin_value = S64_MIN;
+-                              dst_reg->smax_value = S64_MAX;
+-                      }
+-              } else {
+-                      dst_reg->smin_value =
+-                              (u64)(dst_reg->smin_value) >> umax_val;
+-              }
++              /* BPF_RSH is an unsigned shift.  If the value in dst_reg might
++               * be negative, then either:
++               * 1) src_reg might be zero, so the sign bit of the result is
++               *    unknown, so we lose our signed bounds
++               * 2) it's known negative, thus the unsigned bounds capture the
++               *    signed bounds
++               * 3) the signed bounds cross zero, so they tell us nothing
++               *    about the result
++               * If the value in dst_reg is known nonnegative, then again the
++               * unsigned bounts capture the signed bounds.
++               * Thus, in all cases it suffices to blow away our signed bounds
++               * and rely on inferring new ones from the unsigned bounds and
++               * var_off of the result.
++               */
++              dst_reg->smin_value = S64_MIN;
++              dst_reg->smax_value = S64_MAX;
+               if (src_known)
+                       dst_reg->var_off = tnum_rshift(dst_reg->var_off,
+                                                      umin_val);
diff --git a/queue-4.14/selftests-bpf-add-tests-for-recent-bugfixes.patch b/queue-4.14/selftests-bpf-add-tests-for-recent-bugfixes.patch
new file mode 100644 (file)
index 0000000..584442a
--- /dev/null
@@ -0,0 +1,707 @@
+From foo@baz Fri Dec 22 16:47:02 CET 2017
+From: Daniel Borkmann <daniel@iogearbox.net>
+Date: Fri, 22 Dec 2017 16:23:12 +0100
+Subject: [PATCH stable/4.14 14/14] selftests/bpf: add tests for recent bugfixes
+To: gregkh@linuxfoundation.org
+Cc: ast@kernel.org, daniel@iogearbox.net, jannh@google.com, stable@vger.kernel.org
+Message-ID: <20171222152312.2945-15-daniel@iogearbox.net>
+
+From: Daniel Borkmann <daniel@iogearbox.net>
+
+
+From: Jann Horn <jannh@google.com>
+
+[ Upstream commit 2255f8d520b0a318fc6d387d0940854b2f522a7f ]
+
+These tests should cover the following cases:
+
+ - MOV with both zero-extended and sign-extended immediates
+ - implicit truncation of register contents via ALU32/MOV32
+ - implicit 32-bit truncation of ALU32 output
+ - oversized register source operand for ALU32 shift
+ - right-shift of a number that could be positive or negative
+ - map access where adding the operation size to the offset causes signed
+   32-bit overflow
+ - direct stack access at a ~4GiB offset
+
+Also remove the F_LOAD_WITH_STRICT_ALIGNMENT flag from a bunch of tests
+that should fail independent of what flags userspace passes.
+
+Signed-off-by: Jann Horn <jannh@google.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>
+---
+ tools/testing/selftests/bpf/test_verifier.c |  549 +++++++++++++++++++++++++++-
+ 1 file changed, 533 insertions(+), 16 deletions(-)
+
+--- a/tools/testing/selftests/bpf/test_verifier.c
++++ b/tools/testing/selftests/bpf/test_verifier.c
+@@ -606,7 +606,6 @@ static struct bpf_test tests[] = {
+               },
+               .errstr = "misaligned stack access",
+               .result = REJECT,
+-              .flags = F_LOAD_WITH_STRICT_ALIGNMENT,
+       },
+       {
+               "invalid map_fd for function call",
+@@ -1797,7 +1796,6 @@ static struct bpf_test tests[] = {
+               },
+               .result = REJECT,
+               .errstr = "misaligned stack access off (0x0; 0x0)+-8+2 size 8",
+-              .flags = F_LOAD_WITH_STRICT_ALIGNMENT,
+       },
+       {
+               "PTR_TO_STACK store/load - bad alignment on reg",
+@@ -1810,7 +1808,6 @@ static struct bpf_test tests[] = {
+               },
+               .result = REJECT,
+               .errstr = "misaligned stack access off (0x0; 0x0)+-10+8 size 8",
+-              .flags = F_LOAD_WITH_STRICT_ALIGNMENT,
+       },
+       {
+               "PTR_TO_STACK store/load - out of bounds low",
+@@ -6115,7 +6112,7 @@ static struct bpf_test tests[] = {
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map1 = { 3 },
+-              .errstr = "R0 min value is negative",
++              .errstr = "unbounded min value",
+               .result = REJECT,
+       },
+       {
+@@ -6139,7 +6136,7 @@ static struct bpf_test tests[] = {
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map1 = { 3 },
+-              .errstr = "R0 min value is negative",
++              .errstr = "unbounded min value",
+               .result = REJECT,
+       },
+       {
+@@ -6165,7 +6162,7 @@ static struct bpf_test tests[] = {
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map1 = { 3 },
+-              .errstr = "R8 invalid mem access 'inv'",
++              .errstr = "unbounded min value",
+               .result = REJECT,
+       },
+       {
+@@ -6190,7 +6187,7 @@ static struct bpf_test tests[] = {
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map1 = { 3 },
+-              .errstr = "R8 invalid mem access 'inv'",
++              .errstr = "unbounded min value",
+               .result = REJECT,
+       },
+       {
+@@ -6238,7 +6235,7 @@ static struct bpf_test tests[] = {
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map1 = { 3 },
+-              .errstr = "R0 min value is negative",
++              .errstr = "unbounded min value",
+               .result = REJECT,
+       },
+       {
+@@ -6309,7 +6306,7 @@ static struct bpf_test tests[] = {
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map1 = { 3 },
+-              .errstr = "R0 min value is negative",
++              .errstr = "unbounded min value",
+               .result = REJECT,
+       },
+       {
+@@ -6360,7 +6357,7 @@ static struct bpf_test tests[] = {
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map1 = { 3 },
+-              .errstr = "R0 min value is negative",
++              .errstr = "unbounded min value",
+               .result = REJECT,
+       },
+       {
+@@ -6387,7 +6384,7 @@ static struct bpf_test tests[] = {
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map1 = { 3 },
+-              .errstr = "R0 min value is negative",
++              .errstr = "unbounded min value",
+               .result = REJECT,
+       },
+       {
+@@ -6413,7 +6410,7 @@ static struct bpf_test tests[] = {
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map1 = { 3 },
+-              .errstr = "R0 min value is negative",
++              .errstr = "unbounded min value",
+               .result = REJECT,
+       },
+       {
+@@ -6442,7 +6439,7 @@ static struct bpf_test tests[] = {
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map1 = { 3 },
+-              .errstr = "R0 min value is negative",
++              .errstr = "unbounded min value",
+               .result = REJECT,
+       },
+       {
+@@ -6472,7 +6469,7 @@ static struct bpf_test tests[] = {
+                       BPF_JMP_IMM(BPF_JA, 0, 0, -7),
+               },
+               .fixup_map1 = { 4 },
+-              .errstr = "R0 min value is negative",
++              .errstr = "unbounded min value",
+               .result = REJECT,
+       },
+       {
+@@ -6500,8 +6497,7 @@ static struct bpf_test tests[] = {
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map1 = { 3 },
+-              .errstr_unpriv = "R0 pointer comparison prohibited",
+-              .errstr = "R0 min value is negative",
++              .errstr = "unbounded min value",
+               .result = REJECT,
+               .result_unpriv = REJECT,
+       },
+@@ -6557,6 +6553,462 @@ static struct bpf_test tests[] = {
+               .result = REJECT,
+       },
+       {
++              "bounds check based on zero-extended MOV",
++              .insns = {
++                      BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
++                      BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
++                      BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
++                      BPF_LD_MAP_FD(BPF_REG_1, 0),
++                      BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
++                                   BPF_FUNC_map_lookup_elem),
++                      BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
++                      /* r2 = 0x0000'0000'ffff'ffff */
++                      BPF_MOV32_IMM(BPF_REG_2, 0xffffffff),
++                      /* r2 = 0 */
++                      BPF_ALU64_IMM(BPF_RSH, BPF_REG_2, 32),
++                      /* no-op */
++                      BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_2),
++                      /* access at offset 0 */
++                      BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0),
++                      /* exit */
++                      BPF_MOV64_IMM(BPF_REG_0, 0),
++                      BPF_EXIT_INSN(),
++              },
++              .fixup_map1 = { 3 },
++              .result = ACCEPT
++      },
++      {
++              "bounds check based on sign-extended MOV. test1",
++              .insns = {
++                      BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
++                      BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
++                      BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
++                      BPF_LD_MAP_FD(BPF_REG_1, 0),
++                      BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
++                                   BPF_FUNC_map_lookup_elem),
++                      BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
++                      /* r2 = 0xffff'ffff'ffff'ffff */
++                      BPF_MOV64_IMM(BPF_REG_2, 0xffffffff),
++                      /* r2 = 0xffff'ffff */
++                      BPF_ALU64_IMM(BPF_RSH, BPF_REG_2, 32),
++                      /* r0 = <oob pointer> */
++                      BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_2),
++                      /* access to OOB pointer */
++                      BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0),
++                      /* exit */
++                      BPF_MOV64_IMM(BPF_REG_0, 0),
++                      BPF_EXIT_INSN(),
++              },
++              .fixup_map1 = { 3 },
++              .errstr = "map_value pointer and 4294967295",
++              .result = REJECT
++      },
++      {
++              "bounds check based on sign-extended MOV. test2",
++              .insns = {
++                      BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
++                      BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
++                      BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
++                      BPF_LD_MAP_FD(BPF_REG_1, 0),
++                      BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
++                                   BPF_FUNC_map_lookup_elem),
++                      BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
++                      /* r2 = 0xffff'ffff'ffff'ffff */
++                      BPF_MOV64_IMM(BPF_REG_2, 0xffffffff),
++                      /* r2 = 0xfff'ffff */
++                      BPF_ALU64_IMM(BPF_RSH, BPF_REG_2, 36),
++                      /* r0 = <oob pointer> */
++                      BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_2),
++                      /* access to OOB pointer */
++                      BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0),
++                      /* exit */
++                      BPF_MOV64_IMM(BPF_REG_0, 0),
++                      BPF_EXIT_INSN(),
++              },
++              .fixup_map1 = { 3 },
++              .errstr = "R0 min value is outside of the array range",
++              .result = REJECT
++      },
++      {
++              "bounds check based on reg_off + var_off + insn_off. test1",
++              .insns = {
++                      BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
++                                  offsetof(struct __sk_buff, mark)),
++                      BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
++                      BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
++                      BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
++                      BPF_LD_MAP_FD(BPF_REG_1, 0),
++                      BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
++                                   BPF_FUNC_map_lookup_elem),
++                      BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
++                      BPF_ALU64_IMM(BPF_AND, BPF_REG_6, 1),
++                      BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, (1 << 29) - 1),
++                      BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_6),
++                      BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, (1 << 29) - 1),
++                      BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 3),
++                      BPF_MOV64_IMM(BPF_REG_0, 0),
++                      BPF_EXIT_INSN(),
++              },
++              .fixup_map1 = { 4 },
++              .errstr = "value_size=8 off=1073741825",
++              .result = REJECT,
++              .prog_type = BPF_PROG_TYPE_SCHED_CLS,
++      },
++      {
++              "bounds check based on reg_off + var_off + insn_off. test2",
++              .insns = {
++                      BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1,
++                                  offsetof(struct __sk_buff, mark)),
++                      BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
++                      BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
++                      BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
++                      BPF_LD_MAP_FD(BPF_REG_1, 0),
++                      BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
++                                   BPF_FUNC_map_lookup_elem),
++                      BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
++                      BPF_ALU64_IMM(BPF_AND, BPF_REG_6, 1),
++                      BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, (1 << 30) - 1),
++                      BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_6),
++                      BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, (1 << 29) - 1),
++                      BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 3),
++                      BPF_MOV64_IMM(BPF_REG_0, 0),
++                      BPF_EXIT_INSN(),
++              },
++              .fixup_map1 = { 4 },
++              .errstr = "value 1073741823",
++              .result = REJECT,
++              .prog_type = BPF_PROG_TYPE_SCHED_CLS,
++      },
++      {
++              "bounds check after truncation of non-boundary-crossing range",
++              .insns = {
++                      BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
++                      BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
++                      BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
++                      BPF_LD_MAP_FD(BPF_REG_1, 0),
++                      BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
++                                   BPF_FUNC_map_lookup_elem),
++                      BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 9),
++                      /* r1 = [0x00, 0xff] */
++                      BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
++                      BPF_MOV64_IMM(BPF_REG_2, 1),
++                      /* r2 = 0x10'0000'0000 */
++                      BPF_ALU64_IMM(BPF_LSH, BPF_REG_2, 36),
++                      /* r1 = [0x10'0000'0000, 0x10'0000'00ff] */
++                      BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_2),
++                      /* r1 = [0x10'7fff'ffff, 0x10'8000'00fe] */
++                      BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0x7fffffff),
++                      /* r1 = [0x00, 0xff] */
++                      BPF_ALU32_IMM(BPF_SUB, BPF_REG_1, 0x7fffffff),
++                      /* r1 = 0 */
++                      BPF_ALU64_IMM(BPF_RSH, BPF_REG_1, 8),
++                      /* no-op */
++                      BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
++                      /* access at offset 0 */
++                      BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0),
++                      /* exit */
++                      BPF_MOV64_IMM(BPF_REG_0, 0),
++                      BPF_EXIT_INSN(),
++              },
++              .fixup_map1 = { 3 },
++              .result = ACCEPT
++      },
++      {
++              "bounds check after truncation of boundary-crossing range (1)",
++              .insns = {
++                      BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
++                      BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
++                      BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
++                      BPF_LD_MAP_FD(BPF_REG_1, 0),
++                      BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
++                                   BPF_FUNC_map_lookup_elem),
++                      BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 9),
++                      /* r1 = [0x00, 0xff] */
++                      BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
++                      BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0xffffff80 >> 1),
++                      /* r1 = [0xffff'ff80, 0x1'0000'007f] */
++                      BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0xffffff80 >> 1),
++                      /* r1 = [0xffff'ff80, 0xffff'ffff] or
++                       *      [0x0000'0000, 0x0000'007f]
++                       */
++                      BPF_ALU32_IMM(BPF_ADD, BPF_REG_1, 0),
++                      BPF_ALU64_IMM(BPF_SUB, BPF_REG_1, 0xffffff80 >> 1),
++                      /* r1 = [0x00, 0xff] or
++                       *      [0xffff'ffff'0000'0080, 0xffff'ffff'ffff'ffff]
++                       */
++                      BPF_ALU64_IMM(BPF_SUB, BPF_REG_1, 0xffffff80 >> 1),
++                      /* r1 = 0 or
++                       *      [0x00ff'ffff'ff00'0000, 0x00ff'ffff'ffff'ffff]
++                       */
++                      BPF_ALU64_IMM(BPF_RSH, BPF_REG_1, 8),
++                      /* no-op or OOB pointer computation */
++                      BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
++                      /* potentially OOB access */
++                      BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0),
++                      /* exit */
++                      BPF_MOV64_IMM(BPF_REG_0, 0),
++                      BPF_EXIT_INSN(),
++              },
++              .fixup_map1 = { 3 },
++              /* not actually fully unbounded, but the bound is very high */
++              .errstr = "R0 unbounded memory access",
++              .result = REJECT
++      },
++      {
++              "bounds check after truncation of boundary-crossing range (2)",
++              .insns = {
++                      BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
++                      BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
++                      BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
++                      BPF_LD_MAP_FD(BPF_REG_1, 0),
++                      BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
++                                   BPF_FUNC_map_lookup_elem),
++                      BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 9),
++                      /* r1 = [0x00, 0xff] */
++                      BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
++                      BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0xffffff80 >> 1),
++                      /* r1 = [0xffff'ff80, 0x1'0000'007f] */
++                      BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0xffffff80 >> 1),
++                      /* r1 = [0xffff'ff80, 0xffff'ffff] or
++                       *      [0x0000'0000, 0x0000'007f]
++                       * difference to previous test: truncation via MOV32
++                       * instead of ALU32.
++                       */
++                      BPF_MOV32_REG(BPF_REG_1, BPF_REG_1),
++                      BPF_ALU64_IMM(BPF_SUB, BPF_REG_1, 0xffffff80 >> 1),
++                      /* r1 = [0x00, 0xff] or
++                       *      [0xffff'ffff'0000'0080, 0xffff'ffff'ffff'ffff]
++                       */
++                      BPF_ALU64_IMM(BPF_SUB, BPF_REG_1, 0xffffff80 >> 1),
++                      /* r1 = 0 or
++                       *      [0x00ff'ffff'ff00'0000, 0x00ff'ffff'ffff'ffff]
++                       */
++                      BPF_ALU64_IMM(BPF_RSH, BPF_REG_1, 8),
++                      /* no-op or OOB pointer computation */
++                      BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
++                      /* potentially OOB access */
++                      BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0),
++                      /* exit */
++                      BPF_MOV64_IMM(BPF_REG_0, 0),
++                      BPF_EXIT_INSN(),
++              },
++              .fixup_map1 = { 3 },
++              /* not actually fully unbounded, but the bound is very high */
++              .errstr = "R0 unbounded memory access",
++              .result = REJECT
++      },
++      {
++              "bounds check after wrapping 32-bit addition",
++              .insns = {
++                      BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
++                      BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
++                      BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
++                      BPF_LD_MAP_FD(BPF_REG_1, 0),
++                      BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
++                                   BPF_FUNC_map_lookup_elem),
++                      BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 5),
++                      /* r1 = 0x7fff'ffff */
++                      BPF_MOV64_IMM(BPF_REG_1, 0x7fffffff),
++                      /* r1 = 0xffff'fffe */
++                      BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0x7fffffff),
++                      /* r1 = 0 */
++                      BPF_ALU32_IMM(BPF_ADD, BPF_REG_1, 2),
++                      /* no-op */
++                      BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
++                      /* access at offset 0 */
++                      BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0),
++                      /* exit */
++                      BPF_MOV64_IMM(BPF_REG_0, 0),
++                      BPF_EXIT_INSN(),
++              },
++              .fixup_map1 = { 3 },
++              .result = ACCEPT
++      },
++      {
++              "bounds check after shift with oversized count operand",
++              .insns = {
++                      BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
++                      BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
++                      BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
++                      BPF_LD_MAP_FD(BPF_REG_1, 0),
++                      BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
++                                   BPF_FUNC_map_lookup_elem),
++                      BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6),
++                      BPF_MOV64_IMM(BPF_REG_2, 32),
++                      BPF_MOV64_IMM(BPF_REG_1, 1),
++                      /* r1 = (u32)1 << (u32)32 = ? */
++                      BPF_ALU32_REG(BPF_LSH, BPF_REG_1, BPF_REG_2),
++                      /* r1 = [0x0000, 0xffff] */
++                      BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0xffff),
++                      /* computes unknown pointer, potentially OOB */
++                      BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
++                      /* potentially OOB access */
++                      BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0),
++                      /* exit */
++                      BPF_MOV64_IMM(BPF_REG_0, 0),
++                      BPF_EXIT_INSN(),
++              },
++              .fixup_map1 = { 3 },
++              .errstr = "R0 max value is outside of the array range",
++              .result = REJECT
++      },
++      {
++              "bounds check after right shift of maybe-negative number",
++              .insns = {
++                      BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
++                      BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
++                      BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
++                      BPF_LD_MAP_FD(BPF_REG_1, 0),
++                      BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
++                                   BPF_FUNC_map_lookup_elem),
++                      BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6),
++                      /* r1 = [0x00, 0xff] */
++                      BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
++                      /* r1 = [-0x01, 0xfe] */
++                      BPF_ALU64_IMM(BPF_SUB, BPF_REG_1, 1),
++                      /* r1 = 0 or 0xff'ffff'ffff'ffff */
++                      BPF_ALU64_IMM(BPF_RSH, BPF_REG_1, 8),
++                      /* r1 = 0 or 0xffff'ffff'ffff */
++                      BPF_ALU64_IMM(BPF_RSH, BPF_REG_1, 8),
++                      /* computes unknown pointer, potentially OOB */
++                      BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
++                      /* potentially OOB access */
++                      BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0),
++                      /* exit */
++                      BPF_MOV64_IMM(BPF_REG_0, 0),
++                      BPF_EXIT_INSN(),
++              },
++              .fixup_map1 = { 3 },
++              .errstr = "R0 unbounded memory access",
++              .result = REJECT
++      },
++      {
++              "bounds check map access with off+size signed 32bit overflow. test1",
++              .insns = {
++                      BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
++                      BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
++                      BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
++                      BPF_LD_MAP_FD(BPF_REG_1, 0),
++                      BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
++                                   BPF_FUNC_map_lookup_elem),
++                      BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
++                      BPF_EXIT_INSN(),
++                      BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 0x7ffffffe),
++                      BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0),
++                      BPF_JMP_A(0),
++                      BPF_EXIT_INSN(),
++              },
++              .fixup_map1 = { 3 },
++              .errstr = "map_value pointer and 2147483646",
++              .result = REJECT
++      },
++      {
++              "bounds check map access with off+size signed 32bit overflow. test2",
++              .insns = {
++                      BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
++                      BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
++                      BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
++                      BPF_LD_MAP_FD(BPF_REG_1, 0),
++                      BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
++                                   BPF_FUNC_map_lookup_elem),
++                      BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
++                      BPF_EXIT_INSN(),
++                      BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 0x1fffffff),
++                      BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 0x1fffffff),
++                      BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 0x1fffffff),
++                      BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0),
++                      BPF_JMP_A(0),
++                      BPF_EXIT_INSN(),
++              },
++              .fixup_map1 = { 3 },
++              .errstr = "pointer offset 1073741822",
++              .result = REJECT
++      },
++      {
++              "bounds check map access with off+size signed 32bit overflow. test3",
++              .insns = {
++                      BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
++                      BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
++                      BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
++                      BPF_LD_MAP_FD(BPF_REG_1, 0),
++                      BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
++                                   BPF_FUNC_map_lookup_elem),
++                      BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
++                      BPF_EXIT_INSN(),
++                      BPF_ALU64_IMM(BPF_SUB, BPF_REG_0, 0x1fffffff),
++                      BPF_ALU64_IMM(BPF_SUB, BPF_REG_0, 0x1fffffff),
++                      BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 2),
++                      BPF_JMP_A(0),
++                      BPF_EXIT_INSN(),
++              },
++              .fixup_map1 = { 3 },
++              .errstr = "pointer offset -1073741822",
++              .result = REJECT
++      },
++      {
++              "bounds check map access with off+size signed 32bit overflow. test4",
++              .insns = {
++                      BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
++                      BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
++                      BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
++                      BPF_LD_MAP_FD(BPF_REG_1, 0),
++                      BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
++                                   BPF_FUNC_map_lookup_elem),
++                      BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
++                      BPF_EXIT_INSN(),
++                      BPF_MOV64_IMM(BPF_REG_1, 1000000),
++                      BPF_ALU64_IMM(BPF_MUL, BPF_REG_1, 1000000),
++                      BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
++                      BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 2),
++                      BPF_JMP_A(0),
++                      BPF_EXIT_INSN(),
++              },
++              .fixup_map1 = { 3 },
++              .errstr = "map_value pointer and 1000000000000",
++              .result = REJECT
++      },
++      {
++              "pointer/scalar confusion in state equality check (way 1)",
++              .insns = {
++                      BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
++                      BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
++                      BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
++                      BPF_LD_MAP_FD(BPF_REG_1, 0),
++                      BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
++                                   BPF_FUNC_map_lookup_elem),
++                      BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2),
++                      BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0),
++                      BPF_JMP_A(1),
++                      BPF_MOV64_REG(BPF_REG_0, BPF_REG_10),
++                      BPF_JMP_A(0),
++                      BPF_EXIT_INSN(),
++              },
++              .fixup_map1 = { 3 },
++              .result = ACCEPT,
++              .result_unpriv = REJECT,
++              .errstr_unpriv = "R0 leaks addr as return value"
++      },
++      {
++              "pointer/scalar confusion in state equality check (way 2)",
++              .insns = {
++                      BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
++                      BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
++                      BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
++                      BPF_LD_MAP_FD(BPF_REG_1, 0),
++                      BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
++                                   BPF_FUNC_map_lookup_elem),
++                      BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 2),
++                      BPF_MOV64_REG(BPF_REG_0, BPF_REG_10),
++                      BPF_JMP_A(1),
++                      BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0),
++                      BPF_EXIT_INSN(),
++              },
++              .fixup_map1 = { 3 },
++              .result = ACCEPT,
++              .result_unpriv = REJECT,
++              .errstr_unpriv = "R0 leaks addr as return value"
++      },
++      {
+               "variable-offset ctx access",
+               .insns = {
+                       /* Get an unknown value */
+@@ -6598,6 +7050,71 @@ static struct bpf_test tests[] = {
+               .prog_type = BPF_PROG_TYPE_LWT_IN,
+       },
+       {
++              "indirect variable-offset stack access",
++              .insns = {
++                      /* Fill the top 8 bytes of the stack */
++                      BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
++                      /* Get an unknown value */
++                      BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
++                      /* Make it small and 4-byte aligned */
++                      BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4),
++                      BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 8),
++                      /* add it to fp.  We now have either fp-4 or fp-8, but
++                       * we don't know which
++                       */
++                      BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
++                      /* dereference it indirectly */
++                      BPF_LD_MAP_FD(BPF_REG_1, 0),
++                      BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
++                                   BPF_FUNC_map_lookup_elem),
++                      BPF_MOV64_IMM(BPF_REG_0, 0),
++                      BPF_EXIT_INSN(),
++              },
++              .fixup_map1 = { 5 },
++              .errstr = "variable stack read R2",
++              .result = REJECT,
++              .prog_type = BPF_PROG_TYPE_LWT_IN,
++      },
++      {
++              "direct stack access with 32-bit wraparound. test1",
++              .insns = {
++                      BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
++                      BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0x7fffffff),
++                      BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0x7fffffff),
++                      BPF_MOV32_IMM(BPF_REG_0, 0),
++                      BPF_STX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
++                      BPF_EXIT_INSN()
++              },
++              .errstr = "fp pointer and 2147483647",
++              .result = REJECT
++      },
++      {
++              "direct stack access with 32-bit wraparound. test2",
++              .insns = {
++                      BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
++                      BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0x3fffffff),
++                      BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0x3fffffff),
++                      BPF_MOV32_IMM(BPF_REG_0, 0),
++                      BPF_STX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
++                      BPF_EXIT_INSN()
++              },
++              .errstr = "fp pointer and 1073741823",
++              .result = REJECT
++      },
++      {
++              "direct stack access with 32-bit wraparound. test3",
++              .insns = {
++                      BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
++                      BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0x1fffffff),
++                      BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0x1fffffff),
++                      BPF_MOV32_IMM(BPF_REG_0, 0),
++                      BPF_STX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
++                      BPF_EXIT_INSN()
++              },
++              .errstr = "fp pointer offset 1073741822",
++              .result = REJECT
++      },
++      {
+               "liveness pruning and write screening",
+               .insns = {
+                       /* Get an unknown value */
index d3ec280473b862b676060faedc49a8b1eb4aaa7c..284dfbe3eb9900dae2ce338ee201e8d96590beb2 100644 (file)
@@ -158,3 +158,17 @@ thermal-drivers-hisi-simplify-the-temperature-step-computation.patch
 thermal-drivers-hisi-fix-multiple-alarm-interrupts-firing.patch
 platform-x86-asus-wireless-send-an-ev_syn-syn_report-between-state-changes.patch
 mm-sparsemem-fix-arm64-boot-crash-when-config_sparsemem_extreme-y.patch
+bpf-fix-branch-pruning-logic.patch
+bpf-fix-corruption-on-concurrent-perf_event_output-calls.patch
+bpf-s390x-do-not-reload-skb-pointers-in-non-skb-context.patch
+bpf-ppc64-do-not-reload-skb-pointers-in-non-skb-context.patch
+bpf-sparc-fix-usage-of-wrong-reg-for-load_skb_regs-after-call.patch
+bpf-verifier-fix-bounds-calculation-on-bpf_rsh.patch
+bpf-fix-incorrect-sign-extension-in-check_alu_op.patch
+bpf-fix-incorrect-tracking-of-register-size-truncation.patch
+bpf-fix-32-bit-alu-op-verification.patch
+bpf-fix-missing-error-return-in-check_stack_boundary.patch
+bpf-force-strict-alignment-checks-for-stack-pointers.patch
+bpf-don-t-prune-branches-when-a-scalar-is-replaced-with-a-pointer.patch
+bpf-fix-integer-overflows.patch
+selftests-bpf-add-tests-for-recent-bugfixes.patch