On big-endian, the port is available in the second __u16, not the first one. Therefore, provide a big-endian-specific definition that reflects that. Also, define remote_port_compat in order to have nicer architecture-agnostic code in the verifier and in tests. Fixes: 9a69e2b385f4 ("bpf: Make remote_port field in struct bpf_sk_lookup 16-bit wide") Signed-off-by: Ilya Leoshkevich <iii@xxxxxxxxxxxxx> --- include/uapi/linux/bpf.h | 17 +++++++++++++++-- net/core/filter.c | 5 ++--- tools/include/uapi/linux/bpf.h | 17 +++++++++++++++-- 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index afe3d0d7f5f2..7b0e5efa58e0 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -10,6 +10,7 @@ #include <linux/types.h> #include <linux/bpf_common.h> +#include <asm/byteorder.h> /* Extended instruction set based on top of classic BPF */ @@ -6453,8 +6454,20 @@ struct bpf_sk_lookup { __u32 protocol; /* IP protocol (IPPROTO_TCP, IPPROTO_UDP) */ __u32 remote_ip4; /* Network byte order */ __u32 remote_ip6[4]; /* Network byte order */ - __be16 remote_port; /* Network byte order */ - __u16 :16; /* Zero padding */ + union { + struct { +#if defined(__BYTE_ORDER) ? __BYTE_ORDER == __LITTLE_ENDIAN : defined(__LITTLE_ENDIAN) + __be16 remote_port; /* Network byte order */ + __u16 :16; /* Zero padding */ +#elif defined(__BYTE_ORDER) ? __BYTE_ORDER == __BIG_ENDIAN : defined(__BIG_ENDIAN) + __u16 :16; /* Zero padding */ + __be16 remote_port; /* Network byte order */ +#else +#error unspecified endianness +#endif + }; + __u32 remote_port_compat; + }; __u32 local_ip4; /* Network byte order */ __u32 local_ip6[4]; /* Network byte order */ __u32 local_port; /* Host byte order */ diff --git a/net/core/filter.c b/net/core/filter.c index 65869fd510e8..4b247d5aebe8 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -10856,8 +10856,7 @@ static bool sk_lookup_is_valid_access(int off, int size, case bpf_ctx_range(struct bpf_sk_lookup, local_ip4): case bpf_ctx_range_till(struct bpf_sk_lookup, remote_ip6[0], remote_ip6[3]): case bpf_ctx_range_till(struct bpf_sk_lookup, local_ip6[0], local_ip6[3]): - case offsetof(struct bpf_sk_lookup, remote_port) ... - offsetof(struct bpf_sk_lookup, local_ip4) - 1: + case bpf_ctx_range(struct bpf_sk_lookup, remote_port_compat): case bpf_ctx_range(struct bpf_sk_lookup, local_port): case bpf_ctx_range(struct bpf_sk_lookup, ingress_ifindex): bpf_ctx_record_field_size(info, sizeof(__u32)); @@ -10938,7 +10937,7 @@ static u32 sk_lookup_convert_ctx_access(enum bpf_access_type type, #endif break; } - case offsetof(struct bpf_sk_lookup, remote_port): + case offsetof(struct bpf_sk_lookup, remote_port_compat): *insn++ = BPF_LDX_MEM(BPF_H, si->dst_reg, si->src_reg, bpf_target_off(struct bpf_sk_lookup_kern, sport, 2, target_size)); diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index afe3d0d7f5f2..7b0e5efa58e0 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -10,6 +10,7 @@ #include <linux/types.h> #include <linux/bpf_common.h> +#include <asm/byteorder.h> /* Extended instruction set based on top of classic BPF */ @@ -6453,8 +6454,20 @@ struct bpf_sk_lookup { __u32 protocol; /* IP protocol (IPPROTO_TCP, IPPROTO_UDP) */ __u32 remote_ip4; /* Network byte order */ __u32 remote_ip6[4]; /* Network byte order */ - __be16 remote_port; /* Network byte order */ - __u16 :16; /* Zero padding */ + union { + struct { +#if defined(__BYTE_ORDER) ? __BYTE_ORDER == __LITTLE_ENDIAN : defined(__LITTLE_ENDIAN) + __be16 remote_port; /* Network byte order */ + __u16 :16; /* Zero padding */ +#elif defined(__BYTE_ORDER) ? __BYTE_ORDER == __BIG_ENDIAN : defined(__BIG_ENDIAN) + __u16 :16; /* Zero padding */ + __be16 remote_port; /* Network byte order */ +#else +#error unspecified endianness +#endif + }; + __u32 remote_port_compat; + }; __u32 local_ip4; /* Network byte order */ __u32 local_ip6[4]; /* Network byte order */ __u32 local_port; /* Host byte order */ -- 2.34.1