vrf: make sure skb->data contains ip header to make routing [Linux 4.9.187]

This Linux kernel change "vrf: make sure skb->data contains ip header to make routing" is included in the Linux 4.9.187 release. This change is authored by Peter Kosyh <p.kosyh [at] gmail.com> on Fri Jul 19 11:11:47 2019 +0300. The commit for this change in Linux stable tree is 0ce67cd (patch) which is from upstream commit 107e47c. The same Linux upstream change may have been applied to various maintained Linux releases and you can find all Linux releases containing changes from upstream 107e47c.

vrf: make sure skb->data contains ip header to make routing

[ Upstream commit 107e47cc80ec37cb332bd41b22b1c7779e22e018 ]

vrf_process_v4_outbound() and vrf_process_v6_outbound() do routing
using ip/ipv6 addresses, but don't make sure the header is available
in skb->data[] (skb_headlen() is less then header size).

Case:

1) igb driver from intel.
2) Packet size is greater then 255.
3) MPLS forwards to VRF device.

So, patch adds pskb_may_pull() calls in vrf_process_v4/v6_outbound()
functions.

Signed-off-by: Peter Kosyh <p.kosyh@gmail.com>
Reviewed-by: David Ahern <dsa@cumulusnetworks.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

There are 58 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 drivers/net/vrf.c | 58 +++++++++++++++++++++++++++++++++----------------------
 1 file changed, 35 insertions(+), 23 deletions(-)

diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c
index 42c9480..3b6e908 100644
--- a/drivers/net/vrf.c
+++ b/drivers/net/vrf.c
@@ -153,23 +153,29 @@ static int vrf_ip6_local_out(struct net *net, struct sock *sk,
 static netdev_tx_t vrf_process_v6_outbound(struct sk_buff *skb,
                       struct net_device *dev)
 {
-   const struct ipv6hdr *iph = ipv6_hdr(skb);
+   const struct ipv6hdr *iph;
    struct net *net = dev_net(skb->dev);
-   struct flowi6 fl6 = {
-       /* needed to match OIF rule */
-       .flowi6_oif = dev->ifindex,
-       .flowi6_iif = LOOPBACK_IFINDEX,
-       .daddr = iph->daddr,
-       .saddr = iph->saddr,
-       .flowlabel = ip6_flowinfo(iph),
-       .flowi6_mark = skb->mark,
-       .flowi6_proto = iph->nexthdr,
-       .flowi6_flags = FLOWI_FLAG_SKIP_NH_OIF,
-   };
+   struct flowi6 fl6;
    int ret = NET_XMIT_DROP;
    struct dst_entry *dst;
    struct dst_entry *dst_null = &net->ipv6.ip6_null_entry->dst;

+   if (!pskb_may_pull(skb, ETH_HLEN + sizeof(struct ipv6hdr)))
+       goto err;
+
+   iph = ipv6_hdr(skb);
+
+   memset(&fl6, 0, sizeof(fl6));
+   /* needed to match OIF rule */
+   fl6.flowi6_oif = dev->ifindex;
+   fl6.flowi6_iif = LOOPBACK_IFINDEX;
+   fl6.daddr = iph->daddr;
+   fl6.saddr = iph->saddr;
+   fl6.flowlabel = ip6_flowinfo(iph);
+   fl6.flowi6_mark = skb->mark;
+   fl6.flowi6_proto = iph->nexthdr;
+   fl6.flowi6_flags = FLOWI_FLAG_SKIP_NH_OIF;
+
    dst = ip6_route_output(net, NULL, &fl6);
    if (dst == dst_null)
        goto err;
@@ -257,21 +263,27 @@ static int vrf_ip_local_out(struct net *net, struct sock *sk,
 static netdev_tx_t vrf_process_v4_outbound(struct sk_buff *skb,
                       struct net_device *vrf_dev)
 {
-   struct iphdr *ip4h = ip_hdr(skb);
+   struct iphdr *ip4h;
    int ret = NET_XMIT_DROP;
-   struct flowi4 fl4 = {
-       /* needed to match OIF rule */
-       .flowi4_oif = vrf_dev->ifindex,
-       .flowi4_iif = LOOPBACK_IFINDEX,
-       .flowi4_tos = RT_TOS(ip4h->tos),
-       .flowi4_flags = FLOWI_FLAG_ANYSRC | FLOWI_FLAG_SKIP_NH_OIF,
-       .flowi4_proto = ip4h->protocol,
-       .daddr = ip4h->daddr,
-       .saddr = ip4h->saddr,
-   };
+   struct flowi4 fl4;
    struct net *net = dev_net(vrf_dev);
    struct rtable *rt;

+   if (!pskb_may_pull(skb, ETH_HLEN + sizeof(struct iphdr)))
+       goto err;
+
+   ip4h = ip_hdr(skb);
+
+   memset(&fl4, 0, sizeof(fl4));
+   /* needed to match OIF rule */
+   fl4.flowi4_oif = vrf_dev->ifindex;
+   fl4.flowi4_iif = LOOPBACK_IFINDEX;
+   fl4.flowi4_tos = RT_TOS(ip4h->tos);
+   fl4.flowi4_flags = FLOWI_FLAG_ANYSRC | FLOWI_FLAG_SKIP_NH_OIF;
+   fl4.flowi4_proto = ip4h->protocol;
+   fl4.daddr = ip4h->daddr;
+   fl4.saddr = ip4h->saddr;
+
    rt = ip_route_output_flow(net, &fl4, NULL);
    if (IS_ERR(rt))
        goto err;

Leave a Reply

Your email address will not be published. Required fields are marked *