xfrm4: Fix uninitialized memory read in _decode_session4
authorSteffen Klassert <steffen.klassert@secunet.com>
Tue, 26 Feb 2019 06:04:50 +0000 (07:04 +0100)
committerSteffen Klassert <steffen.klassert@secunet.com>
Tue, 2 Apr 2019 06:18:39 +0000 (08:18 +0200)
We currently don't reload pointers pointing into skb header
after doing pskb_may_pull() in _decode_session4(). So in case
pskb_may_pull() changed the pointers, we read from random
memory. Fix this by putting all the needed infos on the
stack, so that we don't need to access the header pointers
after doing pskb_may_pull().

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
net/ipv4/xfrm4_policy.c

index d73a6d6652f60f8b81d47bb36766aa0d0329f3ce..2b144b92ae46a430d184fca120616166e8010f53 100644 (file)
@@ -111,7 +111,8 @@ static void
 _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse)
 {
        const struct iphdr *iph = ip_hdr(skb);
-       u8 *xprth = skb_network_header(skb) + iph->ihl * 4;
+       int ihl = iph->ihl;
+       u8 *xprth = skb_network_header(skb) + ihl * 4;
        struct flowi4 *fl4 = &fl->u.ip4;
        int oif = 0;
 
@@ -122,6 +123,11 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse)
        fl4->flowi4_mark = skb->mark;
        fl4->flowi4_oif = reverse ? skb->skb_iif : oif;
 
+       fl4->flowi4_proto = iph->protocol;
+       fl4->daddr = reverse ? iph->saddr : iph->daddr;
+       fl4->saddr = reverse ? iph->daddr : iph->saddr;
+       fl4->flowi4_tos = iph->tos;
+
        if (!ip_is_fragment(iph)) {
                switch (iph->protocol) {
                case IPPROTO_UDP:
@@ -133,7 +139,7 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse)
                            pskb_may_pull(skb, xprth + 4 - skb->data)) {
                                __be16 *ports;
 
-                               xprth = skb_network_header(skb) + iph->ihl * 4;
+                               xprth = skb_network_header(skb) + ihl * 4;
                                ports = (__be16 *)xprth;
 
                                fl4->fl4_sport = ports[!!reverse];
@@ -146,7 +152,7 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse)
                            pskb_may_pull(skb, xprth + 2 - skb->data)) {
                                u8 *icmp;
 
-                               xprth = skb_network_header(skb) + iph->ihl * 4;
+                               xprth = skb_network_header(skb) + ihl * 4;
                                icmp = xprth;
 
                                fl4->fl4_icmp_type = icmp[0];
@@ -159,7 +165,7 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse)
                            pskb_may_pull(skb, xprth + 4 - skb->data)) {
                                __be32 *ehdr;
 
-                               xprth = skb_network_header(skb) + iph->ihl * 4;
+                               xprth = skb_network_header(skb) + ihl * 4;
                                ehdr = (__be32 *)xprth;
 
                                fl4->fl4_ipsec_spi = ehdr[0];
@@ -171,7 +177,7 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse)
                            pskb_may_pull(skb, xprth + 8 - skb->data)) {
                                __be32 *ah_hdr;
 
-                               xprth = skb_network_header(skb) + iph->ihl * 4;
+                               xprth = skb_network_header(skb) + ihl * 4;
                                ah_hdr = (__be32 *)xprth;
 
                                fl4->fl4_ipsec_spi = ah_hdr[1];
@@ -183,7 +189,7 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse)
                            pskb_may_pull(skb, xprth + 4 - skb->data)) {
                                __be16 *ipcomp_hdr;
 
-                               xprth = skb_network_header(skb) + iph->ihl * 4;
+                               xprth = skb_network_header(skb) + ihl * 4;
                                ipcomp_hdr = (__be16 *)xprth;
 
                                fl4->fl4_ipsec_spi = htonl(ntohs(ipcomp_hdr[1]));
@@ -196,7 +202,7 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse)
                                __be16 *greflags;
                                __be32 *gre_hdr;
 
-                               xprth = skb_network_header(skb) + iph->ihl * 4;
+                               xprth = skb_network_header(skb) + ihl * 4;
                                greflags = (__be16 *)xprth;
                                gre_hdr = (__be32 *)xprth;
 
@@ -213,10 +219,6 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse)
                        break;
                }
        }
-       fl4->flowi4_proto = iph->protocol;
-       fl4->daddr = reverse ? iph->saddr : iph->daddr;
-       fl4->saddr = reverse ? iph->daddr : iph->saddr;
-       fl4->flowi4_tos = iph->tos;
 }
 
 static void xfrm4_update_pmtu(struct dst_entry *dst, struct sock *sk,