aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorPravin B Shelar <pshelar@nicira.com>2014-12-23 19:20:32 -0500
committerDavid S. Miller <davem@davemloft.net>2014-12-23 23:57:31 -0500
commit997e068ebc17d8d57e735578df44b6341cd5f2f3 (patch)
tree2fc6e7b30a84898baeb28fd3ec783e292541335c /net
parentcbe7e76d94f59e89302bd514e4b685e03d1ebbe4 (diff)
openvswitch: Fix vport_send double free
Today vport-send has complex error handling because it involves freeing skb and updating stats depending on return value from vport send implementation. This can be simplified by delegating responsibility of freeing skb to the vport implementation for all cases. So that vport-send needs just update stats. Fixes: 91b7514cdf ("openvswitch: Unify vport error stats handling") Signed-off-by: Pravin B Shelar <pshelar@nicira.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/geneve.c6
-rw-r--r--net/openvswitch/vport-geneve.c3
-rw-r--r--net/openvswitch/vport-gre.c18
-rw-r--r--net/openvswitch/vport-vxlan.c2
-rw-r--r--net/openvswitch/vport.c5
5 files changed, 23 insertions, 11 deletions
diff --git a/net/ipv4/geneve.c b/net/ipv4/geneve.c
index 95e47c97585e..394a200f93c1 100644
--- a/net/ipv4/geneve.c
+++ b/net/ipv4/geneve.c
@@ -122,14 +122,18 @@ int geneve_xmit_skb(struct geneve_sock *gs, struct rtable *rt,
122 int err; 122 int err;
123 123
124 skb = udp_tunnel_handle_offloads(skb, !gs->sock->sk->sk_no_check_tx); 124 skb = udp_tunnel_handle_offloads(skb, !gs->sock->sk->sk_no_check_tx);
125 if (IS_ERR(skb))
126 return PTR_ERR(skb);
125 127
126 min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len 128 min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len
127 + GENEVE_BASE_HLEN + opt_len + sizeof(struct iphdr) 129 + GENEVE_BASE_HLEN + opt_len + sizeof(struct iphdr)
128 + (vlan_tx_tag_present(skb) ? VLAN_HLEN : 0); 130 + (vlan_tx_tag_present(skb) ? VLAN_HLEN : 0);
129 131
130 err = skb_cow_head(skb, min_headroom); 132 err = skb_cow_head(skb, min_headroom);
131 if (unlikely(err)) 133 if (unlikely(err)) {
134 kfree_skb(skb);
132 return err; 135 return err;
136 }
133 137
134 skb = vlan_hwaccel_push_inside(skb); 138 skb = vlan_hwaccel_push_inside(skb);
135 if (unlikely(!skb)) 139 if (unlikely(!skb))
diff --git a/net/openvswitch/vport-geneve.c b/net/openvswitch/vport-geneve.c
index 347fa2325b22..484864dd0e68 100644
--- a/net/openvswitch/vport-geneve.c
+++ b/net/openvswitch/vport-geneve.c
@@ -219,7 +219,10 @@ static int geneve_tnl_send(struct vport *vport, struct sk_buff *skb)
219 false); 219 false);
220 if (err < 0) 220 if (err < 0)
221 ip_rt_put(rt); 221 ip_rt_put(rt);
222 return err;
223
222error: 224error:
225 kfree_skb(skb);
223 return err; 226 return err;
224} 227}
225 228
diff --git a/net/openvswitch/vport-gre.c b/net/openvswitch/vport-gre.c
index 6b69df545b1d..28f54e9a6b80 100644
--- a/net/openvswitch/vport-gre.c
+++ b/net/openvswitch/vport-gre.c
@@ -73,7 +73,7 @@ static struct sk_buff *__build_header(struct sk_buff *skb,
73 73
74 skb = gre_handle_offloads(skb, !!(tun_key->tun_flags & TUNNEL_CSUM)); 74 skb = gre_handle_offloads(skb, !!(tun_key->tun_flags & TUNNEL_CSUM));
75 if (IS_ERR(skb)) 75 if (IS_ERR(skb))
76 return NULL; 76 return skb;
77 77
78 tpi.flags = filter_tnl_flags(tun_key->tun_flags); 78 tpi.flags = filter_tnl_flags(tun_key->tun_flags);
79 tpi.proto = htons(ETH_P_TEB); 79 tpi.proto = htons(ETH_P_TEB);
@@ -144,7 +144,7 @@ static int gre_tnl_send(struct vport *vport, struct sk_buff *skb)
144 144
145 if (unlikely(!OVS_CB(skb)->egress_tun_info)) { 145 if (unlikely(!OVS_CB(skb)->egress_tun_info)) {
146 err = -EINVAL; 146 err = -EINVAL;
147 goto error; 147 goto err_free_skb;
148 } 148 }
149 149
150 tun_key = &OVS_CB(skb)->egress_tun_info->tunnel; 150 tun_key = &OVS_CB(skb)->egress_tun_info->tunnel;
@@ -157,8 +157,10 @@ static int gre_tnl_send(struct vport *vport, struct sk_buff *skb)
157 fl.flowi4_proto = IPPROTO_GRE; 157 fl.flowi4_proto = IPPROTO_GRE;
158 158
159 rt = ip_route_output_key(net, &fl); 159 rt = ip_route_output_key(net, &fl);
160 if (IS_ERR(rt)) 160 if (IS_ERR(rt)) {
161 return PTR_ERR(rt); 161 err = PTR_ERR(rt);
162 goto err_free_skb;
163 }
162 164
163 tunnel_hlen = ip_gre_calc_hlen(tun_key->tun_flags); 165 tunnel_hlen = ip_gre_calc_hlen(tun_key->tun_flags);
164 166
@@ -183,8 +185,9 @@ static int gre_tnl_send(struct vport *vport, struct sk_buff *skb)
183 185
184 /* Push Tunnel header. */ 186 /* Push Tunnel header. */
185 skb = __build_header(skb, tunnel_hlen); 187 skb = __build_header(skb, tunnel_hlen);
186 if (unlikely(!skb)) { 188 if (IS_ERR(skb)) {
187 err = 0; 189 err = PTR_ERR(rt);
190 skb = NULL;
188 goto err_free_rt; 191 goto err_free_rt;
189 } 192 }
190 193
@@ -198,7 +201,8 @@ static int gre_tnl_send(struct vport *vport, struct sk_buff *skb)
198 tun_key->ipv4_tos, tun_key->ipv4_ttl, df, false); 201 tun_key->ipv4_tos, tun_key->ipv4_ttl, df, false);
199err_free_rt: 202err_free_rt:
200 ip_rt_put(rt); 203 ip_rt_put(rt);
201error: 204err_free_skb:
205 kfree_skb(skb);
202 return err; 206 return err;
203} 207}
204 208
diff --git a/net/openvswitch/vport-vxlan.c b/net/openvswitch/vport-vxlan.c
index 38f95a52241b..d7c46b301024 100644
--- a/net/openvswitch/vport-vxlan.c
+++ b/net/openvswitch/vport-vxlan.c
@@ -187,7 +187,9 @@ static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb)
187 false); 187 false);
188 if (err < 0) 188 if (err < 0)
189 ip_rt_put(rt); 189 ip_rt_put(rt);
190 return err;
190error: 191error:
192 kfree_skb(skb);
191 return err; 193 return err;
192} 194}
193 195
diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c
index 9584526c0778..53f3ebbfceab 100644
--- a/net/openvswitch/vport.c
+++ b/net/openvswitch/vport.c
@@ -519,10 +519,9 @@ int ovs_vport_send(struct vport *vport, struct sk_buff *skb)
519 u64_stats_update_end(&stats->syncp); 519 u64_stats_update_end(&stats->syncp);
520 } else if (sent < 0) { 520 } else if (sent < 0) {
521 ovs_vport_record_error(vport, VPORT_E_TX_ERROR); 521 ovs_vport_record_error(vport, VPORT_E_TX_ERROR);
522 kfree_skb(skb); 522 } else {
523 } else
524 ovs_vport_record_error(vport, VPORT_E_TX_DROPPED); 523 ovs_vport_record_error(vport, VPORT_E_TX_DROPPED);
525 524 }
526 return sent; 525 return sent;
527} 526}
528 527