Re: [bpf PATCH 1/3] bpf: fix a verifier issue when assigning 32bit reg states to 64bit ones

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 





On 5/29/20 10:28 AM, John Fastabend wrote:
With the latest trunk llvm (llvm 11), I hit a verifier issue for
test_prog subtest test_verif_scale1.

The following simplified example illustrate the issue:
     w9 = 0  /* R9_w=inv0 */
     r8 = *(u32 *)(r1 + 80)  /* __sk_buff->data_end */
     r7 = *(u32 *)(r1 + 76)  /* __sk_buff->data */
     ......
     w2 = w9 /* R2_w=inv0 */
     r6 = r7 /* R6_w=pkt(id=0,off=0,r=0,imm=0) */
     r6 += r2 /* R6_w=inv(id=0) */
     r3 = r6 /* R3_w=inv(id=0) */
     r3 += 14 /* R3_w=inv(id=0) */
     if r3 > r8 goto end
     r5 = *(u32 *)(r6 + 0) /* R6_w=inv(id=0) */
        <== error here: R6 invalid mem access 'inv'
     ...
   end:

In real test_verif_scale1 code, "w9 = 0" and "w2 = w9" are in
different basic blocks.

In the above, after "r6 += r2", r6 becomes a scalar, which eventually
caused the memory access error. The correct register state should be
a pkt pointer.

The inprecise register state starts at "w2 = w9".
The 32bit register w9 is 0, in __reg_assign_32_into_64(),
the 64bit reg->smax_value is assigned to be U32_MAX.
The 64bit reg->smin_value is 0 and the 64bit register
itself remains constant based on reg->var_off.

In adjust_ptr_min_max_vals(), the verifier checks for a known constant,
smin_val must be equal to smax_val. Since they are not equal,
the verifier decides r6 is a unknown scalar, which caused later failure.

The llvm10 does not have this issue as it generates different code:
     w9 = 0  /* R9_w=inv0 */
     r8 = *(u32 *)(r1 + 80)  /* __sk_buff->data_end */
     r7 = *(u32 *)(r1 + 76)  /* __sk_buff->data */
     ......
     r6 = r7 /* R6_w=pkt(id=0,off=0,r=0,imm=0) */
     r6 += r9 /* R6_w=pkt(id=0,off=0,r=0,imm=0) */
     r3 = r6 /* R3_w=pkt(id=0,off=0,r=0,imm=0) */
     r3 += 14 /* R3_w=pkt(id=0,off=14,r=0,imm=0) */
     if r3 > r8 goto end
     ...

To fix the above issue, we can include zero in the test condition for
assigning the s32_max_value and s32_min_value to their 64-bit equivalents
smax_value and smin_value.

Further, fix the condition to avoid doing zero extension bounds checks
when s32_min_value <= 0. This could allow for the case where bounds
32-bit bounds (-1,1) get incorrectly translated to (0,1) 64-bit bounds.
When in-fact the -1 min value needs to force U32_MAX bound.

Fixes: 3f50f132d840 ("bpf: Verifier, do explicit ALU32 bounds tracking")
Signed-off-by: John Fastabend <john.fastabend@xxxxxxxxx>
---
  kernel/bpf/verifier.c |   10 +++++-----
  1 file changed, 5 insertions(+), 5 deletions(-)

Thanks for the fix. LGTM.
Acked-by: Yonghong Song <yhs@xxxxxx>



[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux