Skip to content

Commit

Permalink
udp: restrict offloads to one namespace
Browse files Browse the repository at this point in the history
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 <[email protected]>
Cc: Eric Dumazet <[email protected]>
Signed-off-by: Hannes Frederic Sowa <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
strssndktn authored and davem330 committed Jan 10, 2016
1 parent 07b9b37 commit 787d7ac
Show file tree
Hide file tree
Showing 5 changed files with 11 additions and 7 deletions.
2 changes: 1 addition & 1 deletion drivers/net/geneve.c
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ static void geneve_notify_add_rx_port(struct geneve_sock *gs)
int err;

if (sa_family == AF_INET) {
err = udp_add_offload(&gs->udp_offloads);
err = udp_add_offload(sock_net(sk), &gs->udp_offloads);
if (err)
pr_warn("geneve: udp_add_offload failed with status %d\n",
err);
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/vxlan.c
Original file line number Diff line number Diff line change
Expand Up @@ -621,7 +621,7 @@ static void vxlan_notify_add_rx_port(struct vxlan_sock *vs)
int err;

if (sa_family == AF_INET) {
err = udp_add_offload(&vs->udp_offloads);
err = udp_add_offload(net, &vs->udp_offloads);
if (err)
pr_warn("vxlan: udp_add_offload failed with status %d\n", err);
}
Expand Down
2 changes: 1 addition & 1 deletion include/net/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ int inet_del_offload(const struct net_offload *prot, unsigned char num);
void inet_register_protosw(struct inet_protosw *p);
void inet_unregister_protosw(struct inet_protosw *p);

int udp_add_offload(struct udp_offload *prot);
int udp_add_offload(struct net *net, struct udp_offload *prot);
void udp_del_offload(struct udp_offload *prot);

#if IS_ENABLED(CONFIG_IPV6)
Expand Down
2 changes: 1 addition & 1 deletion net/ipv4/fou.c
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,7 @@ static int fou_create(struct net *net, struct fou_cfg *cfg,
sk->sk_allocation = GFP_ATOMIC;

if (cfg->udp_config.family == AF_INET) {
err = udp_add_offload(&fou->udp_offloads);
err = udp_add_offload(net, &fou->udp_offloads);
if (err)
goto error;
}
Expand Down
10 changes: 7 additions & 3 deletions net/ipv4/udp_offload.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand Down Expand Up @@ -241,13 +242,14 @@ static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb,
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);
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand Down

0 comments on commit 787d7ac

Please sign in to comment.