]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
net: preserve IP control block during GSO segmentation
authorKonstantin Khlebnikov <koct9i@gmail.com>
Fri, 8 Jan 2016 12:21:46 +0000 (15:21 +0300)
committerChuck Anderson <chuck.anderson@oracle.com>
Fri, 20 Jan 2017 09:19:57 +0000 (01:19 -0800)
Orabug: 24469379

[ Upstream commit 9207f9d45b0ad071baa128e846d7e7ed85016df3 ]

Skb_gso_segment() uses skb control block during segmentation.
This patch adds 32-bytes room for previous control block which
will be copied into all resulting segments.

This patch fixes kernel crash during fragmenting forwarded packets.
Fragmentation requires valid IP CB in skb for clearing ip options.
Also patch removes custom save/restore in ovs code, now it's redundant.

Signed-off-by: Konstantin Khlebnikov <koct9i@gmail.com>
Link: http://lkml.kernel.org/r/CALYGNiP-0MZ-FExV2HutTvE9U-QQtkKSoE--KN=JQE5STYsjAA@mail.gmail.com
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
(cherry picked from commit abefd1b4087b9b5e83e7b4e7689f8b8e3cb2899c)

Signed-off-by: Dan Duval <dan.duval@oracle.com>
Signed-off-by: Ajaykumar Hotchandani <ajaykumar.hotchandani@oracle.com>
include/linux/skbuff.h
net/core/dev.c
net/ipv4/ip_output.c
net/openvswitch/datapath.c
net/xfrm/xfrm_output.c

index fd400922ccf882f29f5d4d8211ef7363b8a688cf..1e8e033be7bf7effd2a1322931886373b0f23f65 100644 (file)
@@ -3322,7 +3322,8 @@ struct skb_gso_cb {
        int     encap_level;
        __u16   csum_start;
 };
-#define SKB_GSO_CB(skb) ((struct skb_gso_cb *)(skb)->cb)
+#define SKB_SGO_CB_OFFSET      32
+#define SKB_GSO_CB(skb) ((struct skb_gso_cb *)((skb)->cb + SKB_SGO_CB_OFFSET))
 
 static inline int skb_tnl_header_len(const struct sk_buff *inner_skb)
 {
index 9ec0d9cd7f55c20c8b0185b111298af0d4e6a278..7505d7e8d8ea30c4e7ea25f205047ada7ffbfb48 100644 (file)
@@ -2483,6 +2483,8 @@ static inline bool skb_needs_check(struct sk_buff *skb, bool tx_path)
  *
  *     It may return NULL if the skb requires no segmentation.  This is
  *     only possible when GSO is used for verifying header integrity.
+ *
+ *     Segmentation preserves SKB_SGO_CB_OFFSET bytes of previous skb cb.
  */
 struct sk_buff *__skb_gso_segment(struct sk_buff *skb,
                                  netdev_features_t features, bool tx_path)
@@ -2497,6 +2499,9 @@ struct sk_buff *__skb_gso_segment(struct sk_buff *skb,
                        return ERR_PTR(err);
        }
 
+       BUILD_BUG_ON(SKB_SGO_CB_OFFSET +
+                    sizeof(*SKB_GSO_CB(skb)) > sizeof(skb->cb));
+
        SKB_GSO_CB(skb)->mac_offset = skb_headroom(skb);
        SKB_GSO_CB(skb)->encap_level = 0;
 
index c65b93a7b7113660d9f946128c0a4acee810de0f..b3c54638183c8bb325ee61a5c09c9b4ef8a77b32 100644 (file)
@@ -235,6 +235,7 @@ static int ip_finish_output_gso(struct sock *sk, struct sk_buff *skb)
         * from host network stack.
         */
        features = netif_skb_features(skb);
+       BUILD_BUG_ON(sizeof(*IPCB(skb)) > SKB_SGO_CB_OFFSET);
        segs = skb_gso_segment(skb, features & ~NETIF_F_GSO_MASK);
        if (IS_ERR_OR_NULL(segs)) {
                kfree_skb(skb);
index 096c6276e6b92680542ed1204bf396470c08caf5..302cd1e10bbc2da02dec8f4abdc7b4c7397f9afe 100644 (file)
@@ -337,12 +337,10 @@ static int queue_gso_packets(struct datapath *dp, struct sk_buff *skb,
        unsigned short gso_type = skb_shinfo(skb)->gso_type;
        struct sw_flow_key later_key;
        struct sk_buff *segs, *nskb;
-       struct ovs_skb_cb ovs_cb;
        int err;
 
-       ovs_cb = *OVS_CB(skb);
+       BUILD_BUG_ON(sizeof(*OVS_CB(skb)) > SKB_SGO_CB_OFFSET);
        segs = __skb_gso_segment(skb, NETIF_F_SG, false);
-       *OVS_CB(skb) = ovs_cb;
        if (IS_ERR(segs))
                return PTR_ERR(segs);
        if (segs == NULL)
@@ -360,7 +358,6 @@ static int queue_gso_packets(struct datapath *dp, struct sk_buff *skb,
        /* Queue all of the segments. */
        skb = segs;
        do {
-               *OVS_CB(skb) = ovs_cb;
                if (gso_type & SKB_GSO_UDP && skb != segs)
                        key = &later_key;
 
index fbcedbe33190346a40fc148369757a6ef64a2106..5097dce5b916661484cb0a1de5820fd8c8e19ae5 100644 (file)
@@ -153,6 +153,8 @@ static int xfrm_output_gso(struct sock *sk, struct sk_buff *skb)
 {
        struct sk_buff *segs;
 
+       BUILD_BUG_ON(sizeof(*IPCB(skb)) > SKB_SGO_CB_OFFSET);
+       BUILD_BUG_ON(sizeof(*IP6CB(skb)) > SKB_SGO_CB_OFFSET);
        segs = skb_gso_segment(skb, 0);
        kfree_skb(skb);
        if (IS_ERR(segs))