]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - net/core/filter.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[linux.git] / net / core / filter.c
index 8904e3407163e10385d951acbb1a066c18b37b1d..07687e2a2e661a9a1eda2c506893cf1a99cfe524 100644 (file)
@@ -2970,11 +2970,14 @@ static u32 bpf_skb_net_base_len(const struct sk_buff *skb)
 #define BPF_F_ADJ_ROOM_MASK            (BPF_F_ADJ_ROOM_FIXED_GSO | \
                                         BPF_F_ADJ_ROOM_ENCAP_L3_MASK | \
                                         BPF_F_ADJ_ROOM_ENCAP_L4_GRE | \
-                                        BPF_F_ADJ_ROOM_ENCAP_L4_UDP)
+                                        BPF_F_ADJ_ROOM_ENCAP_L4_UDP | \
+                                        BPF_F_ADJ_ROOM_ENCAP_L2( \
+                                         BPF_ADJ_ROOM_ENCAP_L2_MASK))
 
 static int bpf_skb_net_grow(struct sk_buff *skb, u32 off, u32 len_diff,
                            u64 flags)
 {
+       u8 inner_mac_len = flags >> BPF_ADJ_ROOM_ENCAP_L2_SHIFT;
        bool encap = flags & BPF_F_ADJ_ROOM_ENCAP_L3_MASK;
        u16 mac_len = 0, inner_net = 0, inner_trans = 0;
        unsigned int gso_type = SKB_GSO_DODGY;
@@ -3009,6 +3012,8 @@ static int bpf_skb_net_grow(struct sk_buff *skb, u32 off, u32 len_diff,
 
                mac_len = skb->network_header - skb->mac_header;
                inner_net = skb->network_header;
+               if (inner_mac_len > len_diff)
+                       return -EINVAL;
                inner_trans = skb->transport_header;
        }
 
@@ -3017,8 +3022,7 @@ static int bpf_skb_net_grow(struct sk_buff *skb, u32 off, u32 len_diff,
                return ret;
 
        if (encap) {
-               /* inner mac == inner_net on l3 encap */
-               skb->inner_mac_header = inner_net;
+               skb->inner_mac_header = inner_net - inner_mac_len;
                skb->inner_network_header = inner_net;
                skb->inner_transport_header = inner_trans;
                skb_set_inner_protocol(skb, skb->protocol);
@@ -3032,7 +3036,7 @@ static int bpf_skb_net_grow(struct sk_buff *skb, u32 off, u32 len_diff,
                        gso_type |= SKB_GSO_GRE;
                else if (flags & BPF_F_ADJ_ROOM_ENCAP_L3_IPV6)
                        gso_type |= SKB_GSO_IPXIP6;
-               else
+               else if (flags & BPF_F_ADJ_ROOM_ENCAP_L3_IPV4)
                        gso_type |= SKB_GSO_IPXIP4;
 
                if (flags & BPF_F_ADJ_ROOM_ENCAP_L4_GRE ||
@@ -4458,6 +4462,8 @@ BPF_CALL_3(bpf_bind, struct bpf_sock_addr_kern *, ctx, struct sockaddr *, addr,
         * Only binding to IP is supported.
         */
        err = -EINVAL;
+       if (addr_len < offsetofend(struct sockaddr, sa_family))
+               return err;
        if (addr->sa_family == AF_INET) {
                if (addr_len < sizeof(struct sockaddr_in))
                        return err;
@@ -4639,15 +4645,26 @@ static int bpf_ipv4_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
                return BPF_FIB_LKUP_RET_UNSUPP_LWT;
 
        dev = nhc->nhc_dev;
-       if (nhc->nhc_has_gw)
-               params->ipv4_dst = nhc->nhc_gw.ipv4;
 
        params->rt_metric = res.fi->fib_priority;
 
        /* xdp and cls_bpf programs are run in RCU-bh so
         * rcu_read_lock_bh is not needed here
         */
-       neigh = __ipv4_neigh_lookup_noref(dev, (__force u32)params->ipv4_dst);
+       if (likely(nhc->nhc_gw_family != AF_INET6)) {
+               if (nhc->nhc_gw_family)
+                       params->ipv4_dst = nhc->nhc_gw.ipv4;
+
+               neigh = __ipv4_neigh_lookup_noref(dev,
+                                                (__force u32)params->ipv4_dst);
+       } else {
+               struct in6_addr *dst = (struct in6_addr *)params->ipv6_dst;
+
+               params->family = AF_INET6;
+               *dst = nhc->nhc_gw.ipv6;
+               neigh = __ipv6_neigh_lookup_noref_stub(dev, dst);
+       }
+
        if (!neigh)
                return BPF_FIB_LKUP_RET_NO_NEIGH;
 
@@ -4752,18 +4769,16 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
        if (f6i->fib6_nh.fib_nh_lws)
                return BPF_FIB_LKUP_RET_UNSUPP_LWT;
 
-       if (f6i->fib6_nh.fib_nh_has_gw)
+       if (f6i->fib6_nh.fib_nh_gw_family)
                *dst = f6i->fib6_nh.fib_nh_gw6;
 
        dev = f6i->fib6_nh.fib_nh_dev;
        params->rt_metric = f6i->fib6_metric;
 
        /* xdp and cls_bpf programs are run in RCU-bh so rcu_read_lock_bh is
-        * not needed here. Can not use __ipv6_neigh_lookup_noref here
-        * because we need to get nd_tbl via the stub
+        * not needed here.
         */
-       neigh = ___neigh_lookup_noref(ipv6_stub->nd_tbl, neigh_key_eq128,
-                                     ndisc_hashfn, dst, dev);
+       neigh = __ipv6_neigh_lookup_noref_stub(dev, dst);
        if (!neigh)
                return BPF_FIB_LKUP_RET_NO_NEIGH;