From cf1f6e2019e1094dce7213f49bd99a89915eefda Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 22 Dec 2017 03:10:11 +0000 Subject: [PATCH] bpf/verifier: Fix multiple security issues (Closes: #883558) --- debian/changelog | 12 + ...branches-when-a-scalar-is-replaced-w.patch | 44 + ...-verifier-log-state-into-a-structure.patch | 201 ++ .../bpf-fix-32-bit-alu-op-verification.patch | 82 + .../all/bpf-fix-branch-pruning-logic.patch | 112 ++ ...rrect-sign-extension-in-check_alu_op.patch | 44 + ...t-tracking-of-register-size-truncati.patch | 119 ++ .../all/bpf-fix-integer-overflows.patch | 121 ++ ...error-return-in-check_stack_boundary.patch | 26 + ...-alignment-checks-for-stack-pointers.patch | 31 + ...verifier-log-into-verifier-environme.patch | 1665 +++++++++++++++++ ...er-fix-bounds-calculation-on-bpf_rsh.patch | 61 + debian/patches/series | 11 + 13 files changed, 2529 insertions(+) create mode 100644 debian/patches/bugfix/all/bpf-don-t-prune-branches-when-a-scalar-is-replaced-w.patch create mode 100644 debian/patches/bugfix/all/bpf-encapsulate-verifier-log-state-into-a-structure.patch create mode 100644 debian/patches/bugfix/all/bpf-fix-32-bit-alu-op-verification.patch create mode 100644 debian/patches/bugfix/all/bpf-fix-branch-pruning-logic.patch create mode 100644 debian/patches/bugfix/all/bpf-fix-incorrect-sign-extension-in-check_alu_op.patch create mode 100644 debian/patches/bugfix/all/bpf-fix-incorrect-tracking-of-register-size-truncati.patch create mode 100644 debian/patches/bugfix/all/bpf-fix-integer-overflows.patch create mode 100644 debian/patches/bugfix/all/bpf-fix-missing-error-return-in-check_stack_boundary.patch create mode 100644 debian/patches/bugfix/all/bpf-force-strict-alignment-checks-for-stack-pointers.patch create mode 100644 debian/patches/bugfix/all/bpf-move-global-verifier-log-into-verifier-environme.patch create mode 100644 debian/patches/bugfix/all/bpf-verifier-fix-bounds-calculation-on-bpf_rsh.patch diff --git a/debian/changelog b/debian/changelog index 0cd356096..df54066c2 100644 --- a/debian/changelog +++ b/debian/changelog @@ -535,6 +535,18 @@ linux (4.14.7-1) UNRELEASED; urgency=medium (CVE-2017-17741) * bluetooth: Prevent stack info leak from the EFS element. (CVE-2017-1000410) + * bpf/verifier: Fix multiple security issues (Closes: #883558): + - encapsulate verifier log state into a structure + - move global verifier log into verifier environment + - fix branch pruning logic + - fix bounds calculation on BPF_RSH + - fix incorrect sign extension in check_alu_op() (CVE-2017-16995) + - fix incorrect tracking of register size truncation (CVE-2017-16996) + - fix 32-bit ALU op verification + - fix missing error return in check_stack_boundary() + - force strict alignment checks for stack pointers + - don't prune branches when a scalar is replaced with a pointer + - fix integer overflows -- Salvatore Bonaccorso Sun, 03 Dec 2017 10:18:39 +0100 diff --git a/debian/patches/bugfix/all/bpf-don-t-prune-branches-when-a-scalar-is-replaced-w.patch b/debian/patches/bugfix/all/bpf-don-t-prune-branches-when-a-scalar-is-replaced-w.patch new file mode 100644 index 000000000..074953d00 --- /dev/null +++ b/debian/patches/bugfix/all/bpf-don-t-prune-branches-when-a-scalar-is-replaced-w.patch @@ -0,0 +1,44 @@ +From: Jann Horn +Date: Mon, 18 Dec 2017 20:11:59 -0800 +Subject: [7/9] bpf: don't prune branches when a scalar is replaced with a + pointer +Origin: https://git.kernel.org/linus/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 +Signed-off-by: Alexei Starovoitov +Signed-off-by: Daniel Borkmann +--- + kernel/bpf/verifier.c | 15 +++++++-------- + 1 file changed, 7 insertions(+), 8 deletions(-) + +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -3366,15 +3366,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/debian/patches/bugfix/all/bpf-encapsulate-verifier-log-state-into-a-structure.patch b/debian/patches/bugfix/all/bpf-encapsulate-verifier-log-state-into-a-structure.patch new file mode 100644 index 000000000..bf0f1c5b0 --- /dev/null +++ b/debian/patches/bugfix/all/bpf-encapsulate-verifier-log-state-into-a-structure.patch @@ -0,0 +1,201 @@ +From: Jakub Kicinski +Date: Mon, 9 Oct 2017 10:30:10 -0700 +Subject: bpf: encapsulate verifier log state into a structure +Origin: https://git.kernel.org/linus/e7bf8249e8f1bac64885eeccb55bcf6111901a81 + +Put the loose log_* variables into a structure. This will make +it simpler to remove the global verifier state in following patches. + +Signed-off-by: Jakub Kicinski +Reviewed-by: Simon Horman +Acked-by: Alexei Starovoitov +Acked-by: Daniel Borkmann +Signed-off-by: David S. Miller +--- + include/linux/bpf_verifier.h | 13 ++++++++++ + kernel/bpf/verifier.c | 57 +++++++++++++++++++++++--------------------- + 2 files changed, 43 insertions(+), 27 deletions(-) + +--- a/include/linux/bpf_verifier.h ++++ b/include/linux/bpf_verifier.h +@@ -115,6 +115,19 @@ struct bpf_insn_aux_data { + + #define MAX_USED_MAPS 64 /* max number of maps accessed by one eBPF program */ + ++struct bpf_verifer_log { ++ u32 level; ++ char *kbuf; ++ char __user *ubuf; ++ u32 len_used; ++ u32 len_total; ++}; ++ ++static inline bool bpf_verifier_log_full(const struct bpf_verifer_log *log) ++{ ++ return log->len_used >= log->len_total - 1; ++} ++ + struct bpf_verifier_env; + struct bpf_ext_analyzer_ops { + int (*insn_hook)(struct bpf_verifier_env *env, +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -156,8 +156,7 @@ struct bpf_call_arg_meta { + /* verbose verifier prints what it's seeing + * bpf_check() is called under lock, so no race to access these global vars + */ +-static u32 log_level, log_size, log_len; +-static char *log_buf; ++static struct bpf_verifer_log verifier_log; + + static DEFINE_MUTEX(bpf_verifier_lock); + +@@ -167,13 +166,15 @@ static DEFINE_MUTEX(bpf_verifier_lock); + */ + static __printf(1, 2) void verbose(const char *fmt, ...) + { ++ struct bpf_verifer_log *log = &verifier_log; + va_list args; + +- if (log_level == 0 || log_len >= log_size - 1) ++ if (!log->level || bpf_verifier_log_full(log)) + return; + + va_start(args, fmt); +- log_len += vscnprintf(log_buf + log_len, log_size - log_len, fmt, args); ++ log->len_used += vscnprintf(log->kbuf + log->len_used, ++ log->len_total - log->len_used, fmt, args); + va_end(args); + } + +@@ -834,7 +835,7 @@ static int check_map_access(struct bpf_v + * need to try adding each of min_value and max_value to off + * to make sure our theoretical access will be safe. + */ +- if (log_level) ++ if (verifier_log.level) + print_verifier_state(state); + /* The minimum value is only important with signed + * comparisons where we can't assume the floor of a +@@ -2915,7 +2916,7 @@ static int check_cond_jmp_op(struct bpf_ + verbose("R%d pointer comparison prohibited\n", insn->dst_reg); + return -EACCES; + } +- if (log_level) ++ if (verifier_log.level) + print_verifier_state(this_branch); + return 0; + } +@@ -3633,7 +3634,7 @@ static int do_check(struct bpf_verifier_ + return err; + if (err == 1) { + /* found equivalent state, can prune the search */ +- if (log_level) { ++ if (verifier_log.level) { + if (do_print_state) + verbose("\nfrom %d to %d: safe\n", + prev_insn_idx, insn_idx); +@@ -3646,8 +3647,9 @@ static int do_check(struct bpf_verifier_ + if (need_resched()) + cond_resched(); + +- if (log_level > 1 || (log_level && do_print_state)) { +- if (log_level > 1) ++ if (verifier_log.level > 1 || ++ (verifier_log.level && do_print_state)) { ++ if (verifier_log.level > 1) + verbose("%d:", insn_idx); + else + verbose("\nfrom %d to %d:", +@@ -3656,7 +3658,7 @@ static int do_check(struct bpf_verifier_ + do_print_state = false; + } + +- if (log_level) { ++ if (verifier_log.level) { + verbose("%d: ", insn_idx); + print_bpf_insn(env, insn); + } +@@ -4307,7 +4309,7 @@ static void free_states(struct bpf_verif + + int bpf_check(struct bpf_prog **prog, union bpf_attr *attr) + { +- char __user *log_ubuf = NULL; ++ struct bpf_verifer_log *log = &verifier_log; + struct bpf_verifier_env *env; + int ret = -EINVAL; + +@@ -4332,23 +4334,23 @@ int bpf_check(struct bpf_prog **prog, un + /* user requested verbose verifier output + * and supplied buffer to store the verification trace + */ +- log_level = attr->log_level; +- log_ubuf = (char __user *) (unsigned long) attr->log_buf; +- log_size = attr->log_size; +- log_len = 0; ++ log->level = attr->log_level; ++ log->ubuf = (char __user *) (unsigned long) attr->log_buf; ++ log->len_total = attr->log_size; ++ log->len_used = 0; + + ret = -EINVAL; +- /* log_* values have to be sane */ +- if (log_size < 128 || log_size > UINT_MAX >> 8 || +- log_level == 0 || log_ubuf == NULL) ++ /* log attributes have to be sane */ ++ if (log->len_total < 128 || log->len_total > UINT_MAX >> 8 || ++ !log->level || !log->ubuf) + goto err_unlock; + + ret = -ENOMEM; +- log_buf = vmalloc(log_size); +- if (!log_buf) ++ log->kbuf = vmalloc(log->len_total); ++ if (!log->kbuf) + goto err_unlock; + } else { +- log_level = 0; ++ log->level = 0; + } + + env->strict_alignment = !!(attr->prog_flags & BPF_F_STRICT_ALIGNMENT); +@@ -4385,15 +4387,16 @@ skip_full_check: + if (ret == 0) + ret = fixup_bpf_calls(env); + +- if (log_level && log_len >= log_size - 1) { +- BUG_ON(log_len >= log_size); ++ if (log->level && bpf_verifier_log_full(log)) { ++ BUG_ON(log->len_used >= log->len_total); + /* verifier log exceeded user supplied buffer */ + ret = -ENOSPC; + /* fall through to return what was recorded */ + } + + /* copy verifier log back to user space including trailing zero */ +- if (log_level && copy_to_user(log_ubuf, log_buf, log_len + 1) != 0) { ++ if (log->level && copy_to_user(log->ubuf, log->kbuf, ++ log->len_used + 1) != 0) { + ret = -EFAULT; + goto free_log_buf; + } +@@ -4420,8 +4423,8 @@ skip_full_check: + } + + free_log_buf: +- if (log_level) +- vfree(log_buf); ++ if (log->level) ++ vfree(log->kbuf); + if (!env->prog->aux->used_maps) + /* if we didn't copy map pointers into bpf_prog_info, release + * them now. Otherwise free_bpf_prog_info() will release them. +@@ -4458,7 +4461,7 @@ int bpf_analyzer(struct bpf_prog *prog, + /* grab the mutex to protect few globals used by verifier */ + mutex_lock(&bpf_verifier_lock); + +- log_level = 0; ++ verifier_log.level = 0; + + env->strict_alignment = false; + if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)) diff --git a/debian/patches/bugfix/all/bpf-fix-32-bit-alu-op-verification.patch b/debian/patches/bugfix/all/bpf-fix-32-bit-alu-op-verification.patch new file mode 100644 index 000000000..c1e08c881 --- /dev/null +++ b/debian/patches/bugfix/all/bpf-fix-32-bit-alu-op-verification.patch @@ -0,0 +1,82 @@ +From: Jann Horn +Date: Mon, 18 Dec 2017 20:11:56 -0800 +Subject: [4/9] bpf: fix 32-bit ALU op verification +Origin: https://git.kernel.org/linus/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 +Signed-off-by: Alexei Starovoitov +Signed-off-by: Daniel Borkmann +--- + kernel/bpf/verifier.c | 28 +++++++++++++++++----------- + 1 file changed, 17 insertions(+), 11 deletions(-) + +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -2010,6 +2010,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, +@@ -2020,12 +2024,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; +@@ -2161,9 +2161,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(env, regs, insn->dst_reg); + break; +@@ -2189,9 +2189,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(env, regs, insn->dst_reg); + break; +@@ -2227,6 +2227,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/debian/patches/bugfix/all/bpf-fix-branch-pruning-logic.patch b/debian/patches/bugfix/all/bpf-fix-branch-pruning-logic.patch new file mode 100644 index 000000000..ebb9ee8fa --- /dev/null +++ b/debian/patches/bugfix/all/bpf-fix-branch-pruning-logic.patch @@ -0,0 +1,112 @@ +From: Alexei Starovoitov +Date: Wed, 22 Nov 2017 16:42:05 -0800 +Subject: bpf: fix branch pruning logic +Origin: https://git.kernel.org/linus/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 +Acked-by: Daniel Borkmann +Signed-off-by: Daniel Borkmann +--- + 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 +@@ -3695,6 +3695,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) +@@ -3885,6 +3886,7 @@ process_bpf_exit: + return err; + + insn_idx++; ++ env->insn_aux_data[insn_idx].seen = true; + } else { + verbose(env, "invalid BPF_LD mode\n"); + return -EINVAL; +@@ -4067,6 +4069,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; +@@ -4076,6 +4079,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; +@@ -4094,6 +4099,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' + */ +@@ -4410,6 +4434,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/debian/patches/bugfix/all/bpf-fix-incorrect-sign-extension-in-check_alu_op.patch b/debian/patches/bugfix/all/bpf-fix-incorrect-sign-extension-in-check_alu_op.patch new file mode 100644 index 000000000..62d451056 --- /dev/null +++ b/debian/patches/bugfix/all/bpf-fix-incorrect-sign-extension-in-check_alu_op.patch @@ -0,0 +1,44 @@ +From: Jann Horn +Date: Mon, 18 Dec 2017 20:11:54 -0800 +Subject: [2/9] bpf: fix incorrect sign extension in check_alu_op() +Origin: https://git.kernel.org/linus/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 +Acked-by: Edward Cree +Signed-off-by: Alexei Starovoitov +Signed-off-by: Daniel Borkmann +--- + kernel/bpf/verifier.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -2401,7 +2401,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/debian/patches/bugfix/all/bpf-fix-incorrect-tracking-of-register-size-truncati.patch b/debian/patches/bugfix/all/bpf-fix-incorrect-tracking-of-register-size-truncati.patch new file mode 100644 index 000000000..e43e9da78 --- /dev/null +++ b/debian/patches/bugfix/all/bpf-fix-incorrect-tracking-of-register-size-truncati.patch @@ -0,0 +1,119 @@ +From: Jann Horn +Date: Mon, 18 Dec 2017 20:11:55 -0800 +Subject: [3/9] bpf: fix incorrect tracking of register size truncation +Origin: https://git.kernel.org/linus/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 +Acked-by: Edward Cree +Signed-off-by: Alexei Starovoitov +Signed-off-by: Daniel Borkmann +[bwh: Backported to 4.14] +--- + kernel/bpf/verifier.c | 44 +++++++++++++++++++++++++++----------------- + 1 file changed, 27 insertions(+), 17 deletions(-) + +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -1079,6 +1079,29 @@ static int check_ptr_alignment(struct bp + 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 +@@ -1217,9 +1240,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; + } +@@ -1765,14 +1786,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 */ +@@ -2010,8 +2023,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; +@@ -2391,10 +2404,7 @@ static int check_alu_op(struct bpf_verif + return -EACCES; + } + mark_reg_unknown(env, 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(®s[insn->dst_reg]); ++ coerce_reg_to_size(®s[insn->dst_reg], 4); + } + } else { + /* case: R = imm diff --git a/debian/patches/bugfix/all/bpf-fix-integer-overflows.patch b/debian/patches/bugfix/all/bpf-fix-integer-overflows.patch new file mode 100644 index 000000000..745014a71 --- /dev/null +++ b/debian/patches/bugfix/all/bpf-fix-integer-overflows.patch @@ -0,0 +1,121 @@ +From: Alexei Starovoitov +Date: Mon, 18 Dec 2017 20:12:00 -0800 +Subject: [8/9] bpf: fix integer overflows +Origin: https://git.kernel.org/linus/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 +Signed-off-by: Alexei Starovoitov +Signed-off-by: Daniel Borkmann +--- + 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 +@@ -1812,6 +1812,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(env, "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(env, "%s pointer offset %d is not allowed\n", ++ reg_type_str[type], reg->off); ++ return false; ++ } ++ ++ if (smin == S64_MIN) { ++ verbose(env, "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(env, "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 +@@ -1880,6 +1915,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 +@@ -2010,6 +2049,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); +@@ -2039,6 +2081,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/debian/patches/bugfix/all/bpf-fix-missing-error-return-in-check_stack_boundary.patch b/debian/patches/bugfix/all/bpf-fix-missing-error-return-in-check_stack_boundary.patch new file mode 100644 index 000000000..e80bde378 --- /dev/null +++ b/debian/patches/bugfix/all/bpf-fix-missing-error-return-in-check_stack_boundary.patch @@ -0,0 +1,26 @@ +From: Jann Horn +Date: Mon, 18 Dec 2017 20:11:57 -0800 +Subject: [5/9] bpf: fix missing error return in check_stack_boundary() +Origin: https://git.kernel.org/linus/ea25f914dc164c8d56b36147ecc86bc65f83c469 + +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 +Signed-off-by: Alexei Starovoitov +Signed-off-by: Daniel Borkmann +--- + kernel/bpf/verifier.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -1320,6 +1320,7 @@ static int check_stack_boundary(struct b + tnum_strn(tn_buf, sizeof(tn_buf), regs[regno].var_off); + verbose(env, "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/debian/patches/bugfix/all/bpf-force-strict-alignment-checks-for-stack-pointers.patch b/debian/patches/bugfix/all/bpf-force-strict-alignment-checks-for-stack-pointers.patch new file mode 100644 index 000000000..db7e55799 --- /dev/null +++ b/debian/patches/bugfix/all/bpf-force-strict-alignment-checks-for-stack-pointers.patch @@ -0,0 +1,31 @@ +From: Jann Horn +Date: Mon, 18 Dec 2017 20:11:58 -0800 +Subject: [6/9] bpf: force strict alignment checks for stack pointers +Origin: https://git.kernel.org/linus/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 +Signed-off-by: Alexei Starovoitov +Signed-off-by: Daniel Borkmann +--- + kernel/bpf/verifier.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -1071,6 +1071,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/debian/patches/bugfix/all/bpf-move-global-verifier-log-into-verifier-environme.patch b/debian/patches/bugfix/all/bpf-move-global-verifier-log-into-verifier-environme.patch new file mode 100644 index 000000000..a64445733 --- /dev/null +++ b/debian/patches/bugfix/all/bpf-move-global-verifier-log-into-verifier-environme.patch @@ -0,0 +1,1665 @@ +From: Jakub Kicinski +Date: Mon, 9 Oct 2017 10:30:11 -0700 +Subject: bpf: move global verifier log into verifier environment +Origin: https://git.kernel.org/linus/61bd5218eef349fcacc4976a251bc83a4748b4af + +The biggest piece of global state protected by the verifier lock +is the verifier_log. Move that log to struct bpf_verifier_env. +struct bpf_verifier_env has to be passed now to all invocations +of verbose(). + +Signed-off-by: Jakub Kicinski +Reviewed-by: Simon Horman +Acked-by: Alexei Starovoitov +Acked-by: Daniel Borkmann +Signed-off-by: David S. Miller +[bwh: Backported to 4.14] +--- + include/linux/bpf_verifier.h | 2 + + kernel/bpf/verifier.c | 491 +++++++++++++++++++++++-------------------- + 2 files changed, 261 insertions(+), 232 deletions(-) + +--- a/include/linux/bpf_verifier.h ++++ b/include/linux/bpf_verifier.h +@@ -152,6 +152,8 @@ struct bpf_verifier_env { + bool allow_ptr_leaks; + bool seen_direct_write; + struct bpf_insn_aux_data *insn_aux_data; /* array of per-insn state */ ++ ++ struct bpf_verifer_log log; + }; + + int bpf_analyzer(struct bpf_prog *prog, const struct bpf_ext_analyzer_ops *ops, +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -153,20 +153,16 @@ struct bpf_call_arg_meta { + int access_size; + }; + +-/* verbose verifier prints what it's seeing +- * bpf_check() is called under lock, so no race to access these global vars +- */ +-static struct bpf_verifer_log verifier_log; +- + static DEFINE_MUTEX(bpf_verifier_lock); + + /* log_level controls verbosity level of eBPF verifier. + * verbose() is used to dump the verification trace to the log, so the user + * can figure out what's wrong with the program + */ +-static __printf(1, 2) void verbose(const char *fmt, ...) ++static __printf(2, 3) void verbose(struct bpf_verifier_env *env, ++ const char *fmt, ...) + { +- struct bpf_verifer_log *log = &verifier_log; ++ struct bpf_verifer_log *log = &env->log; + va_list args; + + if (!log->level || bpf_verifier_log_full(log)) +@@ -207,7 +203,8 @@ static const char *func_id_name(int id) + return "unknown"; + } + +-static void print_verifier_state(struct bpf_verifier_state *state) ++static void print_verifier_state(struct bpf_verifier_env *env, ++ struct bpf_verifier_state *state) + { + struct bpf_reg_state *reg; + enum bpf_reg_type t; +@@ -218,21 +215,21 @@ static void print_verifier_state(struct + t = reg->type; + if (t == NOT_INIT) + continue; +- verbose(" R%d=%s", i, reg_type_str[t]); ++ verbose(env, " R%d=%s", i, reg_type_str[t]); + if ((t == SCALAR_VALUE || t == PTR_TO_STACK) && + tnum_is_const(reg->var_off)) { + /* reg->off should be 0 for SCALAR_VALUE */ +- verbose("%lld", reg->var_off.value + reg->off); ++ verbose(env, "%lld", reg->var_off.value + reg->off); + } else { +- verbose("(id=%d", reg->id); ++ verbose(env, "(id=%d", reg->id); + if (t != SCALAR_VALUE) +- verbose(",off=%d", reg->off); ++ verbose(env, ",off=%d", reg->off); + if (t == PTR_TO_PACKET) +- verbose(",r=%d", reg->range); ++ verbose(env, ",r=%d", reg->range); + else if (t == CONST_PTR_TO_MAP || + t == PTR_TO_MAP_VALUE || + t == PTR_TO_MAP_VALUE_OR_NULL) +- verbose(",ks=%d,vs=%d", ++ verbose(env, ",ks=%d,vs=%d", + reg->map_ptr->key_size, + reg->map_ptr->value_size); + if (tnum_is_const(reg->var_off)) { +@@ -240,38 +237,38 @@ static void print_verifier_state(struct + * could be a pointer whose offset is too big + * for reg->off + */ +- verbose(",imm=%llx", reg->var_off.value); ++ verbose(env, ",imm=%llx", reg->var_off.value); + } else { + if (reg->smin_value != reg->umin_value && + reg->smin_value != S64_MIN) +- verbose(",smin_value=%lld", ++ verbose(env, ",smin_value=%lld", + (long long)reg->smin_value); + if (reg->smax_value != reg->umax_value && + reg->smax_value != S64_MAX) +- verbose(",smax_value=%lld", ++ verbose(env, ",smax_value=%lld", + (long long)reg->smax_value); + if (reg->umin_value != 0) +- verbose(",umin_value=%llu", ++ verbose(env, ",umin_value=%llu", + (unsigned long long)reg->umin_value); + if (reg->umax_value != U64_MAX) +- verbose(",umax_value=%llu", ++ verbose(env, ",umax_value=%llu", + (unsigned long long)reg->umax_value); + if (!tnum_is_unknown(reg->var_off)) { + char tn_buf[48]; + + tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off); +- verbose(",var_off=%s", tn_buf); ++ verbose(env, ",var_off=%s", tn_buf); + } + } +- verbose(")"); ++ verbose(env, ")"); + } + } + for (i = 0; i < MAX_BPF_STACK; i += BPF_REG_SIZE) { + if (state->stack_slot_type[i] == STACK_SPILL) +- verbose(" fp%d=%s", -MAX_BPF_STACK + i, ++ verbose(env, " fp%d=%s", -MAX_BPF_STACK + i, + reg_type_str[state->spilled_regs[i / BPF_REG_SIZE].type]); + } +- verbose("\n"); ++ verbose(env, "\n"); + } + + static const char *const bpf_class_string[] = { +@@ -326,21 +323,21 @@ static const char *const bpf_jmp_string[ + [BPF_EXIT >> 4] = "exit", + }; + +-static void print_bpf_insn(const struct bpf_verifier_env *env, ++static void print_bpf_insn(struct bpf_verifier_env *env, + const struct bpf_insn *insn) + { + u8 class = BPF_CLASS(insn->code); + + if (class == BPF_ALU || class == BPF_ALU64) { + if (BPF_SRC(insn->code) == BPF_X) +- verbose("(%02x) %sr%d %s %sr%d\n", ++ verbose(env, "(%02x) %sr%d %s %sr%d\n", + insn->code, class == BPF_ALU ? "(u32) " : "", + insn->dst_reg, + bpf_alu_string[BPF_OP(insn->code) >> 4], + class == BPF_ALU ? "(u32) " : "", + insn->src_reg); + else +- verbose("(%02x) %sr%d %s %s%d\n", ++ verbose(env, "(%02x) %sr%d %s %s%d\n", + insn->code, class == BPF_ALU ? "(u32) " : "", + insn->dst_reg, + bpf_alu_string[BPF_OP(insn->code) >> 4], +@@ -348,46 +345,46 @@ static void print_bpf_insn(const struct + insn->imm); + } else if (class == BPF_STX) { + if (BPF_MODE(insn->code) == BPF_MEM) +- verbose("(%02x) *(%s *)(r%d %+d) = r%d\n", ++ verbose(env, "(%02x) *(%s *)(r%d %+d) = r%d\n", + insn->code, + bpf_ldst_string[BPF_SIZE(insn->code) >> 3], + insn->dst_reg, + insn->off, insn->src_reg); + else if (BPF_MODE(insn->code) == BPF_XADD) +- verbose("(%02x) lock *(%s *)(r%d %+d) += r%d\n", ++ verbose(env, "(%02x) lock *(%s *)(r%d %+d) += r%d\n", + insn->code, + bpf_ldst_string[BPF_SIZE(insn->code) >> 3], + insn->dst_reg, insn->off, + insn->src_reg); + else +- verbose("BUG_%02x\n", insn->code); ++ verbose(env, "BUG_%02x\n", insn->code); + } else if (class == BPF_ST) { + if (BPF_MODE(insn->code) != BPF_MEM) { +- verbose("BUG_st_%02x\n", insn->code); ++ verbose(env, "BUG_st_%02x\n", insn->code); + return; + } +- verbose("(%02x) *(%s *)(r%d %+d) = %d\n", ++ verbose(env, "(%02x) *(%s *)(r%d %+d) = %d\n", + insn->code, + bpf_ldst_string[BPF_SIZE(insn->code) >> 3], + insn->dst_reg, + insn->off, insn->imm); + } else if (class == BPF_LDX) { + if (BPF_MODE(insn->code) != BPF_MEM) { +- verbose("BUG_ldx_%02x\n", insn->code); ++ verbose(env, "BUG_ldx_%02x\n", insn->code); + return; + } +- verbose("(%02x) r%d = *(%s *)(r%d %+d)\n", ++ verbose(env, "(%02x) r%d = *(%s *)(r%d %+d)\n", + insn->code, insn->dst_reg, + bpf_ldst_string[BPF_SIZE(insn->code) >> 3], + insn->src_reg, insn->off); + } else if (class == BPF_LD) { + if (BPF_MODE(insn->code) == BPF_ABS) { +- verbose("(%02x) r0 = *(%s *)skb[%d]\n", ++ verbose(env, "(%02x) r0 = *(%s *)skb[%d]\n", + insn->code, + bpf_ldst_string[BPF_SIZE(insn->code) >> 3], + insn->imm); + } else if (BPF_MODE(insn->code) == BPF_IND) { +- verbose("(%02x) r0 = *(%s *)skb[r%d + %d]\n", ++ verbose(env, "(%02x) r0 = *(%s *)skb[r%d + %d]\n", + insn->code, + bpf_ldst_string[BPF_SIZE(insn->code) >> 3], + insn->src_reg, insn->imm); +@@ -402,36 +399,37 @@ static void print_bpf_insn(const struct + if (map_ptr && !env->allow_ptr_leaks) + imm = 0; + +- verbose("(%02x) r%d = 0x%llx\n", insn->code, ++ verbose(env, "(%02x) r%d = 0x%llx\n", insn->code, + insn->dst_reg, (unsigned long long)imm); + } else { +- verbose("BUG_ld_%02x\n", insn->code); ++ verbose(env, "BUG_ld_%02x\n", insn->code); + return; + } + } else if (class == BPF_JMP) { + u8 opcode = BPF_OP(insn->code); + + if (opcode == BPF_CALL) { +- verbose("(%02x) call %s#%d\n", insn->code, ++ verbose(env, "(%02x) call %s#%d\n", insn->code, + func_id_name(insn->imm), insn->imm); + } else if (insn->code == (BPF_JMP | BPF_JA)) { +- verbose("(%02x) goto pc%+d\n", ++ verbose(env, "(%02x) goto pc%+d\n", + insn->code, insn->off); + } else if (insn->code == (BPF_JMP | BPF_EXIT)) { +- verbose("(%02x) exit\n", insn->code); ++ verbose(env, "(%02x) exit\n", insn->code); + } else if (BPF_SRC(insn->code) == BPF_X) { +- verbose("(%02x) if r%d %s r%d goto pc%+d\n", ++ verbose(env, "(%02x) if r%d %s r%d goto pc%+d\n", + insn->code, insn->dst_reg, + bpf_jmp_string[BPF_OP(insn->code) >> 4], + insn->src_reg, insn->off); + } else { +- verbose("(%02x) if r%d %s 0x%x goto pc%+d\n", ++ verbose(env, "(%02x) if r%d %s 0x%x goto pc%+d\n", + insn->code, insn->dst_reg, + bpf_jmp_string[BPF_OP(insn->code) >> 4], + insn->imm, insn->off); + } + } else { +- verbose("(%02x) %s\n", insn->code, bpf_class_string[class]); ++ verbose(env, "(%02x) %s\n", ++ insn->code, bpf_class_string[class]); + } + } + +@@ -470,7 +468,7 @@ static struct bpf_verifier_state *push_s + env->head = elem; + env->stack_size++; + if (env->stack_size > BPF_COMPLEXITY_LIMIT_STACK) { +- verbose("BPF program is too complex\n"); ++ verbose(env, "BPF program is too complex\n"); + goto err; + } + return &elem->st; +@@ -508,10 +506,11 @@ static void __mark_reg_known_zero(struct + __mark_reg_known(reg, 0); + } + +-static void mark_reg_known_zero(struct bpf_reg_state *regs, u32 regno) ++static void mark_reg_known_zero(struct bpf_verifier_env *env, ++ struct bpf_reg_state *regs, u32 regno) + { + if (WARN_ON(regno >= MAX_BPF_REG)) { +- verbose("mark_reg_known_zero(regs, %u)\n", regno); ++ verbose(env, "mark_reg_known_zero(regs, %u)\n", regno); + /* Something bad happened, let's kill all regs */ + for (regno = 0; regno < MAX_BPF_REG; regno++) + __mark_reg_not_init(regs + regno); +@@ -596,10 +595,11 @@ static void __mark_reg_unknown(struct bp + __mark_reg_unbounded(reg); + } + +-static void mark_reg_unknown(struct bpf_reg_state *regs, u32 regno) ++static void mark_reg_unknown(struct bpf_verifier_env *env, ++ struct bpf_reg_state *regs, u32 regno) + { + if (WARN_ON(regno >= MAX_BPF_REG)) { +- verbose("mark_reg_unknown(regs, %u)\n", regno); ++ verbose(env, "mark_reg_unknown(regs, %u)\n", regno); + /* Something bad happened, let's kill all regs */ + for (regno = 0; regno < MAX_BPF_REG; regno++) + __mark_reg_not_init(regs + regno); +@@ -614,10 +614,11 @@ static void __mark_reg_not_init(struct b + reg->type = NOT_INIT; + } + +-static void mark_reg_not_init(struct bpf_reg_state *regs, u32 regno) ++static void mark_reg_not_init(struct bpf_verifier_env *env, ++ struct bpf_reg_state *regs, u32 regno) + { + if (WARN_ON(regno >= MAX_BPF_REG)) { +- verbose("mark_reg_not_init(regs, %u)\n", regno); ++ verbose(env, "mark_reg_not_init(regs, %u)\n", regno); + /* Something bad happened, let's kill all regs */ + for (regno = 0; regno < MAX_BPF_REG; regno++) + __mark_reg_not_init(regs + regno); +@@ -626,22 +627,23 @@ static void mark_reg_not_init(struct bpf + __mark_reg_not_init(regs + regno); + } + +-static void init_reg_state(struct bpf_reg_state *regs) ++static void init_reg_state(struct bpf_verifier_env *env, ++ struct bpf_reg_state *regs) + { + int i; + + for (i = 0; i < MAX_BPF_REG; i++) { +- mark_reg_not_init(regs, i); ++ mark_reg_not_init(env, regs, i); + regs[i].live = REG_LIVE_NONE; + } + + /* frame pointer */ + regs[BPF_REG_FP].type = PTR_TO_STACK; +- mark_reg_known_zero(regs, BPF_REG_FP); ++ mark_reg_known_zero(env, regs, BPF_REG_FP); + + /* 1st arg to a function */ + regs[BPF_REG_1].type = PTR_TO_CTX; +- mark_reg_known_zero(regs, BPF_REG_1); ++ mark_reg_known_zero(env, regs, BPF_REG_1); + } + + enum reg_arg_type { +@@ -675,26 +677,26 @@ static int check_reg_arg(struct bpf_veri + struct bpf_reg_state *regs = env->cur_state.regs; + + if (regno >= MAX_BPF_REG) { +- verbose("R%d is invalid\n", regno); ++ verbose(env, "R%d is invalid\n", regno); + return -EINVAL; + } + + if (t == SRC_OP) { + /* check whether register used as source operand can be read */ + if (regs[regno].type == NOT_INIT) { +- verbose("R%d !read_ok\n", regno); ++ verbose(env, "R%d !read_ok\n", regno); + return -EACCES; + } + mark_reg_read(&env->cur_state, regno); + } else { + /* check whether register used as dest operand can be written to */ + if (regno == BPF_REG_FP) { +- verbose("frame pointer is read only\n"); ++ verbose(env, "frame pointer is read only\n"); + return -EACCES; + } + regs[regno].live |= REG_LIVE_WRITTEN; + if (t == DST_OP) +- mark_reg_unknown(regs, regno); ++ mark_reg_unknown(env, regs, regno); + } + return 0; + } +@@ -718,7 +720,8 @@ static bool is_spillable_regtype(enum bp + /* check_stack_read/write functions track spill/fill of registers, + * stack boundary and alignment are checked in check_mem_access() + */ +-static int check_stack_write(struct bpf_verifier_state *state, int off, ++static int check_stack_write(struct bpf_verifier_env *env, ++ struct bpf_verifier_state *state, int off, + int size, int value_regno) + { + int i, spi = (MAX_BPF_STACK + off) / BPF_REG_SIZE; +@@ -731,7 +734,7 @@ static int check_stack_write(struct bpf_ + + /* register containing pointer is being spilled into stack */ + if (size != BPF_REG_SIZE) { +- verbose("invalid size of register spill\n"); ++ verbose(env, "invalid size of register spill\n"); + return -EACCES; + } + +@@ -766,7 +769,8 @@ static void mark_stack_slot_read(const s + } + } + +-static int check_stack_read(struct bpf_verifier_state *state, int off, int size, ++static int check_stack_read(struct bpf_verifier_env *env, ++ struct bpf_verifier_state *state, int off, int size, + int value_regno) + { + u8 *slot_type; +@@ -776,12 +780,12 @@ static int check_stack_read(struct bpf_v + + if (slot_type[0] == STACK_SPILL) { + if (size != BPF_REG_SIZE) { +- verbose("invalid size of register spill\n"); ++ verbose(env, "invalid size of register spill\n"); + return -EACCES; + } + for (i = 1; i < BPF_REG_SIZE; i++) { + if (slot_type[i] != STACK_SPILL) { +- verbose("corrupted spill memory\n"); ++ verbose(env, "corrupted spill memory\n"); + return -EACCES; + } + } +@@ -797,14 +801,14 @@ static int check_stack_read(struct bpf_v + } else { + for (i = 0; i < size; i++) { + if (slot_type[i] != STACK_MISC) { +- verbose("invalid read from stack off %d+%d size %d\n", ++ verbose(env, "invalid read from stack off %d+%d size %d\n", + off, i, size); + return -EACCES; + } + } + if (value_regno >= 0) + /* have read misc data from the stack */ +- mark_reg_unknown(state->regs, value_regno); ++ mark_reg_unknown(env, state->regs, value_regno); + return 0; + } + } +@@ -816,7 +820,7 @@ static int __check_map_access(struct bpf + struct bpf_map *map = env->cur_state.regs[regno].map_ptr; + + if (off < 0 || size <= 0 || off + size > map->value_size) { +- verbose("invalid access to map value, value_size=%d off=%d size=%d\n", ++ verbose(env, "invalid access to map value, value_size=%d off=%d size=%d\n", + map->value_size, off, size); + return -EACCES; + } +@@ -835,8 +839,8 @@ static int check_map_access(struct bpf_v + * need to try adding each of min_value and max_value to off + * to make sure our theoretical access will be safe. + */ +- if (verifier_log.level) +- print_verifier_state(state); ++ if (env->log.level) ++ print_verifier_state(env, state); + /* The minimum value is only important with signed + * comparisons where we can't assume the floor of a + * value is 0. If we are using signed variables for our +@@ -844,13 +848,14 @@ static int check_map_access(struct bpf_v + * will have a set floor within our range. + */ + if (reg->smin_value < 0) { +- verbose("R%d min value is negative, either use unsigned index or do a if (index >=0) check.\n", ++ verbose(env, "R%d min value is negative, either use unsigned index or do a if (index >=0) check.\n", + regno); + return -EACCES; + } + err = __check_map_access(env, regno, reg->smin_value + off, size); + if (err) { +- verbose("R%d min value is outside of the array range\n", regno); ++ verbose(env, "R%d min value is outside of the array range\n", ++ regno); + return err; + } + +@@ -859,13 +864,14 @@ static int check_map_access(struct bpf_v + * If reg->umax_value + off could overflow, treat that as unbounded too. + */ + if (reg->umax_value >= BPF_MAX_VAR_OFF) { +- verbose("R%d unbounded memory access, make sure to bounds check any array access into a map\n", ++ verbose(env, "R%d unbounded memory access, make sure to bounds check any array access into a map\n", + regno); + return -EACCES; + } + err = __check_map_access(env, regno, reg->umax_value + off, size); + if (err) +- verbose("R%d max value is outside of the array range\n", regno); ++ verbose(env, "R%d max value is outside of the array range\n", ++ regno); + return err; + } + +@@ -904,7 +910,7 @@ static int __check_packet_access(struct + struct bpf_reg_state *reg = ®s[regno]; + + if (off < 0 || size <= 0 || (u64)off + size > reg->range) { +- verbose("invalid access to packet, off=%d size=%d, R%d(id=%d,off=%d,r=%d)\n", ++ verbose(env, "invalid access to packet, off=%d size=%d, R%d(id=%d,off=%d,r=%d)\n", + off, size, regno, reg->id, reg->off, reg->range); + return -EACCES; + } +@@ -927,13 +933,13 @@ static int check_packet_access(struct bp + * detail to prove they're safe. + */ + if (reg->smin_value < 0) { +- verbose("R%d min value is negative, either use unsigned index or do a if (index >=0) check.\n", ++ verbose(env, "R%d min value is negative, either use unsigned index or do a if (index >=0) check.\n", + regno); + return -EACCES; + } + err = __check_packet_access(env, regno, off, size); + if (err) { +- verbose("R%d offset is outside of the packet\n", regno); ++ verbose(env, "R%d offset is outside of the packet\n", regno); + return err; + } + return err; +@@ -969,7 +975,7 @@ static int check_ctx_access(struct bpf_v + return 0; + } + +- verbose("invalid bpf_context access off=%d size=%d\n", off, size); ++ verbose(env, "invalid bpf_context access off=%d size=%d\n", off, size); + return -EACCES; + } + +@@ -987,7 +993,8 @@ static bool is_pointer_value(struct bpf_ + return __is_pointer_value(env->allow_ptr_leaks, &env->cur_state.regs[regno]); + } + +-static int check_pkt_ptr_alignment(const struct bpf_reg_state *reg, ++static int check_pkt_ptr_alignment(struct bpf_verifier_env *env, ++ const struct bpf_reg_state *reg, + int off, int size, bool strict) + { + struct tnum reg_off; +@@ -1012,7 +1019,8 @@ static int check_pkt_ptr_alignment(const + char tn_buf[48]; + + tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off); +- verbose("misaligned packet access off %d+%s+%d+%d size %d\n", ++ verbose(env, ++ "misaligned packet access off %d+%s+%d+%d size %d\n", + ip_align, tn_buf, reg->off, off, size); + return -EACCES; + } +@@ -1020,7 +1028,8 @@ static int check_pkt_ptr_alignment(const + return 0; + } + +-static int check_generic_ptr_alignment(const struct bpf_reg_state *reg, ++static int check_generic_ptr_alignment(struct bpf_verifier_env *env, ++ const struct bpf_reg_state *reg, + const char *pointer_desc, + int off, int size, bool strict) + { +@@ -1035,7 +1044,7 @@ static int check_generic_ptr_alignment(c + char tn_buf[48]; + + tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off); +- verbose("misaligned %saccess off %s+%d+%d size %d\n", ++ verbose(env, "misaligned %saccess off %s+%d+%d size %d\n", + pointer_desc, tn_buf, reg->off, off, size); + return -EACCES; + } +@@ -1053,7 +1062,7 @@ static int check_ptr_alignment(struct bp + switch (reg->type) { + case PTR_TO_PACKET: + /* special case, because of NET_IP_ALIGN */ +- return check_pkt_ptr_alignment(reg, off, size, strict); ++ return check_pkt_ptr_alignment(env, reg, off, size, strict); + case PTR_TO_MAP_VALUE: + pointer_desc = "value "; + break; +@@ -1066,7 +1075,8 @@ static int check_ptr_alignment(struct bp + default: + break; + } +- return check_generic_ptr_alignment(reg, pointer_desc, off, size, strict); ++ return check_generic_ptr_alignment(env, reg, pointer_desc, off, size, ++ strict); + } + + /* check whether memory at (regno + off) is accessible for t = (read | write) +@@ -1098,27 +1108,27 @@ static int check_mem_access(struct bpf_v + if (reg->type == PTR_TO_MAP_VALUE) { + if (t == BPF_WRITE && value_regno >= 0 && + is_pointer_value(env, value_regno)) { +- verbose("R%d leaks addr into map\n", value_regno); ++ verbose(env, "R%d leaks addr into map\n", value_regno); + return -EACCES; + } + + err = check_map_access(env, regno, off, size); + if (!err && t == BPF_READ && value_regno >= 0) +- mark_reg_unknown(state->regs, value_regno); ++ mark_reg_unknown(env, state->regs, value_regno); + + } else if (reg->type == PTR_TO_CTX) { + enum bpf_reg_type reg_type = SCALAR_VALUE; + + if (t == BPF_WRITE && value_regno >= 0 && + is_pointer_value(env, value_regno)) { +- verbose("R%d leaks addr into ctx\n", value_regno); ++ verbose(env, "R%d leaks addr into ctx\n", value_regno); + return -EACCES; + } + /* ctx accesses must be at a fixed offset, so that we can + * determine what type of data were returned. + */ + if (reg->off) { +- verbose("dereference of modified ctx ptr R%d off=%d+%d, ctx+const is allowed, ctx+const+const is not\n", ++ verbose(env, "dereference of modified ctx ptr R%d off=%d+%d, ctx+const is allowed, ctx+const+const is not\n", + regno, reg->off, off - reg->off); + return -EACCES; + } +@@ -1126,7 +1136,8 @@ static int check_mem_access(struct bpf_v + char tn_buf[48]; + + tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off); +- verbose("variable ctx access var_off=%s off=%d size=%d", ++ verbose(env, ++ "variable ctx access var_off=%s off=%d size=%d", + tn_buf, off, size); + return -EACCES; + } +@@ -1137,9 +1148,10 @@ static int check_mem_access(struct bpf_v + * the offset is zero. + */ + if (reg_type == SCALAR_VALUE) +- mark_reg_unknown(state->regs, value_regno); ++ mark_reg_unknown(env, state->regs, value_regno); + else +- mark_reg_known_zero(state->regs, value_regno); ++ mark_reg_known_zero(env, state->regs, ++ value_regno); + state->regs[value_regno].id = 0; + state->regs[value_regno].off = 0; + state->regs[value_regno].range = 0; +@@ -1155,13 +1167,14 @@ static int check_mem_access(struct bpf_v + char tn_buf[48]; + + tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off); +- verbose("variable stack access var_off=%s off=%d size=%d", ++ verbose(env, "variable stack access var_off=%s off=%d size=%d", + tn_buf, off, size); + return -EACCES; + } + off += reg->var_off.value; + if (off >= 0 || off < -MAX_BPF_STACK) { +- verbose("invalid stack off=%d size=%d\n", off, size); ++ verbose(env, "invalid stack off=%d size=%d\n", off, ++ size); + return -EACCES; + } + +@@ -1172,28 +1185,31 @@ static int check_mem_access(struct bpf_v + if (!env->allow_ptr_leaks && + state->stack_slot_type[MAX_BPF_STACK + off] == STACK_SPILL && + size != BPF_REG_SIZE) { +- verbose("attempt to corrupt spilled pointer on stack\n"); ++ verbose(env, "attempt to corrupt spilled pointer on stack\n"); + return -EACCES; + } +- err = check_stack_write(state, off, size, value_regno); ++ err = check_stack_write(env, state, off, size, ++ value_regno); + } else { +- err = check_stack_read(state, off, size, value_regno); ++ err = check_stack_read(env, state, off, size, ++ value_regno); + } + } else if (reg->type == PTR_TO_PACKET) { + if (t == BPF_WRITE && !may_access_direct_pkt_data(env, NULL, t)) { +- verbose("cannot write into packet\n"); ++ verbose(env, "cannot write into packet\n"); + return -EACCES; + } + if (t == BPF_WRITE && value_regno >= 0 && + is_pointer_value(env, value_regno)) { +- verbose("R%d leaks addr into packet\n", value_regno); ++ verbose(env, "R%d leaks addr into packet\n", ++ value_regno); + return -EACCES; + } + err = check_packet_access(env, regno, off, size); + if (!err && t == BPF_READ && value_regno >= 0) +- mark_reg_unknown(state->regs, value_regno); ++ mark_reg_unknown(env, state->regs, value_regno); + } else { +- verbose("R%d invalid mem access '%s'\n", ++ verbose(env, "R%d invalid mem access '%s'\n", + regno, reg_type_str[reg->type]); + return -EACCES; + } +@@ -1214,7 +1230,7 @@ static int check_xadd(struct bpf_verifie + + if ((BPF_SIZE(insn->code) != BPF_W && BPF_SIZE(insn->code) != BPF_DW) || + insn->imm != 0) { +- verbose("BPF_XADD uses reserved fields\n"); ++ verbose(env, "BPF_XADD uses reserved fields\n"); + return -EINVAL; + } + +@@ -1229,7 +1245,7 @@ static int check_xadd(struct bpf_verifie + return err; + + if (is_pointer_value(env, insn->src_reg)) { +- verbose("R%d leaks addr into mem\n", insn->src_reg); ++ verbose(env, "R%d leaks addr into mem\n", insn->src_reg); + return -EACCES; + } + +@@ -1270,7 +1286,7 @@ static int check_stack_boundary(struct b + register_is_null(regs[regno])) + return 0; + +- verbose("R%d type=%s expected=%s\n", regno, ++ verbose(env, "R%d type=%s expected=%s\n", regno, + reg_type_str[regs[regno].type], + reg_type_str[PTR_TO_STACK]); + return -EACCES; +@@ -1281,13 +1297,13 @@ static int check_stack_boundary(struct b + char tn_buf[48]; + + tnum_strn(tn_buf, sizeof(tn_buf), regs[regno].var_off); +- verbose("invalid variable stack read R%d var_off=%s\n", ++ verbose(env, "invalid variable stack read R%d var_off=%s\n", + regno, tn_buf); + } + off = regs[regno].off + regs[regno].var_off.value; + if (off >= 0 || off < -MAX_BPF_STACK || off + access_size > 0 || + access_size <= 0) { +- verbose("invalid stack type R%d off=%d access_size=%d\n", ++ verbose(env, "invalid stack type R%d off=%d access_size=%d\n", + regno, off, access_size); + return -EACCES; + } +@@ -1303,7 +1319,7 @@ static int check_stack_boundary(struct b + + for (i = 0; i < access_size; i++) { + if (state->stack_slot_type[MAX_BPF_STACK + off + i] != STACK_MISC) { +- verbose("invalid indirect read from stack off %d+%d size %d\n", ++ verbose(env, "invalid indirect read from stack off %d+%d size %d\n", + off, i, access_size); + return -EACCES; + } +@@ -1345,7 +1361,8 @@ static int check_func_arg(struct bpf_ver + + if (arg_type == ARG_ANYTHING) { + if (is_pointer_value(env, regno)) { +- verbose("R%d leaks addr into helper function\n", regno); ++ verbose(env, "R%d leaks addr into helper function\n", ++ regno); + return -EACCES; + } + return 0; +@@ -1353,7 +1370,7 @@ static int check_func_arg(struct bpf_ver + + if (type == PTR_TO_PACKET && + !may_access_direct_pkt_data(env, meta, BPF_READ)) { +- verbose("helper access to the packet is not allowed\n"); ++ verbose(env, "helper access to the packet is not allowed\n"); + return -EACCES; + } + +@@ -1389,7 +1406,7 @@ static int check_func_arg(struct bpf_ver + goto err_type; + meta->raw_mode = arg_type == ARG_PTR_TO_UNINIT_MEM; + } else { +- verbose("unsupported arg_type %d\n", arg_type); ++ verbose(env, "unsupported arg_type %d\n", arg_type); + return -EFAULT; + } + +@@ -1407,7 +1424,7 @@ static int check_func_arg(struct bpf_ver + * we have to check map_key here. Otherwise it means + * that kernel subsystem misconfigured verifier + */ +- verbose("invalid map_ptr to access map->key\n"); ++ verbose(env, "invalid map_ptr to access map->key\n"); + return -EACCES; + } + if (type == PTR_TO_PACKET) +@@ -1423,7 +1440,7 @@ static int check_func_arg(struct bpf_ver + */ + if (!meta->map_ptr) { + /* kernel subsystem misconfigured verifier */ +- verbose("invalid map_ptr to access map->value\n"); ++ verbose(env, "invalid map_ptr to access map->value\n"); + return -EACCES; + } + if (type == PTR_TO_PACKET) +@@ -1443,7 +1460,8 @@ static int check_func_arg(struct bpf_ver + */ + if (regno == 0) { + /* kernel subsystem misconfigured verifier */ +- verbose("ARG_CONST_SIZE cannot be first argument\n"); ++ verbose(env, ++ "ARG_CONST_SIZE cannot be first argument\n"); + return -EACCES; + } + +@@ -1460,7 +1478,7 @@ static int check_func_arg(struct bpf_ver + meta = NULL; + + if (reg->smin_value < 0) { +- verbose("R%d min value is negative, either use unsigned or 'var &= const'\n", ++ verbose(env, "R%d min value is negative, either use unsigned or 'var &= const'\n", + regno); + return -EACCES; + } +@@ -1474,7 +1492,7 @@ static int check_func_arg(struct bpf_ver + } + + if (reg->umax_value >= BPF_MAX_VAR_SIZ) { +- verbose("R%d unbounded memory access, use 'var &= const' or 'if (var < const)'\n", ++ verbose(env, "R%d unbounded memory access, use 'var &= const' or 'if (var < const)'\n", + regno); + return -EACCES; + } +@@ -1485,12 +1503,13 @@ static int check_func_arg(struct bpf_ver + + return err; + err_type: +- verbose("R%d type=%s expected=%s\n", regno, ++ verbose(env, "R%d type=%s expected=%s\n", regno, + reg_type_str[type], reg_type_str[expected_type]); + return -EACCES; + } + +-static int check_map_func_compatibility(struct bpf_map *map, int func_id) ++static int check_map_func_compatibility(struct bpf_verifier_env *env, ++ struct bpf_map *map, int func_id) + { + if (!map) + return 0; +@@ -1576,7 +1595,7 @@ static int check_map_func_compatibility( + + return 0; + error: +- verbose("cannot pass map_type %d into func %s#%d\n", ++ verbose(env, "cannot pass map_type %d into func %s#%d\n", + map->map_type, func_id_name(func_id), func_id); + return -EINVAL; + } +@@ -1611,7 +1630,7 @@ static void clear_all_pkt_pointers(struc + for (i = 0; i < MAX_BPF_REG; i++) + if (regs[i].type == PTR_TO_PACKET || + regs[i].type == PTR_TO_PACKET_END) +- mark_reg_unknown(regs, i); ++ mark_reg_unknown(env, regs, i); + + for (i = 0; i < MAX_BPF_STACK; i += BPF_REG_SIZE) { + if (state->stack_slot_type[i] != STACK_SPILL) +@@ -1635,7 +1654,8 @@ static int check_call(struct bpf_verifie + + /* find function prototype */ + if (func_id < 0 || func_id >= __BPF_FUNC_MAX_ID) { +- verbose("invalid func %s#%d\n", func_id_name(func_id), func_id); ++ verbose(env, "invalid func %s#%d\n", func_id_name(func_id), ++ func_id); + return -EINVAL; + } + +@@ -1643,13 +1663,14 @@ static int check_call(struct bpf_verifie + fn = env->prog->aux->ops->get_func_proto(func_id); + + if (!fn) { +- verbose("unknown func %s#%d\n", func_id_name(func_id), func_id); ++ verbose(env, "unknown func %s#%d\n", func_id_name(func_id), ++ func_id); + return -EINVAL; + } + + /* eBPF programs must be GPL compatible to use GPL-ed functions */ + if (!env->prog->gpl_compatible && fn->gpl_only) { +- verbose("cannot call GPL only function from proprietary program\n"); ++ verbose(env, "cannot call GPL only function from proprietary program\n"); + return -EINVAL; + } + +@@ -1663,7 +1684,7 @@ static int check_call(struct bpf_verifie + */ + err = check_raw_mode(fn); + if (err) { +- verbose("kernel subsystem misconfigured func %s#%d\n", ++ verbose(env, "kernel subsystem misconfigured func %s#%d\n", + func_id_name(func_id), func_id); + return err; + } +@@ -1696,14 +1717,14 @@ static int check_call(struct bpf_verifie + + /* reset caller saved regs */ + for (i = 0; i < CALLER_SAVED_REGS; i++) { +- mark_reg_not_init(regs, caller_saved[i]); ++ mark_reg_not_init(env, regs, caller_saved[i]); + check_reg_arg(env, caller_saved[i], DST_OP_NO_MARK); + } + + /* update return register (already marked as written above) */ + if (fn->ret_type == RET_INTEGER) { + /* sets type to SCALAR_VALUE */ +- mark_reg_unknown(regs, BPF_REG_0); ++ mark_reg_unknown(env, regs, BPF_REG_0); + } else if (fn->ret_type == RET_VOID) { + regs[BPF_REG_0].type = NOT_INIT; + } else if (fn->ret_type == RET_PTR_TO_MAP_VALUE_OR_NULL) { +@@ -1711,14 +1732,15 @@ static int check_call(struct bpf_verifie + + regs[BPF_REG_0].type = PTR_TO_MAP_VALUE_OR_NULL; + /* There is no offset yet applied, variable or fixed */ +- mark_reg_known_zero(regs, BPF_REG_0); ++ mark_reg_known_zero(env, regs, BPF_REG_0); + regs[BPF_REG_0].off = 0; + /* remember map_ptr, so that check_map_access() + * can check 'value_size' boundary of memory access + * to map element returned from bpf_map_lookup_elem() + */ + if (meta.map_ptr == NULL) { +- verbose("kernel subsystem misconfigured verifier\n"); ++ verbose(env, ++ "kernel subsystem misconfigured verifier\n"); + return -EINVAL; + } + regs[BPF_REG_0].map_ptr = meta.map_ptr; +@@ -1729,12 +1751,12 @@ static int check_call(struct bpf_verifie + else if (insn_aux->map_ptr != meta.map_ptr) + insn_aux->map_ptr = BPF_MAP_PTR_POISON; + } else { +- verbose("unknown return type %d of func %s#%d\n", ++ verbose(env, "unknown return type %d of func %s#%d\n", + fn->ret_type, func_id_name(func_id), func_id); + return -EINVAL; + } + +- err = check_map_func_compatibility(meta.map_ptr, func_id); ++ err = check_map_func_compatibility(env, meta.map_ptr, func_id); + if (err) + return err; + +@@ -1793,39 +1815,42 @@ static int adjust_ptr_min_max_vals(struc + dst_reg = ®s[dst]; + + if (WARN_ON_ONCE(known && (smin_val != smax_val))) { +- print_verifier_state(&env->cur_state); +- verbose("verifier internal error: known but bad sbounds\n"); ++ print_verifier_state(env, &env->cur_state); ++ verbose(env, ++ "verifier internal error: known but bad sbounds\n"); + return -EINVAL; + } + if (WARN_ON_ONCE(known && (umin_val != umax_val))) { +- print_verifier_state(&env->cur_state); +- verbose("verifier internal error: known but bad ubounds\n"); ++ print_verifier_state(env, &env->cur_state); ++ verbose(env, ++ "verifier internal error: known but bad ubounds\n"); + return -EINVAL; + } + + if (BPF_CLASS(insn->code) != BPF_ALU64) { + /* 32-bit ALU ops on pointers produce (meaningless) scalars */ + if (!env->allow_ptr_leaks) +- verbose("R%d 32-bit pointer arithmetic prohibited\n", ++ verbose(env, ++ "R%d 32-bit pointer arithmetic prohibited\n", + dst); + return -EACCES; + } + + if (ptr_reg->type == PTR_TO_MAP_VALUE_OR_NULL) { + if (!env->allow_ptr_leaks) +- verbose("R%d pointer arithmetic on PTR_TO_MAP_VALUE_OR_NULL prohibited, null-check it first\n", ++ verbose(env, "R%d pointer arithmetic on PTR_TO_MAP_VALUE_OR_NULL prohibited, null-check it first\n", + dst); + return -EACCES; + } + if (ptr_reg->type == CONST_PTR_TO_MAP) { + if (!env->allow_ptr_leaks) +- verbose("R%d pointer arithmetic on CONST_PTR_TO_MAP prohibited\n", ++ verbose(env, "R%d pointer arithmetic on CONST_PTR_TO_MAP prohibited\n", + dst); + return -EACCES; + } + if (ptr_reg->type == PTR_TO_PACKET_END) { + if (!env->allow_ptr_leaks) +- verbose("R%d pointer arithmetic on PTR_TO_PACKET_END prohibited\n", ++ verbose(env, "R%d pointer arithmetic on PTR_TO_PACKET_END prohibited\n", + dst); + return -EACCES; + } +@@ -1890,7 +1915,7 @@ static int adjust_ptr_min_max_vals(struc + if (dst_reg == off_reg) { + /* scalar -= pointer. Creates an unknown scalar */ + if (!env->allow_ptr_leaks) +- verbose("R%d tried to subtract pointer from scalar\n", ++ verbose(env, "R%d tried to subtract pointer from scalar\n", + dst); + return -EACCES; + } +@@ -1900,7 +1925,7 @@ static int adjust_ptr_min_max_vals(struc + */ + if (ptr_reg->type == PTR_TO_STACK) { + if (!env->allow_ptr_leaks) +- verbose("R%d subtraction from stack pointer prohibited\n", ++ verbose(env, "R%d subtraction from stack pointer prohibited\n", + dst); + return -EACCES; + } +@@ -1955,13 +1980,13 @@ static int adjust_ptr_min_max_vals(struc + * ptr &= ~3 which would reduce min_value by 3.) + */ + if (!env->allow_ptr_leaks) +- verbose("R%d bitwise operator %s on pointer prohibited\n", ++ verbose(env, "R%d bitwise operator %s on pointer prohibited\n", + dst, bpf_alu_string[opcode >> 4]); + return -EACCES; + default: + /* other operators (e.g. MUL,LSH) produce non-pointer results */ + if (!env->allow_ptr_leaks) +- verbose("R%d pointer arithmetic with %s operator prohibited\n", ++ verbose(env, "R%d pointer arithmetic with %s operator prohibited\n", + dst, bpf_alu_string[opcode >> 4]); + return -EACCES; + } +@@ -2127,7 +2152,7 @@ static int adjust_scalar_min_max_vals(st + /* Shifts greater than 63 are undefined. This includes + * shifts by a negative number. + */ +- mark_reg_unknown(regs, insn->dst_reg); ++ mark_reg_unknown(env, regs, insn->dst_reg); + break; + } + /* We lose all sign bit information (except what we can pick +@@ -2155,7 +2180,7 @@ static int adjust_scalar_min_max_vals(st + /* Shifts greater than 63 are undefined. This includes + * shifts by a negative number. + */ +- mark_reg_unknown(regs, insn->dst_reg); ++ mark_reg_unknown(env, regs, insn->dst_reg); + break; + } + /* BPF_RSH is an unsigned shift, so make the appropriate casts */ +@@ -2183,7 +2208,7 @@ static int adjust_scalar_min_max_vals(st + __update_reg_bounds(dst_reg); + break; + default: +- mark_reg_unknown(regs, insn->dst_reg); ++ mark_reg_unknown(env, regs, insn->dst_reg); + break; + } + +@@ -2215,12 +2240,12 @@ static int adjust_reg_min_max_vals(struc + * an arbitrary scalar. + */ + if (!env->allow_ptr_leaks) { +- verbose("R%d pointer %s pointer prohibited\n", ++ verbose(env, "R%d pointer %s pointer prohibited\n", + insn->dst_reg, + bpf_alu_string[opcode >> 4]); + return -EACCES; + } +- mark_reg_unknown(regs, insn->dst_reg); ++ mark_reg_unknown(env, regs, insn->dst_reg); + return 0; + } else { + /* scalar += pointer +@@ -2272,13 +2297,13 @@ static int adjust_reg_min_max_vals(struc + + /* Got here implies adding two SCALAR_VALUEs */ + if (WARN_ON_ONCE(ptr_reg)) { +- print_verifier_state(&env->cur_state); +- verbose("verifier internal error: unexpected ptr_reg\n"); ++ print_verifier_state(env, &env->cur_state); ++ verbose(env, "verifier internal error: unexpected ptr_reg\n"); + return -EINVAL; + } + if (WARN_ON(!src_reg)) { +- print_verifier_state(&env->cur_state); +- verbose("verifier internal error: no src_reg\n"); ++ print_verifier_state(env, &env->cur_state); ++ verbose(env, "verifier internal error: no src_reg\n"); + return -EINVAL; + } + return adjust_scalar_min_max_vals(env, insn, dst_reg, *src_reg); +@@ -2296,14 +2321,14 @@ static int check_alu_op(struct bpf_verif + if (BPF_SRC(insn->code) != 0 || + insn->src_reg != BPF_REG_0 || + insn->off != 0 || insn->imm != 0) { +- verbose("BPF_NEG uses reserved fields\n"); ++ verbose(env, "BPF_NEG uses reserved fields\n"); + return -EINVAL; + } + } else { + if (insn->src_reg != BPF_REG_0 || insn->off != 0 || + (insn->imm != 16 && insn->imm != 32 && insn->imm != 64) || + BPF_CLASS(insn->code) == BPF_ALU64) { +- verbose("BPF_END uses reserved fields\n"); ++ verbose(env, "BPF_END uses reserved fields\n"); + return -EINVAL; + } + } +@@ -2314,7 +2339,7 @@ static int check_alu_op(struct bpf_verif + return err; + + if (is_pointer_value(env, insn->dst_reg)) { +- verbose("R%d pointer arithmetic prohibited\n", ++ verbose(env, "R%d pointer arithmetic prohibited\n", + insn->dst_reg); + return -EACCES; + } +@@ -2328,7 +2353,7 @@ static int check_alu_op(struct bpf_verif + + if (BPF_SRC(insn->code) == BPF_X) { + if (insn->imm != 0 || insn->off != 0) { +- verbose("BPF_MOV uses reserved fields\n"); ++ verbose(env, "BPF_MOV uses reserved fields\n"); + return -EINVAL; + } + +@@ -2338,7 +2363,7 @@ static int check_alu_op(struct bpf_verif + return err; + } else { + if (insn->src_reg != BPF_REG_0 || insn->off != 0) { +- verbose("BPF_MOV uses reserved fields\n"); ++ verbose(env, "BPF_MOV uses reserved fields\n"); + return -EINVAL; + } + } +@@ -2358,11 +2383,12 @@ static int check_alu_op(struct bpf_verif + } else { + /* R1 = (u32) R2 */ + if (is_pointer_value(env, insn->src_reg)) { +- verbose("R%d partial copy of pointer\n", ++ verbose(env, ++ "R%d partial copy of pointer\n", + insn->src_reg); + return -EACCES; + } +- mark_reg_unknown(regs, insn->dst_reg); ++ mark_reg_unknown(env, 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); +@@ -2377,14 +2403,14 @@ static int check_alu_op(struct bpf_verif + } + + } else if (opcode > BPF_END) { +- verbose("invalid BPF_ALU opcode %x\n", opcode); ++ verbose(env, "invalid BPF_ALU opcode %x\n", opcode); + return -EINVAL; + + } else { /* all other ALU ops: and, sub, xor, add, ... */ + + if (BPF_SRC(insn->code) == BPF_X) { + if (insn->imm != 0 || insn->off != 0) { +- verbose("BPF_ALU uses reserved fields\n"); ++ verbose(env, "BPF_ALU uses reserved fields\n"); + return -EINVAL; + } + /* check src1 operand */ +@@ -2393,7 +2419,7 @@ static int check_alu_op(struct bpf_verif + return err; + } else { + if (insn->src_reg != BPF_REG_0 || insn->off != 0) { +- verbose("BPF_ALU uses reserved fields\n"); ++ verbose(env, "BPF_ALU uses reserved fields\n"); + return -EINVAL; + } + } +@@ -2405,7 +2431,7 @@ static int check_alu_op(struct bpf_verif + + if ((opcode == BPF_MOD || opcode == BPF_DIV) && + BPF_SRC(insn->code) == BPF_K && insn->imm == 0) { +- verbose("div by zero\n"); ++ verbose(env, "div by zero\n"); + return -EINVAL; + } + +@@ -2414,7 +2440,7 @@ static int check_alu_op(struct bpf_verif + int size = BPF_CLASS(insn->code) == BPF_ALU64 ? 64 : 32; + + if (insn->imm < 0 || insn->imm >= size) { +- verbose("invalid shift %d\n", insn->imm); ++ verbose(env, "invalid shift %d\n", insn->imm); + return -EINVAL; + } + } +@@ -2775,13 +2801,13 @@ static int check_cond_jmp_op(struct bpf_ + int err; + + if (opcode > BPF_JSLE) { +- verbose("invalid BPF_JMP opcode %x\n", opcode); ++ verbose(env, "invalid BPF_JMP opcode %x\n", opcode); + return -EINVAL; + } + + if (BPF_SRC(insn->code) == BPF_X) { + if (insn->imm != 0) { +- verbose("BPF_JMP uses reserved fields\n"); ++ verbose(env, "BPF_JMP uses reserved fields\n"); + return -EINVAL; + } + +@@ -2791,13 +2817,13 @@ static int check_cond_jmp_op(struct bpf_ + return err; + + if (is_pointer_value(env, insn->src_reg)) { +- verbose("R%d pointer comparison prohibited\n", ++ verbose(env, "R%d pointer comparison prohibited\n", + insn->src_reg); + return -EACCES; + } + } else { + if (insn->src_reg != BPF_REG_0) { +- verbose("BPF_JMP uses reserved fields\n"); ++ verbose(env, "BPF_JMP uses reserved fields\n"); + return -EINVAL; + } + } +@@ -2913,11 +2939,12 @@ static int check_cond_jmp_op(struct bpf_ + /* pkt_end <= pkt_data' */ + find_good_pkt_pointers(this_branch, ®s[insn->src_reg], true); + } else if (is_pointer_value(env, insn->dst_reg)) { +- verbose("R%d pointer comparison prohibited\n", insn->dst_reg); ++ verbose(env, "R%d pointer comparison prohibited\n", ++ insn->dst_reg); + return -EACCES; + } +- if (verifier_log.level) +- print_verifier_state(this_branch); ++ if (env->log.level) ++ print_verifier_state(env, this_branch); + return 0; + } + +@@ -2936,11 +2963,11 @@ static int check_ld_imm(struct bpf_verif + int err; + + if (BPF_SIZE(insn->code) != BPF_DW) { +- verbose("invalid BPF_LD_IMM insn\n"); ++ verbose(env, "invalid BPF_LD_IMM insn\n"); + return -EINVAL; + } + if (insn->off != 0) { +- verbose("BPF_LD_IMM64 uses reserved fields\n"); ++ verbose(env, "BPF_LD_IMM64 uses reserved fields\n"); + return -EINVAL; + } + +@@ -2998,14 +3025,14 @@ static int check_ld_abs(struct bpf_verif + int i, err; + + if (!may_access_skb(env->prog->type)) { +- verbose("BPF_LD_[ABS|IND] instructions not allowed for this program type\n"); ++ verbose(env, "BPF_LD_[ABS|IND] instructions not allowed for this program type\n"); + return -EINVAL; + } + + if (insn->dst_reg != BPF_REG_0 || insn->off != 0 || + BPF_SIZE(insn->code) == BPF_DW || + (mode == BPF_ABS && insn->src_reg != BPF_REG_0)) { +- verbose("BPF_LD_[ABS|IND] uses reserved fields\n"); ++ verbose(env, "BPF_LD_[ABS|IND] uses reserved fields\n"); + return -EINVAL; + } + +@@ -3015,7 +3042,8 @@ static int check_ld_abs(struct bpf_verif + return err; + + if (regs[BPF_REG_6].type != PTR_TO_CTX) { +- verbose("at the time of BPF_LD_ABS|IND R6 != pointer to skb\n"); ++ verbose(env, ++ "at the time of BPF_LD_ABS|IND R6 != pointer to skb\n"); + return -EINVAL; + } + +@@ -3028,7 +3056,7 @@ static int check_ld_abs(struct bpf_verif + + /* reset caller saved regs to unreadable */ + for (i = 0; i < CALLER_SAVED_REGS; i++) { +- mark_reg_not_init(regs, caller_saved[i]); ++ mark_reg_not_init(env, regs, caller_saved[i]); + check_reg_arg(env, caller_saved[i], DST_OP_NO_MARK); + } + +@@ -3036,7 +3064,7 @@ static int check_ld_abs(struct bpf_verif + * the value fetched from the packet. + * Already marked as written above. + */ +- mark_reg_unknown(regs, BPF_REG_0); ++ mark_reg_unknown(env, regs, BPF_REG_0); + return 0; + } + +@@ -3100,7 +3128,7 @@ static int push_insn(int t, int w, int e + return 0; + + if (w < 0 || w >= env->prog->len) { +- verbose("jump out of range from insn %d to %d\n", t, w); ++ verbose(env, "jump out of range from insn %d to %d\n", t, w); + return -EINVAL; + } + +@@ -3117,13 +3145,13 @@ static int push_insn(int t, int w, int e + insn_stack[cur_stack++] = w; + return 1; + } else if ((insn_state[w] & 0xF0) == DISCOVERED) { +- verbose("back-edge from insn %d to %d\n", t, w); ++ verbose(env, "back-edge from insn %d to %d\n", t, w); + return -EINVAL; + } else if (insn_state[w] == EXPLORED) { + /* forward- or cross-edge */ + insn_state[t] = DISCOVERED | e; + } else { +- verbose("insn state internal bug\n"); ++ verbose(env, "insn state internal bug\n"); + return -EFAULT; + } + return 0; +@@ -3217,7 +3245,7 @@ peek_stack: + mark_explored: + insn_state[t] = EXPLORED; + if (cur_stack-- <= 0) { +- verbose("pop stack internal bug\n"); ++ verbose(env, "pop stack internal bug\n"); + ret = -EFAULT; + goto err_free; + } +@@ -3226,7 +3254,7 @@ mark_explored: + check_state: + for (i = 0; i < insn_cnt; i++) { + if (insn_state[i] != EXPLORED) { +- verbose("unreachable insn %d\n", i); ++ verbose(env, "unreachable insn %d\n", i); + ret = -EINVAL; + goto err_free; + } +@@ -3606,7 +3634,7 @@ static int do_check(struct bpf_verifier_ + int insn_processed = 0; + bool do_print_state = false; + +- init_reg_state(regs); ++ init_reg_state(env, regs); + state->parent = NULL; + insn_idx = 0; + for (;;) { +@@ -3615,7 +3643,7 @@ static int do_check(struct bpf_verifier_ + int err; + + if (insn_idx >= insn_cnt) { +- verbose("invalid insn idx %d insn_cnt %d\n", ++ verbose(env, "invalid insn idx %d insn_cnt %d\n", + insn_idx, insn_cnt); + return -EFAULT; + } +@@ -3624,7 +3652,8 @@ static int do_check(struct bpf_verifier_ + class = BPF_CLASS(insn->code); + + if (++insn_processed > BPF_COMPLEXITY_LIMIT_INSNS) { +- verbose("BPF program is too large. Processed %d insn\n", ++ verbose(env, ++ "BPF program is too large. Processed %d insn\n", + insn_processed); + return -E2BIG; + } +@@ -3634,12 +3663,12 @@ static int do_check(struct bpf_verifier_ + return err; + if (err == 1) { + /* found equivalent state, can prune the search */ +- if (verifier_log.level) { ++ if (env->log.level) { + if (do_print_state) +- verbose("\nfrom %d to %d: safe\n", ++ verbose(env, "\nfrom %d to %d: safe\n", + prev_insn_idx, insn_idx); + else +- verbose("%d: safe\n", insn_idx); ++ verbose(env, "%d: safe\n", insn_idx); + } + goto process_bpf_exit; + } +@@ -3647,19 +3676,18 @@ static int do_check(struct bpf_verifier_ + if (need_resched()) + cond_resched(); + +- if (verifier_log.level > 1 || +- (verifier_log.level && do_print_state)) { +- if (verifier_log.level > 1) +- verbose("%d:", insn_idx); ++ if (env->log.level > 1 || (env->log.level && do_print_state)) { ++ if (env->log.level > 1) ++ verbose(env, "%d:", insn_idx); + else +- verbose("\nfrom %d to %d:", ++ verbose(env, "\nfrom %d to %d:", + prev_insn_idx, insn_idx); +- print_verifier_state(&env->cur_state); ++ print_verifier_state(env, &env->cur_state); + do_print_state = false; + } + +- if (verifier_log.level) { +- verbose("%d: ", insn_idx); ++ if (env->log.level) { ++ verbose(env, "%d: ", insn_idx); + print_bpf_insn(env, insn); + } + +@@ -3716,7 +3744,7 @@ static int do_check(struct bpf_verifier_ + * src_reg == stack|map in some other branch. + * Reject it. + */ +- verbose("same insn cannot be used with different pointers\n"); ++ verbose(env, "same insn cannot be used with different pointers\n"); + return -EINVAL; + } + +@@ -3756,14 +3784,14 @@ static int do_check(struct bpf_verifier_ + } else if (dst_reg_type != *prev_dst_type && + (dst_reg_type == PTR_TO_CTX || + *prev_dst_type == PTR_TO_CTX)) { +- verbose("same insn cannot be used with different pointers\n"); ++ verbose(env, "same insn cannot be used with different pointers\n"); + return -EINVAL; + } + + } else if (class == BPF_ST) { + if (BPF_MODE(insn->code) != BPF_MEM || + insn->src_reg != BPF_REG_0) { +- verbose("BPF_ST uses reserved fields\n"); ++ verbose(env, "BPF_ST uses reserved fields\n"); + return -EINVAL; + } + /* check src operand */ +@@ -3786,7 +3814,7 @@ static int do_check(struct bpf_verifier_ + insn->off != 0 || + insn->src_reg != BPF_REG_0 || + insn->dst_reg != BPF_REG_0) { +- verbose("BPF_CALL uses reserved fields\n"); ++ verbose(env, "BPF_CALL uses reserved fields\n"); + return -EINVAL; + } + +@@ -3799,7 +3827,7 @@ static int do_check(struct bpf_verifier_ + insn->imm != 0 || + insn->src_reg != BPF_REG_0 || + insn->dst_reg != BPF_REG_0) { +- verbose("BPF_JA uses reserved fields\n"); ++ verbose(env, "BPF_JA uses reserved fields\n"); + return -EINVAL; + } + +@@ -3811,7 +3839,7 @@ static int do_check(struct bpf_verifier_ + insn->imm != 0 || + insn->src_reg != BPF_REG_0 || + insn->dst_reg != BPF_REG_0) { +- verbose("BPF_EXIT uses reserved fields\n"); ++ verbose(env, "BPF_EXIT uses reserved fields\n"); + return -EINVAL; + } + +@@ -3826,7 +3854,7 @@ static int do_check(struct bpf_verifier_ + return err; + + if (is_pointer_value(env, BPF_REG_0)) { +- verbose("R0 leaks addr as return value\n"); ++ verbose(env, "R0 leaks addr as return value\n"); + return -EACCES; + } + +@@ -3858,19 +3886,19 @@ process_bpf_exit: + + insn_idx++; + } else { +- verbose("invalid BPF_LD mode\n"); ++ verbose(env, "invalid BPF_LD mode\n"); + return -EINVAL; + } + } else { +- verbose("unknown insn class %d\n", class); ++ verbose(env, "unknown insn class %d\n", class); + return -EINVAL; + } + + insn_idx++; + } + +- verbose("processed %d insns, stack depth %d\n", +- insn_processed, env->prog->aux->stack_depth); ++ verbose(env, "processed %d insns, stack depth %d\n", insn_processed, ++ env->prog->aux->stack_depth); + return 0; + } + +@@ -3882,7 +3910,8 @@ static int check_map_prealloc(struct bpf + !(map->map_flags & BPF_F_NO_PREALLOC); + } + +-static int check_map_prog_compatibility(struct bpf_map *map, ++static int check_map_prog_compatibility(struct bpf_verifier_env *env, ++ struct bpf_map *map, + struct bpf_prog *prog) + + { +@@ -3893,12 +3922,12 @@ static int check_map_prog_compatibility( + */ + if (prog->type == BPF_PROG_TYPE_PERF_EVENT) { + if (!check_map_prealloc(map)) { +- verbose("perf_event programs can only use preallocated hash map\n"); ++ verbose(env, "perf_event programs can only use preallocated hash map\n"); + return -EINVAL; + } + if (map->inner_map_meta && + !check_map_prealloc(map->inner_map_meta)) { +- verbose("perf_event programs can only use preallocated inner hash map\n"); ++ verbose(env, "perf_event programs can only use preallocated inner hash map\n"); + return -EINVAL; + } + } +@@ -3921,14 +3950,14 @@ static int replace_map_fd_with_map_ptr(s + for (i = 0; i < insn_cnt; i++, insn++) { + if (BPF_CLASS(insn->code) == BPF_LDX && + (BPF_MODE(insn->code) != BPF_MEM || insn->imm != 0)) { +- verbose("BPF_LDX uses reserved fields\n"); ++ verbose(env, "BPF_LDX uses reserved fields\n"); + return -EINVAL; + } + + if (BPF_CLASS(insn->code) == BPF_STX && + ((BPF_MODE(insn->code) != BPF_MEM && + BPF_MODE(insn->code) != BPF_XADD) || insn->imm != 0)) { +- verbose("BPF_STX uses reserved fields\n"); ++ verbose(env, "BPF_STX uses reserved fields\n"); + return -EINVAL; + } + +@@ -3939,7 +3968,7 @@ static int replace_map_fd_with_map_ptr(s + if (i == insn_cnt - 1 || insn[1].code != 0 || + insn[1].dst_reg != 0 || insn[1].src_reg != 0 || + insn[1].off != 0) { +- verbose("invalid bpf_ld_imm64 insn\n"); ++ verbose(env, "invalid bpf_ld_imm64 insn\n"); + return -EINVAL; + } + +@@ -3948,19 +3977,20 @@ static int replace_map_fd_with_map_ptr(s + goto next_insn; + + if (insn->src_reg != BPF_PSEUDO_MAP_FD) { +- verbose("unrecognized bpf_ld_imm64 insn\n"); ++ verbose(env, ++ "unrecognized bpf_ld_imm64 insn\n"); + return -EINVAL; + } + + f = fdget(insn->imm); + map = __bpf_map_get(f); + if (IS_ERR(map)) { +- verbose("fd %d is not pointing to valid bpf_map\n", ++ verbose(env, "fd %d is not pointing to valid bpf_map\n", + insn->imm); + return PTR_ERR(map); + } + +- err = check_map_prog_compatibility(map, env->prog); ++ err = check_map_prog_compatibility(env, map, env->prog); + if (err) { + fdput(f); + return err; +@@ -4082,7 +4112,7 @@ static int convert_ctx_accesses(struct b + cnt = ops->gen_prologue(insn_buf, env->seen_direct_write, + env->prog); + if (cnt >= ARRAY_SIZE(insn_buf)) { +- verbose("bpf verifier is misconfigured\n"); ++ verbose(env, "bpf verifier is misconfigured\n"); + return -EINVAL; + } else if (cnt) { + new_prog = bpf_patch_insn_data(env, 0, insn_buf, cnt); +@@ -4130,7 +4160,7 @@ static int convert_ctx_accesses(struct b + u8 size_code; + + if (type == BPF_WRITE) { +- verbose("bpf verifier narrow ctx access misconfigured\n"); ++ verbose(env, "bpf verifier narrow ctx access misconfigured\n"); + return -EINVAL; + } + +@@ -4149,7 +4179,7 @@ static int convert_ctx_accesses(struct b + &target_size); + if (cnt == 0 || cnt >= ARRAY_SIZE(insn_buf) || + (ctx_field_size && !target_size)) { +- verbose("bpf verifier is misconfigured\n"); ++ verbose(env, "bpf verifier is misconfigured\n"); + return -EINVAL; + } + +@@ -4231,7 +4261,7 @@ static int fixup_bpf_calls(struct bpf_ve + + cnt = map_ptr->ops->map_gen_lookup(map_ptr, insn_buf); + if (cnt == 0 || cnt >= ARRAY_SIZE(insn_buf)) { +- verbose("bpf verifier is misconfigured\n"); ++ verbose(env, "bpf verifier is misconfigured\n"); + return -EINVAL; + } + +@@ -4275,7 +4305,8 @@ patch_call_imm: + * programs to call them, must be real in-kernel functions + */ + if (!fn->func) { +- verbose("kernel subsystem misconfigured func %s#%d\n", ++ verbose(env, ++ "kernel subsystem misconfigured func %s#%d\n", + func_id_name(insn->imm), insn->imm); + return -EFAULT; + } +@@ -4309,8 +4340,8 @@ static void free_states(struct bpf_verif + + int bpf_check(struct bpf_prog **prog, union bpf_attr *attr) + { +- struct bpf_verifer_log *log = &verifier_log; + struct bpf_verifier_env *env; ++ struct bpf_verifer_log *log; + int ret = -EINVAL; + + /* 'struct bpf_verifier_env' can be global, but since it's not small, +@@ -4319,6 +4350,7 @@ int bpf_check(struct bpf_prog **prog, un + env = kzalloc(sizeof(struct bpf_verifier_env), GFP_KERNEL); + if (!env) + return -ENOMEM; ++ log = &env->log; + + env->insn_aux_data = vzalloc(sizeof(struct bpf_insn_aux_data) * + (*prog)->len); +@@ -4337,7 +4369,6 @@ int bpf_check(struct bpf_prog **prog, un + log->level = attr->log_level; + log->ubuf = (char __user *) (unsigned long) attr->log_buf; + log->len_total = attr->log_size; +- log->len_used = 0; + + ret = -EINVAL; + /* log attributes have to be sane */ +@@ -4349,8 +4380,6 @@ int bpf_check(struct bpf_prog **prog, un + log->kbuf = vmalloc(log->len_total); + if (!log->kbuf) + goto err_unlock; +- } else { +- log->level = 0; + } + + env->strict_alignment = !!(attr->prog_flags & BPF_F_STRICT_ALIGNMENT); +@@ -4461,8 +4490,6 @@ int bpf_analyzer(struct bpf_prog *prog, + /* grab the mutex to protect few globals used by verifier */ + mutex_lock(&bpf_verifier_lock); + +- verifier_log.level = 0; +- + env->strict_alignment = false; + if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)) + env->strict_alignment = true; diff --git a/debian/patches/bugfix/all/bpf-verifier-fix-bounds-calculation-on-bpf_rsh.patch b/debian/patches/bugfix/all/bpf-verifier-fix-bounds-calculation-on-bpf_rsh.patch new file mode 100644 index 000000000..990d196a2 --- /dev/null +++ b/debian/patches/bugfix/all/bpf-verifier-fix-bounds-calculation-on-bpf_rsh.patch @@ -0,0 +1,61 @@ +From: Edward Cree +Date: Mon, 18 Dec 2017 20:11:53 -0800 +Subject: [1/9] bpf/verifier: fix bounds calculation on BPF_RSH +Origin: https://git.kernel.org/linus/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 +Signed-off-by: Edward Cree +Acked-by: Alexei Starovoitov +[jannh@google.com: changed description to reflect bug impact] +Signed-off-by: Jann Horn +Signed-off-by: Alexei Starovoitov +Signed-off-by: Daniel Borkmann +--- + kernel/bpf/verifier.c | 30 ++++++++++++++++-------------- + 1 file changed, 16 insertions(+), 14 deletions(-) + +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -2183,20 +2183,22 @@ static int adjust_scalar_min_max_vals(st + mark_reg_unknown(env, 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/debian/patches/series b/debian/patches/series index 2becbc1bb..81b6e057e 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -127,6 +127,17 @@ bugfix/all/media-dvb-usb-v2-lmedm04-move-ts2020-attach-to-dm04_.patch bugfix/all/media-hdpvr-fix-an-error-handling-path-in-hdpvr_prob.patch bugfix/all/kvm-fix-stack-out-of-bounds-read-in-write_mmio.patch bugfix/all/bluetooth-prevent-stack-info-leak-from-the-efs-element.patch +bugfix/all/bpf-encapsulate-verifier-log-state-into-a-structure.patch +bugfix/all/bpf-move-global-verifier-log-into-verifier-environme.patch +bugfix/all/bpf-fix-branch-pruning-logic.patch +bugfix/all/bpf-verifier-fix-bounds-calculation-on-bpf_rsh.patch +bugfix/all/bpf-fix-incorrect-sign-extension-in-check_alu_op.patch +bugfix/all/bpf-fix-incorrect-tracking-of-register-size-truncati.patch +bugfix/all/bpf-fix-32-bit-alu-op-verification.patch +bugfix/all/bpf-fix-missing-error-return-in-check_stack_boundary.patch +bugfix/all/bpf-force-strict-alignment-checks-for-stack-pointers.patch +bugfix/all/bpf-don-t-prune-branches-when-a-scalar-is-replaced-w.patch +bugfix/all/bpf-fix-integer-overflows.patch # Fix exported symbol versions bugfix/all/module-disable-matching-missing-version-crc.patch