Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'Make 2-byte access to bpf_sk_lookup->remote_port endian-agnostic'

Jakub Sitnicki says:

====================

This patch set is a result of a discussion we had around the RFC patchset from
Ilya [1]. The fix for the narrow loads from the RFC series is still relevant,
but this series does not depend on it. Nor is it required to unbreak sk_lookup
tests on BE, if this series gets applied.

To summarize the takeaways from [1]:

1) we want to make 2-byte load from ctx->remote_port portable across LE and BE,
2) we keep the 4-byte load from ctx->remote_port as it is today - result varies
on endianess of the platform.

[1] https://lore.kernel.org/bpf/20220222182559.2865596-2-iii@linux.ibm.com/

v1 -> v2:
- Remove needless check that 4-byte load is from &ctx->remote_port offset
(Martin)

[v1]: https://lore.kernel.org/bpf/20220317165826.1099418-1-jakub@cloudflare.com/
====================

Signed-off-by: Alexei Starovoitov <ast@kernel.org>

+27 -6
+18 -2
net/core/filter.c
··· 10989 10989 case bpf_ctx_range(struct bpf_sk_lookup, local_ip4): 10990 10990 case bpf_ctx_range_till(struct bpf_sk_lookup, remote_ip6[0], remote_ip6[3]): 10991 10991 case bpf_ctx_range_till(struct bpf_sk_lookup, local_ip6[0], local_ip6[3]): 10992 - case offsetof(struct bpf_sk_lookup, remote_port) ... 10993 - offsetof(struct bpf_sk_lookup, local_ip4) - 1: 10994 10992 case bpf_ctx_range(struct bpf_sk_lookup, local_port): 10995 10993 case bpf_ctx_range(struct bpf_sk_lookup, ingress_ifindex): 10996 10994 bpf_ctx_record_field_size(info, sizeof(__u32)); 10997 10995 return bpf_ctx_narrow_access_ok(off, size, sizeof(__u32)); 10996 + 10997 + case bpf_ctx_range(struct bpf_sk_lookup, remote_port): 10998 + /* Allow 4-byte access to 2-byte field for backward compatibility */ 10999 + if (size == sizeof(__u32)) 11000 + return true; 11001 + bpf_ctx_record_field_size(info, sizeof(__be16)); 11002 + return bpf_ctx_narrow_access_ok(off, size, sizeof(__be16)); 11003 + 11004 + case offsetofend(struct bpf_sk_lookup, remote_port) ... 11005 + offsetof(struct bpf_sk_lookup, local_ip4) - 1: 11006 + /* Allow access to zero padding for backward compatibility */ 11007 + bpf_ctx_record_field_size(info, sizeof(__u16)); 11008 + return bpf_ctx_narrow_access_ok(off, size, sizeof(__u16)); 10998 11009 10999 11010 default: 11000 11011 return false; ··· 11086 11075 *insn++ = BPF_LDX_MEM(BPF_H, si->dst_reg, si->src_reg, 11087 11076 bpf_target_off(struct bpf_sk_lookup_kern, 11088 11077 sport, 2, target_size)); 11078 + break; 11079 + 11080 + case offsetofend(struct bpf_sk_lookup, remote_port): 11081 + *target_size = 2; 11082 + *insn++ = BPF_MOV32_IMM(si->dst_reg, 0); 11089 11083 break; 11090 11084 11091 11085 case offsetof(struct bpf_sk_lookup, local_port):
+9 -4
tools/testing/selftests/bpf/progs/test_sk_lookup.c
··· 413 413 414 414 /* Narrow loads from remote_port field. Expect SRC_PORT. */ 415 415 if (LSB(ctx->remote_port, 0) != ((SRC_PORT >> 0) & 0xff) || 416 - LSB(ctx->remote_port, 1) != ((SRC_PORT >> 8) & 0xff) || 417 - LSB(ctx->remote_port, 2) != 0 || LSB(ctx->remote_port, 3) != 0) 416 + LSB(ctx->remote_port, 1) != ((SRC_PORT >> 8) & 0xff)) 418 417 return SK_DROP; 419 418 if (LSW(ctx->remote_port, 0) != SRC_PORT) 420 419 return SK_DROP; 421 420 422 - /* Load from remote_port field with zero padding (backward compatibility) */ 421 + /* 422 + * NOTE: 4-byte load from bpf_sk_lookup at remote_port offset 423 + * is quirky. It gets rewritten by the access converter to a 424 + * 2-byte load for backward compatibility. Treating the load 425 + * result as a be16 value makes the code portable across 426 + * little- and big-endian platforms. 427 + */ 423 428 val_u32 = *(__u32 *)&ctx->remote_port; 424 - if (val_u32 != bpf_htonl(bpf_ntohs(SRC_PORT) << 16)) 429 + if (val_u32 != SRC_PORT) 425 430 return SK_DROP; 426 431 427 432 /* Narrow loads from local_port field. Expect DST_PORT. */