From abf7b251c1461dcbe0c1e75d1d0da71662c9fae1 Mon Sep 17 00:00:00 2001 From: Hengqi Chen Date: Sun, 17 Dec 2023 11:27:10 +0000 Subject: [PATCH] libbpf-tools: Fix bindsnoop for kernel v6.6+ The freebind field in struct inet_sock gone in recent kernel versions due to some kernel refactor works ([0]). The change breaks the bindsnoop tool. Fix it in a CO-RE way. This should close #4838. [0]: https://lore.kernel.org/all/20230816081547.1272409-1-edumazet@google.com/ Signed-off-by: Hengqi Chen --- libbpf-tools/bindsnoop.bpf.c | 8 +++-- libbpf-tools/core_fixes.bpf.h | 56 +++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/libbpf-tools/bindsnoop.bpf.c b/libbpf-tools/bindsnoop.bpf.c index 41dce942..ead19c67 100644 --- a/libbpf-tools/bindsnoop.bpf.c +++ b/libbpf-tools/bindsnoop.bpf.c @@ -5,7 +5,9 @@ #include #include #include + #include "bindsnoop.h" +#include "core_fixes.bpf.h" #define MAX_ENTRIES 10240 #define MAX_PORTS 1024 @@ -85,9 +87,9 @@ static int probe_exit(struct pt_regs *ctx, short ver) if (filter_by_port && !port) goto cleanup; - opts.fields.freebind = BPF_CORE_READ_BITFIELD_PROBED(inet_sock, freebind); - opts.fields.transparent = BPF_CORE_READ_BITFIELD_PROBED(inet_sock, transparent); - opts.fields.bind_address_no_port = BPF_CORE_READ_BITFIELD_PROBED(inet_sock, bind_address_no_port); + opts.fields.freebind = get_inet_sock_freebind(inet_sock); + opts.fields.transparent = get_inet_sock_transparent(inet_sock); + opts.fields.bind_address_no_port = get_inet_sock_bind_address_no_port(inet_sock); opts.fields.reuseaddress = BPF_CORE_READ_BITFIELD_PROBED(sock, __sk_common.skc_reuse); opts.fields.reuseport = BPF_CORE_READ_BITFIELD_PROBED(sock, __sk_common.skc_reuseport); event.opts = opts.data; diff --git a/libbpf-tools/core_fixes.bpf.h b/libbpf-tools/core_fixes.bpf.h index 84cb7f18..a4c84c02 100644 --- a/libbpf-tools/core_fixes.bpf.h +++ b/libbpf-tools/core_fixes.bpf.h @@ -249,4 +249,60 @@ static __always_inline __u64 get_sock_ident(struct sock *sk) return (__u64)sk; } +/** + * During kernel 6.6 development cycle, several bitfields in struct inet_sock gone, + * they are placed in inet_sock::inet_flags instead ([0]). + * + * References: + * [0]: https://lore.kernel.org/all/20230816081547.1272409-1-edumazet@google.com/ + */ +struct inet_sock___o { + __u8 freebind: 1; + __u8 transparent: 1; + __u8 bind_address_no_port: 1; +}; + +enum { + INET_FLAGS_FREEBIND___x = 11, + INET_FLAGS_TRANSPARENT___x = 15, + INET_FLAGS_BIND_ADDRESS_NO_PORT___x = 18, +}; + +struct inet_sock___x { + unsigned long inet_flags; +}; + +static __always_inline __u8 get_inet_sock_freebind(void *inet_sock) +{ + unsigned long inet_flags; + + if (bpf_core_field_exists(struct inet_sock___o, freebind)) + return BPF_CORE_READ_BITFIELD_PROBED((struct inet_sock___o *)inet_sock, freebind); + + inet_flags = BPF_CORE_READ((struct inet_sock___x *)inet_sock, inet_flags); + return (1 << INET_FLAGS_FREEBIND___x) & inet_flags ? 1 : 0; +} + +static __always_inline __u8 get_inet_sock_transparent(void *inet_sock) +{ + unsigned long inet_flags; + + if (bpf_core_field_exists(struct inet_sock___o, transparent)) + return BPF_CORE_READ_BITFIELD_PROBED((struct inet_sock___o *)inet_sock, transparent); + + inet_flags = BPF_CORE_READ((struct inet_sock___x *)inet_sock, inet_flags); + return (1 << INET_FLAGS_TRANSPARENT___x) & inet_flags ? 1 : 0; +} + +static __always_inline __u8 get_inet_sock_bind_address_no_port(void *inet_sock) +{ + unsigned long inet_flags; + + if (bpf_core_field_exists(struct inet_sock___o, bind_address_no_port)) + return BPF_CORE_READ_BITFIELD_PROBED((struct inet_sock___o *)inet_sock, bind_address_no_port); + + inet_flags = BPF_CORE_READ((struct inet_sock___x *)inet_sock, inet_flags); + return (1 << INET_FLAGS_BIND_ADDRESS_NO_PORT___x) & inet_flags ? 1 : 0; +} + #endif /* __CORE_FIXES_BPF_H */ -- 2.43.0