From: Greg Kroah-Hartman Date: Mon, 13 Sep 2021 09:18:41 +0000 (+0200) Subject: 5.4-stable patches X-Git-Tag: v5.4.146~33 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0c72fbd6cc88bb1fd26d9b4d06a69ce0562d51e1;p=thirdparty%2Fkernel%2Fstable-queue.git 5.4-stable patches added patches: bpf-fix-leakage-due-to-insufficient-speculative-store-bypass-mitigation.patch bpf-fix-pointer-arithmetic-mask-tightening-under-state-pruning.patch bpf-introduce-bpf-nospec-instruction-for-mitigating-spectre-v4.patch bpf-verifier-allocate-idmap-scratch-in-verifier-env.patch --- diff --git a/queue-5.4/bpf-fix-leakage-due-to-insufficient-speculative-store-bypass-mitigation.patch b/queue-5.4/bpf-fix-leakage-due-to-insufficient-speculative-store-bypass-mitigation.patch new file mode 100644 index 00000000000..efac68df1a5 --- /dev/null +++ b/queue-5.4/bpf-fix-leakage-due-to-insufficient-speculative-store-bypass-mitigation.patch @@ -0,0 +1,451 @@ +From foo@baz Mon Sep 13 10:58:36 AM CEST 2021 +From: Ovidiu Panait +Date: Tue, 7 Sep 2021 16:16:59 +0300 +Subject: bpf: Fix leakage due to insufficient speculative store bypass mitigation +To: stable@vger.kernel.org +Cc: bpf@vger.kernel.org, daniel@iogearbox.net +Message-ID: <20210907131701.1910024-3-ovidiu.panait@windriver.com> + +From: Daniel Borkmann + +commit 2039f26f3aca5b0e419b98f65dd36481337b86ee upstream. + +Spectre v4 gadgets make use of memory disambiguation, which is a set of +techniques that execute memory access instructions, that is, loads and +stores, out of program order; Intel's optimization manual, section 2.4.4.5: + + A load instruction micro-op may depend on a preceding store. Many + microarchitectures block loads until all preceding store addresses are + known. The memory disambiguator predicts which loads will not depend on + any previous stores. When the disambiguator predicts that a load does + not have such a dependency, the load takes its data from the L1 data + cache. Eventually, the prediction is verified. If an actual conflict is + detected, the load and all succeeding instructions are re-executed. + +af86ca4e3088 ("bpf: Prevent memory disambiguation attack") tried to mitigate +this attack by sanitizing the memory locations through preemptive "fast" +(low latency) stores of zero prior to the actual "slow" (high latency) store +of a pointer value such that upon dependency misprediction the CPU then +speculatively executes the load of the pointer value and retrieves the zero +value instead of the attacker controlled scalar value previously stored at +that location, meaning, subsequent access in the speculative domain is then +redirected to the "zero page". + +The sanitized preemptive store of zero prior to the actual "slow" store is +done through a simple ST instruction based on r10 (frame pointer) with +relative offset to the stack location that the verifier has been tracking +on the original used register for STX, which does not have to be r10. Thus, +there are no memory dependencies for this store, since it's only using r10 +and immediate constant of zero; hence af86ca4e3088 /assumed/ a low latency +operation. + +However, a recent attack demonstrated that this mitigation is not sufficient +since the preemptive store of zero could also be turned into a "slow" store +and is thus bypassed as well: + + [...] + // r2 = oob address (e.g. scalar) + // r7 = pointer to map value + 31: (7b) *(u64 *)(r10 -16) = r2 + // r9 will remain "fast" register, r10 will become "slow" register below + 32: (bf) r9 = r10 + // JIT maps BPF reg to x86 reg: + // r9 -> r15 (callee saved) + // r10 -> rbp + // train store forward prediction to break dependency link between both r9 + // and r10 by evicting them from the predictor's LRU table. + 33: (61) r0 = *(u32 *)(r7 +24576) + 34: (63) *(u32 *)(r7 +29696) = r0 + 35: (61) r0 = *(u32 *)(r7 +24580) + 36: (63) *(u32 *)(r7 +29700) = r0 + 37: (61) r0 = *(u32 *)(r7 +24584) + 38: (63) *(u32 *)(r7 +29704) = r0 + 39: (61) r0 = *(u32 *)(r7 +24588) + 40: (63) *(u32 *)(r7 +29708) = r0 + [...] + 543: (61) r0 = *(u32 *)(r7 +25596) + 544: (63) *(u32 *)(r7 +30716) = r0 + // prepare call to bpf_ringbuf_output() helper. the latter will cause rbp + // to spill to stack memory while r13/r14/r15 (all callee saved regs) remain + // in hardware registers. rbp becomes slow due to push/pop latency. below is + // disasm of bpf_ringbuf_output() helper for better visual context: + // + // ffffffff8117ee20: 41 54 push r12 + // ffffffff8117ee22: 55 push rbp + // ffffffff8117ee23: 53 push rbx + // ffffffff8117ee24: 48 f7 c1 fc ff ff ff test rcx,0xfffffffffffffffc + // ffffffff8117ee2b: 0f 85 af 00 00 00 jne ffffffff8117eee0 <-- jump taken + // [...] + // ffffffff8117eee0: 49 c7 c4 ea ff ff ff mov r12,0xffffffffffffffea + // ffffffff8117eee7: 5b pop rbx + // ffffffff8117eee8: 5d pop rbp + // ffffffff8117eee9: 4c 89 e0 mov rax,r12 + // ffffffff8117eeec: 41 5c pop r12 + // ffffffff8117eeee: c3 ret + 545: (18) r1 = map[id:4] + 547: (bf) r2 = r7 + 548: (b7) r3 = 0 + 549: (b7) r4 = 4 + 550: (85) call bpf_ringbuf_output#194288 + // instruction 551 inserted by verifier \ + 551: (7a) *(u64 *)(r10 -16) = 0 | /both/ are now slow stores here + // storing map value pointer r7 at fp-16 | since value of r10 is "slow". + 552: (7b) *(u64 *)(r10 -16) = r7 / + // following "fast" read to the same memory location, but due to dependency + // misprediction it will speculatively execute before insn 551/552 completes. + 553: (79) r2 = *(u64 *)(r9 -16) + // in speculative domain contains attacker controlled r2. in non-speculative + // domain this contains r7, and thus accesses r7 +0 below. + 554: (71) r3 = *(u8 *)(r2 +0) + // leak r3 + +As can be seen, the current speculative store bypass mitigation which the +verifier inserts at line 551 is insufficient since /both/, the write of +the zero sanitation as well as the map value pointer are a high latency +instruction due to prior memory access via push/pop of r10 (rbp) in contrast +to the low latency read in line 553 as r9 (r15) which stays in hardware +registers. Thus, architecturally, fp-16 is r7, however, microarchitecturally, +fp-16 can still be r2. + +Initial thoughts to address this issue was to track spilled pointer loads +from stack and enforce their load via LDX through r10 as well so that /both/ +the preemptive store of zero /as well as/ the load use the /same/ register +such that a dependency is created between the store and load. However, this +option is not sufficient either since it can be bypassed as well under +speculation. An updated attack with pointer spill/fills now _all_ based on +r10 would look as follows: + + [...] + // r2 = oob address (e.g. scalar) + // r7 = pointer to map value + [...] + // longer store forward prediction training sequence than before. + 2062: (61) r0 = *(u32 *)(r7 +25588) + 2063: (63) *(u32 *)(r7 +30708) = r0 + 2064: (61) r0 = *(u32 *)(r7 +25592) + 2065: (63) *(u32 *)(r7 +30712) = r0 + 2066: (61) r0 = *(u32 *)(r7 +25596) + 2067: (63) *(u32 *)(r7 +30716) = r0 + // store the speculative load address (scalar) this time after the store + // forward prediction training. + 2068: (7b) *(u64 *)(r10 -16) = r2 + // preoccupy the CPU store port by running sequence of dummy stores. + 2069: (63) *(u32 *)(r7 +29696) = r0 + 2070: (63) *(u32 *)(r7 +29700) = r0 + 2071: (63) *(u32 *)(r7 +29704) = r0 + 2072: (63) *(u32 *)(r7 +29708) = r0 + 2073: (63) *(u32 *)(r7 +29712) = r0 + 2074: (63) *(u32 *)(r7 +29716) = r0 + 2075: (63) *(u32 *)(r7 +29720) = r0 + 2076: (63) *(u32 *)(r7 +29724) = r0 + 2077: (63) *(u32 *)(r7 +29728) = r0 + 2078: (63) *(u32 *)(r7 +29732) = r0 + 2079: (63) *(u32 *)(r7 +29736) = r0 + 2080: (63) *(u32 *)(r7 +29740) = r0 + 2081: (63) *(u32 *)(r7 +29744) = r0 + 2082: (63) *(u32 *)(r7 +29748) = r0 + 2083: (63) *(u32 *)(r7 +29752) = r0 + 2084: (63) *(u32 *)(r7 +29756) = r0 + 2085: (63) *(u32 *)(r7 +29760) = r0 + 2086: (63) *(u32 *)(r7 +29764) = r0 + 2087: (63) *(u32 *)(r7 +29768) = r0 + 2088: (63) *(u32 *)(r7 +29772) = r0 + 2089: (63) *(u32 *)(r7 +29776) = r0 + 2090: (63) *(u32 *)(r7 +29780) = r0 + 2091: (63) *(u32 *)(r7 +29784) = r0 + 2092: (63) *(u32 *)(r7 +29788) = r0 + 2093: (63) *(u32 *)(r7 +29792) = r0 + 2094: (63) *(u32 *)(r7 +29796) = r0 + 2095: (63) *(u32 *)(r7 +29800) = r0 + 2096: (63) *(u32 *)(r7 +29804) = r0 + 2097: (63) *(u32 *)(r7 +29808) = r0 + 2098: (63) *(u32 *)(r7 +29812) = r0 + // overwrite scalar with dummy pointer; same as before, also including the + // sanitation store with 0 from the current mitigation by the verifier. + 2099: (7a) *(u64 *)(r10 -16) = 0 | /both/ are now slow stores here + 2100: (7b) *(u64 *)(r10 -16) = r7 | since store unit is still busy. + // load from stack intended to bypass stores. + 2101: (79) r2 = *(u64 *)(r10 -16) + 2102: (71) r3 = *(u8 *)(r2 +0) + // leak r3 + [...] + +Looking at the CPU microarchitecture, the scheduler might issue loads (such +as seen in line 2101) before stores (line 2099,2100) because the load execution +units become available while the store execution unit is still busy with the +sequence of dummy stores (line 2069-2098). And so the load may use the prior +stored scalar from r2 at address r10 -16 for speculation. The updated attack +may work less reliable on CPU microarchitectures where loads and stores share +execution resources. + +This concludes that the sanitizing with zero stores from af86ca4e3088 ("bpf: +Prevent memory disambiguation attack") is insufficient. Moreover, the detection +of stack reuse from af86ca4e3088 where previously data (STACK_MISC) has been +written to a given stack slot where a pointer value is now to be stored does +not have sufficient coverage as precondition for the mitigation either; for +several reasons outlined as follows: + + 1) Stack content from prior program runs could still be preserved and is + therefore not "random", best example is to split a speculative store + bypass attack between tail calls, program A would prepare and store the + oob address at a given stack slot and then tail call into program B which + does the "slow" store of a pointer to the stack with subsequent "fast" + read. From program B PoV such stack slot type is STACK_INVALID, and + therefore also must be subject to mitigation. + + 2) The STACK_SPILL must not be coupled to register_is_const(&stack->spilled_ptr) + condition, for example, the previous content of that memory location could + also be a pointer to map or map value. Without the fix, a speculative + store bypass is not mitigated in such precondition and can then lead to + a type confusion in the speculative domain leaking kernel memory near + these pointer types. + +While brainstorming on various alternative mitigation possibilities, we also +stumbled upon a retrospective from Chrome developers [0]: + + [...] For variant 4, we implemented a mitigation to zero the unused memory + of the heap prior to allocation, which cost about 1% when done concurrently + and 4% for scavenging. Variant 4 defeats everything we could think of. We + explored more mitigations for variant 4 but the threat proved to be more + pervasive and dangerous than we anticipated. For example, stack slots used + by the register allocator in the optimizing compiler could be subject to + type confusion, leading to pointer crafting. Mitigating type confusion for + stack slots alone would have required a complete redesign of the backend of + the optimizing compiler, perhaps man years of work, without a guarantee of + completeness. [...] + +>From BPF side, the problem space is reduced, however, options are rather +limited. One idea that has been explored was to xor-obfuscate pointer spills +to the BPF stack: + + [...] + // preoccupy the CPU store port by running sequence of dummy stores. + [...] + 2106: (63) *(u32 *)(r7 +29796) = r0 + 2107: (63) *(u32 *)(r7 +29800) = r0 + 2108: (63) *(u32 *)(r7 +29804) = r0 + 2109: (63) *(u32 *)(r7 +29808) = r0 + 2110: (63) *(u32 *)(r7 +29812) = r0 + // overwrite scalar with dummy pointer; xored with random 'secret' value + // of 943576462 before store ... + 2111: (b4) w11 = 943576462 + 2112: (af) r11 ^= r7 + 2113: (7b) *(u64 *)(r10 -16) = r11 + 2114: (79) r11 = *(u64 *)(r10 -16) + 2115: (b4) w2 = 943576462 + 2116: (af) r2 ^= r11 + // ... and restored with the same 'secret' value with the help of AX reg. + 2117: (71) r3 = *(u8 *)(r2 +0) + [...] + +While the above would not prevent speculation, it would make data leakage +infeasible by directing it to random locations. In order to be effective +and prevent type confusion under speculation, such random secret would have +to be regenerated for each store. The additional complexity involved for a +tracking mechanism that prevents jumps such that restoring spilled pointers +would not get corrupted is not worth the gain for unprivileged. Hence, the +fix in here eventually opted for emitting a non-public BPF_ST | BPF_NOSPEC +instruction which the x86 JIT translates into a lfence opcode. Inserting the +latter in between the store and load instruction is one of the mitigations +options [1]. The x86 instruction manual notes: + + [...] An LFENCE that follows an instruction that stores to memory might + complete before the data being stored have become globally visible. [...] + +The latter meaning that the preceding store instruction finished execution +and the store is at minimum guaranteed to be in the CPU's store queue, but +it's not guaranteed to be in that CPU's L1 cache at that point (globally +visible). The latter would only be guaranteed via sfence. So the load which +is guaranteed to execute after the lfence for that local CPU would have to +rely on store-to-load forwarding. [2], in section 2.3 on store buffers says: + + [...] For every store operation that is added to the ROB, an entry is + allocated in the store buffer. This entry requires both the virtual and + physical address of the target. Only if there is no free entry in the store + buffer, the frontend stalls until there is an empty slot available in the + store buffer again. Otherwise, the CPU can immediately continue adding + subsequent instructions to the ROB and execute them out of order. On Intel + CPUs, the store buffer has up to 56 entries. [...] + +One small upside on the fix is that it lifts constraints from af86ca4e3088 +where the sanitize_stack_off relative to r10 must be the same when coming +from different paths. The BPF_ST | BPF_NOSPEC gets emitted after a BPF_STX +or BPF_ST instruction. This happens either when we store a pointer or data +value to the BPF stack for the first time, or upon later pointer spills. +The former needs to be enforced since otherwise stale stack data could be +leaked under speculation as outlined earlier. For non-x86 JITs the BPF_ST | +BPF_NOSPEC mapping is currently optimized away, but others could emit a +speculation barrier as well if necessary. For real-world unprivileged +programs e.g. generated by LLVM, pointer spill/fill is only generated upon +register pressure and LLVM only tries to do that for pointers which are not +used often. The program main impact will be the initial BPF_ST | BPF_NOSPEC +sanitation for the STACK_INVALID case when the first write to a stack slot +occurs e.g. upon map lookup. In future we might refine ways to mitigate +the latter cost. + + [0] https://arxiv.org/pdf/1902.05178.pdf + [1] https://msrc-blog.microsoft.com/2018/05/21/analysis-and-mitigation-of-speculative-store-bypass-cve-2018-3639/ + [2] https://arxiv.org/pdf/1905.05725.pdf + +Fixes: af86ca4e3088 ("bpf: Prevent memory disambiguation attack") +Fixes: f7cf25b2026d ("bpf: track spill/fill of constants") +Co-developed-by: Piotr Krysiuk +Co-developed-by: Benedict Schlueter +Signed-off-by: Daniel Borkmann +Signed-off-by: Piotr Krysiuk +Signed-off-by: Benedict Schlueter +Acked-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +[OP: - apply check_stack_write_fixed_off() changes in check_stack_write() + - replace env->bypass_spec_v4 -> env->allow_ptr_leaks] +Signed-off-by: Ovidiu Panait +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/bpf_verifier.h | 2 + kernel/bpf/verifier.c | 87 +++++++++++++++---------------------------- + 2 files changed, 33 insertions(+), 56 deletions(-) + +--- a/include/linux/bpf_verifier.h ++++ b/include/linux/bpf_verifier.h +@@ -301,8 +301,8 @@ struct bpf_insn_aux_data { + }; + }; + int ctx_field_size; /* the ctx field size for load insn, maybe 0 */ +- int sanitize_stack_off; /* stack slot to be cleared */ + bool seen; /* this insn was processed by the verifier */ ++ bool sanitize_stack_spill; /* subject to Spectre v4 sanitation */ + bool zext_dst; /* this insn zero extends dst reg */ + u8 alu_state; /* used in combination with alu_limit */ + bool prune_point; +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -1920,6 +1920,19 @@ static int check_stack_write(struct bpf_ + cur = env->cur_state->frame[env->cur_state->curframe]; + if (value_regno >= 0) + reg = &cur->regs[value_regno]; ++ if (!env->allow_ptr_leaks) { ++ bool sanitize = reg && is_spillable_regtype(reg->type); ++ ++ for (i = 0; i < size; i++) { ++ if (state->stack[spi].slot_type[i] == STACK_INVALID) { ++ sanitize = true; ++ break; ++ } ++ } ++ ++ if (sanitize) ++ env->insn_aux_data[insn_idx].sanitize_stack_spill = true; ++ } + + if (reg && size == BPF_REG_SIZE && register_is_const(reg) && + !register_is_null(reg) && env->allow_ptr_leaks) { +@@ -1942,47 +1955,10 @@ static int check_stack_write(struct bpf_ + verbose(env, "invalid size of register spill\n"); + return -EACCES; + } +- + if (state != cur && reg->type == PTR_TO_STACK) { + verbose(env, "cannot spill pointers to stack into stack frame of the caller\n"); + return -EINVAL; + } +- +- if (!env->allow_ptr_leaks) { +- bool sanitize = false; +- +- if (state->stack[spi].slot_type[0] == STACK_SPILL && +- register_is_const(&state->stack[spi].spilled_ptr)) +- sanitize = true; +- for (i = 0; i < BPF_REG_SIZE; i++) +- if (state->stack[spi].slot_type[i] == STACK_MISC) { +- sanitize = true; +- break; +- } +- if (sanitize) { +- int *poff = &env->insn_aux_data[insn_idx].sanitize_stack_off; +- int soff = (-spi - 1) * BPF_REG_SIZE; +- +- /* detected reuse of integer stack slot with a pointer +- * which means either llvm is reusing stack slot or +- * an attacker is trying to exploit CVE-2018-3639 +- * (speculative store bypass) +- * Have to sanitize that slot with preemptive +- * store of zero. +- */ +- if (*poff && *poff != soff) { +- /* disallow programs where single insn stores +- * into two different stack slots, since verifier +- * cannot sanitize them +- */ +- verbose(env, +- "insn %d cannot access two stack slots fp%d and fp%d", +- insn_idx, *poff, soff); +- return -EINVAL; +- } +- *poff = soff; +- } +- } + save_register_state(state, spi, reg); + } else { + u8 type = STACK_MISC; +@@ -8854,35 +8830,33 @@ static int convert_ctx_accesses(struct b + + for (i = 0; i < insn_cnt; i++, insn++) { + bpf_convert_ctx_access_t convert_ctx_access; ++ bool ctx_access; + + if (insn->code == (BPF_LDX | BPF_MEM | BPF_B) || + insn->code == (BPF_LDX | BPF_MEM | BPF_H) || + insn->code == (BPF_LDX | BPF_MEM | BPF_W) || +- insn->code == (BPF_LDX | BPF_MEM | BPF_DW)) ++ insn->code == (BPF_LDX | BPF_MEM | BPF_DW)) { + type = BPF_READ; +- else if (insn->code == (BPF_STX | BPF_MEM | BPF_B) || +- insn->code == (BPF_STX | BPF_MEM | BPF_H) || +- insn->code == (BPF_STX | BPF_MEM | BPF_W) || +- insn->code == (BPF_STX | BPF_MEM | BPF_DW)) ++ ctx_access = true; ++ } else if (insn->code == (BPF_STX | BPF_MEM | BPF_B) || ++ insn->code == (BPF_STX | BPF_MEM | BPF_H) || ++ insn->code == (BPF_STX | BPF_MEM | BPF_W) || ++ insn->code == (BPF_STX | BPF_MEM | BPF_DW) || ++ insn->code == (BPF_ST | BPF_MEM | BPF_B) || ++ insn->code == (BPF_ST | BPF_MEM | BPF_H) || ++ insn->code == (BPF_ST | BPF_MEM | BPF_W) || ++ insn->code == (BPF_ST | BPF_MEM | BPF_DW)) { + type = BPF_WRITE; +- else ++ ctx_access = BPF_CLASS(insn->code) == BPF_STX; ++ } else { + continue; ++ } + + if (type == BPF_WRITE && +- env->insn_aux_data[i + delta].sanitize_stack_off) { ++ env->insn_aux_data[i + delta].sanitize_stack_spill) { + struct bpf_insn patch[] = { +- /* Sanitize suspicious stack slot with zero. +- * There are no memory dependencies for this store, +- * since it's only using frame pointer and immediate +- * constant of zero +- */ +- BPF_ST_MEM(BPF_DW, BPF_REG_FP, +- env->insn_aux_data[i + delta].sanitize_stack_off, +- 0), +- /* the original STX instruction will immediately +- * overwrite the same stack slot with appropriate value +- */ + *insn, ++ BPF_ST_NOSPEC(), + }; + + cnt = ARRAY_SIZE(patch); +@@ -8896,6 +8870,9 @@ static int convert_ctx_accesses(struct b + continue; + } + ++ if (!ctx_access) ++ continue; ++ + switch (env->insn_aux_data[i + delta].ptr_type) { + case PTR_TO_CTX: + if (!ops->convert_ctx_access) diff --git a/queue-5.4/bpf-fix-pointer-arithmetic-mask-tightening-under-state-pruning.patch b/queue-5.4/bpf-fix-pointer-arithmetic-mask-tightening-under-state-pruning.patch new file mode 100644 index 00000000000..ec1785d089f --- /dev/null +++ b/queue-5.4/bpf-fix-pointer-arithmetic-mask-tightening-under-state-pruning.patch @@ -0,0 +1,127 @@ +From foo@baz Mon Sep 13 10:58:36 AM CEST 2021 +From: Ovidiu Panait +Date: Tue, 7 Sep 2021 16:17:01 +0300 +Subject: bpf: Fix pointer arithmetic mask tightening under state pruning +To: stable@vger.kernel.org +Cc: bpf@vger.kernel.org, daniel@iogearbox.net +Message-ID: <20210907131701.1910024-5-ovidiu.panait@windriver.com> + +From: Daniel Borkmann + +commit e042aa532c84d18ff13291d00620502ce7a38dda upstream. + +In 7fedb63a8307 ("bpf: Tighten speculative pointer arithmetic mask") we +narrowed the offset mask for unprivileged pointer arithmetic in order to +mitigate a corner case where in the speculative domain it is possible to +advance, for example, the map value pointer by up to value_size-1 out-of- +bounds in order to leak kernel memory via side-channel to user space. + +The verifier's state pruning for scalars leaves one corner case open +where in the first verification path R_x holds an unknown scalar with an +aux->alu_limit of e.g. 7, and in a second verification path that same +register R_x, here denoted as R_x', holds an unknown scalar which has +tighter bounds and would thus satisfy range_within(R_x, R_x') as well as +tnum_in(R_x, R_x') for state pruning, yielding an aux->alu_limit of 3: +Given the second path fits the register constraints for pruning, the final +generated mask from aux->alu_limit will remain at 7. While technically +not wrong for the non-speculative domain, it would however be possible +to craft similar cases where the mask would be too wide as in 7fedb63a8307. + +One way to fix it is to detect the presence of unknown scalar map pointer +arithmetic and force a deeper search on unknown scalars to ensure that +we do not run into a masking mismatch. + +Signed-off-by: Daniel Borkmann +Acked-by: Alexei Starovoitov +Signed-off-by: Greg Kroah-Hartman +[OP: adjusted context in include/linux/bpf_verifier.h for 5.4] +Signed-off-by: Ovidiu Panait +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/bpf_verifier.h | 1 + + kernel/bpf/verifier.c | 27 +++++++++++++++++---------- + 2 files changed, 18 insertions(+), 10 deletions(-) + +--- a/include/linux/bpf_verifier.h ++++ b/include/linux/bpf_verifier.h +@@ -371,6 +371,7 @@ struct bpf_verifier_env { + struct bpf_map *used_maps[MAX_USED_MAPS]; /* array of map's used by eBPF program */ + u32 used_map_cnt; /* number of used maps */ + u32 id_gen; /* used to generate unique reg IDs */ ++ bool explore_alu_limits; + bool allow_ptr_leaks; + bool seen_direct_write; + struct bpf_insn_aux_data *insn_aux_data; /* array of per-insn state */ +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -4449,6 +4449,12 @@ static int sanitize_ptr_alu(struct bpf_v + alu_state |= off_is_imm ? BPF_ALU_IMMEDIATE : 0; + alu_state |= ptr_is_dst_reg ? + BPF_ALU_SANITIZE_SRC : BPF_ALU_SANITIZE_DST; ++ ++ /* Limit pruning on unknown scalars to enable deep search for ++ * potential masking differences from other program paths. ++ */ ++ if (!off_is_imm) ++ env->explore_alu_limits = true; + } + + err = update_alu_sanitation_state(aux, alu_state, alu_limit); +@@ -7102,8 +7108,8 @@ next: + } + + /* Returns true if (rold safe implies rcur safe) */ +-static bool regsafe(struct bpf_reg_state *rold, struct bpf_reg_state *rcur, +- struct bpf_id_pair *idmap) ++static bool regsafe(struct bpf_verifier_env *env, struct bpf_reg_state *rold, ++ struct bpf_reg_state *rcur, struct bpf_id_pair *idmap) + { + bool equal; + +@@ -7129,6 +7135,8 @@ static bool regsafe(struct bpf_reg_state + return false; + switch (rold->type) { + case SCALAR_VALUE: ++ if (env->explore_alu_limits) ++ return false; + if (rcur->type == SCALAR_VALUE) { + if (!rold->precise && !rcur->precise) + return true; +@@ -7218,9 +7226,8 @@ static bool regsafe(struct bpf_reg_state + return false; + } + +-static bool stacksafe(struct bpf_func_state *old, +- struct bpf_func_state *cur, +- struct bpf_id_pair *idmap) ++static bool stacksafe(struct bpf_verifier_env *env, struct bpf_func_state *old, ++ struct bpf_func_state *cur, struct bpf_id_pair *idmap) + { + int i, spi; + +@@ -7265,9 +7272,8 @@ static bool stacksafe(struct bpf_func_st + continue; + if (old->stack[spi].slot_type[0] != STACK_SPILL) + continue; +- if (!regsafe(&old->stack[spi].spilled_ptr, +- &cur->stack[spi].spilled_ptr, +- idmap)) ++ if (!regsafe(env, &old->stack[spi].spilled_ptr, ++ &cur->stack[spi].spilled_ptr, idmap)) + /* when explored and current stack slot are both storing + * spilled registers, check that stored pointers types + * are the same as well. +@@ -7324,10 +7330,11 @@ static bool func_states_equal(struct bpf + + memset(env->idmap_scratch, 0, sizeof(env->idmap_scratch)); + for (i = 0; i < MAX_BPF_REG; i++) +- if (!regsafe(&old->regs[i], &cur->regs[i], env->idmap_scratch)) ++ if (!regsafe(env, &old->regs[i], &cur->regs[i], ++ env->idmap_scratch)) + return false; + +- if (!stacksafe(old, cur, env->idmap_scratch)) ++ if (!stacksafe(env, old, cur, env->idmap_scratch)) + return false; + + if (!refsafe(old, cur)) diff --git a/queue-5.4/bpf-introduce-bpf-nospec-instruction-for-mitigating-spectre-v4.patch b/queue-5.4/bpf-introduce-bpf-nospec-instruction-for-mitigating-spectre-v4.patch new file mode 100644 index 00000000000..0b9ce770619 --- /dev/null +++ b/queue-5.4/bpf-introduce-bpf-nospec-instruction-for-mitigating-spectre-v4.patch @@ -0,0 +1,285 @@ +From foo@baz Mon Sep 13 10:58:36 AM CEST 2021 +From: Ovidiu Panait +Date: Tue, 7 Sep 2021 16:16:58 +0300 +Subject: bpf: Introduce BPF nospec instruction for mitigating Spectre v4 +To: stable@vger.kernel.org +Cc: bpf@vger.kernel.org, daniel@iogearbox.net +Message-ID: <20210907131701.1910024-2-ovidiu.panait@windriver.com> + +From: Daniel Borkmann + +commit f5e81d1117501546b7be050c5fbafa6efd2c722c upstream. + +In case of JITs, each of the JIT backends compiles the BPF nospec instruction +/either/ to a machine instruction which emits a speculation barrier /or/ to +/no/ machine instruction in case the underlying architecture is not affected +by Speculative Store Bypass or has different mitigations in place already. + +This covers both x86 and (implicitly) arm64: In case of x86, we use 'lfence' +instruction for mitigation. In case of arm64, we rely on the firmware mitigation +as controlled via the ssbd kernel parameter. Whenever the mitigation is enabled, +it works for all of the kernel code with no need to provide any additional +instructions here (hence only comment in arm64 JIT). Other archs can follow +as needed. The BPF nospec instruction is specifically targeting Spectre v4 +since i) we don't use a serialization barrier for the Spectre v1 case, and +ii) mitigation instructions for v1 and v4 might be different on some archs. + +The BPF nospec is required for a future commit, where the BPF verifier does +annotate intermediate BPF programs with speculation barriers. + +Co-developed-by: Piotr Krysiuk +Co-developed-by: Benedict Schlueter +Signed-off-by: Daniel Borkmann +Signed-off-by: Piotr Krysiuk +Signed-off-by: Benedict Schlueter +Acked-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +[OP: - adjusted context for 5.4 + - apply riscv changes to /arch/riscv/net/bpf_jit_comp.c] +Signed-off-by: Ovidiu Panait +Signed-off-by: Greg Kroah-Hartman +--- + arch/arm/net/bpf_jit_32.c | 3 +++ + arch/arm64/net/bpf_jit_comp.c | 13 +++++++++++++ + arch/mips/net/ebpf_jit.c | 3 +++ + arch/powerpc/net/bpf_jit_comp64.c | 6 ++++++ + arch/riscv/net/bpf_jit_comp.c | 4 ++++ + arch/s390/net/bpf_jit_comp.c | 5 +++++ + arch/sparc/net/bpf_jit_comp_64.c | 3 +++ + arch/x86/net/bpf_jit_comp.c | 7 +++++++ + arch/x86/net/bpf_jit_comp32.c | 6 ++++++ + include/linux/filter.h | 15 +++++++++++++++ + kernel/bpf/core.c | 18 +++++++++++++++++- + kernel/bpf/disasm.c | 16 +++++++++------- + 12 files changed, 91 insertions(+), 8 deletions(-) + +--- a/arch/arm/net/bpf_jit_32.c ++++ b/arch/arm/net/bpf_jit_32.c +@@ -1602,6 +1602,9 @@ exit: + rn = arm_bpf_get_reg32(src_lo, tmp2[1], ctx); + emit_ldx_r(dst, rn, off, ctx, BPF_SIZE(code)); + break; ++ /* speculation barrier */ ++ case BPF_ST | BPF_NOSPEC: ++ break; + /* ST: *(size *)(dst + off) = imm */ + case BPF_ST | BPF_MEM | BPF_W: + case BPF_ST | BPF_MEM | BPF_H: +--- a/arch/arm64/net/bpf_jit_comp.c ++++ b/arch/arm64/net/bpf_jit_comp.c +@@ -701,6 +701,19 @@ emit_cond_jmp: + } + break; + ++ /* speculation barrier */ ++ case BPF_ST | BPF_NOSPEC: ++ /* ++ * Nothing required here. ++ * ++ * In case of arm64, we rely on the firmware mitigation of ++ * Speculative Store Bypass as controlled via the ssbd kernel ++ * parameter. Whenever the mitigation is enabled, it works ++ * for all of the kernel code with no need to provide any ++ * additional instructions. ++ */ ++ break; ++ + /* ST: *(size *)(dst + off) = imm */ + case BPF_ST | BPF_MEM | BPF_W: + case BPF_ST | BPF_MEM | BPF_H: +--- a/arch/mips/net/ebpf_jit.c ++++ b/arch/mips/net/ebpf_jit.c +@@ -1355,6 +1355,9 @@ jeq_common: + } + break; + ++ case BPF_ST | BPF_NOSPEC: /* speculation barrier */ ++ break; ++ + case BPF_ST | BPF_B | BPF_MEM: + case BPF_ST | BPF_H | BPF_MEM: + case BPF_ST | BPF_W | BPF_MEM: +--- a/arch/powerpc/net/bpf_jit_comp64.c ++++ b/arch/powerpc/net/bpf_jit_comp64.c +@@ -645,6 +645,12 @@ emit_clear: + break; + + /* ++ * BPF_ST NOSPEC (speculation barrier) ++ */ ++ case BPF_ST | BPF_NOSPEC: ++ break; ++ ++ /* + * BPF_ST(X) + */ + case BPF_STX | BPF_MEM | BPF_B: /* *(u8 *)(dst + off) = src */ +--- a/arch/riscv/net/bpf_jit_comp.c ++++ b/arch/riscv/net/bpf_jit_comp.c +@@ -1313,6 +1313,10 @@ out_be: + emit(rv_ld(rd, 0, RV_REG_T1), ctx); + break; + ++ /* speculation barrier */ ++ case BPF_ST | BPF_NOSPEC: ++ break; ++ + /* ST: *(size *)(dst + off) = imm */ + case BPF_ST | BPF_MEM | BPF_B: + emit_imm(RV_REG_T1, imm, ctx); +--- a/arch/s390/net/bpf_jit_comp.c ++++ b/arch/s390/net/bpf_jit_comp.c +@@ -914,6 +914,11 @@ static noinline int bpf_jit_insn(struct + } + break; + /* ++ * BPF_NOSPEC (speculation barrier) ++ */ ++ case BPF_ST | BPF_NOSPEC: ++ break; ++ /* + * BPF_ST(X) + */ + case BPF_STX | BPF_MEM | BPF_B: /* *(u8 *)(dst + off) = src_reg */ +--- a/arch/sparc/net/bpf_jit_comp_64.c ++++ b/arch/sparc/net/bpf_jit_comp_64.c +@@ -1287,6 +1287,9 @@ static int build_insn(const struct bpf_i + return 1; + break; + } ++ /* speculation barrier */ ++ case BPF_ST | BPF_NOSPEC: ++ break; + /* ST: *(size *)(dst + off) = imm */ + case BPF_ST | BPF_MEM | BPF_W: + case BPF_ST | BPF_MEM | BPF_H: +--- a/arch/x86/net/bpf_jit_comp.c ++++ b/arch/x86/net/bpf_jit_comp.c +@@ -728,6 +728,13 @@ static int do_jit(struct bpf_prog *bpf_p + } + break; + ++ /* speculation barrier */ ++ case BPF_ST | BPF_NOSPEC: ++ if (boot_cpu_has(X86_FEATURE_XMM2)) ++ /* Emit 'lfence' */ ++ EMIT3(0x0F, 0xAE, 0xE8); ++ break; ++ + /* ST: *(u8*)(dst_reg + off) = imm */ + case BPF_ST | BPF_MEM | BPF_B: + if (is_ereg(dst_reg)) +--- a/arch/x86/net/bpf_jit_comp32.c ++++ b/arch/x86/net/bpf_jit_comp32.c +@@ -1705,6 +1705,12 @@ static int do_jit(struct bpf_prog *bpf_p + i++; + break; + } ++ /* speculation barrier */ ++ case BPF_ST | BPF_NOSPEC: ++ if (boot_cpu_has(X86_FEATURE_XMM2)) ++ /* Emit 'lfence' */ ++ EMIT3(0x0F, 0xAE, 0xE8); ++ break; + /* ST: *(u8*)(dst_reg + off) = imm */ + case BPF_ST | BPF_MEM | BPF_H: + case BPF_ST | BPF_MEM | BPF_B: +--- a/include/linux/filter.h ++++ b/include/linux/filter.h +@@ -68,6 +68,11 @@ struct ctl_table_header; + /* unused opcode to mark call to interpreter with arguments */ + #define BPF_CALL_ARGS 0xe0 + ++/* unused opcode to mark speculation barrier for mitigating ++ * Speculative Store Bypass ++ */ ++#define BPF_NOSPEC 0xc0 ++ + /* As per nm, we expose JITed images as text (code) section for + * kallsyms. That way, tools like perf can find it to match + * addresses. +@@ -366,6 +371,16 @@ static inline bool insn_is_zext(const st + .dst_reg = 0, \ + .src_reg = 0, \ + .off = 0, \ ++ .imm = 0 }) ++ ++/* Speculation barrier */ ++ ++#define BPF_ST_NOSPEC() \ ++ ((struct bpf_insn) { \ ++ .code = BPF_ST | BPF_NOSPEC, \ ++ .dst_reg = 0, \ ++ .src_reg = 0, \ ++ .off = 0, \ + .imm = 0 }) + + /* Internal classic blocks for direct assignment */ +--- a/kernel/bpf/core.c ++++ b/kernel/bpf/core.c +@@ -31,6 +31,7 @@ + #include + #include + ++#include + #include + + /* Registers */ +@@ -1310,6 +1311,7 @@ static u64 ___bpf_prog_run(u64 *regs, co + /* Non-UAPI available opcodes. */ + [BPF_JMP | BPF_CALL_ARGS] = &&JMP_CALL_ARGS, + [BPF_JMP | BPF_TAIL_CALL] = &&JMP_TAIL_CALL, ++ [BPF_ST | BPF_NOSPEC] = &&ST_NOSPEC, + }; + #undef BPF_INSN_3_LBL + #undef BPF_INSN_2_LBL +@@ -1550,7 +1552,21 @@ out: + COND_JMP(s, JSGE, >=) + COND_JMP(s, JSLE, <=) + #undef COND_JMP +- /* STX and ST and LDX*/ ++ /* ST, STX and LDX*/ ++ ST_NOSPEC: ++ /* Speculation barrier for mitigating Speculative Store Bypass. ++ * In case of arm64, we rely on the firmware mitigation as ++ * controlled via the ssbd kernel parameter. Whenever the ++ * mitigation is enabled, it works for all of the kernel code ++ * with no need to provide any additional instructions here. ++ * In case of x86, we use 'lfence' insn for mitigation. We ++ * reuse preexisting logic from Spectre v1 mitigation that ++ * happens to produce the required code on x86 for v4 as well. ++ */ ++#ifdef CONFIG_X86 ++ barrier_nospec(); ++#endif ++ CONT; + #define LDST(SIZEOP, SIZE) \ + STX_MEM_##SIZEOP: \ + *(SIZE *)(unsigned long) (DST + insn->off) = SRC; \ +--- a/kernel/bpf/disasm.c ++++ b/kernel/bpf/disasm.c +@@ -162,15 +162,17 @@ void print_bpf_insn(const struct bpf_ins + else + verbose(cbs->private_data, "BUG_%02x\n", insn->code); + } else if (class == BPF_ST) { +- if (BPF_MODE(insn->code) != BPF_MEM) { ++ if (BPF_MODE(insn->code) == BPF_MEM) { ++ verbose(cbs->private_data, "(%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 (BPF_MODE(insn->code) == 0xc0 /* BPF_NOSPEC, no UAPI */) { ++ verbose(cbs->private_data, "(%02x) nospec\n", insn->code); ++ } else { + verbose(cbs->private_data, "BUG_st_%02x\n", insn->code); +- return; + } +- verbose(cbs->private_data, "(%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(cbs->private_data, "BUG_ldx_%02x\n", insn->code); diff --git a/queue-5.4/bpf-verifier-allocate-idmap-scratch-in-verifier-env.patch b/queue-5.4/bpf-verifier-allocate-idmap-scratch-in-verifier-env.patch new file mode 100644 index 00000000000..0cf95b7260b --- /dev/null +++ b/queue-5.4/bpf-verifier-allocate-idmap-scratch-in-verifier-env.patch @@ -0,0 +1,155 @@ +From foo@baz Mon Sep 13 10:58:36 AM CEST 2021 +From: Ovidiu Panait +Date: Tue, 7 Sep 2021 16:17:00 +0300 +Subject: bpf: verifier: Allocate idmap scratch in verifier env +To: stable@vger.kernel.org +Cc: bpf@vger.kernel.org, daniel@iogearbox.net +Message-ID: <20210907131701.1910024-4-ovidiu.panait@windriver.com> + +From: Lorenz Bauer + +commit c9e73e3d2b1eb1ea7ff068e05007eec3bd8ef1c9 upstream. + +func_states_equal makes a very short lived allocation for idmap, +probably because it's too large to fit on the stack. However the +function is called quite often, leading to a lot of alloc / free +churn. Replace the temporary allocation with dedicated scratch +space in struct bpf_verifier_env. + +Signed-off-by: Lorenz Bauer +Signed-off-by: Alexei Starovoitov +Acked-by: Edward Cree +Link: https://lore.kernel.org/bpf/20210429134656.122225-4-lmb@cloudflare.com +Signed-off-by: Greg Kroah-Hartman +[OP: adjusted context for 5.4] +Signed-off-by: Ovidiu Panait +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/bpf_verifier.h | 8 +++++++ + kernel/bpf/verifier.c | 46 ++++++++++++++----------------------------- + 2 files changed, 23 insertions(+), 31 deletions(-) + +--- a/include/linux/bpf_verifier.h ++++ b/include/linux/bpf_verifier.h +@@ -194,6 +194,13 @@ struct bpf_idx_pair { + u32 idx; + }; + ++struct bpf_id_pair { ++ u32 old; ++ u32 cur; ++}; ++ ++/* Maximum number of register states that can exist at once */ ++#define BPF_ID_MAP_SIZE (MAX_BPF_REG + MAX_BPF_STACK / BPF_REG_SIZE) + #define MAX_CALL_FRAMES 8 + struct bpf_verifier_state { + /* call stack tracking */ +@@ -370,6 +377,7 @@ struct bpf_verifier_env { + const struct bpf_line_info *prev_linfo; + struct bpf_verifier_log log; + struct bpf_subprog_info subprog_info[BPF_MAX_SUBPROGS + 1]; ++ struct bpf_id_pair idmap_scratch[BPF_ID_MAP_SIZE]; + struct { + int *insn_state; + int *insn_stack; +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -6976,13 +6976,6 @@ static bool range_within(struct bpf_reg_ + old->smax_value >= cur->smax_value; + } + +-/* Maximum number of register states that can exist at once */ +-#define ID_MAP_SIZE (MAX_BPF_REG + MAX_BPF_STACK / BPF_REG_SIZE) +-struct idpair { +- u32 old; +- u32 cur; +-}; +- + /* If in the old state two registers had the same id, then they need to have + * the same id in the new state as well. But that id could be different from + * the old state, so we need to track the mapping from old to new ids. +@@ -6993,11 +6986,11 @@ struct idpair { + * So we look through our idmap to see if this old id has been seen before. If + * so, we require the new id to match; otherwise, we add the id pair to the map. + */ +-static bool check_ids(u32 old_id, u32 cur_id, struct idpair *idmap) ++static bool check_ids(u32 old_id, u32 cur_id, struct bpf_id_pair *idmap) + { + unsigned int i; + +- for (i = 0; i < ID_MAP_SIZE; i++) { ++ for (i = 0; i < BPF_ID_MAP_SIZE; i++) { + if (!idmap[i].old) { + /* Reached an empty slot; haven't seen this id before */ + idmap[i].old = old_id; +@@ -7110,7 +7103,7 @@ next: + + /* Returns true if (rold safe implies rcur safe) */ + static bool regsafe(struct bpf_reg_state *rold, struct bpf_reg_state *rcur, +- struct idpair *idmap) ++ struct bpf_id_pair *idmap) + { + bool equal; + +@@ -7227,7 +7220,7 @@ static bool regsafe(struct bpf_reg_state + + static bool stacksafe(struct bpf_func_state *old, + struct bpf_func_state *cur, +- struct idpair *idmap) ++ struct bpf_id_pair *idmap) + { + int i, spi; + +@@ -7324,32 +7317,23 @@ static bool refsafe(struct bpf_func_stat + * whereas register type in current state is meaningful, it means that + * the current state will reach 'bpf_exit' instruction safely + */ +-static bool func_states_equal(struct bpf_func_state *old, ++static bool func_states_equal(struct bpf_verifier_env *env, struct bpf_func_state *old, + struct bpf_func_state *cur) + { +- struct idpair *idmap; +- bool ret = false; + int i; + +- idmap = kcalloc(ID_MAP_SIZE, sizeof(struct idpair), GFP_KERNEL); +- /* If we failed to allocate the idmap, just say it's not safe */ +- if (!idmap) +- return false; +- +- for (i = 0; i < MAX_BPF_REG; i++) { +- if (!regsafe(&old->regs[i], &cur->regs[i], idmap)) +- goto out_free; +- } ++ memset(env->idmap_scratch, 0, sizeof(env->idmap_scratch)); ++ for (i = 0; i < MAX_BPF_REG; i++) ++ if (!regsafe(&old->regs[i], &cur->regs[i], env->idmap_scratch)) ++ return false; + +- if (!stacksafe(old, cur, idmap)) +- goto out_free; ++ if (!stacksafe(old, cur, env->idmap_scratch)) ++ return false; + + if (!refsafe(old, cur)) +- goto out_free; +- ret = true; +-out_free: +- kfree(idmap); +- return ret; ++ return false; ++ ++ return true; + } + + static bool states_equal(struct bpf_verifier_env *env, +@@ -7376,7 +7360,7 @@ static bool states_equal(struct bpf_veri + for (i = 0; i <= old->curframe; i++) { + if (old->frame[i]->callsite != cur->frame[i]->callsite) + return false; +- if (!func_states_equal(old->frame[i], cur->frame[i])) ++ if (!func_states_equal(env, old->frame[i], cur->frame[i])) + return false; + } + return true; diff --git a/queue-5.4/series b/queue-5.4/series index 21f681fa20c..8b1fbc90ab0 100644 --- a/queue-5.4/series +++ b/queue-5.4/series @@ -124,3 +124,7 @@ net-sched-fix-qdisc_rate_table-refcount-leak-when-ge.patch net-qualcomm-fix-qca7000-checksum-handling.patch octeontx2-af-fix-loop-in-free-and-unmap-counter.patch ipv4-fix-endianness-issue-in-inet_rtm_getroute_build.patch +bpf-introduce-bpf-nospec-instruction-for-mitigating-spectre-v4.patch +bpf-fix-leakage-due-to-insufficient-speculative-store-bypass-mitigation.patch +bpf-verifier-allocate-idmap-scratch-in-verifier-env.patch +bpf-fix-pointer-arithmetic-mask-tightening-under-state-pruning.patch