skb protocol offsets are relative to the beginning of the
buffer and therefore must be updated if the buffer size is
expanded. Kernel functions do this automatically for existing
fields but obviously not for anything that we backport. This
introduces a wrapper for pskb_expand_head() to update the
inner protocol fields that we have backported.

Without this, a kernel crash can be triggered with tunnel
packets that do not have enough headroom and need to be
segmented.

Reported-by: Yinpeijun <yinpei...@huawei.com>
Signed-off-by: Jesse Gross <je...@nicira.com>
---
 datapath/linux/compat/gso.h | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/datapath/linux/compat/gso.h b/datapath/linux/compat/gso.h
index 337d13a..ba94eae 100644
--- a/datapath/linux/compat/gso.h
+++ b/datapath/linux/compat/gso.h
@@ -125,6 +125,27 @@ static inline void skb_reset_inner_headers(struct sk_buff 
*skb)
        skb_set_inner_network_header(skb, skb_network_offset(skb));
        skb_set_inner_transport_header(skb, skb_transport_offset(skb));
 }
+
+static inline int rpl_pskb_expand_head(struct sk_buff *skb, int nhead,
+                                      int ntail, gfp_t gfp_mask)
+{
+       int err;
+
+       err = pskb_expand_head(skb, nhead, ntail, gfp_mask);
+       if (err)
+               return err;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0)
+       OVS_GSO_CB(skb)->inner_mac_header += nhead;
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)
+       OVS_GSO_CB(skb)->inner_network_header += nhead;
+#endif
+
+       return 0;
+}
+#define pskb_expand_head rpl_pskb_expand_head
+
 #endif /* 3.18 */
 
 #endif
-- 
1.9.1

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to