From 2d046ce88b7f6bab96f40856e3d450a6daa7364c Mon Sep 17 00:00:00 2001 From: Andreas Wellving Date: Tue, 21 May 2019 14:16:44 +0200 Subject: 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 --- .../CVE-2017-17854-bpf-fix-integer-overflows.patch | 137 +++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 patches/cve/CVE-2017-17854-bpf-fix-integer-overflows.patch (limited to 'patches/cve') 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 @@ +From de31796c052e47c99b1bb342bc70aa826733e862 Mon Sep 17 00:00:00 2001 +From: Daniel Borkmann +Date: Fri, 22 Dec 2017 16:23:11 +0100 +Subject: [PATCH] bpf: fix integer overflows + +From: Alexei Starovoitov + +[ 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. + +CVE: CVE-2017-17854 +Upstream-Status: Backport [https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=linux-4.14.y&id=de31796c052e47c99b1bb342bc70aa826733e862] + +Fixes: f1174f77b50c ("bpf/verifier: rework value tracking") +Reported-by: Jann Horn +Signed-off-by: Alexei Starovoitov +Signed-off-by: Daniel Borkmann +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Andreas Wellving +--- + include/linux/bpf_verifier.h | 4 +-- + kernel/bpf/verifier.c | 48 ++++++++++++++++++++++++++++++++++++ + 2 files changed, 50 insertions(+), 2 deletions(-) + +diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h +index 5d6de3b57758..73bec75b74c8 100644 +--- 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 +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index 5a30eda17c4f..c5ff809e86d0 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -1789,6 +1789,41 @@ static bool signed_sub_overflows(s64 a, s64 b) + 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(struct bpf_verifier_env *env, + 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(struct bpf_verifier_env *env, + 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(struct bpf_verifier_env *env, + 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) || +-- +2.20.1 + -- cgit v1.2.3-54-g00ecf