[ovs-dev] [PATCHv2] datapath: Fix panic sending IP frags over tunnels.

Joe Stringer joe at ovn.org
Wed Jan 20 23:26:49 UTC 2016


The entire OVS_GSO_CB was not preserved when handling IP fragments,
leading to the following NULL pointer dereference in ovs_stt_xmit(). Fix
this in the fragmentation handling code by preserving the whole CB.

BUG: unable to handle kernel NULL pointer dereference at 000000000000001c
IP: [<ffffffffa0cfc5b1>] ovs_stt_xmit+0x61/0x260 [openvswitch]
Call Trace:
 [<ffffffff815f682e>] ? __alloc_skb+0x7e/0x2b0
 [<ffffffffa0cf1134>] ovs_vport_send+0x44/0xb0 [openvswitch]
 [<ffffffffa0ce241f>] ovs_vport_output+0x10f/0x190 [openvswitch]
 [<ffffffff8163fe98>] ip_fragment+0x238/0x870
 [<ffffffffa0ce2310>] ? do_output.isra.35+0x120/0x120 [openvswitch]
 [<ffffffffa0d02093>] ovs_fragment+0x283/0x292 [openvswitch]
 [<ffffffff81073ff7>] ? mod_timer_pending+0x67/0x1b0
 [<ffffffff8160e2d0>] ? dst_ifdown+0x90/0x90
 [<ffffffff8160e2d0>] ? dst_ifdown+0x90/0x90
 [<ffffffffa0b30165>] ? nfnetlink_has_listeners+0x15/0x20 [nfnetlink]
 [<ffffffffa0cdb164>] ? ctnetlink_conntrack_event+0x74/0x7ee [nf_conntrack_netlink]
 [<ffffffffa0b873cd>] ? nf_ct_deliver_cached_events+0xad/0xf0 [nf_conntrack]
 [<ffffffff81360331>] ? csum_partial+0x11/0x20
 [<ffffffffa0ce2747>] ? execute_masked_set_action+0x2a7/0xa60 [openvswitch]
 [<ffffffffa0ce22a8>] do_output.isra.35+0xb8/0x120 [openvswitch]
 [<ffffffffa0ce2ff4>] do_execute_actions+0xf4/0x7f0 [openvswitch]
 [<ffffffffa0ce3730>] ovs_execute_actions+0x40/0x130 [openvswitch]
 [<ffffffffa0ce7c69>] ovs_packet_cmd_execute+0x2b9/0x2e0 [openvswitch]
 [<ffffffff81634fad>] genl_family_rcv_msg+0x18d/0x370
 [<ffffffff81635190>] ? genl_family_rcv_msg+0x370/0x370
 [<ffffffff81635221>] genl_rcv_msg+0x91/0xd0
 [<ffffffff816332c9>] netlink_rcv_skb+0xa9/0xc0
 [<ffffffff816337c8>] genl_rcv+0x28/0x40
 [<ffffffff816329b5>] netlink_unicast+0xd5/0x1b0
 [<ffffffff81632d9e>] netlink_sendmsg+0x30e/0x680
 [<ffffffff8162fc84>] ? netlink_rcv_wake+0x44/0x60
 [<ffffffff81630d12>] ? netlink_recvmsg+0x1a2/0x3a0
 [<ffffffff815ed7fb>] sock_sendmsg+0x8b/0xc0
 [<ffffffff8114d06d>] ? __alloc_pages_nodemask+0x16d/0xac0
 [<ffffffff8101c4b9>] ? sched_clock+0x9/0x10
 [<ffffffff815edbc9>] ___sys_sendmsg+0x349/0x360
 [<ffffffff811f8a39>] ? ep_scan_ready_list.isra.7+0x199/0x1c0
 [<ffffffff8110705c>] ? acct_account_cputime+0x1c/0x20
 [<ffffffff811cd90f>] ? fget_light+0x8f/0xf0
 [<ffffffff815ee922>] __sys_sendmsg+0x42/0x80
 [<ffffffff815ee972>] SyS_sendmsg+0x12/0x20
 [<ffffffff8170f22f>] tracesys+0xe1/0xe6

VMware-BZ: #1587324
Fixes: a94ebc39996b ("datapath: Add conntrack action")
Signed-off-by: Joe Stringer <joe at ovn.org>
---
v2: Also save GSO_CB in handle_fragments().
---
 datapath/actions.c   | 6 +++---
 datapath/conntrack.c | 9 +++++----
 2 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/datapath/actions.c b/datapath/actions.c
index 6917d5169197..20413c950f3c 100644
--- a/datapath/actions.c
+++ b/datapath/actions.c
@@ -60,7 +60,7 @@ struct deferred_action {
 struct ovs_frag_data {
 	unsigned long dst;
 	struct vport *vport;
-	struct ovs_skb_cb cb;
+	struct ovs_gso_cb cb;
 	__be16 inner_protocol;
 	__u16 vlan_tci;
 	__be16 vlan_proto;
@@ -637,7 +637,7 @@ static int ovs_vport_output(OVS_VPORT_OUTPUT_PARAMS)
 	}
 
 	__skb_dst_copy(skb, data->dst);
-	*OVS_CB(skb) = data->cb;
+	*OVS_GSO_CB(skb) = data->cb;
 	ovs_skb_set_inner_protocol(skb, data->inner_protocol);
 	skb->vlan_tci = data->vlan_tci;
 	skb->vlan_proto = data->vlan_proto;
@@ -674,7 +674,7 @@ static void prepare_frag(struct vport *vport, struct sk_buff *skb)
 	data = get_pcpu_ptr(ovs_frag_data_storage);
 	data->dst = (unsigned long) skb_dst(skb);
 	data->vport = vport;
-	data->cb = *OVS_CB(skb);
+	data->cb = *OVS_GSO_CB(skb);
 	data->inner_protocol = ovs_skb_get_inner_protocol(skb);
 	data->vlan_tci = skb->vlan_tci;
 	data->vlan_proto = skb->vlan_proto;
diff --git a/datapath/conntrack.c b/datapath/conntrack.c
index 403d1b424074..795ed91056bd 100644
--- a/datapath/conntrack.c
+++ b/datapath/conntrack.c
@@ -30,6 +30,7 @@
 #include "conntrack.h"
 #include "flow.h"
 #include "flow_netlink.h"
+#include "gso.h"
 
 struct ovs_ct_len_tbl {
 	size_t maxlen;
@@ -310,7 +311,7 @@ static int ovs_ct_helper(struct sk_buff *skb, u16 proto)
 static int handle_fragments(struct net *net, struct sw_flow_key *key,
 			    u16 zone, struct sk_buff *skb)
 {
-	struct ovs_skb_cb ovs_cb = *OVS_CB(skb);
+	struct ovs_gso_cb ovs_cb = *OVS_GSO_CB(skb);
 
 	if (!skb->dev) {
 		OVS_NLERR(true, "%s: skb has no dev; dropping", __func__);
@@ -326,7 +327,7 @@ static int handle_fragments(struct net *net, struct sw_flow_key *key,
 		if (err)
 			return err;
 
-		ovs_cb.mru = IPCB(skb)->frag_max_size;
+		ovs_cb.dp_cb.mru = IPCB(skb)->frag_max_size;
 #if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
 	} else if (key->eth.type == htons(ETH_P_IPV6)) {
 		enum ip6_defrag_users user = IP6_DEFRAG_CONNTRACK_IN + zone;
@@ -352,7 +353,7 @@ static int handle_fragments(struct net *net, struct sw_flow_key *key,
 		skb_morph(skb, reasm);
 		skb->next = reasm->next;
 		consume_skb(reasm);
-		ovs_cb.mru = IP6CB(skb)->frag_max_size;
+		ovs_cb.dp_cb.mru = IP6CB(skb)->frag_max_size;
 #endif /* IP frag support */
 	} else {
 		kfree_skb(skb);
@@ -362,7 +363,7 @@ static int handle_fragments(struct net *net, struct sw_flow_key *key,
 	key->ip.frag = OVS_FRAG_TYPE_NONE;
 	skb_clear_hash(skb);
 	skb->ignore_df = 1;
-	*OVS_CB(skb) = ovs_cb;
+	*OVS_GSO_CB(skb) = ovs_cb;
 
 	return 0;
 }
-- 
2.1.4




More information about the dev mailing list