From 0bee3835ba86886fdf86d592d064236ecc4f25c9 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 4 May 2021 13:33:29 +0200 Subject: [PATCH] 5.10-stable patches added patches: bpf-fix-leakage-of-uninitialized-bpf-stack-under-speculation.patch bpf-fix-masking-negation-logic-upon-negative-dst-register.patch --- ...tialized-bpf-stack-under-speculation.patch | 133 ++++++++++++++++++ ...ion-logic-upon-negative-dst-register.patch | 50 +++++++ queue-5.10/series | 2 + 3 files changed, 185 insertions(+) create mode 100644 queue-5.10/bpf-fix-leakage-of-uninitialized-bpf-stack-under-speculation.patch create mode 100644 queue-5.10/bpf-fix-masking-negation-logic-upon-negative-dst-register.patch diff --git a/queue-5.10/bpf-fix-leakage-of-uninitialized-bpf-stack-under-speculation.patch b/queue-5.10/bpf-fix-leakage-of-uninitialized-bpf-stack-under-speculation.patch new file mode 100644 index 00000000000..f951087e4fb --- /dev/null +++ b/queue-5.10/bpf-fix-leakage-of-uninitialized-bpf-stack-under-speculation.patch @@ -0,0 +1,133 @@ +From 801c6058d14a82179a7ee17a4b532cac6fad067f Mon Sep 17 00:00:00 2001 +From: Daniel Borkmann +Date: Thu, 29 Apr 2021 15:19:37 +0000 +Subject: bpf: Fix leakage of uninitialized bpf stack under speculation + +From: Daniel Borkmann + +commit 801c6058d14a82179a7ee17a4b532cac6fad067f upstream. + +The current implemented mechanisms to mitigate data disclosure under +speculation mainly address stack and map value oob access from the +speculative domain. However, Piotr discovered that uninitialized BPF +stack is not protected yet, and thus old data from the kernel stack, +potentially including addresses of kernel structures, could still be +extracted from that 512 bytes large window. The BPF stack is special +compared to map values since it's not zero initialized for every +program invocation, whereas map values /are/ zero initialized upon +their initial allocation and thus cannot leak any prior data in either +domain. In the non-speculative domain, the verifier ensures that every +stack slot read must have a prior stack slot write by the BPF program +to avoid such data leaking issue. + +However, this is not enough: for example, when the pointer arithmetic +operation moves the stack pointer from the last valid stack offset to +the first valid offset, the sanitation logic allows for any intermediate +offsets during speculative execution, which could then be used to +extract any restricted stack content via side-channel. + +Given for unprivileged stack pointer arithmetic the use of unknown +but bounded scalars is generally forbidden, we can simply turn the +register-based arithmetic operation into an immediate-based arithmetic +operation without the need for masking. This also gives the benefit +of reducing the needed instructions for the operation. Given after +the work in 7fedb63a8307 ("bpf: Tighten speculative pointer arithmetic +mask"), the aux->alu_limit already holds the final immediate value for +the offset register with the known scalar. Thus, a simple mov of the +immediate to AX register with using AX as the source for the original +instruction is sufficient and possible now in this case. + +Reported-by: Piotr Krysiuk +Signed-off-by: Daniel Borkmann +Tested-by: Piotr Krysiuk +Reviewed-by: Piotr Krysiuk +Reviewed-by: John Fastabend +Acked-by: Alexei Starovoitov +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/bpf_verifier.h | 5 +++-- + kernel/bpf/verifier.c | 27 +++++++++++++++++---------- + 2 files changed, 20 insertions(+), 12 deletions(-) + +--- a/include/linux/bpf_verifier.h ++++ b/include/linux/bpf_verifier.h +@@ -291,10 +291,11 @@ struct bpf_verifier_state_list { + }; + + /* Possible states for alu_state member. */ +-#define BPF_ALU_SANITIZE_SRC 1U +-#define BPF_ALU_SANITIZE_DST 2U ++#define BPF_ALU_SANITIZE_SRC (1U << 0) ++#define BPF_ALU_SANITIZE_DST (1U << 1) + #define BPF_ALU_NEG_VALUE (1U << 2) + #define BPF_ALU_NON_POINTER (1U << 3) ++#define BPF_ALU_IMMEDIATE (1U << 4) + #define BPF_ALU_SANITIZE (BPF_ALU_SANITIZE_SRC | \ + BPF_ALU_SANITIZE_DST) + +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -5755,6 +5755,7 @@ static int sanitize_ptr_alu(struct bpf_v + { + struct bpf_insn_aux_data *aux = commit_window ? cur_aux(env) : tmp_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; + bool ptr_is_dst_reg = ptr_reg == dst_reg; + u8 opcode = BPF_OP(insn->code); +@@ -5785,6 +5786,7 @@ static int sanitize_ptr_alu(struct bpf_v + alu_limit = abs(tmp_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; + alu_state |= ptr_is_dst_reg ? + BPF_ALU_SANITIZE_SRC : BPF_ALU_SANITIZE_DST; + } +@@ -11383,7 +11385,7 @@ static int fixup_bpf_calls(struct bpf_ve + const u8 code_sub = BPF_ALU64 | BPF_SUB | BPF_X; + struct bpf_insn insn_buf[16]; + struct bpf_insn *patch = &insn_buf[0]; +- bool issrc, isneg; ++ bool issrc, isneg, isimm; + u32 off_reg; + + aux = &env->insn_aux_data[i + delta]; +@@ -11394,16 +11396,21 @@ static int fixup_bpf_calls(struct bpf_ve + isneg = aux->alu_state & BPF_ALU_NEG_VALUE; + issrc = (aux->alu_state & BPF_ALU_SANITIZE) == + BPF_ALU_SANITIZE_SRC; ++ isimm = aux->alu_state & BPF_ALU_IMMEDIATE; + + off_reg = issrc ? insn->src_reg : insn->dst_reg; +- if (isneg) +- *patch++ = BPF_ALU64_IMM(BPF_MUL, off_reg, -1); +- *patch++ = BPF_MOV32_IMM(BPF_REG_AX, aux->alu_limit); +- *patch++ = BPF_ALU64_REG(BPF_SUB, BPF_REG_AX, off_reg); +- *patch++ = BPF_ALU64_REG(BPF_OR, BPF_REG_AX, off_reg); +- *patch++ = BPF_ALU64_IMM(BPF_NEG, BPF_REG_AX, 0); +- *patch++ = BPF_ALU64_IMM(BPF_ARSH, BPF_REG_AX, 63); +- *patch++ = BPF_ALU64_REG(BPF_AND, BPF_REG_AX, off_reg); ++ if (isimm) { ++ *patch++ = BPF_MOV32_IMM(BPF_REG_AX, aux->alu_limit); ++ } else { ++ if (isneg) ++ *patch++ = BPF_ALU64_IMM(BPF_MUL, off_reg, -1); ++ *patch++ = BPF_MOV32_IMM(BPF_REG_AX, aux->alu_limit); ++ *patch++ = BPF_ALU64_REG(BPF_SUB, BPF_REG_AX, off_reg); ++ *patch++ = BPF_ALU64_REG(BPF_OR, BPF_REG_AX, off_reg); ++ *patch++ = BPF_ALU64_IMM(BPF_NEG, BPF_REG_AX, 0); ++ *patch++ = BPF_ALU64_IMM(BPF_ARSH, BPF_REG_AX, 63); ++ *patch++ = BPF_ALU64_REG(BPF_AND, BPF_REG_AX, off_reg); ++ } + if (!issrc) + *patch++ = BPF_MOV64_REG(insn->dst_reg, insn->src_reg); + insn->src_reg = BPF_REG_AX; +@@ -11411,7 +11418,7 @@ static int fixup_bpf_calls(struct bpf_ve + insn->code = insn->code == code_add ? + code_sub : code_add; + *patch++ = *insn; +- if (issrc && isneg) ++ if (issrc && isneg && !isimm) + *patch++ = BPF_ALU64_IMM(BPF_MUL, off_reg, -1); + cnt = patch - insn_buf; + diff --git a/queue-5.10/bpf-fix-masking-negation-logic-upon-negative-dst-register.patch b/queue-5.10/bpf-fix-masking-negation-logic-upon-negative-dst-register.patch new file mode 100644 index 00000000000..a8964d6623f --- /dev/null +++ b/queue-5.10/bpf-fix-masking-negation-logic-upon-negative-dst-register.patch @@ -0,0 +1,50 @@ +From b9b34ddbe2076ade359cd5ce7537d5ed019e9807 Mon Sep 17 00:00:00 2001 +From: Daniel Borkmann +Date: Fri, 30 Apr 2021 16:21:46 +0200 +Subject: bpf: Fix masking negation logic upon negative dst register + +From: Daniel Borkmann + +commit b9b34ddbe2076ade359cd5ce7537d5ed019e9807 upstream. + +The negation logic for the case where the off_reg is sitting in the +dst register is not correct given then we cannot just invert the add +to a sub or vice versa. As a fix, perform the final bitwise and-op +unconditionally into AX from the off_reg, then move the pointer from +the src to dst and finally use AX as the source for the original +pointer arithmetic operation such that the inversion yields a correct +result. The single non-AX mov in between is possible given constant +blinding is retaining it as it's not an immediate based operation. + +Fixes: 979d63d50c0c ("bpf: prevent out of bounds speculation on pointer arithmetic") +Signed-off-by: Daniel Borkmann +Tested-by: Piotr Krysiuk +Reviewed-by: Piotr Krysiuk +Reviewed-by: John Fastabend +Acked-by: Alexei Starovoitov +Signed-off-by: Greg Kroah-Hartman +--- + kernel/bpf/verifier.c | 12 ++++-------- + 1 file changed, 4 insertions(+), 8 deletions(-) + +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -11403,14 +11403,10 @@ static int fixup_bpf_calls(struct bpf_ve + *patch++ = BPF_ALU64_REG(BPF_OR, BPF_REG_AX, off_reg); + *patch++ = BPF_ALU64_IMM(BPF_NEG, BPF_REG_AX, 0); + *patch++ = BPF_ALU64_IMM(BPF_ARSH, BPF_REG_AX, 63); +- if (issrc) { +- *patch++ = BPF_ALU64_REG(BPF_AND, BPF_REG_AX, +- off_reg); +- insn->src_reg = BPF_REG_AX; +- } else { +- *patch++ = BPF_ALU64_REG(BPF_AND, off_reg, +- BPF_REG_AX); +- } ++ *patch++ = BPF_ALU64_REG(BPF_AND, BPF_REG_AX, off_reg); ++ if (!issrc) ++ *patch++ = BPF_MOV64_REG(insn->dst_reg, insn->src_reg); ++ insn->src_reg = BPF_REG_AX; + if (isneg) + insn->code = insn->code == code_add ? + code_sub : code_add; diff --git a/queue-5.10/series b/queue-5.10/series index 13577efac27..3bdeee1cb56 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -2,3 +2,5 @@ mips-do-not-include-hi-and-lo-in-clobber-list-for-r6.patch netfilter-conntrack-make-global-sysctls-readonly-in-non-init-netns.patch net-usb-ax88179_178a-initialize-local-variables-before-use.patch igb-enable-rss-for-intel-i211-ethernet-controller.patch +bpf-fix-masking-negation-logic-upon-negative-dst-register.patch +bpf-fix-leakage-of-uninitialized-bpf-stack-under-speculation.patch -- 2.47.3