OSDN Git Service

bpf: Add state, dst_ip4, dst_ip6 and dst_port to bpf_sock
authorMartin KaFai Lau <kafai@fb.com>
Sun, 10 Feb 2019 07:22:21 +0000 (23:22 -0800)
committerAlexei Starovoitov <ast@kernel.org>
Mon, 11 Feb 2019 03:46:17 +0000 (19:46 -0800)
This patch adds "state", "dst_ip4", "dst_ip6" and "dst_port" to the
bpf_sock.  The userspace has already been using "state",
e.g. inet_diag (ss -t) and getsockopt(TCP_INFO).

This patch also allows narrow load on the following existing fields:
"family", "type", "protocol" and "src_port".  Unlike IP address,
the load offset is resticted to the first byte for them but it
can be relaxed later if there is a use case.

This patch also folds __sock_filter_check_size() into
bpf_sock_is_valid_access() since it is not called
by any where else.  All bpf_sock checking is in
one place.

Signed-off-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
include/uapi/linux/bpf.h
net/core/filter.c

index 5d79cba..d8f9177 100644 (file)
@@ -2606,15 +2606,14 @@ struct bpf_sock {
        __u32 protocol;
        __u32 mark;
        __u32 priority;
-       __u32 src_ip4;          /* Allows 1,2,4-byte read.
-                                * Stored in network byte order.
-                                */
-       __u32 src_ip6[4];       /* Allows 1,2,4-byte read.
-                                * Stored in network byte order.
-                                */
-       __u32 src_port;         /* Allows 4-byte read.
-                                * Stored in host byte order
-                                */
+       /* IP address also allows 1 and 2 bytes access */
+       __u32 src_ip4;
+       __u32 src_ip6[4];
+       __u32 src_port;         /* host byte order */
+       __u32 dst_port;         /* network byte order */
+       __u32 dst_ip4;
+       __u32 dst_ip6[4];
+       __u32 state;
 };
 
 struct bpf_sock_tuple {
index 401d2e0..01bb64b 100644 (file)
@@ -5958,21 +5958,6 @@ full_access:
        return true;
 }
 
-static bool __sock_filter_check_size(int off, int size,
-                                    struct bpf_insn_access_aux *info)
-{
-       const int size_default = sizeof(__u32);
-
-       switch (off) {
-       case bpf_ctx_range(struct bpf_sock, src_ip4):
-       case bpf_ctx_range_till(struct bpf_sock, src_ip6[0], src_ip6[3]):
-               bpf_ctx_record_field_size(info, size_default);
-               return bpf_ctx_narrow_access_ok(off, size, size_default);
-       }
-
-       return size == size_default;
-}
-
 bool bpf_sock_common_is_valid_access(int off, int size,
                                     enum bpf_access_type type,
                                     struct bpf_insn_access_aux *info)
@@ -5988,13 +5973,29 @@ bool bpf_sock_common_is_valid_access(int off, int size,
 bool bpf_sock_is_valid_access(int off, int size, enum bpf_access_type type,
                              struct bpf_insn_access_aux *info)
 {
+       const int size_default = sizeof(__u32);
+
        if (off < 0 || off >= sizeof(struct bpf_sock))
                return false;
        if (off % size != 0)
                return false;
-       if (!__sock_filter_check_size(off, size, info))
-               return false;
-       return true;
+
+       switch (off) {
+       case offsetof(struct bpf_sock, state):
+       case offsetof(struct bpf_sock, family):
+       case offsetof(struct bpf_sock, type):
+       case offsetof(struct bpf_sock, protocol):
+       case offsetof(struct bpf_sock, dst_port):
+       case offsetof(struct bpf_sock, src_port):
+       case bpf_ctx_range(struct bpf_sock, src_ip4):
+       case bpf_ctx_range_till(struct bpf_sock, src_ip6[0], src_ip6[3]):
+       case bpf_ctx_range(struct bpf_sock, dst_ip4):
+       case bpf_ctx_range_till(struct bpf_sock, dst_ip6[0], dst_ip6[3]):
+               bpf_ctx_record_field_size(info, size_default);
+               return bpf_ctx_narrow_access_ok(off, size, size_default);
+       }
+
+       return size == size_default;
 }
 
 static bool sock_filter_is_valid_access(int off, int size,
@@ -6838,24 +6839,32 @@ u32 bpf_sock_convert_ctx_access(enum bpf_access_type type,
                break;
 
        case offsetof(struct bpf_sock, family):
-               BUILD_BUG_ON(FIELD_SIZEOF(struct sock, sk_family) != 2);
-
-               *insn++ = BPF_LDX_MEM(BPF_H, si->dst_reg, si->src_reg,
-                                     offsetof(struct sock, sk_family));
+               *insn++ = BPF_LDX_MEM(
+                       BPF_FIELD_SIZEOF(struct sock_common, skc_family),
+                       si->dst_reg, si->src_reg,
+                       bpf_target_off(struct sock_common,
+                                      skc_family,
+                                      FIELD_SIZEOF(struct sock_common,
+                                                   skc_family),
+                                      target_size));
                break;
 
        case offsetof(struct bpf_sock, type):
+               BUILD_BUG_ON(HWEIGHT32(SK_FL_TYPE_MASK) != BITS_PER_BYTE * 2);
                *insn++ = BPF_LDX_MEM(BPF_W, si->dst_reg, si->src_reg,
                                      offsetof(struct sock, __sk_flags_offset));
                *insn++ = BPF_ALU32_IMM(BPF_AND, si->dst_reg, SK_FL_TYPE_MASK);
                *insn++ = BPF_ALU32_IMM(BPF_RSH, si->dst_reg, SK_FL_TYPE_SHIFT);
+               *target_size = 2;
                break;
 
        case offsetof(struct bpf_sock, protocol):
+               BUILD_BUG_ON(HWEIGHT32(SK_FL_PROTO_MASK) != BITS_PER_BYTE);
                *insn++ = BPF_LDX_MEM(BPF_W, si->dst_reg, si->src_reg,
                                      offsetof(struct sock, __sk_flags_offset));
                *insn++ = BPF_ALU32_IMM(BPF_AND, si->dst_reg, SK_FL_PROTO_MASK);
                *insn++ = BPF_ALU32_IMM(BPF_RSH, si->dst_reg, SK_FL_PROTO_SHIFT);
+               *target_size = 1;
                break;
 
        case offsetof(struct bpf_sock, src_ip4):
@@ -6867,6 +6876,15 @@ u32 bpf_sock_convert_ctx_access(enum bpf_access_type type,
                                       target_size));
                break;
 
+       case offsetof(struct bpf_sock, dst_ip4):
+               *insn++ = BPF_LDX_MEM(
+                       BPF_SIZE(si->code), si->dst_reg, si->src_reg,
+                       bpf_target_off(struct sock_common, skc_daddr,
+                                      FIELD_SIZEOF(struct sock_common,
+                                                   skc_daddr),
+                                      target_size));
+               break;
+
        case bpf_ctx_range_till(struct bpf_sock, src_ip6[0], src_ip6[3]):
 #if IS_ENABLED(CONFIG_IPV6)
                off = si->off;
@@ -6885,6 +6903,23 @@ u32 bpf_sock_convert_ctx_access(enum bpf_access_type type,
 #endif
                break;
 
+       case bpf_ctx_range_till(struct bpf_sock, dst_ip6[0], dst_ip6[3]):
+#if IS_ENABLED(CONFIG_IPV6)
+               off = si->off;
+               off -= offsetof(struct bpf_sock, dst_ip6[0]);
+               *insn++ = BPF_LDX_MEM(
+                       BPF_SIZE(si->code), si->dst_reg, si->src_reg,
+                       bpf_target_off(struct sock_common,
+                                      skc_v6_daddr.s6_addr32[0],
+                                      FIELD_SIZEOF(struct sock_common,
+                                                   skc_v6_daddr.s6_addr32[0]),
+                                      target_size) + off);
+#else
+               *insn++ = BPF_MOV32_IMM(si->dst_reg, 0);
+               *target_size = 4;
+#endif
+               break;
+
        case offsetof(struct bpf_sock, src_port):
                *insn++ = BPF_LDX_MEM(
                        BPF_FIELD_SIZEOF(struct sock_common, skc_num),
@@ -6894,6 +6929,26 @@ u32 bpf_sock_convert_ctx_access(enum bpf_access_type type,
                                                    skc_num),
                                       target_size));
                break;
+
+       case offsetof(struct bpf_sock, dst_port):
+               *insn++ = BPF_LDX_MEM(
+                       BPF_FIELD_SIZEOF(struct sock_common, skc_dport),
+                       si->dst_reg, si->src_reg,
+                       bpf_target_off(struct sock_common, skc_dport,
+                                      FIELD_SIZEOF(struct sock_common,
+                                                   skc_dport),
+                                      target_size));
+               break;
+
+       case offsetof(struct bpf_sock, state):
+               *insn++ = BPF_LDX_MEM(
+                       BPF_FIELD_SIZEOF(struct sock_common, skc_state),
+                       si->dst_reg, si->src_reg,
+                       bpf_target_off(struct sock_common, skc_state,
+                                      FIELD_SIZEOF(struct sock_common,
+                                                   skc_state),
+                                      target_size));
+               break;
        }
 
        return insn - insn_buf;