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>
This commit is contained in:

committed by
David S. Miller

parent
07b9b37c22
commit
787d7ac308
@@ -21,6 +21,7 @@ static struct udp_offload_priv __rcu *udp_offload_base __read_mostly;
|
||||
|
||||
struct udp_offload_priv {
|
||||
struct udp_offload *offload;
|
||||
possible_net_t net;
|
||||
struct rcu_head rcu;
|
||||
struct udp_offload_priv __rcu *next;
|
||||
};
|
||||
@@ -241,13 +242,14 @@ out:
|
||||
return segs;
|
||||
}
|
||||
|
||||
int udp_add_offload(struct udp_offload *uo)
|
||||
int udp_add_offload(struct net *net, struct udp_offload *uo)
|
||||
{
|
||||
struct udp_offload_priv *new_offload = kzalloc(sizeof(*new_offload), GFP_ATOMIC);
|
||||
|
||||
if (!new_offload)
|
||||
return -ENOMEM;
|
||||
|
||||
write_pnet(&new_offload->net, net);
|
||||
new_offload->offload = uo;
|
||||
|
||||
spin_lock(&udp_offload_lock);
|
||||
@@ -311,7 +313,8 @@ struct sk_buff **udp_gro_receive(struct sk_buff **head, struct sk_buff *skb,
|
||||
rcu_read_lock();
|
||||
uo_priv = rcu_dereference(udp_offload_base);
|
||||
for (; uo_priv != NULL; uo_priv = rcu_dereference(uo_priv->next)) {
|
||||
if (uo_priv->offload->port == uh->dest &&
|
||||
if (net_eq(read_pnet(&uo_priv->net), dev_net(skb->dev)) &&
|
||||
uo_priv->offload->port == uh->dest &&
|
||||
uo_priv->offload->callbacks.gro_receive)
|
||||
goto unflush;
|
||||
}
|
||||
@@ -389,7 +392,8 @@ int udp_gro_complete(struct sk_buff *skb, int nhoff)
|
||||
|
||||
uo_priv = rcu_dereference(udp_offload_base);
|
||||
for (; uo_priv != NULL; uo_priv = rcu_dereference(uo_priv->next)) {
|
||||
if (uo_priv->offload->port == uh->dest &&
|
||||
if (net_eq(read_pnet(&uo_priv->net), dev_net(skb->dev)) &&
|
||||
uo_priv->offload->port == uh->dest &&
|
||||
uo_priv->offload->callbacks.gro_complete)
|
||||
break;
|
||||
}
|
||||
|
Reference in New Issue
Block a user