summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Wellving <andreas.wellving@enea.com>2019-05-21 14:57:14 +0200
committerAdrian Mangeac <Adrian.Mangeac@enea.com>2019-05-21 16:58:39 +0200
commit82eb63205189aa1ba98a38e774abd5d78c507ee8 (patch)
treefda5fe9d36f4af9419297918d4e5b6ebedad27f9
parent15927a53a67f71f6220a95cc900aa40d9a69201f (diff)
downloadenea-kernel-cache-82eb63205189aa1ba98a38e774abd5d78c507ee8.tar.gz
bpf: CVE-2017-17862
bpf: fix branch pruning logic Reference: https://nvd.nist.gov/vuln/detail/CVE-2017-17862 https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=linux-4.14.y&id=2b3ea8ceb2bb71e9e58527661261dba127137d9b Change-Id: I3a8415361491da3c92688a715291c5026999776f Signed-off-by: Andreas Wellving <andreas.wellving@enea.com>
-rw-r--r--patches/cve/CVE-2017-17862-bpf-fix-branch-pruning-logic.patch128
1 files changed, 128 insertions, 0 deletions
diff --git a/patches/cve/CVE-2017-17862-bpf-fix-branch-pruning-logic.patch b/patches/cve/CVE-2017-17862-bpf-fix-branch-pruning-logic.patch
new file mode 100644
index 0000000..3e53a89
--- /dev/null
+++ b/patches/cve/CVE-2017-17862-bpf-fix-branch-pruning-logic.patch
@@ -0,0 +1,128 @@
1From 2b3ea8ceb2bb71e9e58527661261dba127137d9b Mon Sep 17 00:00:00 2001
2From: Daniel Borkmann <daniel@iogearbox.net>
3Date: Fri, 22 Dec 2017 16:22:59 +0100
4Subject: [PATCH] bpf: fix branch pruning logic
5
6From: Alexei Starovoitov <ast@fb.com>
7
8[ Upstream commit c131187db2d3fa2f8bf32fdf4e9a4ef805168467 ]
9
10when the verifier detects that register contains a runtime constant
11and it's compared with another constant it will prune exploration
12of the branch that is guaranteed not to be taken at runtime.
13This is all correct, but malicious program may be constructed
14in such a way that it always has a constant comparison and
15the other branch is never taken under any conditions.
16In this case such path through the program will not be explored
17by the verifier. It won't be taken at run-time either, but since
18all instructions are JITed the malicious program may cause JITs
19to complain about using reserved fields, etc.
20To fix the issue we have to track the instructions explored by
21the verifier and sanitize instructions that are dead at run time
22with NOPs. We cannot reject such dead code, since llvm generates
23it for valid C code, since it doesn't do as much data flow
24analysis as the verifier does.
25
26CVE: CVE-2017-17862
27Upstream-Status: Backport [https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=linux-4.14.y&id=2b3ea8ceb2bb71e9e58527661261dba127137d9b]
28
29Fixes: 17a5267067f3 ("bpf: verifier (add verifier core)")
30Signed-off-by: Alexei Starovoitov <ast@kernel.org>
31Acked-by: Daniel Borkmann <daniel@iogearbox.net>
32Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
33Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
34Signed-off-by: Andreas Wellving <andreas.wellving@enea.com>
35---
36 include/linux/bpf_verifier.h | 2 +-
37 kernel/bpf/verifier.c | 27 +++++++++++++++++++++++++++
38 2 files changed, 28 insertions(+), 1 deletion(-)
39
40diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
41index b8d200f60a40..5d6de3b57758 100644
42--- a/include/linux/bpf_verifier.h
43+++ b/include/linux/bpf_verifier.h
44@@ -110,7 +110,7 @@ struct bpf_insn_aux_data {
45 struct bpf_map *map_ptr; /* pointer for call insn into lookup_elem */
46 };
47 int ctx_field_size; /* the ctx field size for load insn, maybe 0 */
48- int converted_op_size; /* the valid value width after perceived conversion */
49+ bool seen; /* this insn was processed by the verifier */
50 };
51
52 #define MAX_USED_MAPS 64 /* max number of maps accessed by one eBPF program */
53diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
54index c48ca2a34b5e..201d6b965811 100644
55--- a/kernel/bpf/verifier.c
56+++ b/kernel/bpf/verifier.c
57@@ -3665,6 +3665,7 @@ static int do_check(struct bpf_verifier_env *env)
58 if (err)
59 return err;
60
61+ env->insn_aux_data[insn_idx].seen = true;
62 if (class == BPF_ALU || class == BPF_ALU64) {
63 err = check_alu_op(env, insn);
64 if (err)
65@@ -3855,6 +3856,7 @@ static int do_check(struct bpf_verifier_env *env)
66 return err;
67
68 insn_idx++;
69+ env->insn_aux_data[insn_idx].seen = true;
70 } else {
71 verbose("invalid BPF_LD mode\n");
72 return -EINVAL;
73@@ -4035,6 +4037,7 @@ static int adjust_insn_aux_data(struct bpf_verifier_env *env, u32 prog_len,
74 u32 off, u32 cnt)
75 {
76 struct bpf_insn_aux_data *new_data, *old_data = env->insn_aux_data;
77+ int i;
78
79 if (cnt == 1)
80 return 0;
81@@ -4044,6 +4047,8 @@ static int adjust_insn_aux_data(struct bpf_verifier_env *env, u32 prog_len,
82 memcpy(new_data, old_data, sizeof(struct bpf_insn_aux_data) * off);
83 memcpy(new_data + off + cnt - 1, old_data + off,
84 sizeof(struct bpf_insn_aux_data) * (prog_len - off - cnt + 1));
85+ for (i = off; i < off + cnt - 1; i++)
86+ new_data[i].seen = true;
87 env->insn_aux_data = new_data;
88 vfree(old_data);
89 return 0;
90@@ -4062,6 +4067,25 @@ static struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 of
91 return new_prog;
92 }
93
94+/* The verifier does more data flow analysis than llvm and will not explore
95+ * branches that are dead at run time. Malicious programs can have dead code
96+ * too. Therefore replace all dead at-run-time code with nops.
97+ */
98+static void sanitize_dead_code(struct bpf_verifier_env *env)
99+{
100+ struct bpf_insn_aux_data *aux_data = env->insn_aux_data;
101+ struct bpf_insn nop = BPF_MOV64_REG(BPF_REG_0, BPF_REG_0);
102+ struct bpf_insn *insn = env->prog->insnsi;
103+ const int insn_cnt = env->prog->len;
104+ int i;
105+
106+ for (i = 0; i < insn_cnt; i++) {
107+ if (aux_data[i].seen)
108+ continue;
109+ memcpy(insn + i, &nop, sizeof(nop));
110+ }
111+}
112+
113 /* convert load instructions that access fields of 'struct __sk_buff'
114 * into sequence of instructions that access fields of 'struct sk_buff'
115 */
116@@ -4378,6 +4402,9 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr)
117 while (pop_stack(env, NULL) >= 0);
118 free_states(env);
119
120+ if (ret == 0)
121+ sanitize_dead_code(env);
122+
123 if (ret == 0)
124 /* program is valid, convert *(u32*)(ctx + off) accesses */
125 ret = convert_ctx_accesses(env);
126--
1272.20.1
128