summaryrefslogtreecommitdiff
path: root/net/ipv6
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-03-30 18:47:28 -1000
committerLinus Torvalds <torvalds@linux-foundation.org>2018-03-30 18:47:28 -1000
commita44406ec3d31de773ce50e794900546f22c1cc7b (patch)
treec313035c8c2fc77103e0b34523168e81aa170650 /net/ipv6
parent9dd2326890d89a5179967c947dab2bab34d7ddee (diff)
parente81b5e01c14add8395dfba7130f8829206bb507d (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Pull networking fixes from David Miller: 1) Fix RCU locking in xfrm_local_error(), from Taehee Yoo. 2) Fix return value assignments and thus error checking in iwl_mvm_start_ap_ibss(), from Johannes Berg. 3) Don't count header length twice in vti4, from Stefano Brivio. 4) Fix deadlock in rt6_age_examine_exception, from Eric Dumazet. 5) Fix out-of-bounds access in nf_sk_lookup_slow{v4,v6}() from Subash Abhinov. 6) Check nladdr size in netlink_connect(), from Alexander Potapenko. 7) VF representor SQ numbers are 32 not 16 bits, in mlx5 driver, from Or Gerlitz. 8) Out of bounds read in skb_network_protocol(), from Eric Dumazet. 9) r8169 driver sets driver data pointer after register_netdev() which is too late. Fix from Heiner Kallweit. 10) Fix memory leak in mlx4 driver, from Moshe Shemesh. 11) The multi-VLAN decap fix added a regression when dealing with device that lack a MAC header, such as tun. Fix from Toshiaki Makita. 12) Fix integer overflow in dynamic interrupt coalescing code. From Tal Gilboa. 13) Use after free in vrf code, from David Ahern. 14) IPV6 route leak between VRFs fix, also from David Ahern. * git://git.kernel.org/pub/scm/linux/kernel/git/davem/net: (81 commits) net: mvneta: fix enable of all initialized RXQs net/ipv6: Fix route leaking between VRFs vrf: Fix use after free and double free in vrf_finish_output ipv6: sr: fix seg6 encap performances with TSO enabled net/dim: Fix int overflow vlan: Fix vlan insertion for packets without ethernet header net: Fix untag for vlan packets without ethernet header atm: iphase: fix spelling mistake: "Receiverd" -> "Received" vhost: validate log when IOTLB is enabled qede: Do not drop rx-checksum invalidated packets. hv_netvsc: enable multicast if necessary ip_tunnel: Resolve ipsec merge conflict properly. lan78xx: Crash in lan78xx_writ_reg (Workqueue: events lan78xx_deferred_multicast_write) qede: Fix barrier usage after tx doorbell write. vhost: correctly remove wait queue during poll failure net/mlx4_core: Fix memory leak while delete slave's resources net/mlx4_en: Fix mixed PFC and Global pause user control requests net/smc: use announced length in sock_recvmsg() llc: properly handle dev_queue_xmit() return value strparser: Fix sign of err codes ...
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/ip6_output.c13
-rw-r--r--net/ipv6/ip6_vti.c36
-rw-r--r--net/ipv6/netfilter/nf_socket_ipv6.c6
-rw-r--r--net/ipv6/route.c16
-rw-r--r--net/ipv6/seg6_iptunnel.c16
-rw-r--r--net/ipv6/syncookies.c2
6 files changed, 55 insertions, 34 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index a8a919520090..5cb18c8ba9b2 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1246,7 +1246,7 @@ static int __ip6_append_data(struct sock *sk,
const struct sockcm_cookie *sockc)
{
struct sk_buff *skb, *skb_prev = NULL;
- unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu;
+ unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu, pmtu;
int exthdrlen = 0;
int dst_exthdrlen = 0;
int hh_len;
@@ -1282,6 +1282,12 @@ static int __ip6_append_data(struct sock *sk,
sizeof(struct frag_hdr) : 0) +
rt->rt6i_nfheader_len;
+ /* as per RFC 7112 section 5, the entire IPv6 Header Chain must fit
+ * the first fragment
+ */
+ if (headersize + transhdrlen > mtu)
+ goto emsgsize;
+
if (cork->length + length > mtu - headersize && ipc6->dontfrag &&
(sk->sk_protocol == IPPROTO_UDP ||
sk->sk_protocol == IPPROTO_RAW)) {
@@ -1297,9 +1303,8 @@ static int __ip6_append_data(struct sock *sk,
if (cork->length + length > maxnonfragsize - headersize) {
emsgsize:
- ipv6_local_error(sk, EMSGSIZE, fl6,
- mtu - headersize +
- sizeof(struct ipv6hdr));
+ pmtu = max_t(int, mtu - headersize + sizeof(struct ipv6hdr), 0);
+ ipv6_local_error(sk, EMSGSIZE, fl6, pmtu);
return -EMSGSIZE;
}
diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c
index fa3ae1cb50d3..ce18cd20389d 100644
--- a/net/ipv6/ip6_vti.c
+++ b/net/ipv6/ip6_vti.c
@@ -622,11 +622,12 @@ static int vti6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
return 0;
}
-static void vti6_link_config(struct ip6_tnl *t)
+static void vti6_link_config(struct ip6_tnl *t, bool keep_mtu)
{
struct net_device *dev = t->dev;
struct __ip6_tnl_parm *p = &t->parms;
struct net_device *tdev = NULL;
+ int mtu;
memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr));
memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr));
@@ -640,6 +641,11 @@ static void vti6_link_config(struct ip6_tnl *t)
else
dev->flags &= ~IFF_POINTOPOINT;
+ if (keep_mtu && dev->mtu) {
+ dev->mtu = clamp(dev->mtu, dev->min_mtu, dev->max_mtu);
+ return;
+ }
+
if (p->flags & IP6_TNL_F_CAP_XMIT) {
int strict = (ipv6_addr_type(&p->raddr) &
(IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL));
@@ -656,20 +662,25 @@ static void vti6_link_config(struct ip6_tnl *t)
tdev = __dev_get_by_index(t->net, p->link);
if (tdev)
- dev->mtu = max_t(int, tdev->mtu - dev->hard_header_len,
- IPV6_MIN_MTU);
+ mtu = tdev->mtu - sizeof(struct ipv6hdr);
+ else
+ mtu = ETH_DATA_LEN - LL_MAX_HEADER - sizeof(struct ipv6hdr);
+
+ dev->mtu = max_t(int, mtu, IPV6_MIN_MTU);
}
/**
* vti6_tnl_change - update the tunnel parameters
* @t: tunnel to be changed
* @p: tunnel configuration parameters
+ * @keep_mtu: MTU was set from userspace, don't re-compute it
*
* Description:
* vti6_tnl_change() updates the tunnel parameters
**/
static int
-vti6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p)
+vti6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p,
+ bool keep_mtu)
{
t->parms.laddr = p->laddr;
t->parms.raddr = p->raddr;
@@ -679,11 +690,12 @@ vti6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p)
t->parms.proto = p->proto;
t->parms.fwmark = p->fwmark;
dst_cache_reset(&t->dst_cache);
- vti6_link_config(t);
+ vti6_link_config(t, keep_mtu);
return 0;
}
-static int vti6_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p)
+static int vti6_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p,
+ bool keep_mtu)
{
struct net *net = dev_net(t->dev);
struct vti6_net *ip6n = net_generic(net, vti6_net_id);
@@ -691,7 +703,7 @@ static int vti6_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p)
vti6_tnl_unlink(ip6n, t);
synchronize_net();
- err = vti6_tnl_change(t, p);
+ err = vti6_tnl_change(t, p, keep_mtu);
vti6_tnl_link(ip6n, t);
netdev_state_change(t->dev);
return err;
@@ -804,7 +816,7 @@ vti6_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
} else
t = netdev_priv(dev);
- err = vti6_update(t, &p1);
+ err = vti6_update(t, &p1, false);
}
if (t) {
err = 0;
@@ -866,10 +878,8 @@ static void vti6_dev_setup(struct net_device *dev)
dev->priv_destructor = vti6_dev_free;
dev->type = ARPHRD_TUNNEL6;
- dev->hard_header_len = LL_MAX_HEADER + sizeof(struct ipv6hdr);
- dev->mtu = ETH_DATA_LEN;
dev->min_mtu = IPV6_MIN_MTU;
- dev->max_mtu = IP_MAX_MTU;
+ dev->max_mtu = IP_MAX_MTU - sizeof(struct ipv6hdr);
dev->flags |= IFF_NOARP;
dev->addr_len = sizeof(struct in6_addr);
netif_keep_dst(dev);
@@ -905,7 +915,7 @@ static int vti6_dev_init(struct net_device *dev)
if (err)
return err;
- vti6_link_config(t);
+ vti6_link_config(t, true);
return 0;
}
@@ -1010,7 +1020,7 @@ static int vti6_changelink(struct net_device *dev, struct nlattr *tb[],
} else
t = netdev_priv(dev);
- return vti6_update(t, &p);
+ return vti6_update(t, &p, tb && tb[IFLA_MTU]);
}
static size_t vti6_get_size(const struct net_device *dev)
diff --git a/net/ipv6/netfilter/nf_socket_ipv6.c b/net/ipv6/netfilter/nf_socket_ipv6.c
index ebb2bf84232a..f14de4b6d639 100644
--- a/net/ipv6/netfilter/nf_socket_ipv6.c
+++ b/net/ipv6/netfilter/nf_socket_ipv6.c
@@ -116,9 +116,11 @@ struct sock *nf_sk_lookup_slow_v6(struct net *net, const struct sk_buff *skb,
}
if (tproto == IPPROTO_UDP || tproto == IPPROTO_TCP) {
- struct udphdr _hdr, *hp;
+ struct tcphdr _hdr;
+ struct udphdr *hp;
- hp = skb_header_pointer(skb, thoff, sizeof(_hdr), &_hdr);
+ hp = skb_header_pointer(skb, thoff, tproto == IPPROTO_UDP ?
+ sizeof(*hp) : sizeof(_hdr), &_hdr);
if (hp == NULL)
return NULL;
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index b0d5c64e1978..fc74352fac12 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -919,6 +919,9 @@ static struct rt6_info *ip6_pol_route_lookup(struct net *net,
struct rt6_info *rt, *rt_cache;
struct fib6_node *fn;
+ if (fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF)
+ flags &= ~RT6_LOOKUP_F_IFACE;
+
rcu_read_lock();
fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
restart:
@@ -1626,11 +1629,10 @@ static void rt6_age_examine_exception(struct rt6_exception_bucket *bucket,
struct neighbour *neigh;
__u8 neigh_flags = 0;
- neigh = dst_neigh_lookup(&rt->dst, &rt->rt6i_gateway);
- if (neigh) {
+ neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
+ if (neigh)
neigh_flags = neigh->flags;
- neigh_release(neigh);
- }
+
if (!(neigh_flags & NTF_ROUTER)) {
RT6_TRACE("purging route %p via non-router but gateway\n",
rt);
@@ -1654,7 +1656,8 @@ void rt6_age_exceptions(struct rt6_info *rt,
if (!rcu_access_pointer(rt->rt6i_exception_bucket))
return;
- spin_lock_bh(&rt6_exception_lock);
+ rcu_read_lock_bh();
+ spin_lock(&rt6_exception_lock);
bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
lockdep_is_held(&rt6_exception_lock));
@@ -1668,7 +1671,8 @@ void rt6_age_exceptions(struct rt6_info *rt,
bucket++;
}
}
- spin_unlock_bh(&rt6_exception_lock);
+ spin_unlock(&rt6_exception_lock);
+ rcu_read_unlock_bh();
}
struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c
index 7a78dcfda68a..f343e6f0fc95 100644
--- a/net/ipv6/seg6_iptunnel.c
+++ b/net/ipv6/seg6_iptunnel.c
@@ -16,6 +16,7 @@
#include <linux/net.h>
#include <linux/module.h>
#include <net/ip.h>
+#include <net/ip_tunnels.h>
#include <net/lwtunnel.h>
#include <net/netevent.h>
#include <net/netns/generic.h>
@@ -211,11 +212,6 @@ static int seg6_do_srh(struct sk_buff *skb)
tinfo = seg6_encap_lwtunnel(dst->lwtstate);
- if (likely(!skb->encapsulation)) {
- skb_reset_inner_headers(skb);
- skb->encapsulation = 1;
- }
-
switch (tinfo->mode) {
case SEG6_IPTUN_MODE_INLINE:
if (skb->protocol != htons(ETH_P_IPV6))
@@ -224,10 +220,12 @@ static int seg6_do_srh(struct sk_buff *skb)
err = seg6_do_srh_inline(skb, tinfo->srh);
if (err)
return err;
-
- skb_reset_inner_headers(skb);
break;
case SEG6_IPTUN_MODE_ENCAP:
+ err = iptunnel_handle_offloads(skb, SKB_GSO_IPXIP6);
+ if (err)
+ return err;
+
if (skb->protocol == htons(ETH_P_IPV6))
proto = IPPROTO_IPV6;
else if (skb->protocol == htons(ETH_P_IP))
@@ -239,6 +237,8 @@ static int seg6_do_srh(struct sk_buff *skb)
if (err)
return err;
+ skb_set_inner_transport_header(skb, skb_transport_offset(skb));
+ skb_set_inner_protocol(skb, skb->protocol);
skb->protocol = htons(ETH_P_IPV6);
break;
case SEG6_IPTUN_MODE_L2ENCAP:
@@ -262,8 +262,6 @@ static int seg6_do_srh(struct sk_buff *skb)
ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
skb_set_transport_header(skb, sizeof(struct ipv6hdr));
- skb_set_inner_protocol(skb, skb->protocol);
-
return 0;
}
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index e7a3a6b6cf56..e997141aed8c 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -217,6 +217,8 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
treq->snt_isn = cookie;
treq->ts_off = 0;
treq->txhash = net_tx_rndhash();
+ if (IS_ENABLED(CONFIG_SMC))
+ ireq->smc_ok = 0;
/*
* We need to lookup the dst_entry to get the correct window size.