aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNatanael Copa <ncopa@alpinelinux.org>2013-07-24 07:37:42 +0000
committerNatanael Copa <ncopa@alpinelinux.org>2013-07-25 08:38:42 +0000
commitf206cc0c44e51172eca6222e9db00e2b89fb080f (patch)
treea01b993bec64134de2557d8f3d1bebc16d0ef565
parent13087cdeea4ffb9af65715229ffd8b4c0a178796 (diff)
downloadaports-f206cc0c44e51172eca6222e9db00e2b89fb080f.tar.bz2
aports-f206cc0c44e51172eca6222e9db00e2b89fb080f.tar.xz
main/linux-grsec: various security fixes (CVE-2013-4125, CVE-2013-4127)
ref #2139 (CVE-2013-4125) fixes #2140 ref #2144 (CVE-2013-4127) fixes #2145 (cherry picked from commit 2090f6be2eb8aa04ae81c1bf456f4dc3709ac886)
-rw-r--r--main/linux-grsec/APKBUILD10
-rw-r--r--main/linux-grsec/grsecurity-2.9.1-3.9.11-unofficial-1.patch (renamed from main/linux-grsec/grsecurity-2.9.1-3.9.11-unofficial-0.patch)398
2 files changed, 389 insertions, 19 deletions
diff --git a/main/linux-grsec/APKBUILD b/main/linux-grsec/APKBUILD
index 6573f802c5..5dfc2d900e 100644
--- a/main/linux-grsec/APKBUILD
+++ b/main/linux-grsec/APKBUILD
@@ -7,7 +7,7 @@ case $pkgver in
*.*.*) _kernver=${pkgver%.*};;
*.*) _kernver=${pkgver};;
esac
-pkgrel=0
+pkgrel=1
pkgdesc="Linux kernel with grsecurity"
url=http://grsecurity.net
depends="mkinitfs linux-firmware"
@@ -17,7 +17,7 @@ _config=${config:-kernelconfig.${CARCH}}
install=
source="http://ftp.kernel.org/pub/linux/kernel/v3.x/linux-$_kernver.tar.xz
http://ftp.kernel.org/pub/linux/kernel/v3.x/patch-$pkgver.xz
- grsecurity-2.9.1-3.9.11-unofficial-0.patch
+ grsecurity-2.9.1-3.9.11-unofficial-1.patch
0001-net-inform-NETDEV_CHANGE-callbacks-which-flags-were-.patch
0002-arp-flush-arp-cache-on-IFF_NOARP-change.patch
@@ -150,7 +150,7 @@ dev() {
md5sums="4348c9b6b2eb3144d601e87c19d5d909 linux-3.9.tar.xz
552146435b7ecc414bf8e3cd8bb6ac4a patch-3.9.11.xz
-6d3715f39d6c9e418550443ddf472ec8 grsecurity-2.9.1-3.9.11-unofficial-0.patch
+0888981bb55e0d27b6ed39edcc7ee45a grsecurity-2.9.1-3.9.11-unofficial-1.patch
a16f11b12381efb3bec79b9bfb329836 0001-net-inform-NETDEV_CHANGE-callbacks-which-flags-were-.patch
656ae7b10dd2f18dbfa1011041d08d60 0002-arp-flush-arp-cache-on-IFF_NOARP-change.patch
aa454ffb96428586447775c21449e284 0003-ipv4-properly-refresh-rtable-entries-on-pmtu-redirec.patch
@@ -161,7 +161,7 @@ d89089b3c7eb94dd9f65cf8a357fc36d kernelconfig.x86
eb147f09fef5996a488c247790205cd6 kernelconfig.x86_64"
sha256sums="60bc3e64ee5dc778de2cd7cd7640abf518a4c9d4f31b8ed624e16fad53f54541 linux-3.9.tar.xz
29be11d16ef152ae1858d567cbf45f0da0193adf364826f5e3fa8b2fcd839682 patch-3.9.11.xz
-09787452cd5f7b0bfcef6c27f4f64c3a8c1f46fad69a6c9604883a4f4d2924df grsecurity-2.9.1-3.9.11-unofficial-0.patch
+fa2223e87b38e225568a36ee2eb00976f74bc109e2ccc21c93abed676f58e3ad grsecurity-2.9.1-3.9.11-unofficial-1.patch
6af3757ac36a6cd3cda7b0a71b08143726383b19261294a569ad7f4042c72df3 0001-net-inform-NETDEV_CHANGE-callbacks-which-flags-were-.patch
dc8e82108615657f1fb9d641efd42255a5761c06edde1b00a41ae0d314d548f0 0002-arp-flush-arp-cache-on-IFF_NOARP-change.patch
0985caa0f3ee8ed0959aeaa4214f5f8057ae8e61d50dcae39194912d31e14892 0003-ipv4-properly-refresh-rtable-entries-on-pmtu-redirec.patch
@@ -172,7 +172,7 @@ de3c17420664ae4e52826c6e602aade0deeae94f72253f85b3e48771491ed5d6 kernelconfig.x
e1cce320f207cc2ba72b9d154c7060c8cbed52c664319dfd21f24e8956d0bf3e kernelconfig.x86_64"
sha512sums="77fa521f42380409f8ab400c26f7b00e225cb075ef40834bb263325cfdcc3e65aef8511ec2fc2b50bbf4f50e226fb5ab07d7a479aaf09162adbbf318325d0790 linux-3.9.tar.xz
c3a0be102d816ae06d7dfdd2738915fc2114cb9bb488b03b34e4f52f2367dcba4d8cb8ba203687bf694c2dcad36d70bb9d3121ac739a28e2c7fb2c44f08a9c71 patch-3.9.11.xz
-a6a4b7fc2b5a532845dc31f7ba539b4f9b643750a4e96870e3fc4ac516953d456e28246c0964493ba5ddd41f5e65f2ca99b9e71d2a3d94dba2385be5a9dcceac grsecurity-2.9.1-3.9.11-unofficial-0.patch
+59e34764fca125d097d1826042dce0e6fb0bf53eb97935b591e57674fb755491d78b1180a6db6253a869ffe56f7ceddf2e80f24812319e2b2f623d3e100aaa00 grsecurity-2.9.1-3.9.11-unofficial-1.patch
81e78593288e8b0fd2c03ea9fc1450323887707f087e911f172450a122bc9b591ee83394836789730d951aeec13d0b75a64e1c05f04364abf8f80d883ddc4a02 0001-net-inform-NETDEV_CHANGE-callbacks-which-flags-were-.patch
51ecb15b669f6a82940a13a38939116e003bf5dfd24496771c8279e907b72adcc63d607f0340a2940d757e12ddadb7d45c7af78ae311d284935a6296dbcac00c 0002-arp-flush-arp-cache-on-IFF_NOARP-change.patch
57d0a8bd35d19cf657ded58efe24517d2252aec6984040713ba173a34edb5887ececaa2985076bc6a149eaa57639fd98a042c1c2d226ed4ad8dd5ed0e230717e 0003-ipv4-properly-refresh-rtable-entries-on-pmtu-redirec.patch
diff --git a/main/linux-grsec/grsecurity-2.9.1-3.9.11-unofficial-0.patch b/main/linux-grsec/grsecurity-2.9.1-3.9.11-unofficial-1.patch
index 2aebee9454..932805c959 100644
--- a/main/linux-grsec/grsecurity-2.9.1-3.9.11-unofficial-0.patch
+++ b/main/linux-grsec/grsecurity-2.9.1-3.9.11-unofficial-1.patch
@@ -39865,6 +39865,42 @@ index aee7671..3ca2651 100644
/* multicast configuration controlling object */
bnx2x_init_mcast_obj(bp, &bp->mcast_obj, bp->fp->cl_id, bp->fp->cid,
+diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
+index edfa67a..d6c52ae 100644
+--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
++++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
+@@ -960,6 +960,9 @@ static int bnx2x_set_dump(struct net_device *dev, struct ethtool_dump *val)
+ struct bnx2x *bp = netdev_priv(dev);
+
+ /* Use the ethtool_dump "flag" field as the dump preset index */
++ if (val->flag < 1 || val->flag > DUMP_MAX_PRESETS)
++ return -EINVAL;
++
+ bp->dump_preset_idx = val->flag;
+ return 0;
+ }
+@@ -986,8 +989,6 @@ static int bnx2x_get_dump_data(struct net_device *dev,
+ struct bnx2x *bp = netdev_priv(dev);
+ struct dump_header dump_hdr = {0};
+
+- memset(p, 0, dump->len);
+-
+ /* Disable parity attentions as long as following dump may
+ * cause false alarms by reading never written registers. We
+ * will re-enable parity attentions right after the dump.
+diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+index c50696b..cf96f52 100644
+--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
++++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+@@ -11394,6 +11394,8 @@ static int bnx2x_init_bp(struct bnx2x *bp)
+ bp->min_msix_vec_cnt = 2;
+ BNX2X_DEV_INFO("bp->min_msix_vec_cnt %d", bp->min_msix_vec_cnt);
+
++ bp->dump_preset_idx = 1;
++
+ return rc;
+ }
+
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
index 7306416..5fb7fb5 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
@@ -39929,6 +39965,20 @@ index 6e8bc9d..94d957d 100644
break;
default:
return -EINVAL;
+diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
+index 2b5e621..32187b8 100644
+--- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
++++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
+@@ -3036,7 +3036,9 @@ static void t3_io_resume(struct pci_dev *pdev)
+ CH_ALERT(adapter, "adapter recovering, PEX ERR 0x%x\n",
+ t3_read_reg(adapter, A_PCIE_PEX_ERR));
+
++ rtnl_lock();
+ t3_resume_ports(adapter);
++ rtnl_unlock();
+ }
+
+ static const struct pci_error_handlers t3_err_handler = {
diff --git a/drivers/net/ethernet/chelsio/cxgb3/l2t.h b/drivers/net/ethernet/chelsio/cxgb3/l2t.h
index 8cffcdf..aadf043 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/l2t.h
@@ -44863,6 +44913,56 @@ index 6ef94bc..1b41265 100644
}
/*
+diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
+index dfff647..3a19054 100644
+--- a/drivers/vhost/net.c
++++ b/drivers/vhost/net.c
+@@ -857,7 +857,7 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd)
+ mutex_unlock(&vq->mutex);
+
+ if (oldubufs) {
+- vhost_ubuf_put_and_wait(oldubufs);
++ vhost_ubuf_put_and_wait_and_free(oldubufs);
+ mutex_lock(&vq->mutex);
+ vhost_zerocopy_signal_used(n, vq);
+ mutex_unlock(&vq->mutex);
+@@ -875,7 +875,7 @@ err_used:
+ rcu_assign_pointer(vq->private_data, oldsock);
+ vhost_net_enable_vq(n, vq);
+ if (ubufs)
+- vhost_ubuf_put_and_wait(ubufs);
++ vhost_ubuf_put_and_wait_and_free(ubufs);
+ err_ubufs:
+ fput(sock->file);
+ err_vq:
+diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
+index 9759249..2e2524c 100644
+--- a/drivers/vhost/vhost.c
++++ b/drivers/vhost/vhost.c
+@@ -1581,5 +1581,11 @@ void vhost_ubuf_put_and_wait(struct vhost_ubuf_ref *ubufs)
+ {
+ kref_put(&ubufs->kref, vhost_zerocopy_done_signal);
+ wait_event(ubufs->wait, !atomic_read(&ubufs->kref.refcount));
++}
++
++void vhost_ubuf_put_and_wait_and_free(struct vhost_ubuf_ref *ubufs)
++{
++ vhost_ubuf_put_and_wait(ubufs);
+ kfree(ubufs);
+ }
++
+diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h
+index 17261e2..70cbe6f 100644
+--- a/drivers/vhost/vhost.h
++++ b/drivers/vhost/vhost.h
+@@ -63,6 +63,7 @@ struct vhost_ubuf_ref {
+ struct vhost_ubuf_ref *vhost_ubuf_alloc(struct vhost_virtqueue *, bool zcopy);
+ void vhost_ubuf_put(struct vhost_ubuf_ref *);
+ void vhost_ubuf_put_and_wait(struct vhost_ubuf_ref *);
++void vhost_ubuf_put_and_wait_and_free(struct vhost_ubuf_ref *);
+
+ struct ubuf_info;
+
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
index 8c55011..eed4ae1a 100644
--- a/drivers/video/aty/aty128fb.c
@@ -73352,6 +73452,18 @@ index a345480..3c65cf4 100644
};
#define TCP_SKB_CB(__skb) ((struct tcp_skb_cb *)&((__skb)->cb[0]))
+diff --git a/include/net/udp.h b/include/net/udp.h
+index 065f379..ad99eed 100644
+--- a/include/net/udp.h
++++ b/include/net/udp.h
+@@ -181,6 +181,7 @@ extern int udp_get_port(struct sock *sk, unsigned short snum,
+ extern void udp_err(struct sk_buff *, u32);
+ extern int udp_sendmsg(struct kiocb *iocb, struct sock *sk,
+ struct msghdr *msg, size_t len);
++extern int udp_push_pending_frames(struct sock *sk);
+ extern void udp_flush_pending_frames(struct sock *sk);
+ extern int udp_rcv(struct sk_buff *skb);
+ extern int udp_ioctl(struct sock *sk, int cmd, unsigned long arg);
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 24c8886..e6fb816 100644
--- a/include/net/xfrm.h
@@ -86463,6 +86575,48 @@ index 6cc0481..59cfb00 100644
}
}
EXPORT_SYMBOL(dev_load);
+diff --git a/net/core/ethtool.c b/net/core/ethtool.c
+index 41f4bdf..9e7c219 100644
+--- a/net/core/ethtool.c
++++ b/net/core/ethtool.c
+@@ -1314,10 +1314,19 @@ static int ethtool_get_dump_data(struct net_device *dev,
+ if (ret)
+ return ret;
+
+- len = (tmp.len > dump.len) ? dump.len : tmp.len;
++ len = min(tmp.len, dump.len);
+ if (!len)
+ return -EFAULT;
+
++ /* Don't ever let the driver think there's more space available
++ * than it requested with .get_dump_flag().
++ */
++ dump.len = len;
++
++ /* Always allocate enough space to hold the whole thing so that the
++ * driver does not need to check the length and bother with partial
++ * dumping.
++ */
+ data = vzalloc(tmp.len);
+ if (!data)
+ return -ENOMEM;
+@@ -1325,6 +1334,16 @@ static int ethtool_get_dump_data(struct net_device *dev,
+ if (ret)
+ goto out;
+
++ /* There are two sane possibilities:
++ * 1. The driver's .get_dump_data() does not touch dump.len.
++ * 2. Or it may set dump.len to how much it really writes, which
++ * should be tmp.len (or len if it can do a partial dump).
++ * In any case respond to userspace with the actual length of data
++ * it's receiving.
++ */
++ WARN_ON(dump.len != len && dump.len != tmp.len);
++ dump.len = len;
++
+ if (copy_to_user(useraddr, &dump, sizeof(dump))) {
+ ret = -EFAULT;
+ goto out;
diff --git a/net/core/flow.c b/net/core/flow.c
index 2bfd081..53c6058 100644
--- a/net/core/flow.c
@@ -87290,7 +87444,7 @@ index d9c4f11..02b82dbc 100644
msg.msg_flags = flags;
diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c
-index c3a4233..7df5626 100644
+index c3a4233..3fa029d 100644
--- a/net/ipv4/ip_vti.c
+++ b/net/ipv4/ip_vti.c
@@ -47,7 +47,7 @@
@@ -87312,7 +87466,25 @@ index c3a4233..7df5626 100644
skb_dst_drop(skb);
skb_dst_set(skb, &rt->dst);
nf_reset(skb);
-@@ -886,7 +885,7 @@ static const struct nla_policy vti_policy[IFLA_VTI_MAX + 1] = {
+@@ -645,17 +644,10 @@ static int __net_init vti_fb_tunnel_init(struct net_device *dev)
+ struct iphdr *iph = &tunnel->parms.iph;
+ struct vti_net *ipn = net_generic(dev_net(dev), vti_net_id);
+
+- tunnel->dev = dev;
+- strcpy(tunnel->parms.name, dev->name);
+-
+ iph->version = 4;
+ iph->protocol = IPPROTO_IPIP;
+ iph->ihl = 5;
+
+- dev->tstats = alloc_percpu(struct pcpu_tstats);
+- if (!dev->tstats)
+- return -ENOMEM;
+-
+ dev_hold(dev);
+ rcu_assign_pointer(ipn->tunnels_wc[0], tunnel);
+ return 0;
+@@ -886,7 +878,7 @@ static const struct nla_policy vti_policy[IFLA_VTI_MAX + 1] = {
[IFLA_VTI_REMOTE] = { .len = FIELD_SIZEOF(struct iphdr, daddr) },
};
@@ -87916,7 +88088,7 @@ index b78aac3..e18230b 100644
syn_set ? 0 : icsk->icsk_user_timeout, syn_set)) {
/* Has it gone just too far? */
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
-index 0a073a2..ddf6279 100644
+index 0a073a2..d4a04de 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -87,6 +87,7 @@
@@ -87948,7 +88120,24 @@ index 0a073a2..ddf6279 100644
/*
* This routine is called by the ICMP module when it gets some
* sort of error condition. If err < 0 then the socket should
-@@ -889,9 +897,18 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+@@ -799,7 +807,7 @@ send:
+ /*
+ * Push out all pending data as one UDP datagram. Socket is locked.
+ */
+-static int udp_push_pending_frames(struct sock *sk)
++int udp_push_pending_frames(struct sock *sk)
+ {
+ struct udp_sock *up = udp_sk(sk);
+ struct inet_sock *inet = inet_sk(sk);
+@@ -818,6 +826,7 @@ out:
+ up->pending = 0;
+ return err;
+ }
++EXPORT_SYMBOL(udp_push_pending_frames);
+
+ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+ size_t len)
+@@ -889,9 +898,18 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
dport = usin->sin_port;
if (dport == 0)
return -EINVAL;
@@ -87967,7 +88156,7 @@ index 0a073a2..ddf6279 100644
daddr = inet->inet_daddr;
dport = inet->inet_dport;
/* Open fast path for connected socket.
-@@ -1133,7 +1150,7 @@ static unsigned int first_packet_length(struct sock *sk)
+@@ -1133,7 +1151,7 @@ static unsigned int first_packet_length(struct sock *sk)
udp_lib_checksum_complete(skb)) {
UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS,
IS_UDPLITE(sk));
@@ -87976,7 +88165,7 @@ index 0a073a2..ddf6279 100644
__skb_unlink(skb, rcvq);
__skb_queue_tail(&list_kill, skb);
}
-@@ -1219,6 +1236,10 @@ try_again:
+@@ -1219,6 +1237,10 @@ try_again:
if (!skb)
goto out;
@@ -87987,7 +88176,7 @@ index 0a073a2..ddf6279 100644
ulen = skb->len - sizeof(struct udphdr);
copied = len;
if (copied > ulen)
-@@ -1252,7 +1273,7 @@ try_again:
+@@ -1252,7 +1274,7 @@ try_again:
if (unlikely(err)) {
trace_kfree_skb(skb, udp_recvmsg);
if (!peeked) {
@@ -87996,7 +88185,7 @@ index 0a073a2..ddf6279 100644
UDP_INC_STATS_USER(sock_net(sk),
UDP_MIB_INERRORS, is_udplite);
}
-@@ -1535,7 +1556,7 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
+@@ -1535,7 +1557,7 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
drop:
UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, is_udplite);
@@ -88005,7 +88194,7 @@ index 0a073a2..ddf6279 100644
kfree_skb(skb);
return -1;
}
-@@ -1554,7 +1575,7 @@ static void flush_stack(struct sock **stack, unsigned int count,
+@@ -1554,7 +1576,7 @@ static void flush_stack(struct sock **stack, unsigned int count,
skb1 = (i == final) ? skb : skb_clone(skb, GFP_ATOMIC);
if (!skb1) {
@@ -88014,7 +88203,7 @@ index 0a073a2..ddf6279 100644
UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_RCVBUFERRORS,
IS_UDPLITE(sk));
UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS,
-@@ -1723,6 +1744,9 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
+@@ -1723,6 +1745,9 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
goto csum_error;
UDP_INC_STATS_BH(net, UDP_MIB_NOPORTS, proto == IPPROTO_UDPLITE);
@@ -88024,7 +88213,7 @@ index 0a073a2..ddf6279 100644
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
/*
-@@ -2152,7 +2176,7 @@ static void udp4_format_sock(struct sock *sp, struct seq_file *f,
+@@ -2152,7 +2177,7 @@ static void udp4_format_sock(struct sock *sp, struct seq_file *f,
from_kuid_munged(seq_user_ns(f), sock_i_uid(sp)),
0, sock_i_ino(sp),
atomic_read(&sp->sk_refcnt), sp,
@@ -88116,6 +88305,53 @@ index fff5bdd..15194fb 100644
table = kmemdup(ipv6_icmp_table_template,
sizeof(ipv6_icmp_table_template),
+diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
+index 192dd1a..5fc9c7a 100644
+--- a/net/ipv6/ip6_fib.c
++++ b/net/ipv6/ip6_fib.c
+@@ -632,6 +632,12 @@ insert_above:
+ return ln;
+ }
+
++static inline bool rt6_qualify_for_ecmp(struct rt6_info *rt)
++{
++ return (rt->rt6i_flags & (RTF_GATEWAY|RTF_ADDRCONF|RTF_DYNAMIC)) ==
++ RTF_GATEWAY;
++}
++
+ /*
+ * Insert routing information in a node.
+ */
+@@ -646,6 +652,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
+ int add = (!info->nlh ||
+ (info->nlh->nlmsg_flags & NLM_F_CREATE));
+ int found = 0;
++ bool rt_can_ecmp = rt6_qualify_for_ecmp(rt);
+
+ ins = &fn->leaf;
+
+@@ -691,9 +698,8 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
+ * To avoid long list, we only had siblings if the
+ * route have a gateway.
+ */
+- if (rt->rt6i_flags & RTF_GATEWAY &&
+- !(rt->rt6i_flags & RTF_EXPIRES) &&
+- !(iter->rt6i_flags & RTF_EXPIRES))
++ if (rt_can_ecmp &&
++ rt6_qualify_for_ecmp(iter))
+ rt->rt6i_nsiblings++;
+ }
+
+@@ -715,7 +721,8 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
+ /* Find the first route that have the same metric */
+ sibling = fn->leaf;
+ while (sibling) {
+- if (sibling->rt6i_metric == rt->rt6i_metric) {
++ if (sibling->rt6i_metric == rt->rt6i_metric &&
++ rt6_qualify_for_ecmp(sibling)) {
+ list_add_tail(&rt->rt6i_siblings,
+ &sibling->rt6i_siblings);
+ break;
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index 95d13c7..791fe2f 100644
--- a/net/ipv6/ip6_gre.c
@@ -88157,7 +88393,7 @@ index 95d13c7..791fe2f 100644
.maxtype = IFLA_GRE_MAX,
.policy = ip6gre_policy,
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
-index 851fdae..9d4d1fd 100644
+index 851fdae..8f6f09a 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -822,11 +822,17 @@ static struct dst_entry *ip6_sk_dst_check(struct sock *sk,
@@ -88179,6 +88415,56 @@ index 851fdae..9d4d1fd 100644
/* Yes, checking route validity in not connected
* case is not very simple. Take into account,
* that we do not support routing by source, TOS,
+@@ -1093,11 +1099,12 @@ static inline struct ipv6_rt_hdr *ip6_rthdr_dup(struct ipv6_rt_hdr *src,
+ return src ? kmemdup(src, (src->hdrlen + 1) * 8, gfp) : NULL;
+ }
+
+-static void ip6_append_data_mtu(int *mtu,
++static void ip6_append_data_mtu(unsigned int *mtu,
+ int *maxfraglen,
+ unsigned int fragheaderlen,
+ struct sk_buff *skb,
+- struct rt6_info *rt)
++ struct rt6_info *rt,
++ bool pmtuprobe)
+ {
+ if (!(rt->dst.flags & DST_XFRM_TUNNEL)) {
+ if (skb == NULL) {
+@@ -1109,7 +1116,9 @@ static void ip6_append_data_mtu(int *mtu,
+ * this fragment is not first, the headers
+ * space is regarded as data space.
+ */
+- *mtu = dst_mtu(rt->dst.path);
++ *mtu = min(*mtu, pmtuprobe ?
++ rt->dst.dev->mtu :
++ dst_mtu(rt->dst.path));
+ }
+ *maxfraglen = ((*mtu - fragheaderlen) & ~7)
+ + fragheaderlen - sizeof(struct frag_hdr);
+@@ -1126,11 +1135,10 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
+ struct ipv6_pinfo *np = inet6_sk(sk);
+ struct inet_cork *cork;
+ struct sk_buff *skb, *skb_prev = NULL;
+- unsigned int maxfraglen, fragheaderlen;
++ unsigned int maxfraglen, fragheaderlen, mtu;
+ int exthdrlen;
+ int dst_exthdrlen;
+ int hh_len;
+- int mtu;
+ int copy;
+ int err;
+ int offset = 0;
+@@ -1290,7 +1298,9 @@ alloc_new_skb:
+ /* update mtu and maxfraglen if necessary */
+ if (skb == NULL || skb_prev == NULL)
+ ip6_append_data_mtu(&mtu, &maxfraglen,
+- fragheaderlen, skb, rt);
++ fragheaderlen, skb, rt,
++ np->pmtudisc ==
++ IPV6_PMTUDISC_PROBE);
+
+ skb_prev = skb;
+
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index fff83cb..82d49dd 100644
--- a/net/ipv6/ip6_tunnel.c
@@ -88539,7 +88825,7 @@ index 0fce928..c52a518 100644
}
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
-index 27f0f8e..949e7ee 100644
+index 27f0f8e..a8928b5 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -52,6 +52,10 @@
@@ -88590,7 +88876,25 @@ index 27f0f8e..949e7ee 100644
icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0);
kfree_skb(skb);
-@@ -1377,7 +1384,7 @@ static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket
+@@ -945,11 +952,16 @@ static int udp_v6_push_pending_frames(struct sock *sk)
+ struct udphdr *uh;
+ struct udp_sock *up = udp_sk(sk);
+ struct inet_sock *inet = inet_sk(sk);
+- struct flowi6 *fl6 = &inet->cork.fl.u.ip6;
++ struct flowi6 *fl6;
+ int err = 0;
+ int is_udplite = IS_UDPLITE(sk);
+ __wsum csum = 0;
+
++ if (up->pending == AF_INET)
++ return udp_push_pending_frames(sk);
++
++ fl6 = &inet->cork.fl.u.ip6;
++
+ /* Grab the skbuff where UDP header space exists. */
+ if ((skb = skb_peek(&sk->sk_write_queue)) == NULL)
+ goto out;
+@@ -1377,7 +1389,7 @@ static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket
0,
sock_i_ino(sp),
atomic_read(&sp->sk_refcnt), sp,
@@ -88789,6 +89093,20 @@ index 5b1e5af..1b929e7 100644
} while (!res);
return res;
}
+diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
+index 8dec687..5ebee2d 100644
+--- a/net/l2tp/l2tp_ppp.c
++++ b/net/l2tp/l2tp_ppp.c
+@@ -1793,7 +1793,8 @@ static const struct proto_ops pppol2tp_ops = {
+
+ static const struct pppox_proto pppol2tp_proto = {
+ .create = pppol2tp_create,
+- .ioctl = pppol2tp_ioctl
++ .ioctl = pppol2tp_ioctl,
++ .owner = THIS_MODULE,
+ };
+
+ #ifdef CONFIG_L2TP_V3
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 843d8c4..cb04fa1 100644
--- a/net/mac80211/cfg.c
@@ -90825,6 +91143,58 @@ index 8343737..677025e 100644
.mode = 0644,
.proc_handler = read_reset_stat,
},
+diff --git a/net/sunrpc/xprtrdma/svc_rdma_marshal.c b/net/sunrpc/xprtrdma/svc_rdma_marshal.c
+index 8d2eddd..65b1462 100644
+--- a/net/sunrpc/xprtrdma/svc_rdma_marshal.c
++++ b/net/sunrpc/xprtrdma/svc_rdma_marshal.c
+@@ -98,6 +98,7 @@ void svc_rdma_rcl_chunk_counts(struct rpcrdma_read_chunk *ch,
+ */
+ static u32 *decode_write_list(u32 *va, u32 *vaend)
+ {
++ unsigned long start, end;
+ int nchunks;
+
+ struct rpcrdma_write_array *ary =
+@@ -113,9 +114,12 @@ static u32 *decode_write_list(u32 *va, u32 *vaend)
+ return NULL;
+ }
+ nchunks = ntohl(ary->wc_nchunks);
+- if (((unsigned long)&ary->wc_array[0] +
+- (sizeof(struct rpcrdma_write_chunk) * nchunks)) >
+- (unsigned long)vaend) {
++
++ start = (unsigned long)&ary->wc_array[0];
++ end = (unsigned long)vaend;
++ if (nchunks < 0 ||
++ nchunks > (SIZE_MAX - start) / sizeof(struct rpcrdma_write_chunk) ||
++ (start + (sizeof(struct rpcrdma_write_chunk) * nchunks)) > end) {
+ dprintk("svcrdma: ary=%p, wc_nchunks=%d, vaend=%p\n",
+ ary, nchunks, vaend);
+ return NULL;
+@@ -129,6 +133,7 @@ static u32 *decode_write_list(u32 *va, u32 *vaend)
+
+ static u32 *decode_reply_array(u32 *va, u32 *vaend)
+ {
++ unsigned long start, end;
+ int nchunks;
+ struct rpcrdma_write_array *ary =
+ (struct rpcrdma_write_array *)va;
+@@ -143,9 +148,12 @@ static u32 *decode_reply_array(u32 *va, u32 *vaend)
+ return NULL;
+ }
+ nchunks = ntohl(ary->wc_nchunks);
+- if (((unsigned long)&ary->wc_array[0] +
+- (sizeof(struct rpcrdma_write_chunk) * nchunks)) >
+- (unsigned long)vaend) {
++
++ start = (unsigned long)&ary->wc_array[0];
++ end = (unsigned long)vaend;
++ if (nchunks < 0 ||
++ nchunks > (SIZE_MAX - start) / sizeof(struct rpcrdma_write_chunk) ||
++ (start + (sizeof(struct rpcrdma_write_chunk) * nchunks)) > end) {
+ dprintk("svcrdma: ary=%p, wc_nchunks=%d, vaend=%p\n",
+ ary, nchunks, vaend);
+ return NULL;
diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
index 0ce7552..d074459 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c