3.16.72-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Steffen Klassert steffen.klassert@secunet.com
commit 8742dc86d0c7a9628117a989c11f04a9b6b898f3 upstream.
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 Signed-off-by: Ben Hutchings ben@decadent.org.uk --- net/ipv4/xfrm4_policy.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-)
--- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -103,7 +103,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;
@@ -114,6 +115,11 @@ _decode_session4(struct sk_buff *skb, st 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: @@ -125,7 +131,7 @@ _decode_session4(struct sk_buff *skb, st 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]; @@ -138,7 +144,7 @@ _decode_session4(struct sk_buff *skb, st 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]; @@ -151,7 +157,7 @@ _decode_session4(struct sk_buff *skb, st 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]; @@ -163,7 +169,7 @@ _decode_session4(struct sk_buff *skb, st 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]; @@ -175,7 +181,7 @@ _decode_session4(struct sk_buff *skb, st 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])); @@ -188,7 +194,7 @@ _decode_session4(struct sk_buff *skb, st __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;
@@ -205,10 +211,6 @@ _decode_session4(struct sk_buff *skb, st 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 inline int xfrm4_garbage_collect(struct dst_ops *ops)