我正试图从XDP程序中TLS hello数据包的SNI扩展中获取服务器名称。当我尝试加载它时,我从BPF验证器得到以下错误:invalid access to packet
struct server_name {
char server_name[256];
};
struct extension {
__u16 type;
__u16 len;
} __attribute__((packed));
struct sni_extension {
__u16 list_len;
__u8 type;
__u16 len;
} __attribute__((packed));
#define SERVER_NAME_EXTENSION 0
SEC("xdp")
int collect_ips_prog(struct xdp_md *ctx) {
char *data_end = (char *)(long)ctx->data_end;
char *data = (char *)(long)ctx->data;
if (data_end < (data + sizeof(__u16))) {
goto end;
}
__u16 extension_method_len = __bpf_htons(*(__u16 *) data);
data += sizeof(__u16);
for(int i = 0; i < extension_method_len; i += sizeof(struct extension)) {
if (data_end < (data + sizeof(struct extension))) {
goto end;
}
struct extension *ext = (struct extension *) data;
data += sizeof(struct extension);
///////////////////// (A) ////////////////////
if (data_end < ((char *) ext) + sizeof(struct extension)) {
goto end;
}
if (ext->type == SERVER_NAME_EXTENSION) { // Error happens here
struct server_name sn;
if (data_end < (data + sizeof(struct sni_extension))) {
goto end;
}
struct sni_extension *sni = (struct sni_extension *) data;
data += sizeof(struct sni_extension);
__u16 server_name_len = __bpf_htons(sni->len);
for(int sn_idx = 0; sn_idx < server_name_len; sn_idx++) {
if (data_end < data + sn_idx) {
goto end;
}
if (sn.server_name + sizeof(struct server_name) < sn.server_name + sn_idx) {
goto end;
}
sn.server_name[sn_idx] = data[sn_idx];
}
sn.server_name[server_name_len] = 0;
goto end;
}
__u16 ext_len = __bpf_htons(ext->len);
if (ext_len > 30000) {
goto end;
}
if (data_end < data + ext_len) {
goto end;
}
data += ext_len;
i += ext_len;
}
end:
return XDP_PASS;
}
忽略data
没有指向TLS数据包的扩展长度字段的开头;我没有包括进入这个领域的代码,因为上面的代码足以重现我看到的问题。
这是我尝试加载此程序时的错误日志的末尾。最后的错误发生在if (ext->type == SERVER_NAME_EXTENSION) {
:
from 31 to 12: R0_w=pkt(id=14,off=58,r=0,umax_value=42000,var_off=(0x0; 0xffffffff)) R1=inv(id=0) R2=pkt_end(id=0,off=0,imm=0) R3_w=inv(id=0,umin_value=56,umax_value=42056,var_off=(0x0; 0xffff),s32_min_value=0,s32_max_value=65535,u32_max_value=65535) R4=inv17179869184 R5_w=pkt(id=14,off=58,r=0,umax_value=42000,var_off=(0x0; 0xffffffff)) R6_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R7_w=inv(id=0) R10=fp0
; if (data_end < (data + sizeof(struct extension))) {
12: (07) r5 += 4
; if (data_end < (data + sizeof(struct extension))) {
13: (2d) if r5 > r2 goto pc+18
R0_w=pkt(id=14,off=58,r=62,umax_value=42000,var_off=(0x0; 0xffffffff)) R1=inv(id=0) R2=pkt_end(id=0,off=0,imm=0) R3_w=inv(id=0,umin_value=56,umax_value=42056,var_off=(0x0; 0xffff),s32_min_value=0,s32_max_value=65535,u32_max_value=65535) R4=inv17179869184 R5_w=pkt(id=14,off=62,r=62,umax_value=42000,var_off=(0x0; 0xffffffff)) R6_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R7_w=inv(id=0) R10=fp0
; if (ext->type == SERVER_NAME_EXTENSION) {
14: (71) r6 = *(u8 *)(r0 +0)
15: (71) r7 = *(u8 *)(r0 +1)
16: (67) r7 <<= 8
17: (4f) r7 |= r6
; if (ext->type == SERVER_NAME_EXTENSION) {
18: (15) if r7 == 0x0 goto pc+13
R0_w=pkt(id=14,off=58,r=62,umax_value=42000,var_off=(0x0; 0xffffffff)) R1=inv(id=0) R2=pkt_end(id=0,off=0,imm=0) R3_w=inv(id=0,umin_value=56,umax_value=42056,var_off=(0x0; 0xffff),s32_min_value=0,s32_max_value=65535,u32_max_value=65535) R4=inv17179869184 R5_w=pkt(id=14,off=62,r=62,umax_value=42000,var_off=(0x0; 0xffffffff)) R6_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R7_w=inv(id=0) R10=fp0
; __u16 ext_len = __bpf_htons(ext->len);
19: (71) r6 = *(u8 *)(r0 +2)
20: (71) r0 = *(u8 *)(r0 +3)
21: (67) r0 <<= 8
22: (4f) r0 |= r6
23: (dc) r0 = be16 r0
; if (ext_len > 3000) {
24: (25) if r0 > 0xbb8 goto pc+7
R0_w=inv(id=0,umax_value=3000,var_off=(0x0; 0xffffffff)) R1=inv(id=0) R2=pkt_end(id=0,off=0,imm=0) R3_w=inv(id=0,umin_value=56,umax_value=42056,var_off=(0x0; 0xffff),s32_min_value=0,s32_max_value=65535,u32_max_value=65535) R4=inv17179869184 R5_w=pkt(id=14,off=62,r=62,umax_value=42000,var_off=(0x0; 0xffffffff)) R6_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R7_w=inv(id=0) R10=fp0
25: (0f) r5 += r0
last_idx 25 first_idx 31
regs=1 stack=0 before 24: (25) if r0 > 0xbb8 goto pc+7
regs=1 stack=0 before 23: (dc) r0 = be16 r0
regs=1 stack=0 before 22: (4f) r0 |= r6
regs=41 stack=0 before 21: (67) r0 <<= 8
regs=41 stack=0 before 20: (71) r0 = *(u8 *)(r0 +3)
regs=40 stack=0 before 19: (71) r6 = *(u8 *)(r0 +2)
26: (0f) r3 += r0
; for(int i = 0; i < extension_methods_len; i += sizeof(struct extension)) {
27: (67) r3 <<= 32
28: (0f) r3 += r4
29: (c7) r3 s>>= 32
30: (bf) r0 = r5
; for(int i = 0; i < extension_methods_len; i += sizeof(struct extension)) {
31: (6d) if r1 s> r3 goto pc-20
from 31 to 12: R0_w=pkt(id=15,off=62,r=0,umax_value=45000,var_off=(0x0; 0xffffffff)) R1=inv(id=0) R2=pkt_end(id=0,off=0,imm=0) R3_w=inv(id=0,umin_value=60,umax_value=45060,var_off=(0x0; 0xffff),s32_min_value=0,s32_max_value=65535,u32_max_value=65535) R4=inv17179869184 R5_w=pkt(id=15,off=62,r=0,umax_value=45000,var_off=(0x0; 0xffffffff)) R6_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R7_w=inv(id=0) R10=fp0
; if (data_end < (data + sizeof(struct extension))) {
12: (07) r5 += 4
; if (data_end < (data + sizeof(struct extension))) {
13: (2d) if r5 > r2 goto pc+18
R0_w=pkt(id=15,off=62,r=66,umax_value=45000,var_off=(0x0; 0xffffffff)) R1=inv(id=0) R2=pkt_end(id=0,off=0,imm=0) R3_w=inv(id=0,umin_value=60,umax_value=45060,var_off=(0x0; 0xffff),s32_min_value=0,s32_max_value=65535,u32_max_value=65535) R4=inv17179869184 R5_w=pkt(id=15,off=66,r=66,umax_value=45000,var_off=(0x0; 0xffffffff)) R6_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R7_w=inv(id=0) R10=fp0
; if (ext->type == SERVER_NAME_EXTENSION) {
14: (71) r6 = *(u8 *)(r0 +0)
15: (71) r7 = *(u8 *)(r0 +1)
16: (67) r7 <<= 8
17: (4f) r7 |= r6
; if (ext->type == SERVER_NAME_EXTENSION) {
18: (15) if r7 == 0x0 goto pc+13
R0_w=pkt(id=15,off=62,r=66,umax_value=45000,var_off=(0x0; 0xffffffff)) R1=inv(id=0) R2=pkt_end(id=0,off=0,imm=0) R3_w=inv(id=0,umin_value=60,umax_value=45060,var_off=(0x0; 0xffff),s32_min_value=0,s32_max_value=65535,u32_max_value=65535) R4=inv17179869184 R5_w=pkt(id=15,off=66,r=66,umax_value=45000,var_off=(0x0; 0xffffffff)) R6_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R7_w=inv(id=0) R10=fp0
; __u16 ext_len = __bpf_htons(ext->len);
19: (71) r6 = *(u8 *)(r0 +2)
20: (71) r0 = *(u8 *)(r0 +3)
21: (67) r0 <<= 8
22: (4f) r0 |= r6
23: (dc) r0 = be16 r0
; if (ext_len > 3000) {
24: (25) if r0 > 0xbb8 goto pc+7
R0_w=inv(id=0,umax_value=3000,var_off=(0x0; 0xffffffff)) R1=inv(id=0) R2=pkt_end(id=0,off=0,imm=0) R3_w=inv(id=0,umin_value=60,umax_value=45060,var_off=(0x0; 0xffff),s32_min_value=0,s32_max_value=65535,u32_max_value=65535) R4=inv17179869184 R5_w=pkt(id=15,off=66,r=66,umax_value=45000,var_off=(0x0; 0xffffffff)) R6_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R7_w=inv(id=0) R10=fp0
25: (0f) r5 += r0
last_idx 25 first_idx 31
regs=1 stack=0 before 24: (25) if r0 > 0xbb8 goto pc+7
regs=1 stack=0 before 23: (dc) r0 = be16 r0
regs=1 stack=0 before 22: (4f) r0 |= r6
regs=41 stack=0 before 21: (67) r0 <<= 8
regs=41 stack=0 before 20: (71) r0 = *(u8 *)(r0 +3)
regs=40 stack=0 before 19: (71) r6 = *(u8 *)(r0 +2)
26: (0f) r3 += r0
; for(int i = 0; i < extension_methods_len; i += sizeof(struct extension)) {
27: (67) r3 <<= 32
28: (0f) r3 += r4
29: (c7) r3 s>>= 32
30: (bf) r0 = r5
; for(int i = 0; i < extension_methods_len; i += sizeof(struct extension)) {
31: (6d) if r1 s> r3 goto pc-20
from 31 to 12: R0_w=pkt(id=16,off=66,r=0,umax_value=48000,var_off=(0x0; 0xffffffff)) R1=inv(id=0) R2=pkt_end(id=0,off=0,imm=0) R3_w=inv(id=0,umin_value=64,umax_value=48064,var_off=(0x0; 0xffff),s32_min_value=0,s32_max_value=65535,u32_max_value=65535) R4=inv17179869184 R5_w=pkt(id=16,off=66,r=0,umax_value=48000,var_off=(0x0; 0xffffffff)) R6_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R7_w=inv(id=0) R10=fp0
; if (data_end < (data + sizeof(struct extension))) {
12: (07) r5 += 4
; if (data_end < (data + sizeof(struct extension))) {
13: (2d) if r5 > r2 goto pc+18
R0_w=pkt(id=16,off=66,r=70,umax_value=48000,var_off=(0x0; 0xffffffff)) R1=inv(id=0) R2=pkt_end(id=0,off=0,imm=0) R3_w=inv(id=0,umin_value=64,umax_value=48064,var_off=(0x0; 0xffff),s32_min_value=0,s32_max_value=65535,u32_max_value=65535) R4=inv17179869184 R5_w=pkt(id=16,off=70,r=70,umax_value=48000,var_off=(0x0; 0xffffffff)) R6_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R7_w=inv(id=0) R10=fp0
; if (ext->type == SERVER_NAME_EXTENSION) {
14: (71) r6 = *(u8 *)(r0 +0)
15: (71) r7 = *(u8 *)(r0 +1)
16: (67) r7 <<= 8
17: (4f) r7 |= r6
; if (ext->type == SERVER_NAME_EXTENSION) {
18: (15) if r7 == 0x0 goto pc+13
R0_w=pkt(id=16,off=66,r=70,umax_value=48000,var_off=(0x0; 0xffffffff)) R1=inv(id=0) R2=pkt_end(id=0,off=0,imm=0) R3_w=inv(id=0,umin_value=64,umax_value=48064,var_off=(0x0; 0xffff),s32_min_value=0,s32_max_value=65535,u32_max_value=65535) R4=inv17179869184 R5_w=pkt(id=16,off=70,r=70,umax_value=48000,var_off=(0x0; 0xffffffff)) R6_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R7_w=inv(id=0) R10=fp0
; __u16 ext_len = __bpf_htons(ext->len);
19: (71) r6 = *(u8 *)(r0 +2)
20: (71) r0 = *(u8 *)(r0 +3)
21: (67) r0 <<= 8
22: (4f) r0 |= r6
23: (dc) r0 = be16 r0
; if (ext_len > 3000) {
24: (25) if r0 > 0xbb8 goto pc+7
R0_w=inv(id=0,umax_value=3000,var_off=(0x0; 0xffffffff)) R1=inv(id=0) R2=pkt_end(id=0,off=0,imm=0) R3_w=inv(id=0,umin_value=64,umax_value=48064,var_off=(0x0; 0xffff),s32_min_value=0,s32_max_value=65535,u32_max_value=65535) R4=inv17179869184 R5_w=pkt(id=16,off=70,r=70,umax_value=48000,var_off=(0x0; 0xffffffff)) R6_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R7_w=inv(id=0) R10=fp0
25: (0f) r5 += r0
last_idx 25 first_idx 31
regs=1 stack=0 before 24: (25) if r0 > 0xbb8 goto pc+7
regs=1 stack=0 before 23: (dc) r0 = be16 r0
regs=1 stack=0 before 22: (4f) r0 |= r6
regs=41 stack=0 before 21: (67) r0 <<= 8
regs=41 stack=0 before 20: (71) r0 = *(u8 *)(r0 +3)
regs=40 stack=0 before 19: (71) r6 = *(u8 *)(r0 +2)
26: (0f) r3 += r0
; for(int i = 0; i < extension_methods_len; i += sizeof(struct extension)) {
27: (67) r3 <<= 32
28: (0f) r3 += r4
29: (c7) r3 s>>= 32
30: (bf) r0 = r5
; for(int i = 0; i < extension_methods_len; i += sizeof(struct extension)) {
31: (6d) if r1 s> r3 goto pc-20
from 31 to 12: R0_w=pkt(id=17,off=70,r=0,umax_value=51000,var_off=(0x0; 0xffffffff)) R1=inv(id=0) R2=pkt_end(id=0,off=0,imm=0) R3_w=inv(id=0,umin_value=68,umax_value=51068,var_off=(0x0; 0xffff),s32_min_value=0,s32_max_value=65535,u32_max_value=65535) R4=inv17179869184 R5_w=pkt(id=17,off=70,r=0,umax_value=51000,var_off=(0x0; 0xffffffff)) R6_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R7_w=inv(id=0) R10=fp0
; if (data_end < (data + sizeof(struct extension))) {
12: (07) r5 += 4
; if (data_end < (data + sizeof(struct extension))) {
13: (2d) if r5 > r2 goto pc+18
R0_w=pkt(id=17,off=70,r=74,umax_value=51000,var_off=(0x0; 0xffffffff)) R1=inv(id=0) R2=pkt_end(id=0,off=0,imm=0) R3_w=inv(id=0,umin_value=68,umax_value=51068,var_off=(0x0; 0xffff),s32_min_value=0,s32_max_value=65535,u32_max_value=65535) R4=inv17179869184 R5_w=pkt(id=17,off=74,r=74,umax_value=51000,var_off=(0x0; 0xffffffff)) R6_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R7_w=inv(id=0) R10=fp0
; if (ext->type == SERVER_NAME_EXTENSION) {
14: (71) r6 = *(u8 *)(r0 +0)
15: (71) r7 = *(u8 *)(r0 +1)
16: (67) r7 <<= 8
17: (4f) r7 |= r6
; if (ext->type == SERVER_NAME_EXTENSION) {
18: (15) if r7 == 0x0 goto pc+13
R0_w=pkt(id=17,off=70,r=74,umax_value=51000,var_off=(0x0; 0xffffffff)) R1=inv(id=0) R2=pkt_end(id=0,off=0,imm=0) R3_w=inv(id=0,umin_value=68,umax_value=51068,var_off=(0x0; 0xffff),s32_min_value=0,s32_max_value=65535,u32_max_value=65535) R4=inv17179869184 R5_w=pkt(id=17,off=74,r=74,umax_value=51000,var_off=(0x0; 0xffffffff)) R6_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R7_w=inv(id=0) R10=fp0
; __u16 ext_len = __bpf_htons(ext->len);
19: (71) r6 = *(u8 *)(r0 +2)
20: (71) r0 = *(u8 *)(r0 +3)
21: (67) r0 <<= 8
22: (4f) r0 |= r6
23: (dc) r0 = be16 r0
; if (ext_len > 3000) {
24: (25) if r0 > 0xbb8 goto pc+7
R0_w=inv(id=0,umax_value=3000,var_off=(0x0; 0xffffffff)) R1=inv(id=0) R2=pkt_end(id=0,off=0,imm=0) R3_w=inv(id=0,umin_value=68,umax_value=51068,var_off=(0x0; 0xffff),s32_min_value=0,s32_max_value=65535,u32_max_value=65535) R4=inv17179869184 R5_w=pkt(id=17,off=74,r=74,umax_value=51000,var_off=(0x0; 0xffffffff)) R6_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R7_w=inv(id=0) R10=fp0
25: (0f) r5 += r0
last_idx 25 first_idx 31
regs=1 stack=0 before 24: (25) if r0 > 0xbb8 goto pc+7
regs=1 stack=0 before 23: (dc) r0 = be16 r0
regs=1 stack=0 before 22: (4f) r0 |= r6
regs=41 stack=0 before 21: (67) r0 <<= 8
regs=41 stack=0 before 20: (71) r0 = *(u8 *)(r0 +3)
regs=40 stack=0 before 19: (71) r6 = *(u8 *)(r0 +2)
26: (0f) r3 += r0
; for(int i = 0; i < extension_methods_len; i += sizeof(struct extension)) {
27: (67) r3 <<= 32
28: (0f) r3 += r4
29: (c7) r3 s>>= 32
30: (bf) r0 = r5
; for(int i = 0; i < extension_methods_len; i += sizeof(struct extension)) {
31: (6d) if r1 s> r3 goto pc-20
from 31 to 12: R0=pkt(id=18,off=74,r=0,umax_value=54000,var_off=(0x0; 0xffffffff)) R1=inv(id=0) R2=pkt_end(id=0,off=0,imm=0) R3=inv(id=0,umin_value=72,umax_value=54072,var_off=(0x0; 0xffff),s32_min_value=0,s32_max_value=65535,u32_max_value=65535) R4=inv17179869184 R5=pkt(id=18,off=74,r=0,umax_value=54000,var_off=(0x0; 0xffffffff)) R6=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R7=inv(id=0) R10=fp0
; if (data_end < (data + sizeof(struct extension))) {
12: (07) r5 += 4
; if (data_end < (data + sizeof(struct extension))) {
13: (2d) if r5 > r2 goto pc+18
R0=pkt(id=18,off=74,r=78,umax_value=54000,var_off=(0x0; 0xffffffff)) R1=inv(id=0) R2=pkt_end(id=0,off=0,imm=0) R3=inv(id=0,umin_value=72,umax_value=54072,var_off=(0x0; 0xffff),s32_min_value=0,s32_max_value=65535,u32_max_value=65535) R4=inv17179869184 R5_w=pkt(id=18,off=78,r=78,umax_value=54000,var_off=(0x0; 0xffffffff)) R6=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R7=inv(id=0) R10=fp0
; if (ext->type == SERVER_NAME_EXTENSION) {
14: (71) r6 = *(u8 *)(r0 +0)
15: (71) r7 = *(u8 *)(r0 +1)
16: (67) r7 <<= 8
17: (4f) r7 |= r6
; if (ext->type == SERVER_NAME_EXTENSION) {
18: (15) if r7 == 0x0 goto pc+13
R0=pkt(id=18,off=74,r=78,umax_value=54000,var_off=(0x0; 0xffffffff)) R1=inv(id=0) R2=pkt_end(id=0,off=0,imm=0) R3=inv(id=0,umin_value=72,umax_value=54072,var_off=(0x0; 0xffff),s32_min_value=0,s32_max_value=65535,u32_max_value=65535) R4=inv17179869184 R5_w=pkt(id=18,off=78,r=78,umax_value=54000,var_off=(0x0; 0xffffffff)) R6_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R7_w=inv(id=0) R10=fp0
; __u16 ext_len = __bpf_htons(ext->len);
19: (71) r6 = *(u8 *)(r0 +2)
20: (71) r0 = *(u8 *)(r0 +3)
21: (67) r0 <<= 8
22: (4f) r0 |= r6
23: (dc) r0 = be16 r0
; if (ext_len > 3000) {
24: (25) if r0 > 0xbb8 goto pc+7
R0_w=inv(id=0,umax_value=3000,var_off=(0x0; 0xffffffff)) R1=inv(id=0) R2=pkt_end(id=0,off=0,imm=0) R3=inv(id=0,umin_value=72,umax_value=54072,var_off=(0x0; 0xffff),s32_min_value=0,s32_max_value=65535,u32_max_value=65535) R4=inv17179869184 R5_w=pkt(id=18,off=78,r=78,umax_value=54000,var_off=(0x0; 0xffffffff)) R6_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R7_w=inv(id=0) R10=fp0
25: (0f) r5 += r0
last_idx 25 first_idx 31
regs=1 stack=0 before 24: (25) if r0 > 0xbb8 goto pc+7
regs=1 stack=0 before 23: (dc) r0 = be16 r0
regs=1 stack=0 before 22: (4f) r0 |= r6
regs=41 stack=0 before 21: (67) r0 <<= 8
regs=41 stack=0 before 20: (71) r0 = *(u8 *)(r0 +3)
regs=40 stack=0 before 19: (71) r6 = *(u8 *)(r0 +2)
26: (0f) r3 += r0
; for(int i = 0; i < extension_methods_len; i += sizeof(struct extension)) {
27: (67) r3 <<= 32
28: (0f) r3 += r4
29: (c7) r3 s>>= 32
30: (bf) r0 = r5
; for(int i = 0; i < extension_methods_len; i += sizeof(struct extension)) {
31: (6d) if r1 s> r3 goto pc-20
from 31 to 12: R0_w=pkt(id=19,off=78,r=0,umax_value=57000,var_off=(0x0; 0xffffffff)) R1=inv(id=0) R2=pkt_end(id=0,off=0,imm=0) R3_w=inv(id=0,umin_value=76,umax_value=57076,var_off=(0x0; 0xffff),s32_min_value=0,s32_max_value=65535,u32_max_value=65535) R4=inv17179869184 R5_w=pkt(id=19,off=78,r=0,umax_value=57000,var_off=(0x0; 0xffffffff)) R6_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R7_w=inv(id=0) R10=fp0
; if (data_end < (data + sizeof(struct extension))) {
12: (07) r5 += 4
; if (data_end < (data + sizeof(struct extension))) {
13: (2d) if r5 > r2 goto pc+18
R0_w=pkt(id=19,off=78,r=82,umax_value=57000,var_off=(0x0; 0xffffffff)) R1=inv(id=0) R2=pkt_end(id=0,off=0,imm=0) R3_w=inv(id=0,umin_value=76,umax_value=57076,var_off=(0x0; 0xffff),s32_min_value=0,s32_max_value=65535,u32_max_value=65535) R4=inv17179869184 R5_w=pkt(id=19,off=82,r=82,umax_value=57000,var_off=(0x0; 0xffffffff)) R6_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R7_w=inv(id=0) R10=fp0
; if (ext->type == SERVER_NAME_EXTENSION) {
14: (71) r6 = *(u8 *)(r0 +0)
15: (71) r7 = *(u8 *)(r0 +1)
16: (67) r7 <<= 8
17: (4f) r7 |= r6
; if (ext->type == SERVER_NAME_EXTENSION) {
18: (15) if r7 == 0x0 goto pc+13
R0_w=pkt(id=19,off=78,r=82,umax_value=57000,var_off=(0x0; 0xffffffff)) R1=inv(id=0) R2=pkt_end(id=0,off=0,imm=0) R3_w=inv(id=0,umin_value=76,umax_value=57076,var_off=(0x0; 0xffff),s32_min_value=0,s32_max_value=65535,u32_max_value=65535) R4=inv17179869184 R5_w=pkt(id=19,off=82,r=82,umax_value=57000,var_off=(0x0; 0xffffffff)) R6_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R7_w=inv(id=0) R10=fp0
; __u16 ext_len = __bpf_htons(ext->len);
19: (71) r6 = *(u8 *)(r0 +2)
20: (71) r0 = *(u8 *)(r0 +3)
21: (67) r0 <<= 8
22: (4f) r0 |= r6
23: (dc) r0 = be16 r0
; if (ext_len > 3000) {
24: (25) if r0 > 0xbb8 goto pc+7
R0_w=inv(id=0,umax_value=3000,var_off=(0x0; 0xffffffff)) R1=inv(id=0) R2=pkt_end(id=0,off=0,imm=0) R3_w=inv(id=0,umin_value=76,umax_value=57076,var_off=(0x0; 0xffff),s32_min_value=0,s32_max_value=65535,u32_max_value=65535) R4=inv17179869184 R5_w=pkt(id=19,off=82,r=82,umax_value=57000,var_off=(0x0; 0xffffffff)) R6_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R7_w=inv(id=0) R10=fp0
25: (0f) r5 += r0
last_idx 25 first_idx 31
regs=1 stack=0 before 24: (25) if r0 > 0xbb8 goto pc+7
regs=1 stack=0 before 23: (dc) r0 = be16 r0
regs=1 stack=0 before 22: (4f) r0 |= r6
regs=41 stack=0 before 21: (67) r0 <<= 8
regs=41 stack=0 before 20: (71) r0 = *(u8 *)(r0 +3)
regs=40 stack=0 before 19: (71) r6 = *(u8 *)(r0 +2)
26: (0f) r3 += r0
; for(int i = 0; i < extension_methods_len; i += sizeof(struct extension)) {
27: (67) r3 <<= 32
28: (0f) r3 += r4
29: (c7) r3 s>>= 32
30: (bf) r0 = r5
; for(int i = 0; i < extension_methods_len; i += sizeof(struct extension)) {
31: (6d) if r1 s> r3 goto pc-20
from 31 to 12: R0_w=pkt(id=20,off=82,r=0,umax_value=60000,var_off=(0x0; 0xffffffff)) R1=inv(id=0) R2=pkt_end(id=0,off=0,imm=0) R3_w=inv(id=0,umin_value=80,umax_value=60080,var_off=(0x0; 0xffff),s32_min_value=0,s32_max_value=65535,u32_max_value=65535) R4=inv17179869184 R5_w=pkt(id=20,off=82,r=0,umax_value=60000,var_off=(0x0; 0xffffffff)) R6_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R7_w=inv(id=0) R10=fp0
; if (data_end < (data + sizeof(struct extension))) {
12: (07) r5 += 4
; if (data_end < (data + sizeof(struct extension))) {
13: (2d) if r5 > r2 goto pc+18
R0_w=pkt(id=20,off=82,r=86,umax_value=60000,var_off=(0x0; 0xffffffff)) R1=inv(id=0) R2=pkt_end(id=0,off=0,imm=0) R3_w=inv(id=0,umin_value=80,umax_value=60080,var_off=(0x0; 0xffff),s32_min_value=0,s32_max_value=65535,u32_max_value=65535) R4=inv17179869184 R5_w=pkt(id=20,off=86,r=86,umax_value=60000,var_off=(0x0; 0xffffffff)) R6_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R7_w=inv(id=0) R10=fp0
; if (ext->type == SERVER_NAME_EXTENSION) {
14: (71) r6 = *(u8 *)(r0 +0)
15: (71) r7 = *(u8 *)(r0 +1)
16: (67) r7 <<= 8
17: (4f) r7 |= r6
; if (ext->type == SERVER_NAME_EXTENSION) {
18: (15) if r7 == 0x0 goto pc+13
R0_w=pkt(id=20,off=82,r=86,umax_value=60000,var_off=(0x0; 0xffffffff)) R1=inv(id=0) R2=pkt_end(id=0,off=0,imm=0) R3_w=inv(id=0,umin_value=80,umax_value=60080,var_off=(0x0; 0xffff),s32_min_value=0,s32_max_value=65535,u32_max_value=65535) R4=inv17179869184 R5_w=pkt(id=20,off=86,r=86,umax_value=60000,var_off=(0x0; 0xffffffff)) R6_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R7_w=inv(id=0) R10=fp0
; __u16 ext_len = __bpf_htons(ext->len);
19: (71) r6 = *(u8 *)(r0 +2)
20: (71) r0 = *(u8 *)(r0 +3)
21: (67) r0 <<= 8
22: (4f) r0 |= r6
23: (dc) r0 = be16 r0
; if (ext_len > 3000) {
24: (25) if r0 > 0xbb8 goto pc+7
R0_w=inv(id=0,umax_value=3000,var_off=(0x0; 0xffffffff)) R1=inv(id=0) R2=pkt_end(id=0,off=0,imm=0) R3_w=inv(id=0,umin_value=80,umax_value=60080,var_off=(0x0; 0xffff),s32_min_value=0,s32_max_value=65535,u32_max_value=65535) R4=inv17179869184 R5_w=pkt(id=20,off=86,r=86,umax_value=60000,var_off=(0x0; 0xffffffff)) R6_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R7_w=inv(id=0) R10=fp0
25: (0f) r5 += r0
last_idx 25 first_idx 31
regs=1 stack=0 before 24: (25) if r0 > 0xbb8 goto pc+7
regs=1 stack=0 before 23: (dc) r0 = be16 r0
regs=1 stack=0 before 22: (4f) r0 |= r6
regs=41 stack=0 before 21: (67) r0 <<= 8
regs=41 stack=0 before 20: (71) r0 = *(u8 *)(r0 +3)
regs=40 stack=0 before 19: (71) r6 = *(u8 *)(r0 +2)
26: (0f) r3 += r0
; for(int i = 0; i < extension_methods_len; i += sizeof(struct extension)) {
27: (67) r3 <<= 32
28: (0f) r3 += r4
29: (c7) r3 s>>= 32
30: (bf) r0 = r5
; for(int i = 0; i < extension_methods_len; i += sizeof(struct extension)) {
31: (6d) if r1 s> r3 goto pc-20
from 31 to 12: R0_w=pkt(id=21,off=86,r=0,umax_value=63000,var_off=(0x0; 0xffffffff)) R1=inv(id=0) R2=pkt_end(id=0,off=0,imm=0) R3_w=inv(id=0,umin_value=84,umax_value=63084,var_off=(0x0; 0xffff),s32_min_value=0,s32_max_value=65535,u32_max_value=65535) R4=inv17179869184 R5_w=pkt(id=21,off=86,r=0,umax_value=63000,var_off=(0x0; 0xffffffff)) R6_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R7_w=inv(id=0) R10=fp0
; if (data_end < (data + sizeof(struct extension))) {
12: (07) r5 += 4
; if (data_end < (data + sizeof(struct extension))) {
13: (2d) if r5 > r2 goto pc+18
R0_w=pkt(id=21,off=86,r=90,umax_value=63000,var_off=(0x0; 0xffffffff)) R1=inv(id=0) R2=pkt_end(id=0,off=0,imm=0) R3_w=inv(id=0,umin_value=84,umax_value=63084,var_off=(0x0; 0xffff),s32_min_value=0,s32_max_value=65535,u32_max_value=65535) R4=inv17179869184 R5_w=pkt(id=21,off=90,r=90,umax_value=63000,var_off=(0x0; 0xffffffff)) R6_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R7_w=inv(id=0) R10=fp0
; if (ext->type == SERVER_NAME_EXTENSION) {
14: (71) r6 = *(u8 *)(r0 +0)
15: (71) r7 = *(u8 *)(r0 +1)
16: (67) r7 <<= 8
17: (4f) r7 |= r6
; if (ext->type == SERVER_NAME_EXTENSION) {
18: (15) if r7 == 0x0 goto pc+13
R0_w=pkt(id=21,off=86,r=90,umax_value=63000,var_off=(0x0; 0xffffffff)) R1=inv(id=0) R2=pkt_end(id=0,off=0,imm=0) R3_w=inv(id=0,umin_value=84,umax_value=63084,var_off=(0x0; 0xffff),s32_min_value=0,s32_max_value=65535,u32_max_value=65535) R4=inv17179869184 R5_w=pkt(id=21,off=90,r=90,umax_value=63000,var_off=(0x0; 0xffffffff)) R6_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R7_w=inv(id=0) R10=fp0
; __u16 ext_len = __bpf_htons(ext->len);
19: (71) r6 = *(u8 *)(r0 +2)
20: (71) r0 = *(u8 *)(r0 +3)
21: (67) r0 <<= 8
22: (4f) r0 |= r6
23: (dc) r0 = be16 r0
; if (ext_len > 3000) {
24: (25) if r0 > 0xbb8 goto pc+7
R0_w=inv(id=0,umax_value=3000,var_off=(0x0; 0xffffffff)) R1=inv(id=0) R2=pkt_end(id=0,off=0,imm=0) R3_w=inv(id=0,umin_value=84,umax_value=63084,var_off=(0x0; 0xffff),s32_min_value=0,s32_max_value=65535,u32_max_value=65535) R4=inv17179869184 R5_w=pkt(id=21,off=90,r=90,umax_value=63000,var_off=(0x0; 0xffffffff)) R6_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R7_w=inv(id=0) R10=fp0
25: (0f) r5 += r0
last_idx 25 first_idx 31
regs=1 stack=0 before 24: (25) if r0 > 0xbb8 goto pc+7
regs=1 stack=0 before 23: (dc) r0 = be16 r0
regs=1 stack=0 before 22: (4f) r0 |= r6
regs=41 stack=0 before 21: (67) r0 <<= 8
regs=41 stack=0 before 20: (71) r0 = *(u8 *)(r0 +3)
regs=40 stack=0 before 19: (71) r6 = *(u8 *)(r0 +2)
26: (0f) r3 += r0
; for(int i = 0; i < extension_methods_len; i += sizeof(struct extension)) {
27: (67) r3 <<= 32
28: (0f) r3 += r4
29: (c7) r3 s>>= 32
30: (bf) r0 = r5
; for(int i = 0; i < extension_methods_len; i += sizeof(struct extension)) {
31: (6d) if r1 s> r3 goto pc-20
from 31 to 12: R0_w=pkt(id=22,off=90,r=0,umax_value=66000,var_off=(0x0; 0xffffffff)) R1=inv(id=0) R2=pkt_end(id=0,off=0,imm=0) R3_w=inv(id=0,umin_value=88,umax_value=66088,var_off=(0x0; 0x1ffff),s32_min_value=0,s32_max_value=131071,u32_max_value=131071) R4=inv17179869184 R5_w=pkt(id=22,off=90,r=0,umax_value=66000,var_off=(0x0; 0xffffffff)) R6_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R7_w=inv(id=0) R10=fp0
; if (data_end < (data + sizeof(struct extension))) {
12: (07) r5 += 4
; if (data_end < (data + sizeof(struct extension))) {
13: (2d) if r5 > r2 goto pc+18
R0_w=pkt(id=22,off=90,r=0,umax_value=66000,var_off=(0x0; 0xffffffff)) R1=inv(id=0) R2=pkt_end(id=0,off=0,imm=0) R3_w=inv(id=0,umin_value=88,umax_value=66088,var_off=(0x0; 0x1ffff),s32_min_value=0,s32_max_value=131071,u32_max_value=131071) R4=inv17179869184 R5_w=pkt(id=22,off=94,r=0,umax_value=66000,var_off=(0x0; 0xffffffff)) R6_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R7_w=inv(id=0) R10=fp0
; if (ext->type == SERVER_NAME_EXTENSION) {
14: (71) r6 = *(u8 *)(r0 +0)
invalid access to packet, off=90 size=1, R0(id=22,off=90,r=0)
R0 offset is outside of the packet
processed 477 insns (limit 1000000) max_states_per_insn 4 total_states 9 peak_states 9 mark_read 2
我想如果语句(A)
足以验证ext
是否指向有效地址,尽管由于if (data_end < (data + sizeof(struct extension))) {
检查,最初不应该需要它。
当我使用__s16 ext_len
时会出现此错误。我也不明白它失败的地方是14: (71) r6 = *(u8 *)(r0 +0)
。那么len
字段是__u16
,那么它不应该是*(u16 *)
吗?
我正在运行内核5.13.0-19-generic.
我想我已经找到了问题的核心。验证器跟踪变量的几个属性,这些属性允许它确定程序是否可以访问不应该访问的数据。其中一个属性是umax_value
,它跟踪最大无符号int值是什么,这可能是动态的。
由于分组具有有限的大小,验证器断言分组中偏移的umax_value
可能永远不会超过MAX_PACKET_OFF
(65536(。
每次程序循环时,我们都会将ext_len
添加到data
中,因为ext_len
是__u16
,默认情况下其最大uint值为65536
。该程序通过以下声明将其限制为30000:
if (ext_len > 30000) {
goto end;
}
然而,data
的umax_value
在每次迭代中累积。我们可以在验证器日志中看到这一点:
;if(data_end<(data+sizeof(struct extension(({13:(2d(如果r5>r2 goto pc+18R0_w=pkt(id=22,off=90,r=0,umax_value=66000,var_off=(0x0;0xffffffff((R1=inv,u32_max_value=131071(R4=inv17179869184 R5_w=pkt(id=22,off=94,r=0,umax_value=66000,var_off=(0x0;0xffffffff((R6_w=inv;if(ext->type==SERVER_NAME_EXTENSION({14:(71(r6=*(u8*((r0+0(
umax_value
大于65536,因此出现错误。
现在,为了解决这个问题,我们需要更改代码,使data
不能超过65536。我们通过指定最大迭代次数(扩展(并设置每个扩展的最大大小来实现这一点。我修改了程序以添加这些约束,我选择了最大32
扩展和每个扩展的最大2048
字节,这似乎是合理的值(32*2048=65536(,这些都可以更改。
#include <stddef.h>
#include <linux/bpf.h>
#include "./bpf_endian.h"
#define SEC(NAME) __attribute__((section(NAME), used))
struct server_name
{
char server_name[256];
};
struct extension
{
__u16 type;
__u16 len;
} __attribute__((packed));
struct sni_extension
{
__u16 list_len;
__u8 type;
__u16 len;
} __attribute__((packed));
#define SERVER_NAME_EXTENSION 0
SEC("xdp")
int collect_ips_prog(struct xdp_md *ctx)
{
void *data_end = (void *)(long)ctx->data_end;
void *data = (void *)(long)ctx->data;
void *cursor = (void *)(long)ctx->data;
if (data_end < (cursor + sizeof(__u16)))
{
goto end;
}
__s64 extension_method_len = *(__u16 *)cursor;
if (extension_method_len < 0)
{
goto end;
}
cursor += sizeof(__u16);
for (int i = 0; i < 32; i++)
{
struct extension *ext;
if (cursor > extension_method_len + data)
{
goto end;
}
if (data_end < (cursor + sizeof(*ext)))
{
goto end;
}
ext = (struct extension *)cursor;
cursor += sizeof(*ext);
if (ext->type == SERVER_NAME_EXTENSION)
{
struct server_name sn;
if (data_end < (cursor + sizeof(struct sni_extension)))
{
goto end;
}
struct sni_extension *sni = (struct sni_extension *)cursor;
cursor += sizeof(struct sni_extension);
__u16 server_name_len = sni->len;
for (int sn_idx = 0; sn_idx < server_name_len; sn_idx++)
{
if (data_end < cursor + sn_idx)
{
goto end;
}
if (sn.server_name + sizeof(struct server_name) < sn.server_name + sn_idx)
{
goto end;
}
sn.server_name[sn_idx] = ((char *)cursor)[sn_idx];
}
sn.server_name[server_name_len] = 0;
goto end;
}
if (ext->len > 2048)
{
goto end;
}
if (data_end < cursor + ext->len)
{
goto end;
}
cursor += ext->len;
}
end:
return XDP_PASS;
}
这里的限制是显而易见的,即使我们有31个只有几个字节的扩展,32’nd也永远不会大于2048字节。可能有一种方法可以跟踪到目前为止所有扩展的总和,并检查这个总和是否永远不会超过65536,从而使我们能够消除这些"扩展";最坏情况下的塞纳里奥;常数,并检查实际的umax_value
,但我将把它作为一个研究主题留给其他人。
除了Dylan的出色回答之外,从SNI复制服务器名称的内部for循环的另一种选择是:
struct server_name sn = {"a"};
bpf_core_read(sn.server_name, server_name_len, data);
这将从data
复制到sn.server_name
。
这样可以避免边界检查。需要将结构初始化为默认值。否则,如果调用任何BPF辅助函数(如bpf_map_update_elem
(,就会得到invalid indirect read from stack ...
错误。