[ovs-dev] [PATCH 2/8] gre: Check that the IP header is actually there before using it.

Jesse Gross jesse at nicira.com
Thu Mar 4 18:22:07 UTC 2010


GRE is nominally operating at layer 2 but it has some special
features for IP packets.  This checks that the IP header is present
before trying to read it.  If it is not there, we just disable the
special features but still process the packet.
---
 datapath/linux-2.6/compat-2.6/ip_gre.c |   25 +++++++++++++++++++++++++
 1 files changed, 25 insertions(+), 0 deletions(-)

diff --git a/datapath/linux-2.6/compat-2.6/ip_gre.c b/datapath/linux-2.6/compat-2.6/ip_gre.c
index ec0f0c5..d39dfb0 100644
--- a/datapath/linux-2.6/compat-2.6/ip_gre.c
+++ b/datapath/linux-2.6/compat-2.6/ip_gre.c
@@ -536,8 +536,16 @@ static inline void ipgre_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb)
 {
 	if (INET_ECN_is_ce(iph->tos)) {
 		if (skb->protocol == htons(ETH_P_IP)) {
+			if (unlikely(!pskb_may_pull(skb, skb_network_header(skb)
+			    + sizeof(struct iphdr) - skb->data)))
+				return;
+
 			IP_ECN_set_ce(ip_hdr(skb));
 		} else if (skb->protocol == htons(ETH_P_IPV6)) {
+			if (unlikely(!pskb_may_pull(skb, skb_network_header(skb)
+			    + sizeof(struct ipv6hdr) - skb->data)))
+				return;
+
 			IP6_ECN_set_ce(ipv6_hdr(skb));
 		}
 	}
@@ -683,6 +691,8 @@ static int ipgre_rcv(struct sk_buff *skb)
 		nf_reset(skb);
 
 		skb_reset_network_header(skb);
+
+		/* Invalidates pointers. */
 		ipgre_ecn_decapsulate(iph, skb);
 
 		netif_rx(skb);
@@ -716,6 +726,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
 	int    gre_hlen;
 	__be32 dst;
 	int    mtu;
+	u8   original_protocol;
 
 #ifdef HAVE_NETDEV_STATS
 	stats = &dev->stats;
@@ -723,6 +734,18 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
 	stats = &tunnel->stat;
 #endif
 
+	/* Validate the protocol headers before we try to use them. */
+	original_protocol = skb->protocol;
+	if (skb->protocol == htons(ETH_P_IP)) {
+		if (unlikely(!pskb_may_pull(skb, skb_network_header(skb)
+		    + sizeof(struct iphdr) - skb->data)))
+			skb->protocol = 0;
+	} else if (skb->protocol == htons(ETH_P_IPV6)) {
+		if (unlikely(!pskb_may_pull(skb, skb_network_header(skb)
+		    + sizeof(struct ipv6hdr) - skb->data)))
+			skb->protocol = 0;
+	}
+
 	if (dev->type == ARPHRD_ETHER)
 		IPCB(skb)->flags = 0;
 
@@ -917,6 +940,8 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
 			iph->ttl = dst_metric(&rt->u.dst, RTAX_HOPLIMIT);
 	}
 
+	skb->protocol = original_protocol;
+
 	((__be16 *)(iph + 1))[0] = tunnel->parms.o_flags;
 	((__be16 *)(iph + 1))[1] = (dev->type == ARPHRD_ETHER) ?
 				   htons(ETH_P_TEB) : skb->protocol;
-- 
1.6.3.3





More information about the dev mailing list