Skip to content

Commit e092992

Browse files
pchaignoMartin KaFai Lau
authored andcommitted
bpf: Reject narrower access to pointer ctx fields
The following BPF program, simplified from a syzkaller repro, causes a kernel warning: r0 = *(u8 *)(r1 + 169); exit; With pointer field sk being at offset 168 in __sk_buff. This access is detected as a narrower read in bpf_skb_is_valid_access because it doesn't match offsetof(struct __sk_buff, sk). It is therefore allowed and later proceeds to bpf_convert_ctx_access. Note that for the "is_narrower_load" case in the convert_ctx_accesses(), the insn->off is aligned, so the cnt may not be 0 because it matches the offsetof(struct __sk_buff, sk) in the bpf_convert_ctx_access. However, the target_size stays 0 and the verifier errors with a kernel warning: verifier bug: error during ctx access conversion(1) This patch fixes that to return a proper "invalid bpf_context access off=X size=Y" error on the load instruction. The same issue affects multiple other fields in context structures that allow narrow access. Some other non-affected fields (for sk_msg, sk_lookup, and sockopt) were also changed to use bpf_ctx_range_ptr for consistency. Note this syzkaller crash was reported in the "Closes" link below, which used to be about a different bug, fixed in commit fce7bd8 ("bpf/verifier: Handle BPF_LOAD_ACQ instructions in insn_def_regno()"). Because syzbot somehow confused the two bugs, the new crash and repro didn't get reported to the mailing list. Fixes: f96da09 ("bpf: simplify narrower ctx access") Fixes: 0df1a55 ("bpf: Warn on internal verifier errors") Reported-by: [email protected] Closes: https://syzkaller.appspot.com/bug?extid=0ef84a7bdf5301d4cbec Signed-off-by: Paul Chaignon <[email protected]> Signed-off-by: Martin KaFai Lau <[email protected]> Acked-by: Eduard Zingerman <[email protected]> Link: https://patch.msgid.link/3b8dcee67ff4296903351a974ddd9c4dca768b64.1753194596.git.paul.chaignon@gmail.com
1 parent 17ce3e5 commit e092992

File tree

2 files changed

+14
-14
lines changed

2 files changed

+14
-14
lines changed

kernel/bpf/cgroup.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2440,22 +2440,22 @@ static bool cg_sockopt_is_valid_access(int off, int size,
24402440
}
24412441

24422442
switch (off) {
2443-
case offsetof(struct bpf_sockopt, sk):
2443+
case bpf_ctx_range_ptr(struct bpf_sockopt, sk):
24442444
if (size != sizeof(__u64))
24452445
return false;
24462446
info->reg_type = PTR_TO_SOCKET;
24472447
break;
2448-
case offsetof(struct bpf_sockopt, optval):
2448+
case bpf_ctx_range_ptr(struct bpf_sockopt, optval):
24492449
if (size != sizeof(__u64))
24502450
return false;
24512451
info->reg_type = PTR_TO_PACKET;
24522452
break;
2453-
case offsetof(struct bpf_sockopt, optval_end):
2453+
case bpf_ctx_range_ptr(struct bpf_sockopt, optval_end):
24542454
if (size != sizeof(__u64))
24552455
return false;
24562456
info->reg_type = PTR_TO_PACKET_END;
24572457
break;
2458-
case offsetof(struct bpf_sockopt, retval):
2458+
case bpf_ctx_range(struct bpf_sockopt, retval):
24592459
if (size != size_default)
24602460
return false;
24612461
return prog->expected_attach_type == BPF_CGROUP_GETSOCKOPT;

net/core/filter.c

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8699,7 +8699,7 @@ static bool bpf_skb_is_valid_access(int off, int size, enum bpf_access_type type
86998699
if (size != sizeof(__u64))
87008700
return false;
87018701
break;
8702-
case offsetof(struct __sk_buff, sk):
8702+
case bpf_ctx_range_ptr(struct __sk_buff, sk):
87038703
if (type == BPF_WRITE || size != sizeof(__u64))
87048704
return false;
87058705
info->reg_type = PTR_TO_SOCK_COMMON_OR_NULL;
@@ -9277,7 +9277,7 @@ static bool sock_addr_is_valid_access(int off, int size,
92779277
return false;
92789278
}
92799279
break;
9280-
case offsetof(struct bpf_sock_addr, sk):
9280+
case bpf_ctx_range_ptr(struct bpf_sock_addr, sk):
92819281
if (type != BPF_READ)
92829282
return false;
92839283
if (size != sizeof(__u64))
@@ -9327,17 +9327,17 @@ static bool sock_ops_is_valid_access(int off, int size,
93279327
if (size != sizeof(__u64))
93289328
return false;
93299329
break;
9330-
case offsetof(struct bpf_sock_ops, sk):
9330+
case bpf_ctx_range_ptr(struct bpf_sock_ops, sk):
93319331
if (size != sizeof(__u64))
93329332
return false;
93339333
info->reg_type = PTR_TO_SOCKET_OR_NULL;
93349334
break;
9335-
case offsetof(struct bpf_sock_ops, skb_data):
9335+
case bpf_ctx_range_ptr(struct bpf_sock_ops, skb_data):
93369336
if (size != sizeof(__u64))
93379337
return false;
93389338
info->reg_type = PTR_TO_PACKET;
93399339
break;
9340-
case offsetof(struct bpf_sock_ops, skb_data_end):
9340+
case bpf_ctx_range_ptr(struct bpf_sock_ops, skb_data_end):
93419341
if (size != sizeof(__u64))
93429342
return false;
93439343
info->reg_type = PTR_TO_PACKET_END;
@@ -9346,7 +9346,7 @@ static bool sock_ops_is_valid_access(int off, int size,
93469346
bpf_ctx_record_field_size(info, size_default);
93479347
return bpf_ctx_narrow_access_ok(off, size,
93489348
size_default);
9349-
case offsetof(struct bpf_sock_ops, skb_hwtstamp):
9349+
case bpf_ctx_range(struct bpf_sock_ops, skb_hwtstamp):
93509350
if (size != sizeof(__u64))
93519351
return false;
93529352
break;
@@ -9416,17 +9416,17 @@ static bool sk_msg_is_valid_access(int off, int size,
94169416
return false;
94179417

94189418
switch (off) {
9419-
case offsetof(struct sk_msg_md, data):
9419+
case bpf_ctx_range_ptr(struct sk_msg_md, data):
94209420
info->reg_type = PTR_TO_PACKET;
94219421
if (size != sizeof(__u64))
94229422
return false;
94239423
break;
9424-
case offsetof(struct sk_msg_md, data_end):
9424+
case bpf_ctx_range_ptr(struct sk_msg_md, data_end):
94259425
info->reg_type = PTR_TO_PACKET_END;
94269426
if (size != sizeof(__u64))
94279427
return false;
94289428
break;
9429-
case offsetof(struct sk_msg_md, sk):
9429+
case bpf_ctx_range_ptr(struct sk_msg_md, sk):
94309430
if (size != sizeof(__u64))
94319431
return false;
94329432
info->reg_type = PTR_TO_SOCKET;
@@ -11632,7 +11632,7 @@ static bool sk_lookup_is_valid_access(int off, int size,
1163211632
return false;
1163311633

1163411634
switch (off) {
11635-
case offsetof(struct bpf_sk_lookup, sk):
11635+
case bpf_ctx_range_ptr(struct bpf_sk_lookup, sk):
1163611636
info->reg_type = PTR_TO_SOCKET_OR_NULL;
1163711637
return size == sizeof(__u64);
1163811638

0 commit comments

Comments
 (0)