diff mbox series

[bpf,v1,1/2] bpf: sync_linked_regs() must preserve subreg_def

Message ID 20240924210844.1758441-1-eddyz87@gmail.com (mailing list archive)
State Accepted
Commit 27cda47e781928290574e9d875dffaf43613dd3e
Delegated to: BPF
Headers show
Series [bpf,v1,1/2] bpf: sync_linked_regs() must preserve subreg_def | expand

Checks

Context Check Description
netdev/series_format success Single patches do not need cover letters
netdev/tree_selection success Clearly marked for bpf
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present fail Series targets non-next tree, but doesn't contain any Fixes tags
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 9 this patch: 9
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers warning 6 maintainers not CCed: song@kernel.org sdf@fomichev.me haoluo@google.com jolsa@kernel.org kpsingh@kernel.org john.fastabend@gmail.com
netdev/build_clang success Errors and warnings before: 7 this patch: 7
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 17 this patch: 17
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 19 lines checked
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
bpf/vmtest-bpf-PR success PR summary
bpf/vmtest-bpf-VM_Test-0 success Logs for Lint
bpf/vmtest-bpf-VM_Test-1 success Logs for ShellCheck
bpf/vmtest-bpf-VM_Test-2 success Logs for Unittests
bpf/vmtest-bpf-VM_Test-3 success Logs for Validate matrix.py
bpf/vmtest-bpf-VM_Test-5 success Logs for aarch64-gcc / build-release
bpf/vmtest-bpf-VM_Test-4 success Logs for aarch64-gcc / build / build for aarch64 with gcc
bpf/vmtest-bpf-VM_Test-12 success Logs for s390x-gcc / build-release
bpf/vmtest-bpf-VM_Test-10 success Logs for aarch64-gcc / veristat
bpf/vmtest-bpf-VM_Test-6 success Logs for aarch64-gcc / test (test_maps, false, 360) / test_maps on aarch64 with gcc
bpf/vmtest-bpf-VM_Test-9 success Logs for aarch64-gcc / test (test_verifier, false, 360) / test_verifier on aarch64 with gcc
bpf/vmtest-bpf-VM_Test-7 success Logs for aarch64-gcc / test (test_progs, false, 360) / test_progs on aarch64 with gcc
bpf/vmtest-bpf-VM_Test-8 success Logs for aarch64-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on aarch64 with gcc
bpf/vmtest-bpf-VM_Test-17 success Logs for set-matrix
bpf/vmtest-bpf-VM_Test-15 success Logs for s390x-gcc / test (test_verifier, false, 360) / test_verifier on s390x with gcc
bpf/vmtest-bpf-VM_Test-33 success Logs for x86_64-llvm-17 / veristat
bpf/vmtest-bpf-VM_Test-11 success Logs for s390x-gcc / build / build for s390x with gcc
bpf/vmtest-bpf-VM_Test-19 success Logs for x86_64-gcc / build-release
bpf/vmtest-bpf-VM_Test-16 success Logs for s390x-gcc / veristat
bpf/vmtest-bpf-VM_Test-28 success Logs for x86_64-llvm-17 / build-release / build for x86_64 with llvm-17-O2
bpf/vmtest-bpf-VM_Test-27 success Logs for x86_64-llvm-17 / build / build for x86_64 with llvm-17
bpf/vmtest-bpf-VM_Test-18 success Logs for x86_64-gcc / build / build for x86_64 with gcc
bpf/vmtest-bpf-VM_Test-14 success Logs for s390x-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on s390x with gcc
bpf/vmtest-bpf-VM_Test-13 success Logs for s390x-gcc / test (test_progs, false, 360) / test_progs on s390x with gcc
bpf/vmtest-bpf-VM_Test-35 success Logs for x86_64-llvm-18 / build-release / build for x86_64 with llvm-18-O2
bpf/vmtest-bpf-VM_Test-34 success Logs for x86_64-llvm-18 / build / build for x86_64 with llvm-18
bpf/vmtest-bpf-VM_Test-41 success Logs for x86_64-llvm-18 / veristat
bpf/vmtest-bpf-VM_Test-20 success Logs for x86_64-gcc / test (test_maps, false, 360) / test_maps on x86_64 with gcc
bpf/vmtest-bpf-VM_Test-23 success Logs for x86_64-gcc / test (test_progs_no_alu32_parallel, true, 30) / test_progs_no_alu32_parallel on x86_64 with gcc
bpf/vmtest-bpf-VM_Test-25 success Logs for x86_64-gcc / test (test_verifier, false, 360) / test_verifier on x86_64 with gcc
bpf/vmtest-bpf-VM_Test-26 success Logs for x86_64-gcc / veristat / veristat on x86_64 with gcc
bpf/vmtest-bpf-VM_Test-24 success Logs for x86_64-gcc / test (test_progs_parallel, true, 30) / test_progs_parallel on x86_64 with gcc
bpf/vmtest-bpf-VM_Test-29 success Logs for x86_64-llvm-17 / test (test_maps, false, 360) / test_maps on x86_64 with llvm-17
bpf/vmtest-bpf-VM_Test-21 success Logs for x86_64-gcc / test (test_progs, false, 360) / test_progs on x86_64 with gcc
bpf/vmtest-bpf-VM_Test-32 success Logs for x86_64-llvm-17 / test (test_verifier, false, 360) / test_verifier on x86_64 with llvm-17
bpf/vmtest-bpf-VM_Test-22 success Logs for x86_64-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with gcc
bpf/vmtest-bpf-VM_Test-40 success Logs for x86_64-llvm-18 / test (test_verifier, false, 360) / test_verifier on x86_64 with llvm-18
bpf/vmtest-bpf-VM_Test-36 success Logs for x86_64-llvm-18 / test (test_maps, false, 360) / test_maps on x86_64 with llvm-18
bpf/vmtest-bpf-VM_Test-31 success Logs for x86_64-llvm-17 / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with llvm-17
bpf/vmtest-bpf-VM_Test-30 success Logs for x86_64-llvm-17 / test (test_progs, false, 360) / test_progs on x86_64 with llvm-17
bpf/vmtest-bpf-VM_Test-38 success Logs for x86_64-llvm-18 / test (test_progs_cpuv4, false, 360) / test_progs_cpuv4 on x86_64 with llvm-18
bpf/vmtest-bpf-VM_Test-39 success Logs for x86_64-llvm-18 / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with llvm-18
bpf/vmtest-bpf-VM_Test-37 success Logs for x86_64-llvm-18 / test (test_progs, false, 360) / test_progs on x86_64 with llvm-18

Commit Message

Eduard Zingerman Sept. 24, 2024, 9:08 p.m. UTC
Range propagation must not affect subreg_def marks, otherwise the
following example is rewritten by verifier incorrectly when
BPF_F_TEST_RND_HI32 flag is set:

  0: call bpf_ktime_get_ns                   call bpf_ktime_get_ns
  1: r0 &= 0x7fffffff       after verifier   r0 &= 0x7fffffff
  2: w1 = w0                rewrites         w1 = w0
  3: if w0 < 10 goto +0     -------------->  r11 = 0x2f5674a6     (r)
  4: r1 >>= 32                               r11 <<= 32           (r)
  5: r0 = r1                                 r1 |= r11            (r)
  6: exit;                                   if w0 < 0xa goto pc+0
                                             r1 >>= 32
                                             r0 = r1
                                             exit

(or zero extension of w1 at (2) is missing for architectures that
 require zero extension for upper register half).

The following happens w/o this patch:
- r0 is marked as not a subreg at (0);
- w1 is marked as subreg at (2);
- w1 subreg_def is overridden at (3) by copy_register_state();
- w1 is read at (5) but mark_insn_zext() does not mark (2)
  for zero extension, because w1 subreg_def is not set;
- because of BPF_F_TEST_RND_HI32 flag verifier inserts random
  value for hi32 bits of (2) (marked (r));
- this random value is read at (5).

Reported-by: Lonial Con <kongln9170@gmail.com>
Closes: https://lore.kernel.org/bpf/7e2aa30a62d740db182c170fdd8f81c596df280d.camel@gmail.com/
Signed-off-by: Lonial Con <kongln9170@gmail.com>
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
---
 kernel/bpf/verifier.c | 5 +++++
 1 file changed, 5 insertions(+)

Comments

Daniel Borkmann Sept. 25, 2024, 9:44 a.m. UTC | #1
On 9/24/24 11:08 PM, Eduard Zingerman wrote:
> Range propagation must not affect subreg_def marks, otherwise the
> following example is rewritten by verifier incorrectly when
> BPF_F_TEST_RND_HI32 flag is set:
>
>    0: call bpf_ktime_get_ns                   call bpf_ktime_get_ns
>    1: r0 &= 0x7fffffff       after verifier   r0 &= 0x7fffffff
>    2: w1 = w0                rewrites         w1 = w0
>    3: if w0 < 10 goto +0     -------------->  r11 = 0x2f5674a6     (r)
>    4: r1 >>= 32                               r11 <<= 32           (r)
>    5: r0 = r1                                 r1 |= r11            (r)
>    6: exit;                                   if w0 < 0xa goto pc+0
>                                               r1 >>= 32
>                                               r0 = r1
>                                               exit
>
> (or zero extension of w1 at (2) is missing for architectures that
>   require zero extension for upper register half).
>
> The following happens w/o this patch:
> - r0 is marked as not a subreg at (0);
> - w1 is marked as subreg at (2);
> - w1 subreg_def is overridden at (3) by copy_register_state();
> - w1 is read at (5) but mark_insn_zext() does not mark (2)
>    for zero extension, because w1 subreg_def is not set;
> - because of BPF_F_TEST_RND_HI32 flag verifier inserts random
>    value for hi32 bits of (2) (marked (r));
> - this random value is read at (5).
>
> Reported-by: Lonial Con <kongln9170@gmail.com>
> Closes: https://lore.kernel.org/bpf/7e2aa30a62d740db182c170fdd8f81c596df280d.camel@gmail.com/
> Signed-off-by: Lonial Con <kongln9170@gmail.com>
> Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Do we have a Fixes tag for stable?
Eduard Zingerman Sept. 25, 2024, 7:48 p.m. UTC | #2
On Wed, 2024-09-25 at 11:44 +0200, Daniel Borkmann wrote:

[...]

> Do we have a Fixes tag for stable?

I think this bug persisted from the beginning:
75748837b7e5 ("bpf: Propagate scalar ranges through register assignments.")

E.g. here is original find_equal_scalars():
static void find_equal_scalars(struct bpf_verifier_state *vstate,
			       struct bpf_reg_state *known_reg)
{
	...
	struct bpf_reg_state *reg;
	...
				*reg = *known_reg;
	...
}

And bpf_reg_state for 75748837b7e5 has subreg_def as a member.

I can post v2 with this "Fixes" tag if you'd like.
Daniel Borkmann Sept. 25, 2024, 8:17 p.m. UTC | #3
On 9/25/24 9:48 PM, Eduard Zingerman wrote:
> On Wed, 2024-09-25 at 11:44 +0200, Daniel Borkmann wrote:
>
> [...]
>
>> Do we have a Fixes tag for stable?
> I think this bug persisted from the beginning:
> 75748837b7e5 ("bpf: Propagate scalar ranges through register assignments.")
>
> E.g. here is original find_equal_scalars():
> static void find_equal_scalars(struct bpf_verifier_state *vstate,
> 			       struct bpf_reg_state *known_reg)
> {
> 	...
> 	struct bpf_reg_state *reg;
> 	...
> 				*reg = *known_reg;
> 	...
> }
>
> And bpf_reg_state for 75748837b7e5 has subreg_def as a member.
>
> I can post v2 with this "Fixes" tag if you'd like.
No need, thanks, this can easily be added while applying.
patchwork-bot+netdevbpf@kernel.org Sept. 27, 2024, 11 p.m. UTC | #4
Hello:

This series was applied to bpf/bpf.git (master)
by Andrii Nakryiko <andrii@kernel.org>:

On Tue, 24 Sep 2024 14:08:43 -0700 you wrote:
> Range propagation must not affect subreg_def marks, otherwise the
> following example is rewritten by verifier incorrectly when
> BPF_F_TEST_RND_HI32 flag is set:
> 
>   0: call bpf_ktime_get_ns                   call bpf_ktime_get_ns
>   1: r0 &= 0x7fffffff       after verifier   r0 &= 0x7fffffff
>   2: w1 = w0                rewrites         w1 = w0
>   3: if w0 < 10 goto +0     -------------->  r11 = 0x2f5674a6     (r)
>   4: r1 >>= 32                               r11 <<= 32           (r)
>   5: r0 = r1                                 r1 |= r11            (r)
>   6: exit;                                   if w0 < 0xa goto pc+0
>                                              r1 >>= 32
>                                              r0 = r1
>                                              exit
> 
> [...]

Here is the summary with links:
  - [bpf,v1,1/2] bpf: sync_linked_regs() must preserve subreg_def
    https://git.kernel.org/bpf/bpf/c/27cda47e7819
  - [bpf,v1,2/2] selftests/bpf: verify that sync_linked_regs preserves subreg_def
    https://git.kernel.org/bpf/bpf/c/99a648c951ba

You are awesome, thank you!
diff mbox series

Patch

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index dd86282ccaa4..1aa0c6360a55 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -15326,8 +15326,12 @@  static void sync_linked_regs(struct bpf_verifier_state *vstate, struct bpf_reg_s
 			continue;
 		if ((!(reg->id & BPF_ADD_CONST) && !(known_reg->id & BPF_ADD_CONST)) ||
 		    reg->off == known_reg->off) {
+			s32 saved_subreg_def = reg->subreg_def;
+
 			copy_register_state(reg, known_reg);
+			reg->subreg_def = saved_subreg_def;
 		} else {
+			s32 saved_subreg_def = reg->subreg_def;
 			s32 saved_off = reg->off;
 
 			fake_reg.type = SCALAR_VALUE;
@@ -15340,6 +15344,7 @@  static void sync_linked_regs(struct bpf_verifier_state *vstate, struct bpf_reg_s
 			 * otherwise another sync_linked_regs() will be incorrect.
 			 */
 			reg->off = saved_off;
+			reg->subreg_def = saved_subreg_def;
 
 			scalar32_min_max_add(reg, &fake_reg);
 			scalar_min_max_add(reg, &fake_reg);