From nobody Tue Sep 16 00:30:08 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7C3C1C61DB3 for ; Mon, 9 Jan 2023 15:08:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231406AbjAIPIH (ORCPT ); Mon, 9 Jan 2023 10:08:07 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52730 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235112AbjAIPHb (ORCPT ); Mon, 9 Jan 2023 10:07:31 -0500 X-Greylist: delayed 249 seconds by postgrey-1.37 at lindbergh.monkeyblade.net; Mon, 09 Jan 2023 07:07:29 PST Received: from faui40.informatik.uni-erlangen.de (faui40.informatik.uni-erlangen.de [IPv6:2001:638:a000:4134::ffff:40]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 869DEB8D; Mon, 9 Jan 2023 07:07:29 -0800 (PST) Received: from luis-i4.informatik.uni-erlangen.de (i4laptop35.informatik.uni-erlangen.de [10.188.34.202]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: gerhorst) by faui40.informatik.uni-erlangen.de (Postfix) with ESMTPSA id 4NrHNs2GvsznkXl; Mon, 9 Jan 2023 16:07:25 +0100 (CET) From: Luis Gerhorst To: Alexei Starovoitov , Daniel Borkmann , John Fastabend , Andrii Nakryiko , Martin KaFai Lau , Song Liu , Yonghong Song , KP Singh , Stanislav Fomichev , Hao Luo , Jiri Olsa , Nathan Chancellor , Nick Desaulniers , Tom Rix , Piotr Krysiuk , Benedict Schlueter , bpf@vger.kernel.org, linux-kernel@vger.kernel.org, llvm@lists.linux.dev Cc: Luis Gerhorst , stefan.saecherl@use.startmail.com, Henriette Hofmeier Subject: [PATCH] bpf: Fix pointer-leak due to insufficient speculative store bypass mitigation Date: Mon, 9 Jan 2023 16:05:46 +0100 Message-Id: <20230109150544.41465-1-gerhorst@cs.fau.de> X-Mailer: git-send-email 2.34.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" To mitigate Spectre v4, 2039f26f3aca ("bpf: Fix leakage due to insufficient speculative store bypass mitigation") inserts lfence instructions after 1) initializing a stack slot and 2) spilling a pointer to the stack. However, this does not cover cases where a stack slot is first initialized with a pointer (subject to sanitization) but then overwritten with a scalar (not subject to sanitization because the slot was already initialized). In this case, the second write may be subject to speculative store bypass (SSB) creating a speculative pointer-as-scalar type confusion. This allows the program to subsequently leak the numerical pointer value using, for example, a branch-based cache side channel. To fix this, also sanitize scalars if they write a stack slot that previously contained a pointer. Assuming that pointer-spills are only generated by LLVM on register-pressure, the performance impact on most real-world BPF programs should be small. The following unprivileged BPF bytecode drafts a minimal exploit and the mitigation: [...] // r6 =3D 0 or 1 (skalar, unknown user input) // r7 =3D accessible ptr for side channel // r10 =3D frame pointer (fp), to be leaked // r9 =3D r10 # fp alias to encourage ssb *(u64 *)(r9 - 8) =3D r10 // fp[-8] =3D ptr, to be leaked // lfence added here because of pointer spill to stack. // // Ommitted: Dummy bpf_ringbuf_output() here to train alias predictor // for no r9-r10 dependency. // *(u64 *)(r10 - 8) =3D r6 // fp[-8] =3D scalar, overwrites ptr // 2039f26f3aca: no lfence added because stack slot was not STACK_INVALID, // store may be subject to SSB // // fix: also add an lfence when the slot contained a ptr // r8 =3D *(u64 *)(r9 - 8) // r8 =3D architecturally a scalar, speculatively a ptr // // leak ptr using branch-based cache side channel: r8 &=3D 1 // choose bit to leak if r8 =3D=3D 0 goto SLOW // no mispredict // architecturally dead code if input r6 is 0, // only executes speculatively iff ptr bit is 1 r8 =3D *(u64 *)(r7 + 0) # encode bit in cache (0: slow, 1: fast) SLOW: [...] After running this, the program can time the access to *(r7 + 0) to determine whether the chosen pointer bit was 0 or 1. Repeat this 64 times to recover the whole address on amd64. In summary, sanitization can only be skipped if one scalar is overwritten with another scalar. Scalar-confusion due to speculative store bypass can not lead to invalid accesses because the pointer bounds deducted during verification are enforced using branchless logic. See 979d63d50c0c ("bpf: prevent out of bounds speculation on pointer arithmetic") for details. Do not make the mitigation depend on !env->allow_{uninit_stack,ptr_leaks} because speculative leaks are likely unexpected if these were enabled. For example, leaking the address to a protected log file may be acceptable while disabling the mitigation might unintentionally leak the address into the cached-state of a map that is accessible to unprivileged processes. Fixes: 2039f26f3aca ("bpf: Fix leakage due to insufficient speculative stor= e bypass mitigation") Signed-off-by: Luis Gerhorst Acked-by: Henriette Hofmeier --- kernel/bpf/verifier.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index a5255a0dcbb6..5e3aa4a75bd6 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -3287,7 +3287,8 @@ static int check_stack_write_fixed_off(struct bpf_ver= ifier_env *env, bool sanitize =3D reg && is_spillable_regtype(reg->type); =20 for (i =3D 0; i < size; i++) { - if (state->stack[spi].slot_type[i] =3D=3D STACK_INVALID) { + u8 type =3D state->stack[spi].slot_type[i]; + if (type !=3D STACK_MISC && type !=3D STACK_ZERO) { sanitize =3D true; break; } --=20 2.34.1