diff options
author | Andreas Wellving <andreas.wellving@enea.com> | 2019-05-21 14:16:44 +0200 |
---|---|---|
committer | Adrian Mangeac <Adrian.Mangeac@enea.com> | 2019-05-21 16:39:53 +0200 |
commit | 2d046ce88b7f6bab96f40856e3d450a6daa7364c (patch) | |
tree | 9c77322d138b45fb53bac54f91e31ad470a6e475 | |
parent | fab791dcdc422b78816917e207fd2563ab14a3a2 (diff) | |
download | enea-kernel-cache-2d046ce88b7f6bab96f40856e3d450a6daa7364c.tar.gz |
bpf: CVE-2017-17854
bpf: fix integer overflows
Reference:
https://nvd.nist.gov/vuln/detail/CVE-2017-17854
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=linux-4.14.y&id=de31796c052e47c99b1bb342bc70aa826733e862
Change-Id: I00c2d0e05420994cd67f689f0ad63f0a0fbde2e9
Signed-off-by: Andreas Wellving <andreas.wellving@enea.com>
-rw-r--r-- | patches/cve/CVE-2017-17854-bpf-fix-integer-overflows.patch | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/patches/cve/CVE-2017-17854-bpf-fix-integer-overflows.patch b/patches/cve/CVE-2017-17854-bpf-fix-integer-overflows.patch new file mode 100644 index 0000000..3ac7eca --- /dev/null +++ b/patches/cve/CVE-2017-17854-bpf-fix-integer-overflows.patch | |||
@@ -0,0 +1,137 @@ | |||
1 | From de31796c052e47c99b1bb342bc70aa826733e862 Mon Sep 17 00:00:00 2001 | ||
2 | From: Daniel Borkmann <daniel@iogearbox.net> | ||
3 | Date: Fri, 22 Dec 2017 16:23:11 +0100 | ||
4 | Subject: [PATCH] bpf: fix integer overflows | ||
5 | |||
6 | From: Alexei Starovoitov <ast@kernel.org> | ||
7 | |||
8 | [ Upstream commit bb7f0f989ca7de1153bd128a40a71709e339fa03 ] | ||
9 | |||
10 | There were various issues related to the limited size of integers used in | ||
11 | the verifier: | ||
12 | - `off + size` overflow in __check_map_access() | ||
13 | - `off + reg->off` overflow in check_mem_access() | ||
14 | - `off + reg->var_off.value` overflow or 32-bit truncation of | ||
15 | `reg->var_off.value` in check_mem_access() | ||
16 | - 32-bit truncation in check_stack_boundary() | ||
17 | |||
18 | Make sure that any integer math cannot overflow by not allowing | ||
19 | pointer math with large values. | ||
20 | |||
21 | Also reduce the scope of "scalar op scalar" tracking. | ||
22 | |||
23 | CVE: CVE-2017-17854 | ||
24 | Upstream-Status: Backport [https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=linux-4.14.y&id=de31796c052e47c99b1bb342bc70aa826733e862] | ||
25 | |||
26 | Fixes: f1174f77b50c ("bpf/verifier: rework value tracking") | ||
27 | Reported-by: Jann Horn <jannh@google.com> | ||
28 | Signed-off-by: Alexei Starovoitov <ast@kernel.org> | ||
29 | Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> | ||
30 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | ||
31 | Signed-off-by: Andreas Wellving <andreas.wellving@enea.com> | ||
32 | --- | ||
33 | include/linux/bpf_verifier.h | 4 +-- | ||
34 | kernel/bpf/verifier.c | 48 ++++++++++++++++++++++++++++++++++++ | ||
35 | 2 files changed, 50 insertions(+), 2 deletions(-) | ||
36 | |||
37 | diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h | ||
38 | index 5d6de3b57758..73bec75b74c8 100644 | ||
39 | --- a/include/linux/bpf_verifier.h | ||
40 | +++ b/include/linux/bpf_verifier.h | ||
41 | @@ -15,11 +15,11 @@ | ||
42 | * In practice this is far bigger than any realistic pointer offset; this limit | ||
43 | * ensures that umax_value + (int)off + (int)size cannot overflow a u64. | ||
44 | */ | ||
45 | -#define BPF_MAX_VAR_OFF (1ULL << 31) | ||
46 | +#define BPF_MAX_VAR_OFF (1 << 29) | ||
47 | /* Maximum variable size permitted for ARG_CONST_SIZE[_OR_ZERO]. This ensures | ||
48 | * that converting umax_value to int cannot overflow. | ||
49 | */ | ||
50 | -#define BPF_MAX_VAR_SIZ INT_MAX | ||
51 | +#define BPF_MAX_VAR_SIZ (1 << 29) | ||
52 | |||
53 | /* Liveness marks, used for registers and spilled-regs (in stack slots). | ||
54 | * Read marks propagate upwards until they find a write mark; they record that | ||
55 | diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c | ||
56 | index 5a30eda17c4f..c5ff809e86d0 100644 | ||
57 | --- a/kernel/bpf/verifier.c | ||
58 | +++ b/kernel/bpf/verifier.c | ||
59 | @@ -1789,6 +1789,41 @@ static bool signed_sub_overflows(s64 a, s64 b) | ||
60 | return res > a; | ||
61 | } | ||
62 | |||
63 | +static bool check_reg_sane_offset(struct bpf_verifier_env *env, | ||
64 | + const struct bpf_reg_state *reg, | ||
65 | + enum bpf_reg_type type) | ||
66 | +{ | ||
67 | + bool known = tnum_is_const(reg->var_off); | ||
68 | + s64 val = reg->var_off.value; | ||
69 | + s64 smin = reg->smin_value; | ||
70 | + | ||
71 | + if (known && (val >= BPF_MAX_VAR_OFF || val <= -BPF_MAX_VAR_OFF)) { | ||
72 | + verbose("math between %s pointer and %lld is not allowed\n", | ||
73 | + reg_type_str[type], val); | ||
74 | + return false; | ||
75 | + } | ||
76 | + | ||
77 | + if (reg->off >= BPF_MAX_VAR_OFF || reg->off <= -BPF_MAX_VAR_OFF) { | ||
78 | + verbose("%s pointer offset %d is not allowed\n", | ||
79 | + reg_type_str[type], reg->off); | ||
80 | + return false; | ||
81 | + } | ||
82 | + | ||
83 | + if (smin == S64_MIN) { | ||
84 | + verbose("math between %s pointer and register with unbounded min value is not allowed\n", | ||
85 | + reg_type_str[type]); | ||
86 | + return false; | ||
87 | + } | ||
88 | + | ||
89 | + if (smin >= BPF_MAX_VAR_OFF || smin <= -BPF_MAX_VAR_OFF) { | ||
90 | + verbose("value %lld makes %s pointer be out of bounds\n", | ||
91 | + smin, reg_type_str[type]); | ||
92 | + return false; | ||
93 | + } | ||
94 | + | ||
95 | + return true; | ||
96 | +} | ||
97 | + | ||
98 | /* Handles arithmetic on a pointer and a scalar: computes new min/max and var_off. | ||
99 | * Caller should also handle BPF_MOV case separately. | ||
100 | * If we return -EACCES, caller may want to try again treating pointer as a | ||
101 | @@ -1854,6 +1889,10 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, | ||
102 | dst_reg->type = ptr_reg->type; | ||
103 | dst_reg->id = ptr_reg->id; | ||
104 | |||
105 | + if (!check_reg_sane_offset(env, off_reg, ptr_reg->type) || | ||
106 | + !check_reg_sane_offset(env, ptr_reg, ptr_reg->type)) | ||
107 | + return -EINVAL; | ||
108 | + | ||
109 | switch (opcode) { | ||
110 | case BPF_ADD: | ||
111 | /* We can take a fixed offset as long as it doesn't overflow | ||
112 | @@ -1984,6 +2023,9 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, | ||
113 | return -EACCES; | ||
114 | } | ||
115 | |||
116 | + if (!check_reg_sane_offset(env, dst_reg, ptr_reg->type)) | ||
117 | + return -EINVAL; | ||
118 | + | ||
119 | __update_reg_bounds(dst_reg); | ||
120 | __reg_deduce_bounds(dst_reg); | ||
121 | __reg_bound_offset(dst_reg); | ||
122 | @@ -2013,6 +2055,12 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env, | ||
123 | src_known = tnum_is_const(src_reg.var_off); | ||
124 | dst_known = tnum_is_const(dst_reg->var_off); | ||
125 | |||
126 | + if (!src_known && | ||
127 | + opcode != BPF_ADD && opcode != BPF_SUB && opcode != BPF_AND) { | ||
128 | + __mark_reg_unknown(dst_reg); | ||
129 | + return 0; | ||
130 | + } | ||
131 | + | ||
132 | switch (opcode) { | ||
133 | case BPF_ADD: | ||
134 | if (signed_add_overflows(dst_reg->smin_value, smin_val) || | ||
135 | -- | ||
136 | 2.20.1 | ||
137 | |||