From 86c2eb45fd82d7e12436a8d692a524729420fe30 Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Wed, 20 Jan 2016 15:26:49 -0800 Subject: [PATCH] datapath: Fix panic sending IP frags over tunnels. 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: [] ovs_stt_xmit+0x61/0x260 [openvswitch] Call Trace: [] ? __alloc_skb+0x7e/0x2b0 [] ovs_vport_send+0x44/0xb0 [openvswitch] [] ovs_vport_output+0x10f/0x190 [openvswitch] [] ip_fragment+0x238/0x870 [] ? do_output.isra.35+0x120/0x120 [openvswitch] [] ovs_fragment+0x283/0x292 [openvswitch] [] ? mod_timer_pending+0x67/0x1b0 [] ? dst_ifdown+0x90/0x90 [] ? dst_ifdown+0x90/0x90 [] ? nfnetlink_has_listeners+0x15/0x20 [nfnetlink] [] ? ctnetlink_conntrack_event+0x74/0x7ee [nf_conntrack_netlink] [] ? nf_ct_deliver_cached_events+0xad/0xf0 [nf_conntrack] [] ? csum_partial+0x11/0x20 [] ? execute_masked_set_action+0x2a7/0xa60 [openvswitch] [] do_output.isra.35+0xb8/0x120 [openvswitch] [] do_execute_actions+0xf4/0x7f0 [openvswitch] [] ovs_execute_actions+0x40/0x130 [openvswitch] [] ovs_packet_cmd_execute+0x2b9/0x2e0 [openvswitch] [] genl_family_rcv_msg+0x18d/0x370 [] ? genl_family_rcv_msg+0x370/0x370 [] genl_rcv_msg+0x91/0xd0 [] netlink_rcv_skb+0xa9/0xc0 [] genl_rcv+0x28/0x40 [] netlink_unicast+0xd5/0x1b0 [] netlink_sendmsg+0x30e/0x680 [] ? netlink_rcv_wake+0x44/0x60 [] ? netlink_recvmsg+0x1a2/0x3a0 [] sock_sendmsg+0x8b/0xc0 [] ? __alloc_pages_nodemask+0x16d/0xac0 [] ? sched_clock+0x9/0x10 [] ___sys_sendmsg+0x349/0x360 [] ? ep_scan_ready_list.isra.7+0x199/0x1c0 [] ? acct_account_cputime+0x1c/0x20 [] ? fget_light+0x8f/0xf0 [] __sys_sendmsg+0x42/0x80 [] SyS_sendmsg+0x12/0x20 [] tracesys+0xe1/0xe6 VMware-BZ: #1587324 Fixes: a94ebc39996b ("datapath: Add conntrack action") Signed-off-by: Joe Stringer Acked-by: Pravin B Shelar --- 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 6917d5169..20413c950 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 403d1b424..795ed9105 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.20.1