0

我编写了一个 XDP 程序来查看传入的 SCTP 数据包。

一个 SCTP 数据包可以包含多个块。我对包含应用程序层有效负载的 DATA 块特别感兴趣。现在,问题是单个 SCTP 消息中可以有许多 DATA 块。下面是一个wireshark 捕获并代表我正在处理的内容。

快照显示一个 SCTP 数据包中的多个块

我需要查看每个 DATA 块并运行一些逻辑。至于我的用例,我注意到捆绑到一个 SCTP 数据包中的总块数从不超过 32。

因此,我在 XDP 程序中使用了一个循环,硬编码为 32。程序编译得很好。但是当我尝试以 Native 模式将 XDP 程序加载到内核中时,它会显示“R7 偏移量在数据包之外”。因此,我尝试将迭代次数减少到 16 次,并且程序再次编译正常,但这次它也成功加载。

尝试再次回到 32(仅此更改而没有其他更改),但失败了。实在想不通为什么。在这方面的任何帮助将不胜感激。

我还应该提到,我需要处理每个块的逻辑有点冗长。也许这就是问题的原因?

以下是代码:

#define AMF_CPUS 4
#define INV_RET_U32 4294967295
#define INV_RET_U16 65535
#define INV_RET_U8 255
#define DATA_CHUNK 0

/* Header cursor to keep track of current parsing position */
struct hdr_cursor {
  void *pos;
};

// Return the chunk type of the corresponding sctp chunk
static __always_inline __u8 parse_sctp_chunk_type(void *data, void *data_end) {
  if (data + 1 > data_end)
    return INV_RET_U8;
  return *(__u8 *)data;
}

// Return the chunk size of the corresponding sctp chunk
static __always_inline __u16 parse_sctp_chunk_size(void *data, void *data_end) {
  if (data + 4 > data_end)
    return INV_RET_U16;
  __u16 size = bpf_ntohs(*(__u16 *)(data + 2));
  return size;
}

static __always_inline __u32 parse_sctp_hdr(struct hdr_cursor *nh,
                                            void *data_end) {
  struct sctphdr *sctph = nh->pos;
  int hdrsize = sizeof(*sctph);

  if (sctph + 1 > data_end)
    return INV_RET_U32;

  nh->pos += hdrsize;

#pragma clang loop unroll(full)
  for (int i = 0; i < 16; ++i) {
    __u8 type = parse_sctp_chunk_type(nh->pos, data_end);
    if (type == INV_RET_U8)
      return INV_RET_U32;

    __u16 size = parse_sctp_chunk_size(nh->pos, data_end);
    if (size > 512)
      return INV_RET_U32;

    //Adjust for padding
    size += (size % 4) == 0 ? 0 : 4 - size % 4;

    if (type == DATA_CHUNK) {
        // Run logic
    }

    if (nh->pos + size < data_end)
      nh->pos += size;
    else
      return INV_RET_U32;
  }
  return INV_RET_U32;
}

SEC("parse_sctp")
int xdp_parse_sctp(struct xdp_md *ctx) {
  void *data_end = (void *)(long)ctx->data_end;
  void *data = (void *)(long)ctx->data;

  /* These keep track of the next header type and iterator pointer */
  struct hdr_cursor nh;
  __u32 nh_type, ip_type;

  /* Start next header cursor position at data start */
  nh.pos = data;
  nh_type = parse_ethhdr(&nh, data_end);

  if (bpf_ntohs(nh_type) != ETH_P_IP)
    return XDP_PASS;

  ip_type = parse_iphdr(&nh, data_end);

  if (ip_type != IPPROTO_SCTP)
    return XDP_PASS;

  parse_sctp_hdr(&nh, data_end);
  return XDP_PASS;
}

char _license[] SEC("license") = "GPL";

以下是 eBPF 验证程序在加载上述程序时吐出的日志转储的最后几行:

完整日志可在此处获得。

; if (nh->pos + size < data_end)
2937: (57) r2 &= 65535
2938: (bf) r7 = r8
2939: (0f) r7 += r2
last_idx 2939 first_idx 2931
regs=4 stack=0 before 2938: (bf) r7 = r8
regs=4 stack=0 before 2937: (57) r2 &= 65535
regs=4 stack=0 before 2936: (0f) r2 += r1
regs=6 stack=0 before 2935: (79) r2 = *(u64 *)(r10 -40)
regs=2 stack=10 before 2934: (79) r1 = *(u64 *)(r10 -32)
regs=0 stack=18 before 2933: (6b) *(u16 *)(r8 +8) = r1
regs=0 stack=18 before 2932: (dc) r1 = be16 r1
regs=0 stack=18 before 2931: (57) r1 &= 3
 R0=map_value(id=0,off=0,ks=4,vs=2,imm=0) R1_r=inv(id=0,umax_value=4294967295,var_off=(0x0; 0xffffffff)) R2_w=pkt(id=65,off=37,r=55,umin_value=20,umax_value=8316,var_off=(0x0; 0xffffffff)) R6=pkt_end(id=0,off=0,imm=0) R7=pkt(id=65,off=27,r=55,umin_value=20,umax_value=8316,var_off=(0x0; 0xffffffff)) R8_r=pkt(id=65,off=26,r=55,umin_value=20,umax_value=8316,var_off=(0x0; 0xffffffff)) R9=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R10=fp0 fp-8=mmmm???? fp-24=pkt fp-32_r=mmmmmmmm fp-40_r=invP fp-48=pkt
parent didn't have regs=0 stack=10 marks
last_idx 2835 first_idx 2828
regs=0 stack=10 before 2835: (05) goto pc+95
regs=0 stack=10 before 2834: (2d) if r2 > r6 goto pc+99
regs=0 stack=10 before 2833: (07) r2 += 11
regs=0 stack=10 before 2832: (bf) r2 = r8
regs=0 stack=10 before 2831: (73) *(u8 *)(r7 +0) = r2
regs=0 stack=10 before 2830: (47) r2 |= 4
regs=0 stack=10 before 2829: (71) r2 = *(u8 *)(r7 +0)
regs=0 stack=10 before 2828: (3d) if r2 >= r6 goto pc+3
 R0_w=map_value(id=0,off=0,ks=4,vs=2,imm=0) R1_rw=inv(id=0,umax_value=4294967295,var_off=(0x0; 0xffffffff)) R2_rw=pkt(id=65,off=28,r=55,umin_value=20,umax_value=8316,var_off=(0x0; 0xffffffff)) R6_r=pkt_end(id=0,off=0,imm=0) R7_r=pkt(id=65,off=27,r=55,umin_value=20,umax_value=8316,var_off=(0x0; 0xffffffff)) R8_r=pkt(id=65,off=26,r=55,umin_value=20,umax_value=8316,var_off=(0x0; 0xffffffff)) R9=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R10=fp0 fp-8=mmmm???? fp-24=pkt fp-32_r=mmmmmmmm fp-40_r=invP fp-48=pkt
parent didn't have regs=0 stack=10 marks
last_idx 2827 first_idx 2817
regs=0 stack=10 before 2827: (79) r2 = *(u64 *)(r10 -24)
regs=0 stack=10 before 2826: (61) r1 = *(u32 *)(r10 -4)
regs=0 stack=10 before 2825: (15) if r1 == 0x0 goto pc+35
regs=0 stack=10 before 2824: (69) r1 = *(u16 *)(r0 +0)
regs=0 stack=10 before 2823: (15) if r0 == 0x0 goto pc+37
regs=0 stack=10 before 2822: (85) call bpf_map_lookup_elem#1
regs=0 stack=10 before 2820: (18) r1 = 0xffffb27245d41000
regs=0 stack=10 before 2819: (07) r2 += -4
regs=0 stack=10 before 2818: (bf) r2 = r10
regs=0 stack=10 before 2817: (15) if r2 == 0xffff goto pc-2758
 R0=map_value(id=0,off=0,ks=4,vs=2,imm=0) R1_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R2_rw=inv(id=0,umax_value=65535,var_off=(0x0; 0xffff)) R3=inv(id=0,umin_value=1,umax_value=4,var_off=(0x0; 0x7)) R6_r=pkt_end(id=0,off=0,imm=0) R7_r=pkt(id=65,off=27,r=55,umin_value=20,umax_value=8316,var_off=(0x0; 0xffffffff)) R8_r=pkt(id=65,off=26,r=55,umin_value=20,umax_value=8316,var_off=(0x0; 0xffffffff)) R9=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R10=fp0 fp-8_r=mmmm???? fp-24_r=pkt fp-32_r=mmmmmmmm fp-40_r=invP fp-48=pkt
parent didn't have regs=0 stack=10 marks
last_idx 2816 first_idx 2808
regs=0 stack=10 before 2816: (63) *(u32 *)(r10 -4) = r2
regs=0 stack=10 before 2815: (57) r2 &= 65535
regs=0 stack=10 before 2814: (4f) r2 |= r1
regs=0 stack=10 before 2813: (67) r2 <<= 8
regs=0 stack=10 before 2812: (71) r2 = *(u8 *)(r2 +27)
regs=0 stack=10 before 2811: (71) r1 = *(u8 *)(r2 +28)
regs=0 stack=10 before 2810: (55) if r1 != 0xa00 goto pc-2753
regs=0 stack=10 before 2809: (69) r1 = *(u16 *)(r2 +23)
regs=0 stack=10 before 2808: (2d) if r1 > r6 goto pc-2751
 R0=map_value(id=0,off=0,ks=4,vs=2,imm=0) R1_rw=pkt(id=65,off=55,r=44,umin_value=20,umax_value=8316,var_off=(0x0; 0xffffffff)) R2_rw=pkt(id=65,off=26,r=44,umin_value=20,umax_value=8316,var_off=(0x0; 0xffffffff)) R3=inv(id=0,umin_value=1,umax_value=4,var_off=(0x0; 0x7)) R6_r=pkt_end(id=0,off=0,imm=0) R7_r=pkt(id=65,off=27,r=44,umin_value=20,umax_value=8316,var_off=(0x0; 0xffffffff)) R8_r=pkt(id=65,off=26,r=44,umin_value=20,umax_value=8316,var_off=(0x0; 0xffffffff)) R9_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R10=fp0 fp-8_r=mmmm???? fp-24_rw=pkt fp-32_r=mmmmmmmm fp-40_r=invP fp-48_w=pkt
parent didn't have regs=0 stack=10 marks
last_idx 2807 first_idx 2798
regs=0 stack=10 before 2807: (7b) *(u64 *)(r10 -48) = r1
regs=0 stack=10 before 2806: (07) r1 += 29
regs=0 stack=10 before 2805: (bf) r1 = r2
regs=0 stack=10 before 2804: (bf) r2 = r8
regs=0 stack=10 before 2803: (15) if r9 == 0xf goto pc+32
regs=0 stack=10 before 2802: (71) r9 = *(u8 *)(r2 +17)
regs=0 stack=10 before 2801: (7b) *(u64 *)(r10 -24) = r1
regs=0 stack=10 before 2800: (07) r1 += 2
regs=0 stack=10 before 2799: (bf) r1 = r2
regs=0 stack=10 before 2798: (2d) if r1 > r6 goto pc-2739
 R0=map_value(id=0,off=0,ks=4,vs=2,imm=0) R1_rw=pkt(id=65,off=44,r=30,umin_value=20,umax_value=8316,var_off=(0x0; 0xffffffff)) R2_rw=pkt(id=65,off=26,r=30,umin_value=20,umax_value=8316,var_off=(0x0; 0xffffffff)) R3_w=inv(id=0,umin_value=1,umax_value=4,var_off=(0x0; 0x7)) R6_r=pkt_end(id=0,off=0,imm=0) R7_r=pkt(id=65,off=27,r=30,umin_value=20,umax_value=8316,var_off=(0x0; 0xffffffff)) R8_r=pkt(id=65,off=26,r=30,umin_value=20,umax_value=8316,var_off=(0x0; 0xffffffff)) R9=invP(id=0,umax_value=516,var_off=(0x0; 0xffff),s32_max_value=65535,u32_max_value=65535) R10=fp0 fp-8_r=mmmm???? fp-24=pkt fp-32_r=mmmmmmmm fp-40_rw=invP fp-48=pkt
parent didn't have regs=0 stack=10 marks
last_idx 2797 first_idx 2790
regs=0 stack=10 before 2797: (07) r1 += 18
regs=0 stack=10 before 2796: (bf) r1 = r2
regs=0 stack=10 before 2795: (bf) r2 = r8
regs=0 stack=10 before 2794: (55) if r1 != 0x0 goto pc+139
regs=0 stack=10 before 2793: (7b) *(u64 *)(r10 -40) = r3
regs=8 stack=0 before 2792: (1f) r3 -= r2
regs=c stack=0 before 2791: (b7) r3 = 4
regs=4 stack=0 before 2790: (15) if r2 == 0x0 goto pc+3
 R0=map_value(id=0,off=0,ks=4,vs=2,imm=0) R1_rw=inv(id=66,umax_value=255,var_off=(0x0; 0xff)) R2_rw=invP(id=0,umax_value=3,var_off=(0x0; 0x3)) R3_w=invP0 R6_r=pkt_end(id=0,off=0,imm=0) R7_r=pkt(id=65,off=27,r=30,umin_value=20,umax_value=8316,var_off=(0x0; 0xffffffff)) R8_r=pkt(id=65,off=26,r=30,umin_value=20,umax_value=8316,var_off=(0x0; 0xffffffff)) R9=invP(id=0,umax_value=516,var_off=(0x0; 0xffff),s32_max_value=65535,u32_max_value=65535) R10=fp0 fp-8_r=mmmm???? fp-24=pkt fp-32_rw=mmmmmmmm fp-40_w=00000000 fp-48=pkt
parent didn't have regs=4 stack=0 marks
last_idx 2789 first_idx 2778
regs=4 stack=0 before 2789: (7b) *(u64 *)(r10 -40) = r3
regs=4 stack=0 before 2788: (b7) r3 = 0
regs=4 stack=0 before 2787: (57) r2 &= 3
regs=4 stack=0 before 2786: (79) r2 = *(u64 *)(r10 -32)
regs=0 stack=8 before 2785: (25) if r2 > 0x200 goto pc-2726
regs=0 stack=8 before 2784: (7b) *(u64 *)(r10 -32) = r2
regs=4 stack=0 before 2783: (dc) r2 = be16 r2
regs=5 stack=0 before 2782: (69) r2 = *(u16 *)(r8 +2)
regs=1 stack=0 before 2781: (15) if r2 == 0xff goto pc-2722
regs=1 stack=0 before 2780: (bf) r2 = r1
regs=1 stack=0 before 2779: (71) r1 = *(u8 *)(r8 +0)
regs=1 stack=0 before 2778: (2d) if r1 > r6 goto pc-2719
 R0=map_value(id=0,off=0,ks=4,vs=2,imm=0) R1_rw=pkt(id=65,off=30,r=27,umin_value=20,umax_value=8316,var_off=(0x0; 0xffffffff)) R2_w=pkt(id=61,off=26,r=55,umin_value=20,umax_value=7800,var_off=(0x0; 0x7fffffff),s32_min_value=0,u32_max_value=2147483647) R6_r=pkt_end(id=0,off=0,imm=0) R7_rw=pkt(id=65,off=27,r=27,umin_value=20,umax_value=8316,var_off=(0x0; 0xffffffff)) R8_rw=pkt(id=65,off=26,r=27,umin_value=20,umax_value=8316,var_off=(0x0; 0xffffffff)) R9_w=invP(id=0,umax_value=516,var_off=(0x0; 0xffff),s32_max_value=65535,u32_max_value=65535) R10=fp0 fp-8_r=mmmm???? fp-24=pkt fp-32=pkt fp-40=inv fp-48=pkt
parent already had regs=0 stack=0 marks
; if (nh->pos + size < data_end)
2940: (3d) if r7 >= r6 goto pc-2881
 R0=map_value(id=0,off=0,ks=4,vs=2,imm=0) R1_w=inv(id=0) R2_w=invP(id=0,umax_value=65535,var_off=(0x0; 0xffff)) R6=pkt_end(id=0,off=0,imm=0) R7_w=pkt(id=68,off=26,r=0,umin_value=20,umax_value=73851,var_off=(0x0; 0xffffffff)) R8=pkt(id=65,off=26,r=55,umin_value=20,umax_value=8316,var_off=(0x0; 0xffffffff)) R9=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R10=fp0 fp-8=mmmm???? fp-24=pkt fp-32=mmmmmmmm fp-40=inv fp-48=pkt
2941: (bf) r1 = r7
2942: (07) r1 += 1
2943: (7b) *(u64 *)(r10 -24) = r1
2944: (2d) if r1 > r6 goto pc-2885
 R0=map_value(id=0,off=0,ks=4,vs=2,imm=0) R1_w=pkt(id=68,off=27,r=0,umin_value=20,umax_value=73851,var_off=(0x0; 0xffffffff)) R2_w=invP(id=0,umax_value=65535,var_off=(0x0; 0xffff)) R6=pkt_end(id=0,off=0,imm=0) R7_w=pkt(id=68,off=26,r=0,umin_value=20,umax_value=73851,var_off=(0x0; 0xffffffff)) R8=pkt(id=65,off=26,r=55,umin_value=20,umax_value=8316,var_off=(0x0; 0xffffffff)) R9=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R10=fp0 fp-8=mmmm???? fp-24_w=pkt fp-32=mmmmmmmm fp-40=inv fp-48=pkt
2945: (bf) r1 = r7
2946: (07) r1 += 4
; if (type == INV_RET_U8)
2947: (2d) if r1 > r6 goto pc-2888
 R0=map_value(id=0,off=0,ks=4,vs=2,imm=0) R1=pkt(id=68,off=30,r=0,umin_value=20,umax_value=73851,var_off=(0x0; 0xffffffff)) R2=invP(id=0,umax_value=65535,var_off=(0x0; 0xffff)) R6=pkt_end(id=0,off=0,imm=0) R7=pkt(id=68,off=26,r=0,umin_value=20,umax_value=73851,var_off=(0x0; 0xffffffff)) R8=pkt(id=65,off=26,r=55,umin_value=20,umax_value=8316,var_off=(0x0; 0xffffffff)) R9=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R10=fp0 fp-8=mmmm???? fp-24=pkt fp-32=mmmmmmmm fp-40=inv fp-48=pkt
2948: (71) r1 = *(u8 *)(r7 +0)
invalid access to packet, off=26 size=1, R7(id=68,off=26,r=0)
R7 offset is outside of the packet
processed 1225 insns (limit 1000000) max_states_per_insn 0 total_states 107 peak_states 107 mark_read 7

libbpf: -- END LOG --
libbpf: failed to load program 'xdp_cpu_redirect_stream'
libbpf: failed to load object 'xdp_stream_nat_new.o'
ERR: loading BPF-OBJ file(xdp_stream_nat_new.o) (-4007): Unknown error 4007
ERR: loading file: xdp_stream_nat_new.o
4

1 回答 1

3

TL;博士。您遇到了 verifier 的极端情况限制for将循环的结尾更改为以下内容可能会有所帮助。

#define MAX_PACKET_OFF 0xffff
...
nh->pos += size;
if (nh->pos > MAX_PACKET_OFF)
     return INV_RET_U32;
if (nh->pos >= data_end)
    return INV_RET_U32;

完整的解释有点长,见下文。


验证器错误说明

2945: (bf) r1 = r7
2946: (07) r1 += 4
2947: (2d) if r1 > r6 goto pc-2888
 R0=map_value(id=0,off=0,ks=4,vs=2,imm=0) R1=pkt(id=68,off=30,r=0,umin_value=20,umax_value=73851,var_off=(0x0; 0xffffffff)) R2=invP(id=0,umax_value=65535,var_off=(0x0; 0xffff)) R6=pkt_end(id=0,off=0,imm=0) R7=pkt(id=68,off=26,r=0,umin_value=20,umax_value=73851,var_off=(0x0; 0xffffffff)) R8=pkt(id=65,off=26,r=55,umin_value=20,umax_value=8316,var_off=(0x0; 0xffffffff)) R9=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R10=fp0 fp-8=mmmm???? fp-24=pkt fp-32=mmmmmmmm fp-40=inv fp-48=pkt
2948: (71) r1 = *(u8 *)(r7 +0)
invalid access to packet, off=26 size=1, R7(id=68,off=26,r=0)
R7 offset is outside of the packet

验证器出错是因为它认为R7超出了数据包的已知范围。它告诉我们您正在尝试在偏移量 26 处对数据包指针进行大小为 1B 的访问,但数据包的已知大小为 0 ( r=0, for range=0)。

最大数据包大小限制

这很奇怪,因为您确实检查了数据包边界。在指令 2947 上,将包指针R1R6指向包末尾的指针进行比较。因此,在检查之后,R1应该更新已知的最小大小,但它仍然是 0 ( r=0)。

发生这种情况是因为您遇到了验证者的极端情况限制

if (dst_reg->umax_value > MAX_PACKET_OFF ||
    dst_reg->umax_value + dst_reg->off > MAX_PACKET_OFF)
    /* Risk of overflow.  For instance, ptr + (1<<63) may be less
     * than pkt_end, but that's because it's also less than pkt.
     */
    return;

如评论中所述,此检查是为了防止溢出。由于R1的无符号最大值是 73851 ( umax_value=73851),因此条件为真,并且不更新数据包的已知大小。

防止这种情况发生的一种方法可能是确保对 R1 进行额外的边界检查。例如:

#define MAX_PACKET_OFF 0xffff
...
if (nh->pos + size > MAX_PACKET_OFF)
     return INV_RET_U32;

为什么 R1 的无符号最大值如此之高?

R1来自R7,根据这些指令进行初始化:

2934: (79) r1 = *(u64 *)(r10 -32)
2935: (79) r2 = *(u64 *)(r10 -40)
2936: (0f) r2 += r1
; if (nh->pos + size < data_end)
2937: (57) r2 &= 65535
2938: (bf) r7 = r8
2939: (0f) r7 += r2
; if (nh->pos + size < data_end)
2940: (3d) if r7 >= r6 goto pc-2881
 R0=map_value(id=0,off=0,ks=4,vs=2,imm=0) R1_w=inv(id=0) R2_w=invP(id=0,umax_value=65535,var_off=(0x0; 0xffff)) R6=pkt_end(id=0,off=0,imm=0) R7_w=pkt(id=68,off=26,r=0,umin_value=20,umax_value=73851,var_off=(0x0; 0xffffffff)) R8=pkt(id=65,off=26,r=55,umin_value=20,umax_value=8316,var_off=(0x0; 0xffffffff)) R9=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R10=fp0 fp-8=mmmm???? fp-24=pkt fp-32=mmmmmmmm fp-40=inv fp-48=pkt

从堆栈中检索两个值,偏移量为 -32 和 -40。添加的这两个值保持变量size。因为size是 a __u16,所以它与 65535(最大值__u16)进行与运算。因此验证者识别出R2最大值为 65535。

R2加上时,R7R7最大值当然变得大于MAX_PACKET_OFF = 65535

验证者不应该理解 size < 516 吗?

以下代码确保大小永远不会大于 516(最坏情况下为 512 + 4):

__u16 size = parse_sctp_chunk_size(nh->pos, data_end);
if (size > 512)
  return INV_RET_U32;

//Adjust for padding
size += (size % 4) == 0 ? 0 : 4 - size % 4;

那么为什么验证者会失去对它的追踪呢?

部分变量size保存在堆栈中,偏移量 -32,这里:

2782: (69) r2 = *(u16 *)(r8 +2)
2783: (dc) r2 = be16 r2
2784: (7b) *(u64 *)(r10 -32) = r2
; if (size > 512)
2785: (25) if r2 > 0x200 goto pc-2726
 R0=map_value(id=0,off=0,ks=4,vs=2,imm=0) R1_w=inv(id=66,umax_value=255,var_off=(0x0; 0xff)) R2_w=inv(id=0,umax_value=512,var_off=(0x0; 0xffffffff)) R6=pkt_end(id=0,off=0,imm=0) R7=pkt(id=65,off=27,r=30,umin_value=20,umax_value=8316,var_off=(0x0; 0xffffffff)) R8=pkt(id=65,off=26,r=30,umin_value=20,umax_value=8316,var_off=(0x0; 0xffffffff)) R9=invP(id=0,umax_value=516,var_off=(0x0; 0xffff),s32_max_value=65535,u32_max_value=65535) R10=fp0 fp-8=mmmm???? fp-24=pkt fp-32_w=mmmmmmmm fp-40=inv fp-48=pkt

不幸的是,在与 512 进行比较之前,该值已保存在堆栈中。因此,验证者不知道堆栈中保存的值小于 512。我们可以看到,因为fp-32_w=mmmmmmmm. msMISC表示; 也就是说,从验证者的角度来看,该值可以是任何值。

相信在最近的 Linux 版本中消除了验证器的这种限制。


为什么这个问题只出现在 32 次迭代中?

我怀疑该变量size仅在程序变得非常大时才保存在堆栈中。只要变量没有保存在堆栈中,验证者就不会忘记它的最大值 516。

于 2022-01-16T15:37:46.173 回答