From: Andrii Nakryiko <andrii@kernel.org>
To: <bpf@vger.kernel.org>, <ast@kernel.org>, <daniel@iogearbox.net>,
<martin.lau@kernel.org>
Cc: <andrii@kernel.org>, <kernel-team@meta.com>,
Eduard Zingerman <eddyz87@gmail.com>
Subject: [PATCH v3 bpf-next 04/10] bpf: preserve STACK_ZERO slots on partial reg spills
Date: Mon, 4 Dec 2023 11:25:55 -0800 [thread overview]
Message-ID: <20231204192601.2672497-5-andrii@kernel.org> (raw)
In-Reply-To: <20231204192601.2672497-1-andrii@kernel.org>
Instead of always forcing STACK_ZERO slots to STACK_MISC, preserve it in
situations where this is possible. E.g., when spilling register as
1/2/4-byte subslots on the stack, all the remaining bytes in the stack
slot do not automatically become unknown. If we knew they contained
zeroes, we can preserve those STACK_ZERO markers.
Add a helper mark_stack_slot_misc(), similar to scrub_spilled_slot(),
but that doesn't overwrite either STACK_INVALID nor STACK_ZERO. Note
that we need to take into account possibility of being in unprivileged
mode, in which case STACK_INVALID is forced to STACK_MISC for correctness,
as treating STACK_INVALID as equivalent STACK_MISC is only enabled in
privileged mode.
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
---
kernel/bpf/verifier.c | 28 +++++++++++++++++++++++-----
1 file changed, 23 insertions(+), 5 deletions(-)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 73315e2f20d9..e96c53d0a112 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -1144,6 +1144,21 @@ static bool is_spilled_scalar_reg(const struct bpf_stack_state *stack)
stack->spilled_ptr.type == SCALAR_VALUE;
}
+/* Mark stack slot as STACK_MISC, unless it is already STACK_INVALID, in which
+ * case they are equivalent, or it's STACK_ZERO, in which case we preserve
+ * more precise STACK_ZERO.
+ * Note, in uprivileged mode leaving STACK_INVALID is wrong, so we take
+ * env->allow_ptr_leaks into account and force STACK_MISC, if necessary.
+ */
+static void mark_stack_slot_misc(struct bpf_verifier_env *env, u8 *stype)
+{
+ if (*stype == STACK_ZERO)
+ return;
+ if (env->allow_ptr_leaks && *stype == STACK_INVALID)
+ return;
+ *stype = STACK_MISC;
+}
+
static void scrub_spilled_slot(u8 *stype)
{
if (*stype != STACK_INVALID)
@@ -4386,7 +4401,8 @@ static void copy_register_state(struct bpf_reg_state *dst, const struct bpf_reg_
dst->live = live;
}
-static void save_register_state(struct bpf_func_state *state,
+static void save_register_state(struct bpf_verifier_env *env,
+ struct bpf_func_state *state,
int spi, struct bpf_reg_state *reg,
int size)
{
@@ -4401,7 +4417,7 @@ static void save_register_state(struct bpf_func_state *state,
/* size < 8 bytes spill */
for (; i; i--)
- scrub_spilled_slot(&state->stack[spi].slot_type[i - 1]);
+ mark_stack_slot_misc(env, &state->stack[spi].slot_type[i - 1]);
}
static bool is_bpf_st_mem(struct bpf_insn *insn)
@@ -4463,7 +4479,7 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env,
mark_stack_slot_scratched(env, spi);
if (reg && !(off % BPF_REG_SIZE) && register_is_bounded(reg) &&
!register_is_null(reg) && env->bpf_capable) {
- save_register_state(state, spi, reg, size);
+ save_register_state(env, state, spi, reg, size);
/* Break the relation on a narrowing spill. */
if (fls64(reg->umax_value) > BITS_PER_BYTE * size)
state->stack[spi].spilled_ptr.id = 0;
@@ -4473,7 +4489,7 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env,
__mark_reg_known(&fake_reg, insn->imm);
fake_reg.type = SCALAR_VALUE;
- save_register_state(state, spi, &fake_reg, size);
+ save_register_state(env, state, spi, &fake_reg, size);
insn_flags = 0; /* not a register spill */
} else if (reg && is_spillable_regtype(reg->type)) {
/* register containing pointer is being spilled into stack */
@@ -4486,7 +4502,7 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env,
verbose(env, "cannot spill pointers to stack into stack frame of the caller\n");
return -EINVAL;
}
- save_register_state(state, spi, reg, size);
+ save_register_state(env, state, spi, reg, size);
} else {
u8 type = STACK_MISC;
@@ -4757,6 +4773,8 @@ static int check_stack_read_fixed_off(struct bpf_verifier_env *env,
continue;
if (type == STACK_MISC)
continue;
+ if (type == STACK_ZERO)
+ continue;
if (type == STACK_INVALID && env->allow_uninit_stack)
continue;
verbose(env, "invalid read from stack off %d+%d size %d\n",
--
2.34.1
next prev parent reply other threads:[~2023-12-04 19:26 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-12-04 19:25 [PATCH v3 bpf-next 00/10] Complete BPF verifier precision tracking support for register spills Andrii Nakryiko
2023-12-04 19:25 ` [PATCH v3 bpf-next 01/10] bpf: support non-r10 register spill/fill to/from stack in precision tracking Andrii Nakryiko
2023-12-04 19:25 ` [PATCH v3 bpf-next 02/10] selftests/bpf: add stack access precision test Andrii Nakryiko
2023-12-04 19:25 ` [PATCH v3 bpf-next 03/10] bpf: fix check for attempt to corrupt spilled pointer Andrii Nakryiko
2023-12-04 22:12 ` Eduard Zingerman
2023-12-04 22:15 ` Eduard Zingerman
2023-12-05 0:23 ` Andrii Nakryiko
2023-12-05 0:54 ` Eduard Zingerman
2023-12-05 3:56 ` Andrii Nakryiko
2023-12-05 13:34 ` Eduard Zingerman
2023-12-05 18:30 ` Andrii Nakryiko
2023-12-05 18:49 ` Eduard Zingerman
2023-12-05 18:55 ` Andrii Nakryiko
2023-12-05 1:45 ` Alexei Starovoitov
2023-12-05 3:50 ` Andrii Nakryiko
2023-12-04 19:25 ` Andrii Nakryiko [this message]
2023-12-04 19:25 ` [PATCH v3 bpf-next 05/10] selftests/bpf: validate STACK_ZERO is preserved on subreg spill Andrii Nakryiko
2023-12-04 19:25 ` [PATCH v3 bpf-next 06/10] bpf: preserve constant zero when doing partial register restore Andrii Nakryiko
2023-12-04 19:25 ` [PATCH v3 bpf-next 07/10] selftests/bpf: validate zero preservation for sub-slot loads Andrii Nakryiko
2023-12-04 19:25 ` [PATCH v3 bpf-next 08/10] bpf: track aligned STACK_ZERO cases as imprecise spilled registers Andrii Nakryiko
2023-12-04 19:26 ` [PATCH v3 bpf-next 09/10] selftests/bpf: validate precision logic in partial_stack_load_preserves_zeros Andrii Nakryiko
2023-12-04 19:26 ` [PATCH v3 bpf-next 10/10] bpf: use common instruction history across all states Andrii Nakryiko
2023-12-04 22:32 ` [PATCH v3 bpf-next 00/10] Complete BPF verifier precision tracking support for register spills Andrii Nakryiko
2023-12-04 23:02 ` Yonghong Song
2023-12-04 23:52 ` Andrii Nakryiko
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20231204192601.2672497-5-andrii@kernel.org \
--to=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=eddyz87@gmail.com \
--cc=kernel-team@meta.com \
--cc=martin.lau@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.