BPF List
 help / color / mirror / Atom feed
From: Eduard Zingerman <eddyz87@gmail.com>
To: Andrei Matei <andreimatei1@gmail.com>,
	bpf@vger.kernel.org,  andrii.nakryiko@gmail.com
Cc: sunhao.th@gmail.com, kernel-team@dataexmachina.dev
Subject: Re: [PATCH bpf v2 1/2] bpf: fix accesses to uninit stack slots
Date: Tue, 28 Nov 2023 03:33:36 +0200	[thread overview]
Message-ID: <2facccd4023ee77059fe483e0b1a21f6ef36e16e.camel@gmail.com> (raw)
In-Reply-To: <20231126015045.1092826-2-andreimatei1@gmail.com>

On Sat, 2023-11-25 at 20:50 -0500, Andrei Matei wrote:
> Privileged programs are supposed to be able to read uninitialized stack
> memory (ever since 6715df8d5) but, before this patch, these accesses
> were permitted inconsistently. In particular, accesses were permitted
> above state->allocated_stack, but not below it. In other words, if the
> stack was already "large enough", the access was permitted, but
> otherwise the access was rejected instead of being allowed to "grow the
> stack". This undesired rejection was happening in two places:
> - in check_stack_slot_within_bounds()
> - in check_stack_range_initialized()
> This patch arranges for these accesses to be permitted.
> 
> This patch also fixes the tracking of the stack size for variable-offset
> reads. This second fix is bundled in the same commit as the first one
> because they're inter-related. Before this patch, writes to the stack
> using registers containing a variable offset (as opposed to registers
> with fixed, known values) were not properly contributing to the
> function's needed stack size. As a result, it was possible for a program
> to verify, but then to attempt to read out-of-bounds data at runtime
> because a too small stack had been allocated for it.
> 
> Each function tracks the size of the stack it needs in
> bpf_subprog_info.stack_depth, which is maintained by
> update_stack_depth(). For regular memory accesses, check_mem_access()
> was calling update_state_depth() but it was passing in only the fixed
> part of the offset register, ignoring the variable offset. This was
> incorrect; the minimum possible value of that register should be used
> instead.
> 
> This tracking is now fixed by centralizing the tracking of stack size in
> grow_stack_state(), and by lifting the calls to grow_stack_state() to
> check_stack_access_within_bounds() as suggested by Andrii. The code is
> now simpler and more convincingly tracks the correct maximum stack size.
> check_stack_range_initialized() can now rely on enough stack having been
> allocated for the access; this helps with the fix for the first issue.
> 
> Reported-by: Hao Sun <sunhao.th@gmail.com>
> Fixes: 01f810ace9ed3 ("bpf: Allow variable-offset stack access")
> Closes: https://lore.kernel.org/bpf/CABWLsev9g8UP_c3a=1qbuZUi20tGoUXoU07FPf-5FLvhOKOY+Q@mail.gmail.com/
> Signed-off-by: Andrei Matei <andreimatei1@gmail.com>
> ---

I think these changes make sense.
Question: would it be possible to recover some of the tests (those
converted from failure to success) by changing execution mode from
priv to unpriv?
  
Also, I think there are some tests that do oob stack read in branches
that should be proven unreachable, with expectation that if certain
verifier logic does not work as expected stack access would serve as a
canary. Have no idea how to identify these tests, though.

Acked-by: Eduard Zingerman <eddyz87@gmail.com>

[...]
> @@ -1697,6 +1699,12 @@ static int grow_stack_state(struct bpf_func_state *state, int size)
>  		return -ENOMEM;
>  
>  	state->allocated_stack = size;
> +
> +	/* update known max for given subprogram */
> +	u16 stack = env->subprog_info[state->subprogno].stack_depth;

Nit: 'u16 stack;' should be at the top of the function.

> +	if (stack < size)
> +		env->subprog_info[state->subprogno].stack_depth = size;
> +
>  	return 0;
>  }

[...]

  reply	other threads:[~2023-11-28  1:33 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-11-26  1:50 [PATCH bpf v2 0/2] bpf: fix accesses to uninit stack slots Andrei Matei
2023-11-26  1:50 ` [PATCH bpf v2 1/2] " Andrei Matei
2023-11-28  1:33   ` Eduard Zingerman [this message]
2023-11-28  1:43     ` Eduard Zingerman
2023-11-28 14:14     ` Eduard Zingerman
2023-11-29  6:05   ` Andrii Nakryiko
2023-11-29 16:48     ` Andrei Matei
2023-11-29 23:54       ` Andrii Nakryiko
2023-12-02 22:41         ` Andrei Matei
2023-11-26  1:50 ` [PATCH bpf v2 2/2] bpf: new verifier tests for stack access Andrei Matei
2023-11-28  1:23   ` Eduard Zingerman
2023-11-28  3:15     ` Andrei Matei
2023-11-28 12:55       ` Eduard Zingerman
2023-11-29  6:12         ` 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=2facccd4023ee77059fe483e0b1a21f6ef36e16e.camel@gmail.com \
    --to=eddyz87@gmail.com \
    --cc=andreimatei1@gmail.com \
    --cc=andrii.nakryiko@gmail.com \
    --cc=bpf@vger.kernel.org \
    --cc=kernel-team@dataexmachina.dev \
    --cc=sunhao.th@gmail.com \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox