bpf: allow sk_msg programs to read sock fields
authorJohn Fastabend <john.fastabend@gmail.com>
Thu, 17 May 2018 21:16:58 +0000 (14:16 -0700)
committerDaniel Borkmann <daniel@iogearbox.net>
Fri, 18 May 2018 20:44:10 +0000 (22:44 +0200)
Currently sk_msg programs only have access to the raw data. However,
it is often useful when building policies to have the policies specific
to the socket endpoint. This allows using the socket tuple as input
into filters, etc.

This patch adds ctx access to the sock fields.

Signed-off-by: John Fastabend <john.fastabend@gmail.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
include/linux/filter.h
include/uapi/linux/bpf.h
kernel/bpf/sockmap.c
net/core/filter.c

index 9dbcb9d55921b6914724e90f8c99e21149112527..d358d1815c1652592b16b1940930b0d70dc9c782 100644 (file)
@@ -517,6 +517,7 @@ struct sk_msg_buff {
        bool sg_copy[MAX_SKB_FRAGS];
        __u32 flags;
        struct sock *sk_redir;
+       struct sock *sk;
        struct sk_buff *skb;
        struct list_head list;
 };
index d94d333a82259cbf07f6725445f7768b96a24419..97446bbe2ca52699b6cc11090b4093c35da77348 100644 (file)
@@ -2176,6 +2176,14 @@ enum sk_action {
 struct sk_msg_md {
        void *data;
        void *data_end;
+
+       __u32 family;
+       __u32 remote_ip4;       /* Stored in network byte order */
+       __u32 local_ip4;        /* Stored in network byte order */
+       __u32 remote_ip6[4];    /* Stored in network byte order */
+       __u32 local_ip6[4];     /* Stored in network byte order */
+       __u32 remote_port;      /* Stored in network byte order */
+       __u32 local_port;       /* stored in host byte order */
 };
 
 #define BPF_TAG_SIZE   8
index c682669570dc45c65f978308141d8352cde16f7e..3b28955a6383e656513e34213ebc9adcbec86ddb 100644 (file)
@@ -523,6 +523,7 @@ static unsigned int smap_do_tx_msg(struct sock *sk,
        }
 
        bpf_compute_data_pointers_sg(md);
+       md->sk = sk;
        rc = (*prog->bpf_func)(md, prog->insnsi);
        psock->apply_bytes = md->apply_bytes;
 
index 6d0d1560bd70e88c3ebaaf636e4a27e2f3f395d5..aec5ebafb2629424da813c6abe210350ec150f6b 100644 (file)
@@ -5148,18 +5148,23 @@ static bool sk_msg_is_valid_access(int off, int size,
        switch (off) {
        case offsetof(struct sk_msg_md, data):
                info->reg_type = PTR_TO_PACKET;
+               if (size != sizeof(__u64))
+                       return false;
                break;
        case offsetof(struct sk_msg_md, data_end):
                info->reg_type = PTR_TO_PACKET_END;
+               if (size != sizeof(__u64))
+                       return false;
                break;
+       default:
+               if (size != sizeof(__u32))
+                       return false;
        }
 
        if (off < 0 || off >= sizeof(struct sk_msg_md))
                return false;
        if (off % size != 0)
                return false;
-       if (size != sizeof(__u64))
-               return false;
 
        return true;
 }
@@ -5835,7 +5840,8 @@ static u32 sock_ops_convert_ctx_access(enum bpf_access_type type,
                break;
 
        case offsetof(struct bpf_sock_ops, local_ip4):
-               BUILD_BUG_ON(FIELD_SIZEOF(struct sock_common, skc_rcv_saddr) != 4);
+               BUILD_BUG_ON(FIELD_SIZEOF(struct sock_common,
+                                         skc_rcv_saddr) != 4);
 
                *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(
                                              struct bpf_sock_ops_kern, sk),
@@ -6152,6 +6158,7 @@ static u32 sk_msg_convert_ctx_access(enum bpf_access_type type,
                                     struct bpf_prog *prog, u32 *target_size)
 {
        struct bpf_insn *insn = insn_buf;
+       int off;
 
        switch (si->off) {
        case offsetof(struct sk_msg_md, data):
@@ -6164,6 +6171,107 @@ static u32 sk_msg_convert_ctx_access(enum bpf_access_type type,
                                      si->dst_reg, si->src_reg,
                                      offsetof(struct sk_msg_buff, data_end));
                break;
+       case offsetof(struct sk_msg_md, family):
+               BUILD_BUG_ON(FIELD_SIZEOF(struct sock_common, skc_family) != 2);
+
+               *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(
+                                             struct sk_msg_buff, sk),
+                                     si->dst_reg, si->src_reg,
+                                     offsetof(struct sk_msg_buff, sk));
+               *insn++ = BPF_LDX_MEM(BPF_H, si->dst_reg, si->dst_reg,
+                                     offsetof(struct sock_common, skc_family));
+               break;
+
+       case offsetof(struct sk_msg_md, remote_ip4):
+               BUILD_BUG_ON(FIELD_SIZEOF(struct sock_common, skc_daddr) != 4);
+
+               *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(
+                                               struct sk_msg_buff, sk),
+                                     si->dst_reg, si->src_reg,
+                                     offsetof(struct sk_msg_buff, sk));
+               *insn++ = BPF_LDX_MEM(BPF_W, si->dst_reg, si->dst_reg,
+                                     offsetof(struct sock_common, skc_daddr));
+               break;
+
+       case offsetof(struct sk_msg_md, local_ip4):
+               BUILD_BUG_ON(FIELD_SIZEOF(struct sock_common,
+                                         skc_rcv_saddr) != 4);
+
+               *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(
+                                             struct sk_msg_buff, sk),
+                                     si->dst_reg, si->src_reg,
+                                     offsetof(struct sk_msg_buff, sk));
+               *insn++ = BPF_LDX_MEM(BPF_W, si->dst_reg, si->dst_reg,
+                                     offsetof(struct sock_common,
+                                              skc_rcv_saddr));
+               break;
+
+       case offsetof(struct sk_msg_md, remote_ip6[0]) ...
+            offsetof(struct sk_msg_md, remote_ip6[3]):
+#if IS_ENABLED(CONFIG_IPV6)
+               BUILD_BUG_ON(FIELD_SIZEOF(struct sock_common,
+                                         skc_v6_daddr.s6_addr32[0]) != 4);
+
+               off = si->off;
+               off -= offsetof(struct sk_msg_md, remote_ip6[0]);
+               *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(
+                                               struct sk_msg_buff, sk),
+                                     si->dst_reg, si->src_reg,
+                                     offsetof(struct sk_msg_buff, sk));
+               *insn++ = BPF_LDX_MEM(BPF_W, si->dst_reg, si->dst_reg,
+                                     offsetof(struct sock_common,
+                                              skc_v6_daddr.s6_addr32[0]) +
+                                     off);
+#else
+               *insn++ = BPF_MOV32_IMM(si->dst_reg, 0);
+#endif
+               break;
+
+       case offsetof(struct sk_msg_md, local_ip6[0]) ...
+            offsetof(struct sk_msg_md, local_ip6[3]):
+#if IS_ENABLED(CONFIG_IPV6)
+               BUILD_BUG_ON(FIELD_SIZEOF(struct sock_common,
+                                         skc_v6_rcv_saddr.s6_addr32[0]) != 4);
+
+               off = si->off;
+               off -= offsetof(struct sk_msg_md, local_ip6[0]);
+               *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(
+                                               struct sk_msg_buff, sk),
+                                     si->dst_reg, si->src_reg,
+                                     offsetof(struct sk_msg_buff, sk));
+               *insn++ = BPF_LDX_MEM(BPF_W, si->dst_reg, si->dst_reg,
+                                     offsetof(struct sock_common,
+                                              skc_v6_rcv_saddr.s6_addr32[0]) +
+                                     off);
+#else
+               *insn++ = BPF_MOV32_IMM(si->dst_reg, 0);
+#endif
+               break;
+
+       case offsetof(struct sk_msg_md, remote_port):
+               BUILD_BUG_ON(FIELD_SIZEOF(struct sock_common, skc_dport) != 2);
+
+               *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(
+                                               struct sk_msg_buff, sk),
+                                     si->dst_reg, si->src_reg,
+                                     offsetof(struct sk_msg_buff, sk));
+               *insn++ = BPF_LDX_MEM(BPF_H, si->dst_reg, si->dst_reg,
+                                     offsetof(struct sock_common, skc_dport));
+#ifndef __BIG_ENDIAN_BITFIELD
+               *insn++ = BPF_ALU32_IMM(BPF_LSH, si->dst_reg, 16);
+#endif
+               break;
+
+       case offsetof(struct sk_msg_md, local_port):
+               BUILD_BUG_ON(FIELD_SIZEOF(struct sock_common, skc_num) != 2);
+
+               *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(
+                                               struct sk_msg_buff, sk),
+                                     si->dst_reg, si->src_reg,
+                                     offsetof(struct sk_msg_buff, sk));
+               *insn++ = BPF_LDX_MEM(BPF_H, si->dst_reg, si->dst_reg,
+                                     offsetof(struct sock_common, skc_num));
+               break;
        }
 
        return insn - insn_buf;