Commit 63cc8e20 authored by Daniel Borkmann's avatar Daniel Borkmann

Merge branch 'bpf-fix-sock-field-tests'

Jakub Sitnicki says:

====================
I think we have reached a consensus [1] on how the test for the 4-byte load from
bpf_sock->dst_port and bpf_sk_lookup->remote_port should look, so here goes v3.

I will submit a separate set of patches for bpf_sk_lookup->remote_port tests.

This series has been tested on x86_64 and s390 on top of recent bpf-next -
ad13baf4 ("selftests/bpf: Test subprog jit when toggle bpf_jit_harden
repeatedly").

  [1] https://lore.kernel.org/bpf/87k0cwxkzs.fsf@cloudflare.com/

v2 -> v3:
- Split what was previously patch 2 which was doing two things
- Use BPF_TCP_* constants (Martin)
- Treat the result of 4-byte load from dst_port as a 16-bit value (Martin)
- Typo fixup and some rewording in patch 4 description
v1 -> v2:
- Limit read_sk_dst_port only to client traffic (patch 2)
- Make read_sk_dst_port pass on litte- and big-endian (patch 3)

v1: https://lore.kernel.org/bpf/20220225184130.483208-1-jakub@cloudflare.com/
v2: https://lore.kernel.org/bpf/20220227202757.519015-1-jakub@cloudflare.com/
====================
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
parents 60911970 deb59400
...@@ -114,7 +114,7 @@ static void tpcpy(struct bpf_tcp_sock *dst, ...@@ -114,7 +114,7 @@ static void tpcpy(struct bpf_tcp_sock *dst,
#define RET_LOG() ({ \ #define RET_LOG() ({ \
linum = __LINE__; \ linum = __LINE__; \
bpf_map_update_elem(&linum_map, &linum_idx, &linum, BPF_NOEXIST); \ bpf_map_update_elem(&linum_map, &linum_idx, &linum, BPF_ANY); \
return CG_OK; \ return CG_OK; \
}) })
...@@ -134,11 +134,11 @@ int egress_read_sock_fields(struct __sk_buff *skb) ...@@ -134,11 +134,11 @@ int egress_read_sock_fields(struct __sk_buff *skb)
if (!sk) if (!sk)
RET_LOG(); RET_LOG();
/* Not the testing egress traffic or /* Not testing the egress traffic or the listening socket,
* TCP_LISTEN (10) socket will be copied at the ingress side. * which are covered by the cgroup_skb/ingress test program.
*/ */
if (sk->family != AF_INET6 || !is_loopback6(sk->src_ip6) || if (sk->family != AF_INET6 || !is_loopback6(sk->src_ip6) ||
sk->state == 10) sk->state == BPF_TCP_LISTEN)
return CG_OK; return CG_OK;
if (sk->src_port == bpf_ntohs(srv_sa6.sin6_port)) { if (sk->src_port == bpf_ntohs(srv_sa6.sin6_port)) {
...@@ -232,8 +232,8 @@ int ingress_read_sock_fields(struct __sk_buff *skb) ...@@ -232,8 +232,8 @@ int ingress_read_sock_fields(struct __sk_buff *skb)
sk->src_port != bpf_ntohs(srv_sa6.sin6_port)) sk->src_port != bpf_ntohs(srv_sa6.sin6_port))
return CG_OK; return CG_OK;
/* Only interested in TCP_LISTEN */ /* Only interested in the listening socket */
if (sk->state != 10) if (sk->state != BPF_TCP_LISTEN)
return CG_OK; return CG_OK;
/* It must be a fullsock for cgroup_skb/ingress prog */ /* It must be a fullsock for cgroup_skb/ingress prog */
...@@ -251,10 +251,16 @@ int ingress_read_sock_fields(struct __sk_buff *skb) ...@@ -251,10 +251,16 @@ int ingress_read_sock_fields(struct __sk_buff *skb)
return CG_OK; return CG_OK;
} }
/*
* NOTE: 4-byte load from bpf_sock at dst_port offset is quirky. It
* gets rewritten by the access converter to a 2-byte load for
* backward compatibility. Treating the load result as a be16 value
* makes the code portable across little- and big-endian platforms.
*/
static __noinline bool sk_dst_port__load_word(struct bpf_sock *sk) static __noinline bool sk_dst_port__load_word(struct bpf_sock *sk)
{ {
__u32 *word = (__u32 *)&sk->dst_port; __u32 *word = (__u32 *)&sk->dst_port;
return word[0] == bpf_htonl(0xcafe0000); return word[0] == bpf_htons(0xcafe);
} }
static __noinline bool sk_dst_port__load_half(struct bpf_sock *sk) static __noinline bool sk_dst_port__load_half(struct bpf_sock *sk)
...@@ -281,6 +287,10 @@ int read_sk_dst_port(struct __sk_buff *skb) ...@@ -281,6 +287,10 @@ int read_sk_dst_port(struct __sk_buff *skb)
if (!sk) if (!sk)
RET_LOG(); RET_LOG();
/* Ignore everything but the SYN from the client socket */
if (sk->state != BPF_TCP_SYN_SENT)
return CG_OK;
if (!sk_dst_port__load_word(sk)) if (!sk_dst_port__load_word(sk))
RET_LOG(); RET_LOG();
if (!sk_dst_port__load_half(sk)) if (!sk_dst_port__load_half(sk))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment