From: Greg Kroah-Hartman Date: Wed, 26 May 2021 15:16:30 +0000 (+0200) Subject: 5.12-stable patches X-Git-Tag: v5.4.123~20 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a64986010744121abff3068ee6819feaae17e6ff;p=thirdparty%2Fkernel%2Fstable-queue.git 5.12-stable patches added patches: bpf-fix-mask-direction-swap-upon-off-reg-sign-change.patch bpf-no-need-to-simulate-speculative-domain-for-immediates.patch bpf-wrap-aux-data-inside-bpf_sanitize_info-container.patch --- diff --git a/queue-5.12/bpf-fix-mask-direction-swap-upon-off-reg-sign-change.patch b/queue-5.12/bpf-fix-mask-direction-swap-upon-off-reg-sign-change.patch new file mode 100644 index 00000000000..9fe86b5d887 --- /dev/null +++ b/queue-5.12/bpf-fix-mask-direction-swap-upon-off-reg-sign-change.patch @@ -0,0 +1,74 @@ +From bb01a1bba579b4b1c5566af24d95f1767859771e Mon Sep 17 00:00:00 2001 +From: Daniel Borkmann +Date: Fri, 21 May 2021 10:19:22 +0000 +Subject: bpf: Fix mask direction swap upon off reg sign change + +From: Daniel Borkmann + +commit bb01a1bba579b4b1c5566af24d95f1767859771e upstream. + +Masking direction as indicated via mask_to_left is considered to be +calculated once and then used to derive pointer limits. Thus, this +needs to be placed into bpf_sanitize_info instead so we can pass it +to sanitize_ptr_alu() call after the pointer move. Piotr noticed a +corner case where the off reg causes masking direction change which +then results in an incorrect final aux->alu_limit. + +Fixes: 7fedb63a8307 ("bpf: Tighten speculative pointer arithmetic mask") +Reported-by: Piotr Krysiuk +Signed-off-by: Daniel Borkmann +Reviewed-by: Piotr Krysiuk +Acked-by: Alexei Starovoitov +Signed-off-by: Greg Kroah-Hartman +--- + kernel/bpf/verifier.c | 22 ++++++++++++---------- + 1 file changed, 12 insertions(+), 10 deletions(-) + +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -5863,18 +5863,10 @@ enum { + }; + + static int retrieve_ptr_limit(const struct bpf_reg_state *ptr_reg, +- const struct bpf_reg_state *off_reg, +- u32 *alu_limit, u8 opcode) ++ u32 *alu_limit, bool mask_to_left) + { +- bool off_is_neg = off_reg->smin_value < 0; +- bool mask_to_left = (opcode == BPF_ADD && off_is_neg) || +- (opcode == BPF_SUB && !off_is_neg); + u32 max = 0, ptr_limit = 0; + +- if (!tnum_is_const(off_reg->var_off) && +- (off_reg->smin_value < 0) != (off_reg->smax_value < 0)) +- return REASON_BOUNDS; +- + switch (ptr_reg->type) { + case PTR_TO_STACK: + /* Offset 0 is out-of-bounds, but acceptable start for the +@@ -5942,6 +5934,7 @@ static bool sanitize_needed(u8 opcode) + + struct bpf_sanitize_info { + struct bpf_insn_aux_data aux; ++ bool mask_to_left; + }; + + static int sanitize_ptr_alu(struct bpf_verifier_env *env, +@@ -5973,7 +5966,16 @@ static int sanitize_ptr_alu(struct bpf_v + if (vstate->speculative) + goto do_sim; + +- err = retrieve_ptr_limit(ptr_reg, off_reg, &alu_limit, opcode); ++ if (!commit_window) { ++ if (!tnum_is_const(off_reg->var_off) && ++ (off_reg->smin_value < 0) != (off_reg->smax_value < 0)) ++ return REASON_BOUNDS; ++ ++ info->mask_to_left = (opcode == BPF_ADD && off_is_neg) || ++ (opcode == BPF_SUB && !off_is_neg); ++ } ++ ++ err = retrieve_ptr_limit(ptr_reg, &alu_limit, info->mask_to_left); + if (err < 0) + return err; + diff --git a/queue-5.12/bpf-no-need-to-simulate-speculative-domain-for-immediates.patch b/queue-5.12/bpf-no-need-to-simulate-speculative-domain-for-immediates.patch new file mode 100644 index 00000000000..ba3a6ecf8ac --- /dev/null +++ b/queue-5.12/bpf-no-need-to-simulate-speculative-domain-for-immediates.patch @@ -0,0 +1,44 @@ +From a7036191277f9fa68d92f2071ddc38c09b1e5ee5 Mon Sep 17 00:00:00 2001 +From: Daniel Borkmann +Date: Tue, 4 May 2021 08:58:25 +0000 +Subject: bpf: No need to simulate speculative domain for immediates + +From: Daniel Borkmann + +commit a7036191277f9fa68d92f2071ddc38c09b1e5ee5 upstream. + +In 801c6058d14a ("bpf: Fix leakage of uninitialized bpf stack under +speculation") we replaced masking logic with direct loads of immediates +if the register is a known constant. Given in this case we do not apply +any masking, there is also no reason for the operation to be truncated +under the speculative domain. + +Therefore, there is also zero reason for the verifier to branch-off and +simulate this case, it only needs to do it for unknown but bounded scalars. +As a side-effect, this also enables few test cases that were previously +rejected due to simulation under zero truncation. + +Signed-off-by: Daniel Borkmann +Reviewed-by: Piotr Krysiuk +Acked-by: Alexei Starovoitov +Signed-off-by: Greg Kroah-Hartman +--- + kernel/bpf/verifier.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -5999,8 +5999,12 @@ do_sim: + /* If we're in commit phase, we're done here given we already + * pushed the truncated dst_reg into the speculative verification + * stack. ++ * ++ * Also, when register is a known constant, we rewrite register-based ++ * operation to immediate-based, and thus do not need masking (and as ++ * a consequence, do not need to simulate the zero-truncation either). + */ +- if (commit_window) ++ if (commit_window || off_is_imm) + return 0; + + /* Simulate and find potential out-of-bounds access under diff --git a/queue-5.12/bpf-wrap-aux-data-inside-bpf_sanitize_info-container.patch b/queue-5.12/bpf-wrap-aux-data-inside-bpf_sanitize_info-container.patch new file mode 100644 index 00000000000..e4a444bef99 --- /dev/null +++ b/queue-5.12/bpf-wrap-aux-data-inside-bpf_sanitize_info-container.patch @@ -0,0 +1,84 @@ +From 3d0220f6861d713213b015b582e9f21e5b28d2e0 Mon Sep 17 00:00:00 2001 +From: Daniel Borkmann +Date: Fri, 21 May 2021 10:17:36 +0000 +Subject: bpf: Wrap aux data inside bpf_sanitize_info container + +From: Daniel Borkmann + +commit 3d0220f6861d713213b015b582e9f21e5b28d2e0 upstream. + +Add a container structure struct bpf_sanitize_info which holds +the current aux info, and update call-sites to sanitize_ptr_alu() +to pass it in. This is needed for passing in additional state +later on. + +Signed-off-by: Daniel Borkmann +Reviewed-by: Piotr Krysiuk +Acked-by: Alexei Starovoitov +Signed-off-by: Greg Kroah-Hartman +--- + kernel/bpf/verifier.c | 18 +++++++++++------- + 1 file changed, 11 insertions(+), 7 deletions(-) + +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -5940,15 +5940,19 @@ static bool sanitize_needed(u8 opcode) + return opcode == BPF_ADD || opcode == BPF_SUB; + } + ++struct bpf_sanitize_info { ++ struct bpf_insn_aux_data aux; ++}; ++ + static int sanitize_ptr_alu(struct bpf_verifier_env *env, + struct bpf_insn *insn, + const struct bpf_reg_state *ptr_reg, + const struct bpf_reg_state *off_reg, + struct bpf_reg_state *dst_reg, +- struct bpf_insn_aux_data *tmp_aux, ++ struct bpf_sanitize_info *info, + const bool commit_window) + { +- struct bpf_insn_aux_data *aux = commit_window ? cur_aux(env) : tmp_aux; ++ struct bpf_insn_aux_data *aux = commit_window ? cur_aux(env) : &info->aux; + struct bpf_verifier_state *vstate = env->cur_state; + bool off_is_imm = tnum_is_const(off_reg->var_off); + bool off_is_neg = off_reg->smin_value < 0; +@@ -5977,8 +5981,8 @@ static int sanitize_ptr_alu(struct bpf_v + /* In commit phase we narrow the masking window based on + * the observed pointer move after the simulated operation. + */ +- alu_state = tmp_aux->alu_state; +- alu_limit = abs(tmp_aux->alu_limit - alu_limit); ++ alu_state = info->aux.alu_state; ++ alu_limit = abs(info->aux.alu_limit - alu_limit); + } else { + alu_state = off_is_neg ? BPF_ALU_NEG_VALUE : 0; + alu_state |= off_is_imm ? BPF_ALU_IMMEDIATE : 0; +@@ -6139,7 +6143,7 @@ static int adjust_ptr_min_max_vals(struc + smin_ptr = ptr_reg->smin_value, smax_ptr = ptr_reg->smax_value; + u64 umin_val = off_reg->umin_value, umax_val = off_reg->umax_value, + umin_ptr = ptr_reg->umin_value, umax_ptr = ptr_reg->umax_value; +- struct bpf_insn_aux_data tmp_aux = {}; ++ struct bpf_sanitize_info info = {}; + u8 opcode = BPF_OP(insn->code); + u32 dst = insn->dst_reg; + int ret; +@@ -6208,7 +6212,7 @@ static int adjust_ptr_min_max_vals(struc + + if (sanitize_needed(opcode)) { + ret = sanitize_ptr_alu(env, insn, ptr_reg, off_reg, dst_reg, +- &tmp_aux, false); ++ &info, false); + if (ret < 0) + return sanitize_err(env, insn, ret, off_reg, dst_reg); + } +@@ -6349,7 +6353,7 @@ static int adjust_ptr_min_max_vals(struc + return -EACCES; + if (sanitize_needed(opcode)) { + ret = sanitize_ptr_alu(env, insn, dst_reg, off_reg, dst_reg, +- &tmp_aux, true); ++ &info, true); + if (ret < 0) + return sanitize_err(env, insn, ret, off_reg, dst_reg); + }