aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorHannes Frederic Sowa <hannes@stressinduktion.org>2016-01-07 08:28:39 -0500
committerDavid S. Miller <davem@davemloft.net>2016-01-10 17:28:24 -0500
commit787d7ac308ff2279e4b2ea393ad4d990de486ef2 (patch)
tree30370eacf684b73d796ebfa081f4be5a99f87b96 /net
parent07b9b37c227cb8d88d478b4a9c5634fee514ede1 (diff)
udp: restrict offloads to one namespace
udp tunnel offloads tend to aggregate datagrams based on inner headers. gro engine gets notified by tunnel implementations about possible offloads. The match is solely based on the port number. Imagine a tunnel bound to port 53, the offloading will look into all DNS packets and tries to aggregate them based on the inner data found within. This could lead to data corruption and malformed DNS packets. While this patch minimizes the problem and helps an administrator to find the issue by querying ip tunnel/fou, a better way would be to match on the specific destination ip address so if a user space socket is bound to the same address it will conflict. Cc: Tom Herbert <tom@herbertland.com> Cc: Eric Dumazet <edumazet@google.com> Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/fou.c2
-rw-r--r--net/ipv4/udp_offload.c10
2 files changed, 8 insertions, 4 deletions
diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c
index bd903fe0f750..976f0dcf6991 100644
--- a/net/ipv4/fou.c
+++ b/net/ipv4/fou.c
@@ -498,7 +498,7 @@ static int fou_create(struct net *net, struct fou_cfg *cfg,
498 sk->sk_allocation = GFP_ATOMIC; 498 sk->sk_allocation = GFP_ATOMIC;
499 499
500 if (cfg->udp_config.family == AF_INET) { 500 if (cfg->udp_config.family == AF_INET) {
501 err = udp_add_offload(&fou->udp_offloads); 501 err = udp_add_offload(net, &fou->udp_offloads);
502 if (err) 502 if (err)
503 goto error; 503 goto error;
504 } 504 }
diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
index f9386160cbee..5d396b96ae8b 100644
--- a/net/ipv4/udp_offload.c
+++ b/net/ipv4/udp_offload.c
@@ -21,6 +21,7 @@ static struct udp_offload_priv __rcu *udp_offload_base __read_mostly;
21 21
22struct udp_offload_priv { 22struct udp_offload_priv {
23 struct udp_offload *offload; 23 struct udp_offload *offload;
24 possible_net_t net;
24 struct rcu_head rcu; 25 struct rcu_head rcu;
25 struct udp_offload_priv __rcu *next; 26 struct udp_offload_priv __rcu *next;
26}; 27};
@@ -241,13 +242,14 @@ out:
241 return segs; 242 return segs;
242} 243}
243 244
244int udp_add_offload(struct udp_offload *uo) 245int udp_add_offload(struct net *net, struct udp_offload *uo)
245{ 246{
246 struct udp_offload_priv *new_offload = kzalloc(sizeof(*new_offload), GFP_ATOMIC); 247 struct udp_offload_priv *new_offload = kzalloc(sizeof(*new_offload), GFP_ATOMIC);
247 248
248 if (!new_offload) 249 if (!new_offload)
249 return -ENOMEM; 250 return -ENOMEM;
250 251
252 write_pnet(&new_offload->net, net);
251 new_offload->offload = uo; 253 new_offload->offload = uo;
252 254
253 spin_lock(&udp_offload_lock); 255 spin_lock(&udp_offload_lock);
@@ -311,7 +313,8 @@ struct sk_buff **udp_gro_receive(struct sk_buff **head, struct sk_buff *skb,
311 rcu_read_lock(); 313 rcu_read_lock();
312 uo_priv = rcu_dereference(udp_offload_base); 314 uo_priv = rcu_dereference(udp_offload_base);
313 for (; uo_priv != NULL; uo_priv = rcu_dereference(uo_priv->next)) { 315 for (; uo_priv != NULL; uo_priv = rcu_dereference(uo_priv->next)) {
314 if (uo_priv->offload->port == uh->dest && 316 if (net_eq(read_pnet(&uo_priv->net), dev_net(skb->dev)) &&
317 uo_priv->offload->port == uh->dest &&
315 uo_priv->offload->callbacks.gro_receive) 318 uo_priv->offload->callbacks.gro_receive)
316 goto unflush; 319 goto unflush;
317 } 320 }
@@ -389,7 +392,8 @@ int udp_gro_complete(struct sk_buff *skb, int nhoff)
389 392
390 uo_priv = rcu_dereference(udp_offload_base); 393 uo_priv = rcu_dereference(udp_offload_base);
391 for (; uo_priv != NULL; uo_priv = rcu_dereference(uo_priv->next)) { 394 for (; uo_priv != NULL; uo_priv = rcu_dereference(uo_priv->next)) {
392 if (uo_priv->offload->port == uh->dest && 395 if (net_eq(read_pnet(&uo_priv->net), dev_net(skb->dev)) &&
396 uo_priv->offload->port == uh->dest &&
393 uo_priv->offload->callbacks.gro_complete) 397 uo_priv->offload->callbacks.gro_complete)
394 break; 398 break;
395 } 399 }