Commit 540aa5b7 authored by Ben Hutchings's avatar Ben Hutchings

drivers/net, ipv6: Select IPv6 fragment idents for virtio UFO packets

commit 5188cd44 upstream.

UFO is now disabled on all drivers that work with virtio net headers,
but userland may try to send UFO/IPv6 packets anyway.  Instead of
sending with ID=0, we should select identifiers on their behalf (as we
used to).
Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
Fixes: 916e4cf4 ("ipv6: reuse ip6_frag_id from ip6_ufo_append_data")
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
[bwh: For 3.2, net/ipv6/output_core.c is a completely new file]
parent 543563d7
......@@ -15,6 +15,7 @@
#include <linux/cdev.h>
#include <linux/fs.h>
#include <net/ipv6.h>
#include <net/net_namespace.h>
#include <net/rtnetlink.h>
#include <net/sock.h>
......@@ -577,6 +578,8 @@ static int macvtap_skb_from_vnet_hdr(struct sk_buff *skb,
break;
case VIRTIO_NET_HDR_GSO_UDP:
gso_type = SKB_GSO_UDP;
if (skb->protocol == htons(ETH_P_IPV6))
ipv6_proxy_select_ident(skb);
break;
default:
return -EINVAL;
......
......@@ -64,6 +64,7 @@
#include <linux/nsproxy.h>
#include <linux/virtio_net.h>
#include <linux/rcupdate.h>
#include <net/ipv6.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
#include <net/rtnetlink.h>
......@@ -695,6 +696,8 @@ static ssize_t tun_get_user(struct tun_struct *tun,
break;
}
skb_reset_network_header(skb);
if (gso.gso_type != VIRTIO_NET_HDR_GSO_NONE) {
pr_debug("GSO!\n");
switch (gso.gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
......@@ -706,6 +709,8 @@ static ssize_t tun_get_user(struct tun_struct *tun,
break;
case VIRTIO_NET_HDR_GSO_UDP:
skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
if (skb->protocol == htons(ETH_P_IPV6))
ipv6_proxy_select_ident(skb);
break;
default:
tun->dev->stats.rx_frame_errors++;
......
......@@ -481,6 +481,7 @@ static inline int ipv6_addr_diff(const struct in6_addr *a1, const struct in6_add
}
extern void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt);
void ipv6_proxy_select_ident(struct sk_buff *skb);
/*
* Prototypes exported by ipv6
......
......@@ -37,6 +37,6 @@ obj-$(CONFIG_NETFILTER) += netfilter/
obj-$(CONFIG_IPV6_SIT) += sit.o
obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
obj-y += addrconf_core.o exthdrs_core.o
obj-y += addrconf_core.o exthdrs_core.o output_core.o
obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o
#include <linux/export.h>
#include <linux/skbuff.h>
#include <net/ip.h>
#include <net/ipv6.h>
/* This function exists only for tap drivers that must support broken
* clients requesting UFO without specifying an IPv6 fragment ID.
*
* This is similar to ipv6_select_ident() but we use an independent hash
* seed to limit information leakage.
*/
void ipv6_proxy_select_ident(struct sk_buff *skb)
{
static u32 ip6_proxy_idents_hashrnd __read_mostly;
static bool hashrnd_initialized = false;
struct in6_addr buf[2];
struct in6_addr *addrs;
u32 hash, id;
addrs = skb_header_pointer(skb,
skb_network_offset(skb) +
offsetof(struct ipv6hdr, saddr),
sizeof(buf), buf);
if (!addrs)
return;
if (unlikely(!hashrnd_initialized)) {
hashrnd_initialized = true;
get_random_bytes(&ip6_proxy_idents_hashrnd,
sizeof(ip6_proxy_idents_hashrnd));
}
hash = __ipv6_addr_jhash(&addrs[1], ip6_proxy_idents_hashrnd);
hash = __ipv6_addr_jhash(&addrs[0], hash);
id = ip_idents_reserve(hash, 1);
skb_shinfo(skb)->ip6_frag_id = htonl(id);
}
EXPORT_SYMBOL_GPL(ipv6_proxy_select_ident);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment