diff options
| -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 | |||
