A BPF program can read the middle of a u64 field in struct bpf_tcp_sock:

        tp = bpf_tcp_sock(listener);
        /* +0x54 is in the middle of the u64 bytes_received */
        unsigned hi = *(unsigned *)((char *)tp + 0x54);

bpf_tcp_sock_is_valid_access() allows this 4-byte read (the default case
only checks size == 4), but bpf_tcp_sock_convert_ctx_access() only knows
the field starts and has no idea how to handle such an offset. It emits
no instruction, cnt stays 0 and the fixup pass trips verifier_bug():

        verifier bug: error during ctx access conversion (0)

Just disallow the narrower access by matching the whole u64 range of the
two fields, so it is turned down at check time:

        invalid tcp_sock access off=84 size=4

Fixes: 655a51e536c0 ("bpf: Add struct bpf_tcp_sock and BPF_FUNC_tcp_sock")
Reported-by: Kaiyan Mei <[email protected]>
Reported-by: Yinhao Hu <[email protected]>
Reported-by: Dongliang Mu <[email protected]>
Closes: 
https://lore.kernel.org/bpf/[email protected]/
Signed-off-by: Jiayuan Chen <[email protected]>
---
v1 -> v2: Add a selftest (Alexei).
v1: https://lore.kernel.org/bpf/[email protected]/T/#t
---
 net/core/filter.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/net/core/filter.c b/net/core/filter.c
index ba536be2915f..f0eae1c14b2f 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -7600,8 +7600,8 @@ bool bpf_tcp_sock_is_valid_access(int off, int size, enum 
bpf_access_type type,
                return false;
 
        switch (off) {
-       case offsetof(struct bpf_tcp_sock, bytes_received):
-       case offsetof(struct bpf_tcp_sock, bytes_acked):
+       case bpf_ctx_range(struct bpf_tcp_sock, bytes_received):
+       case bpf_ctx_range(struct bpf_tcp_sock, bytes_acked):
                return size == sizeof(__u64);
        default:
                return size == sizeof(__u32);
-- 
2.43.0


Reply via email to