Merge https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next
[linux-2.6-microblaze.git] / net / core / filter.c
index 46f09a8..26e0276 100644 (file)
@@ -9756,22 +9756,46 @@ static u32 sock_ops_convert_ctx_access(enum bpf_access_type type,
 static struct bpf_insn *bpf_convert_data_end_access(const struct bpf_insn *si,
                                                    struct bpf_insn *insn)
 {
-       /* si->dst_reg = skb->data */
+       int reg;
+       int temp_reg_off = offsetof(struct sk_buff, cb) +
+                          offsetof(struct sk_skb_cb, temp_reg);
+
+       if (si->src_reg == si->dst_reg) {
+               /* We need an extra register, choose and save a register. */
+               reg = BPF_REG_9;
+               if (si->src_reg == reg || si->dst_reg == reg)
+                       reg--;
+               if (si->src_reg == reg || si->dst_reg == reg)
+                       reg--;
+               *insn++ = BPF_STX_MEM(BPF_DW, si->src_reg, reg, temp_reg_off);
+       } else {
+               reg = si->dst_reg;
+       }
+
+       /* reg = skb->data */
        *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, data),
-                             si->dst_reg, si->src_reg,
+                             reg, si->src_reg,
                              offsetof(struct sk_buff, data));
        /* AX = skb->len */
        *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, len),
                              BPF_REG_AX, si->src_reg,
                              offsetof(struct sk_buff, len));
-       /* si->dst_reg = skb->data + skb->len */
-       *insn++ = BPF_ALU64_REG(BPF_ADD, si->dst_reg, BPF_REG_AX);
+       /* reg = skb->data + skb->len */
+       *insn++ = BPF_ALU64_REG(BPF_ADD, reg, BPF_REG_AX);
        /* AX = skb->data_len */
        *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, data_len),
                              BPF_REG_AX, si->src_reg,
                              offsetof(struct sk_buff, data_len));
-       /* si->dst_reg = skb->data + skb->len - skb->data_len */
-       *insn++ = BPF_ALU64_REG(BPF_SUB, si->dst_reg, BPF_REG_AX);
+
+       /* reg = skb->data + skb->len - skb->data_len */
+       *insn++ = BPF_ALU64_REG(BPF_SUB, reg, BPF_REG_AX);
+
+       if (si->src_reg == si->dst_reg) {
+               /* Restore the saved register */
+               *insn++ = BPF_MOV64_REG(BPF_REG_AX, si->src_reg);
+               *insn++ = BPF_MOV64_REG(si->dst_reg, reg);
+               *insn++ = BPF_LDX_MEM(BPF_DW, reg, BPF_REG_AX, temp_reg_off);
+       }
 
        return insn;
 }
@@ -9782,11 +9806,33 @@ static u32 sk_skb_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_buff, data_end):
                insn = bpf_convert_data_end_access(si, insn);
                break;
+       case offsetof(struct __sk_buff, cb[0]) ...
+            offsetofend(struct __sk_buff, cb[4]) - 1:
+               BUILD_BUG_ON(sizeof_field(struct sk_skb_cb, data) < 20);
+               BUILD_BUG_ON((offsetof(struct sk_buff, cb) +
+                             offsetof(struct sk_skb_cb, data)) %
+                            sizeof(__u64));
+
+               prog->cb_access = 1;
+               off  = si->off;
+               off -= offsetof(struct __sk_buff, cb[0]);
+               off += offsetof(struct sk_buff, cb);
+               off += offsetof(struct sk_skb_cb, data);
+               if (type == BPF_WRITE)
+                       *insn++ = BPF_STX_MEM(BPF_SIZE(si->code), si->dst_reg,
+                                             si->src_reg, off);
+               else
+                       *insn++ = BPF_LDX_MEM(BPF_SIZE(si->code), si->dst_reg,
+                                             si->src_reg, off);
+               break;
+
+
        default:
                return bpf_convert_ctx_access(type, si, insn_buf, prog,
                                              target_size);
@@ -10423,8 +10469,10 @@ BPF_CALL_3(bpf_sk_lookup_assign, struct bpf_sk_lookup_kern *, ctx,
                return -EINVAL;
        if (unlikely(sk && sk_is_refcounted(sk)))
                return -ESOCKTNOSUPPORT; /* reject non-RCU freed sockets */
-       if (unlikely(sk && sk->sk_state == TCP_ESTABLISHED))
-               return -ESOCKTNOSUPPORT; /* reject connected sockets */
+       if (unlikely(sk && sk_is_tcp(sk) && sk->sk_state != TCP_LISTEN))
+               return -ESOCKTNOSUPPORT; /* only accept TCP socket in LISTEN */
+       if (unlikely(sk && sk_is_udp(sk) && sk->sk_state != TCP_CLOSE))
+               return -ESOCKTNOSUPPORT; /* only accept UDP socket in CLOSE */
 
        /* Check if socket is suitable for packet L3/L4 protocol */
        if (sk && sk->sk_protocol != ctx->protocol)