From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pl1-f176.google.com (mail-pl1-f176.google.com [209.85.214.176]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2ACE5392C3A for ; Thu, 20 Aug 2026 18:25:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.176 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787250330; cv=none; b=BTIiXGE0ASXdv0s7W2+CdaR/i31q6r5lgG3nTN6TIs3oXMl5/Nbsi7ulJQOF0tpqRZn/npyLLhq4QwPKaPT9mA88/Tz2nDGO/+xSo1nBbk/CjLhbte8jUVeP2n0rbE5Mcqhd/wyWBQJsonaAVy7vny0Q2ZNZJxwXdaIPlN/3OmI= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787250330; c=relaxed/simple; bh=ItkmceOa6PF0hafqNv/HENpBIQvUU6VsrrSFvZSXJ+U=; h=Message-ID:Subject:From:To:Cc:Date:In-Reply-To:References: Content-Type:MIME-Version; b=XXvSK9sBwsf7M2gbcqVQAJRc/vGFKwxN1roIbxG3pKSJzTOPH70x1+q0dibIK7wFIGoMOzKciu+v8qOGu8sRNeyV8xy/Omq5Nmq7mV3lAXNOrU4ZtT7UQQgEcWLRjY9pshKeuxGPOtYGtxs8iI5kxInakcISZLlCe30GViFKfaY= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=mrL9g0bS; arc=none smtp.client-ip=209.85.214.176 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="mrL9g0bS" Received: by mail-pl1-f176.google.com with SMTP id d9443c01a7336-2ceab75934dso2596215ad.2 for ; Thu, 20 Aug 2026 11:25:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1787250328; x=1787855128; darn=vger.kernel.org; h=mime-version:user-agent:content-transfer-encoding:content-type :references:in-reply-to:date:cc:to:from:subject:message-id:from:to :cc:subject:date:message-id:reply-to:content-type; bh=necPZCDUxXpaJc9xcDXsM/DZHCx0YmzQTDb4jA22BZg=; b=mrL9g0bSmTLbn8GDe+hysClh3M/9TBIOHtyo4jfu/SRhaFYdDnQrjdVeBog/w3dly9 vz4tnwX79A7Up0fjmn6FqLKgQxXSwSSYjiQ3xHUStx8j2iUHplwaP4KCGVs0nlnyDVkI BjWFoMa+UgBH6MnI9e8kxXaXtcRjUz1VQZlvAgciL3fVnML+2tXyVPRmsiHDTRr8Rckq rIF2h3QSzi17jowfy4E4wn7vlGFNYJdUUXpIUPC7TBDlEo+zymKg4xUXwF4RusdXNnW3 opaWG9sAS8Tvh1YwSY1oBBCZsdtIO2rFml9kKvl5kXvku7yDJL/mG3syEtwKc9oDjzs3 lKOg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787250328; x=1787855128; h=mime-version:user-agent:content-transfer-encoding:content-type :references:in-reply-to:date:cc:to:from:subject:message-id:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=necPZCDUxXpaJc9xcDXsM/DZHCx0YmzQTDb4jA22BZg=; b=jcH3tFCHnDFzIPPB5P6wZxG45OYr8uzBBqqxu9bxGODcbqxERUIeZhcJ8eGcCja9fE V7i3qJDIiwczMJnPwxD5f+Ai4TulNEwggKEtbp6t7DqyRZDc56xcdnNAYrxcezSYLY/8 5RAy+6LMp5VLhqFo6nSheSzH8cMlXWouNaTVm9+vVBBH3EYhK8nPzkk3DY4/pnyz1oxT T4tPozn4Eh2wAj42Kpryxh4xkPqxMJnTjr1EZrPxgdxWsQ7/kTb3xGSgibsRiG/vMQaA PUdSBST+f4ZQjtmCOzywPdS/4AM6ZywWlftW2jTxW+Qpen9joVfULQwShw2A3rOTIgeX FfYg== X-Forwarded-Encrypted: i=1; AHgh+Rq+h9XEsjLBTS+I78P4uCFziYmWVbJAXKRdE4aW+K/QzLcoLTOy/npq5vjwzMtMqZC9RR7ceqxvsDTCkho=@vger.kernel.org X-Gm-Message-State: AFuF++l7MzSuRHqwhkpbABXLJ2IArX1A7hMawbAJ5XJGnTeOGsu4+kiI 3fwOHTGLuwAXtbC8Z12eBrjgeqllOLoCr2fjKgqBIZOde63YcNjfDUNZ X-Gm-Gg: AR+sD12KrI6bby8Sx6FgfOC8WHRlV6qQ/RBRk9o+g90vFLpAHs80bATckaEaLsuZXyz k+gTVVSn2XfeGt5WTLdys37fnkEcUfS7VEZkwV5yxQfxvKZZ5OQClhJ+kUeAxNqhVnnH+efNg6K kgS9jnftiQSM9Di+cUY3yB+fTSn8oBA06yIRXinuL5Tsu9hzfbmBvTIMYen6HT4kjtxMHxTKkMB rjX3HuWjodGALYg31boECNM8EODyCelRJVf0ekZSBxJ1/lpXbZ+p+ywigTCv5XlTtYIPB/hFB0Q svCVWmgos/TvfTwzmIlCXgmZRPC+L/yLL5IB6MaDe1b5wjKC6GfLtservcnQY6Xz8Co5Ly+ZMBO Zwj87TJl4MaWUvuJqd0MlYAQt1inNhqF9LCvydNQdN8sA2xlD9lmYTIylHW/Ip9Q/ufN+Z02wSJ BHxKVvGby0J/J2VNsTVS4rGk9WptVeITyxf0htW9zdtwPSRoqreiicErHMaH66wxuu763VygK99 +mwXZvYrdPYWE+M+Mu38KUdRzZcM1VIpRz2RcHuOSWO4w== X-Received: by 2002:a17:90b:3912:b0:392:e5b1:d833 with SMTP id 98e67ed59e1d1-395c3738b35mr576958a91.13.1787250328314; Thu, 20 Aug 2026 11:25:28 -0700 (PDT) Received: from ?IPv6:2a03:83e0:115c:1:89bc:48d2:9457:6223? ([2620:10d:c090:500::6:c5ba]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-327bf15ff5dsm18788102eec.25.2026.08.20.11.25.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 20 Aug 2026 11:25:27 -0700 (PDT) Message-ID: <57a57ed806a954de19774b7c0833dc1742560cd2.camel@gmail.com> Subject: Re: [PATCH bpf 1/2] bpf: fix REG INVARIANTS VIOLATION on speculative pointer arithmetic From: Eduard Zingerman To: Jiayuan Chen , bpf@vger.kernel.org Cc: Hiker Cl , Alexei Starovoitov , Daniel Borkmann , John Fastabend , Andrii Nakryiko , Kumar Kartikeya Dwivedi , Martin KaFai Lau , Song Liu , Yonghong Song , Jiri Olsa , Emil Tsalapatis , Ihor Solodrai , Shuah Khan , Paul Chaignon , Amery Hung , Shung-Hsi Yu , KaFai Wan , Daniel Wade , linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org Date: Thu, 20 Aug 2026 11:25:25 -0700 In-Reply-To: <20260819125840.286434-1-jiayuan.chen@linux.dev> References: <20260819125840.286434-1-jiayuan.chen@linux.dev> Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable User-Agent: Evolution 3.60.2 (3.60.2-1.fc44) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 On Wed, 2026-08-19 at 20:58 +0800, Jiayuan Chen wrote: > Take the following unprivileged program as an example: >=20 > r0 =3D bpf_map_lookup_elem(...) /* PTR_TO_MAP_VALUE, offset 0 */ > ... > 14: r0 +=3D r1 /* r1 is a bounded scalar */ > 15: r9 =3D r0 >=20 > Loading it triggers a verifier warning from reg_bounds_sanity_check(): >=20 > verifier bug: REG INVARIANTS VIOLATION (alu): const subreg tnum out > of sync with range bounds r64=3D{.base=3D0x0, .size=3D0x0} > r32=3D{.base=3D0x0, .size=3D0xffffffff} var_off=3D(0x0, 0x0) >=20 > What happens: >=20 > 1. Processing insn 14 (r0 +=3D r1) in adjust_ptr_min_max_vals(), the new > offset is computed into dst_reg's var_off and 32/64-bit ranges. >=20 > 2. Because pointer registers do not track 32-bit subregister bounds, > __mark_reg32_unbounded() first sets r32 to the full range; r32 is > re-derived from the offset at the end of the function by > reg_bounds_sync(). >=20 > 3. On the unprivileged path, sanitize_ptr_alu() is called and, via > sanitize_speculative_path() -> push_stack(), snapshots the current > register state and schedules the next instruction (insn 15) to be > verified directly as a speculative path. >=20 > 4. That snapshot is taken between step 2 and the final reg_bounds_sync(): > at this point dst_reg's var_off still holds the (const) original > offset while r32 has just been blanked to the full range, i.e. the two > are out of sync. When the speculative path later verifies insn 15 > (r9 =3D r0), the inconsistent state reaches reg_bounds_sanity_check() = and > trips the warning. >=20 > var_off and the 32-bit range must always be consistent. There are two > ways to keep the snapshot consistent: >=20 > 1. sync var_off and r32 before the snapshot so they match, or > 2. leave r32 at its original (already consistent) value and blank it > only after the snapshot. >=20 > The whole point of sanitize_ptr_alu() is to insert a harmless masking > sequence that keeps the access in bounds under speculation, so the state > it snapshots should faithfully represent that. Take approach 2: move > __mark_reg32_unbounded() to after sanitize_ptr_alu(), so the speculative > snapshot keeps the pointer's original, consistent r32. The non-speculativ= e > path is unchanged: r32 is still blanked before the offset is applied and > re-derived by reg_bounds_sync(). >=20 > Fixes: 5f99f312bd3b ("bpf: add register bounds sanity checks and sanitiza= tion") > Reported-by: Hiker Cl > Closes: https://lore.kernel.org/bpf/CAGM=3DxGB1fJ9kT8XTitVo74B0WGqgjkoUHd= LwzytwV0AyqeVApw@mail.gmail.com/ > Signed-off-by: Jiayuan Chen > --- Acked-by: Eduard Zingerman > kernel/bpf/verifier.c | 11 ++++++++--- > 1 file changed, 8 insertions(+), 3 deletions(-) >=20 > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c > index d17f14b35b79..d79038a8da10 100644 > --- a/kernel/bpf/verifier.c > +++ b/kernel/bpf/verifier.c > @@ -14558,9 +14558,6 @@ static int adjust_ptr_min_max_vals(struct bpf_ver= ifier_env *env, struct bpf_insn > return -EINVAL; > } > =20 > - /* pointer types do not carry 32-bit bounds at the moment. */ > - __mark_reg32_unbounded(dst_reg); > - > if (sanitize_needed(opcode)) { > ret =3D sanitize_ptr_alu(env, insn, ptr_reg, off_reg, dst_reg, > &info, false); > @@ -14568,6 +14565,14 @@ static int adjust_ptr_min_max_vals(struct bpf_ve= rifier_env *env, struct bpf_insn > return sanitize_err(env, insn, ret); > } > =20 > + /* Pointer types do not carry 32-bit bounds at the moment. Blank r32 > + * only after sanitize_ptr_alu() may have snapshotted dst_reg into a > + * speculative path: otherwise that snapshot freezes a const offset > + * with an unbounded r32, which later trips reg_bounds_sanity_check(). > + * reg_bounds_sync() below re-derives r32 from the updated offset. > + */ Nit: comment is a bit too verbose. "... otherwise reg_bounds_sanity_check() might hit some constraints violations" should have been enough. > + __mark_reg32_unbounded(dst_reg); > + > switch (opcode) { > case BPF_ADD: > /*