From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2151A2E412 for ; Tue, 7 Nov 2023 12:11:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="MDtJikBk" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 06E9AC43395; Tue, 7 Nov 2023 12:11:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1699359079; bh=58rGdqFegt3aDt3Mcgisfy7c2gqz6EEl+7gR4Q4ZNF0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=MDtJikBkoTuEEK+sCnkoe+eAq8rMH73HU9WHSsdGbw8/sezXKcWZFZhXW9RfTCnn8 I1CqphLrB2XhFfSFHA+1QuWG7ZyM9uDGQqRzSWvusGxsVK+lw5J57gWBrlSdTj+ICR 3zYFsVT5BOTecM2qQq4Z2mzYEVXKiJiOjgz4PTqHsdH0YVU8UGJXKPHhzo/sVc1AnN qXw+uCU/ji4Tno5erFedTN9KLBkoEJw4qIEgUDD+i2X2pqfPaosF57Bf9F2eLYK7QI Gj7Iy0bhv5GKngFpzg6olm1i8u8jokNeR7n0MvmXvov00c62+QjC4GUNwUg8MY94e1 2848ZlX1ur4yQ== From: Sasha Levin To: linux-kernel@vger.kernel.org, stable@vger.kernel.org Cc: Kumar Kartikeya Dwivedi , Alexei Starovoitov , Sasha Levin , daniel@iogearbox.net, andrii@kernel.org, bpf@vger.kernel.org Subject: [PATCH AUTOSEL 6.1 05/18] bpf: Detect IP == ksym.end as part of BPF program Date: Tue, 7 Nov 2023 07:10:35 -0500 Message-ID: <20231107121104.3757943-5-sashal@kernel.org> X-Mailer: git-send-email 2.42.0 In-Reply-To: <20231107121104.3757943-1-sashal@kernel.org> References: <20231107121104.3757943-1-sashal@kernel.org> Precedence: bulk X-Mailing-List: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-stable: review X-Patchwork-Hint: Ignore X-stable-base: Linux 6.1.61 Content-Transfer-Encoding: 8bit From: Kumar Kartikeya Dwivedi [ Upstream commit 66d9111f3517f85ef2af0337ece02683ce0faf21 ] Now that bpf_throw kfunc is the first such call instruction that has noreturn semantics within the verifier, this also kicks in dead code elimination in unprecedented ways. For one, any instruction following a bpf_throw call will never be marked as seen. Moreover, if a callchain ends up throwing, any instructions after the call instruction to the eventually throwing subprog in callers will also never be marked as seen. The tempting way to fix this would be to emit extra 'int3' instructions which bump the jited_len of a program, and ensure that during runtime when a program throws, we can discover its boundaries even if the call instruction to bpf_throw (or to subprogs that always throw) is emitted as the final instruction in the program. An example of such a program would be this: do_something(): ... r0 = 0 exit foo(): r1 = 0 call bpf_throw r0 = 0 exit bar(cond): if r1 != 0 goto pc+2 call do_something exit call foo r0 = 0 // Never seen by verifier exit // main(ctx): r1 = ... call bar r0 = 0 exit Here, if we do end up throwing, the stacktrace would be the following: bpf_throw foo bar main In bar, the final instruction emitted will be the call to foo, as such, the return address will be the subsequent instruction (which the JIT emits as int3 on x86). This will end up lying outside the jited_len of the program, thus, when unwinding, we will fail to discover the return address as belonging to any program and end up in a panic due to the unreliable stack unwinding of BPF programs that we never expect. To remedy this case, make bpf_prog_ksym_find treat IP == ksym.end as part of the BPF program, so that is_bpf_text_address returns true when such a case occurs, and we are able to unwind reliably when the final instruction ends up being a call instruction. Signed-off-by: Kumar Kartikeya Dwivedi Link: https://lore.kernel.org/r/20230912233214.1518551-12-memxor@gmail.com Signed-off-by: Alexei Starovoitov Signed-off-by: Sasha Levin --- kernel/bpf/core.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index 64706723624b9..7225cb67c0d3a 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -608,7 +608,11 @@ static __always_inline int bpf_tree_comp(void *key, struct latch_tree_node *n) if (val < ksym->start) return -1; - if (val >= ksym->end) + /* Ensure that we detect return addresses as part of the program, when + * the final instruction is a call for a program part of the stack + * trace. Therefore, do val > ksym->end instead of val >= ksym->end. + */ + if (val > ksym->end) return 1; return 0; -- 2.42.0