diff options
author | Yonghong Song <yhs@fb.com> | 2018-04-29 01:28:11 -0400 |
---|---|---|
committer | Alexei Starovoitov <ast@kernel.org> | 2018-04-29 11:45:53 -0400 |
commit | 9cbe1f5a32dcd6d0508326f7d9098e5bc380a4fe (patch) | |
tree | 714686f3ad67476c1f58b86988bb9246d9064d67 /include/linux/tnum.h | |
parent | afbe1a5b79cd18f0ace9107e6b4cd7aa193e5e52 (diff) |
bpf/verifier: improve register value range tracking with ARSH
When helpers like bpf_get_stack returns an int value
and later on used for arithmetic computation, the LSH and ARSH
operations are often required to get proper sign extension into
64-bit. For example, without this patch:
54: R0=inv(id=0,umax_value=800)
54: (bf) r8 = r0
55: R0=inv(id=0,umax_value=800) R8_w=inv(id=0,umax_value=800)
55: (67) r8 <<= 32
56: R8_w=inv(id=0,umax_value=3435973836800,var_off=(0x0; 0x3ff00000000))
56: (c7) r8 s>>= 32
57: R8=inv(id=0)
With this patch:
54: R0=inv(id=0,umax_value=800)
54: (bf) r8 = r0
55: R0=inv(id=0,umax_value=800) R8_w=inv(id=0,umax_value=800)
55: (67) r8 <<= 32
56: R8_w=inv(id=0,umax_value=3435973836800,var_off=(0x0; 0x3ff00000000))
56: (c7) r8 s>>= 32
57: R8=inv(id=0, umax_value=800,var_off=(0x0; 0x3ff))
With better range of "R8", later on when "R8" is added to other register,
e.g., a map pointer or scalar-value register, the better register
range can be derived and verifier failure may be avoided.
In our later example,
......
usize = bpf_get_stack(ctx, raw_data, max_len, BPF_F_USER_STACK);
if (usize < 0)
return 0;
ksize = bpf_get_stack(ctx, raw_data + usize, max_len - usize, 0);
......
Without improving ARSH value range tracking, the register representing
"max_len - usize" will have smin_value equal to S64_MIN and will be
rejected by verifier.
Acked-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Yonghong Song <yhs@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'include/linux/tnum.h')
-rw-r--r-- | include/linux/tnum.h | 4 |
1 files changed, 3 insertions, 1 deletions
diff --git a/include/linux/tnum.h b/include/linux/tnum.h index 0d2d3da46139..c7dc2b5902c0 100644 --- a/include/linux/tnum.h +++ b/include/linux/tnum.h | |||
@@ -23,8 +23,10 @@ struct tnum tnum_range(u64 min, u64 max); | |||
23 | /* Arithmetic and logical ops */ | 23 | /* Arithmetic and logical ops */ |
24 | /* Shift a tnum left (by a fixed shift) */ | 24 | /* Shift a tnum left (by a fixed shift) */ |
25 | struct tnum tnum_lshift(struct tnum a, u8 shift); | 25 | struct tnum tnum_lshift(struct tnum a, u8 shift); |
26 | /* Shift a tnum right (by a fixed shift) */ | 26 | /* Shift (rsh) a tnum right (by a fixed shift) */ |
27 | struct tnum tnum_rshift(struct tnum a, u8 shift); | 27 | struct tnum tnum_rshift(struct tnum a, u8 shift); |
28 | /* Shift (arsh) a tnum right (by a fixed min_shift) */ | ||
29 | struct tnum tnum_arshift(struct tnum a, u8 min_shift); | ||
28 | /* Add two tnums, return @a + @b */ | 30 | /* Add two tnums, return @a + @b */ |
29 | struct tnum tnum_add(struct tnum a, struct tnum b); | 31 | struct tnum tnum_add(struct tnum a, struct tnum b); |
30 | /* Subtract two tnums, return @a - @b */ | 32 | /* Subtract two tnums, return @a - @b */ |