diff --git a/Makefile b/Makefile
index 5e66a3704705..786deb6599f1 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 3
 PATCHLEVEL = 18
-SUBLEVEL = 81
+SUBLEVEL = 82
 EXTRAVERSION =
 NAME = Diseased Newt
 
diff --git a/arch/arm/boot/dts/imx53-qsb-common.dtsi 
b/arch/arm/boot/dts/imx53-qsb-common.dtsi
index 53e81589368a..1f55187ed9ce 100644
--- a/arch/arm/boot/dts/imx53-qsb-common.dtsi
+++ b/arch/arm/boot/dts/imx53-qsb-common.dtsi
@@ -215,16 +215,16 @@
 
                pinctrl_fec: fecgrp {
                        fsl,pins = <
-                               MX53_PAD_FEC_MDC__FEC_MDC               0x4
-                               MX53_PAD_FEC_MDIO__FEC_MDIO             0x1fc
-                               MX53_PAD_FEC_REF_CLK__FEC_TX_CLK        0x180
-                               MX53_PAD_FEC_RX_ER__FEC_RX_ER           0x180
-                               MX53_PAD_FEC_CRS_DV__FEC_RX_DV          0x180
-                               MX53_PAD_FEC_RXD1__FEC_RDATA_1          0x180
-                               MX53_PAD_FEC_RXD0__FEC_RDATA_0          0x180
-                               MX53_PAD_FEC_TX_EN__FEC_TX_EN           0x4
-                               MX53_PAD_FEC_TXD1__FEC_TDATA_1          0x4
-                               MX53_PAD_FEC_TXD0__FEC_TDATA_0          0x4
+                               MX53_PAD_FEC_MDC__FEC_MDC               
0x80000000
+                               MX53_PAD_FEC_MDIO__FEC_MDIO             
0x80000000
+                               MX53_PAD_FEC_REF_CLK__FEC_TX_CLK        
0x80000000
+                               MX53_PAD_FEC_RX_ER__FEC_RX_ER           
0x80000000
+                               MX53_PAD_FEC_CRS_DV__FEC_RX_DV          
0x80000000
+                               MX53_PAD_FEC_RXD1__FEC_RDATA_1          
0x80000000
+                               MX53_PAD_FEC_RXD0__FEC_RDATA_0          
0x80000000
+                               MX53_PAD_FEC_TX_EN__FEC_TX_EN           
0x80000000
+                               MX53_PAD_FEC_TXD1__FEC_TDATA_1          
0x80000000
+                               MX53_PAD_FEC_TXD0__FEC_TDATA_0          
0x80000000
                        >;
                };
 
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 88eace4e28c3..22e64fd346ad 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -1070,11 +1070,6 @@ source "arch/powerpc/Kconfig.debug"
 
 source "security/Kconfig"
 
-config KEYS_COMPAT
-       bool
-       depends on COMPAT && KEYS
-       default y
-
 source "crypto/Kconfig"
 
 config PPC_LIB_RHEAP
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index f2cf1f90295b..1d814b527924 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -332,9 +332,6 @@ config COMPAT
 config SYSVIPC_COMPAT
        def_bool y if COMPAT && SYSVIPC
 
-config KEYS_COMPAT
-       def_bool y if COMPAT && KEYS
-
 config SMP
        def_bool y
        prompt "Symmetric multi-processing support"
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 96ac69c5eba0..e51b50af6373 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -542,9 +542,6 @@ config SYSVIPC_COMPAT
        depends on COMPAT && SYSVIPC
        default y
 
-config KEYS_COMPAT
-       def_bool y if COMPAT && KEYS
-
 endmenu
 
 source "net/Kconfig"
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index c9148e268512..a5d100cf8ed6 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -2471,10 +2471,6 @@ config COMPAT_FOR_U64_ALIGNMENT
 config SYSVIPC_COMPAT
        def_bool y
        depends on SYSVIPC
-
-config KEYS_COMPAT
-       def_bool y
-       depends on KEYS
 endif
 
 endmenu
diff --git a/drivers/input/misc/ims-pcu.c b/drivers/input/misc/ims-pcu.c
index 25bd4d701722..063898d429c7 100644
--- a/drivers/input/misc/ims-pcu.c
+++ b/drivers/input/misc/ims-pcu.c
@@ -1635,13 +1635,25 @@ ims_pcu_get_cdc_union_desc(struct usb_interface *intf)
                return NULL;
        }
 
-       while (buflen > 0) {
+       while (buflen >= sizeof(*union_desc)) {
                union_desc = (struct usb_cdc_union_desc *)buf;
 
+               if (union_desc->bLength > buflen) {
+                       dev_err(&intf->dev, "Too large descriptor\n");
+                       return NULL;
+               }
+
                if (union_desc->bDescriptorType == USB_DT_CS_INTERFACE &&
                    union_desc->bDescriptorSubType == USB_CDC_UNION_TYPE) {
                        dev_dbg(&intf->dev, "Found union header\n");
-                       return union_desc;
+
+                       if (union_desc->bLength >= sizeof(*union_desc))
+                               return union_desc;
+
+                       dev_err(&intf->dev,
+                               "Union descriptor to short (%d vs %zd\n)",
+                               union_desc->bLength, sizeof(*union_desc));
+                       return NULL;
                }
 
                buflen -= union_desc->bLength;
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
index 91120f0ed98c..d058c35b4985 100644
--- a/drivers/net/macvtap.c
+++ b/drivers/net/macvtap.c
@@ -1047,6 +1047,8 @@ static long macvtap_ioctl(struct file *file, unsigned int 
cmd,
        case TUNSETSNDBUF:
                if (get_user(u, up))
                        return -EFAULT;
+               if (u <= 0)
+                       return -EINVAL;
 
                q->sk.sk_sndbuf = u;
                return 0;
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index a4685a22f665..3067f840210e 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -1656,6 +1656,9 @@ static int tun_set_iff(struct net *net, struct file 
*file, struct ifreq *ifr)
 
                if (!dev)
                        return -ENOMEM;
+               err = dev_get_valid_name(net, dev, name);
+               if (err < 0)
+                       goto err_free_dev;
 
                dev_net_set(dev, net);
                dev->rtnl_link_ops = &tun_link_ops;
@@ -2054,6 +2057,10 @@ static long __tun_chr_ioctl(struct file *file, unsigned 
int cmd,
                        ret = -EFAULT;
                        break;
                }
+               if (sndbuf <= 0) {
+                       ret = -EINVAL;
+                       break;
+               }
 
                tun->sndbuf = sndbuf;
                tun_set_sndbuf(tun);
diff --git a/drivers/target/iscsi/iscsi_target.c 
b/drivers/target/iscsi/iscsi_target.c
index ce844e980990..801369f882b3 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -1749,7 +1749,7 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, 
struct iscsi_cmd *cmd,
        struct iscsi_tm *hdr;
        int out_of_order_cmdsn = 0, ret;
        bool sess_ref = false;
-       u8 function;
+       u8 function, tcm_function = TMR_UNKNOWN;
 
        hdr                     = (struct iscsi_tm *) buf;
        hdr->flags &= ~ISCSI_FLAG_CMD_FINAL;
@@ -1795,10 +1795,6 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, 
struct iscsi_cmd *cmd,
         * LIO-Target $FABRIC_MOD
         */
        if (function != ISCSI_TM_FUNC_TASK_REASSIGN) {
-
-               u8 tcm_function;
-               int ret;
-
                transport_init_se_cmd(&cmd->se_cmd,
                                      &lio_target_fabric_configfs->tf_ops,
                                      conn->sess->se_sess, 0, DMA_NONE,
@@ -1835,15 +1831,14 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, 
struct iscsi_cmd *cmd,
                        return iscsit_add_reject_cmd(cmd,
                                ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
                }
-
-               ret = core_tmr_alloc_req(&cmd->se_cmd, cmd->tmr_req,
-                                        tcm_function, GFP_KERNEL);
-               if (ret < 0)
-                       return iscsit_add_reject_cmd(cmd,
+       }
+       ret = core_tmr_alloc_req(&cmd->se_cmd, cmd->tmr_req, tcm_function,
+                                GFP_KERNEL);
+       if (ret < 0)
+               return iscsit_add_reject_cmd(cmd,
                                ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
 
-               cmd->tmr_req->se_tmr_req = cmd->se_cmd.se_tmr_req;
-       }
+       cmd->tmr_req->se_tmr_req = cmd->se_cmd.se_tmr_req;
 
        cmd->iscsi_opcode       = ISCSI_OP_SCSI_TMFUNC;
        cmd->i_state            = ISTATE_SEND_TASKMGTRSP;
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index 58b4c2828ee9..9176837442e9 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -183,12 +183,13 @@ found:
                        return tmp;
        }
 
-       if (in) {
+       if (in)
                dev->in_pipe = usb_rcvbulkpipe(udev,
                        in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+       if (out)
                dev->out_pipe = usb_sndbulkpipe(udev,
                        out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
-       }
+
        if (iso_in) {
                dev->iso_in = &iso_in->desc;
                dev->in_iso_pipe = usb_rcvisocpipe(udev,
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c
index 45692e8a9397..cefca661464b 100644
--- a/fs/ceph/caps.c
+++ b/fs/ceph/caps.c
@@ -1748,7 +1748,6 @@ static int try_flush_caps(struct inode *inode, unsigned 
*flush_tid)
 retry:
        spin_lock(&ci->i_ceph_lock);
        if (ci->i_ceph_flags & CEPH_I_NOFLUSH) {
-               spin_unlock(&ci->i_ceph_lock);
                dout("try_flush_caps skipping %p I_NOFLUSH set\n", inode);
                goto out;
        }
@@ -1766,10 +1765,8 @@ retry:
                        mutex_lock(&session->s_mutex);
                        goto retry;
                }
-               if (cap->session->s_state < CEPH_MDS_SESSION_OPEN) {
-                       spin_unlock(&ci->i_ceph_lock);
+               if (cap->session->s_state < CEPH_MDS_SESSION_OPEN)
                        goto out;
-               }
 
                flushing = __mark_caps_flushing(inode, session);
 
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 49ac10f99da0..de98fd0fc5b0 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -3245,6 +3245,9 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, 
const char *name,
                                    unsigned char name_assign_type,
                                    void (*setup)(struct net_device *),
                                    unsigned int txqs, unsigned int rxqs);
+int dev_get_valid_name(struct net *net, struct net_device *dev,
+                      const char *name);
+
 #define alloc_netdev(sizeof_priv, name, name_assign_type, setup) \
        alloc_netdev_mqs(sizeof_priv, name, name_assign_type, setup, 1, 1)
 
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 7219b8f38cef..2cd7003a8a19 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -1532,12 +1532,12 @@ static inline void tcp_highest_sack_reset(struct sock 
*sk)
        tcp_sk(sk)->highest_sack = tcp_write_queue_head(sk);
 }
 
-/* Called when old skb is about to be deleted (to be combined with new skb) */
-static inline void tcp_highest_sack_combine(struct sock *sk,
+/* Called when old skb is about to be deleted and replaced by new skb */
+static inline void tcp_highest_sack_replace(struct sock *sk,
                                            struct sk_buff *old,
                                            struct sk_buff *new)
 {
-       if (tcp_sk(sk)->sacked_out && (old == tcp_sk(sk)->highest_sack))
+       if (old == tcp_highest_sack(sk))
                tcp_sk(sk)->highest_sack = new;
 }
 
diff --git a/include/target/target_core_base.h 
b/include/target/target_core_base.h
index d1e7cb952168..ab4bff088898 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -231,6 +231,7 @@ enum tcm_tmreq_table {
        TMR_LUN_RESET           = 5,
        TMR_TARGET_WARM_RESET   = 6,
        TMR_TARGET_COLD_RESET   = 7,
+       TMR_UNKNOWN             = 0xff,
 };
 
 /* fabric independent task management response values */
diff --git a/net/core/dev.c b/net/core/dev.c
index 21b0bd976699..93e36e9102e9 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1059,9 +1059,8 @@ static int dev_alloc_name_ns(struct net *net,
        return ret;
 }
 
-static int dev_get_valid_name(struct net *net,
-                             struct net_device *dev,
-                             const char *name)
+int dev_get_valid_name(struct net *net, struct net_device *dev,
+                      const char *name)
 {
        BUG_ON(!net);
 
@@ -1077,6 +1076,7 @@ static int dev_get_valid_name(struct net *net,
 
        return 0;
 }
+EXPORT_SYMBOL(dev_get_valid_name);
 
 /**
  *     dev_change_name - change name of a device
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 37096d64730e..1dac2436b4d5 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -128,43 +128,68 @@ static struct rtnl_link_ops ipip_link_ops __read_mostly;
 
 static int ipip_err(struct sk_buff *skb, u32 info)
 {
-
-/* All the routers (except for Linux) return only
-   8 bytes of packet payload. It means, that precise relaying of
-   ICMP in the real Internet is absolutely infeasible.
- */
+       /* All the routers (except for Linux) return only
+          8 bytes of packet payload. It means, that precise relaying of
+          ICMP in the real Internet is absolutely infeasible.
+        */
        struct net *net = dev_net(skb->dev);
        struct ip_tunnel_net *itn = net_generic(net, ipip_net_id);
        const struct iphdr *iph = (const struct iphdr *)skb->data;
-       struct ip_tunnel *t;
-       int err;
        const int type = icmp_hdr(skb)->type;
        const int code = icmp_hdr(skb)->code;
+       struct ip_tunnel *t;
+       int err = 0;
+
+       switch (type) {
+       case ICMP_DEST_UNREACH:
+               switch (code) {
+               case ICMP_SR_FAILED:
+                       /* Impossible event. */
+                       goto out;
+               default:
+                       /* All others are translated to HOST_UNREACH.
+                        * rfc2003 contains "deep thoughts" about NET_UNREACH,
+                        * I believe they are just ether pollution. --ANK
+                        */
+                       break;
+               }
+               break;
+
+       case ICMP_TIME_EXCEEDED:
+               if (code != ICMP_EXC_TTL)
+                       goto out;
+               break;
+
+       case ICMP_REDIRECT:
+               break;
+
+       default:
+               goto out;
+       }
 
-       err = -ENOENT;
        t = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,
                             iph->daddr, iph->saddr, 0);
-       if (t == NULL)
+       if (!t) {
+               err = -ENOENT;
                goto out;
+       }
 
        if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
-               ipv4_update_pmtu(skb, dev_net(skb->dev), info,
-                                t->parms.link, 0, IPPROTO_IPIP, 0);
-               err = 0;
+               ipv4_update_pmtu(skb, net, info, t->parms.link, 0,
+                                iph->protocol, 0);
                goto out;
        }
 
        if (type == ICMP_REDIRECT) {
-               ipv4_redirect(skb, dev_net(skb->dev), t->parms.link, 0,
-                             IPPROTO_IPIP, 0);
-               err = 0;
+               ipv4_redirect(skb, net, t->parms.link, 0, iph->protocol, 0);
                goto out;
        }
 
-       if (t->parms.iph.daddr == 0)
+       if (t->parms.iph.daddr == 0) {
+               err = -ENOENT;
                goto out;
+       }
 
-       err = 0;
        if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
                goto out;
 
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 2adfa23285be..ff47e881e205 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -1870,6 +1870,7 @@ static int tcp_mtu_probe(struct sock *sk)
        nskb->ip_summed = skb->ip_summed;
 
        tcp_insert_write_queue_before(nskb, skb, sk);
+       tcp_highest_sack_replace(sk, skb, nskb);
 
        len = 0;
        tcp_for_write_queue_from_safe(skb, next, sk) {
@@ -2374,7 +2375,7 @@ static void tcp_collapse_retrans(struct sock *sk, struct 
sk_buff *skb)
 
        BUG_ON(tcp_skb_pcount(skb) != 1 || tcp_skb_pcount(next_skb) != 1);
 
-       tcp_highest_sack_combine(sk, next_skb, skb);
+       tcp_highest_sack_replace(sk, next_skb, skb);
 
        tcp_unlink_write_queue(next_skb, sk);
 
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
index a837f2065d2a..1a83031bcddd 100644
--- a/net/ipv6/ip6_flowlabel.c
+++ b/net/ipv6/ip6_flowlabel.c
@@ -316,6 +316,7 @@ struct ipv6_txoptions *fl6_merge_options(struct 
ipv6_txoptions *opt_space,
        }
        opt_space->dst1opt = fopt->dst1opt;
        opt_space->opt_flen = fopt->opt_flen;
+       opt_space->tot_len = fopt->tot_len;
        return opt_space;
 }
 EXPORT_SYMBOL_GPL(fl6_merge_options);
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index 77adf255d238..a97e74023e34 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -409,13 +409,16 @@ static void ip6gre_err(struct sk_buff *skb, struct 
inet6_skb_parm *opt,
        case ICMPV6_DEST_UNREACH:
                net_warn_ratelimited("%s: Path to destination invalid or 
inactive!\n",
                                     t->parms.name);
-               break;
+               if (code != ICMPV6_PORT_UNREACH)
+                       break;
+               return;
        case ICMPV6_TIME_EXCEED:
                if (code == ICMPV6_EXC_HOPLIMIT) {
                        net_warn_ratelimited("%s: Too small hop limit or 
routing loop in tunnel!\n",
                                             t->parms.name);
+                       break;
                }
-               break;
+               return;
        case ICMPV6_PARAMPROB:
                teli = 0;
                if (code == ICMPV6_HDR_FIELD)
@@ -431,13 +434,13 @@ static void ip6gre_err(struct sk_buff *skb, struct 
inet6_skb_parm *opt,
                        net_warn_ratelimited("%s: Recipient unable to parse 
tunneled packet!\n",
                                             t->parms.name);
                }
-               break;
+               return;
        case ICMPV6_PKT_TOOBIG:
                mtu = be32_to_cpu(info) - offset;
                if (mtu < IPV6_MIN_MTU)
                        mtu = IPV6_MIN_MTU;
                t->dev->mtu = mtu;
-               break;
+               return;
        }
 
        if (time_before(jiffies, t->err_time + IP6TUNNEL_ERR_TIMEO))
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index f71de459139f..6db1f8ad8ac3 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1177,11 +1177,11 @@ int ip6_append_data(struct sock *sk, int getfrag(void 
*from, char *to,
                        if (WARN_ON(np->cork.opt))
                                return -EINVAL;
 
-                       np->cork.opt = kzalloc(opt->tot_len, sk->sk_allocation);
+                       np->cork.opt = kzalloc(sizeof(*opt), sk->sk_allocation);
                        if (unlikely(np->cork.opt == NULL))
                                return -ENOBUFS;
 
-                       np->cork.opt->tot_len = opt->tot_len;
+                       np->cork.opt->tot_len = sizeof(*opt);
                        np->cork.opt->opt_flen = opt->opt_flen;
                        np->cork.opt->opt_nflen = opt->opt_nflen;
 
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
index 5a234fbe2fec..447843b24d7d 100644
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -1017,6 +1017,9 @@ static int pppol2tp_session_ioctl(struct l2tp_session 
*session,
                 session->name, cmd, arg);
 
        sk = ps->sock;
+       if (!sk)
+               return -EBADR;
+
        sock_hold(sk);
 
        switch (cmd) {
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index 94368404744b..375ff902a142 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -4,6 +4,7 @@
  * Copyright 2006-2007 Jiri Benc <[email protected]>
  * Copyright 2007-2008 Johannes Berg <[email protected]>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
+ * Copyright 2017      Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -18,6 +19,7 @@
 #include <linux/slab.h>
 #include <linux/export.h>
 #include <net/mac80211.h>
+#include <crypto/algapi.h>
 #include <asm/unaligned.h>
 #include "ieee80211_i.h"
 #include "driver-ops.h"
@@ -474,6 +476,39 @@ void ieee80211_key_free_unused(struct ieee80211_key *key)
        ieee80211_key_free_common(key);
 }
 
+static bool ieee80211_key_identical(struct ieee80211_sub_if_data *sdata,
+                                   struct ieee80211_key *old,
+                                   struct ieee80211_key *new)
+{
+       u8 tkip_old[WLAN_KEY_LEN_TKIP], tkip_new[WLAN_KEY_LEN_TKIP];
+       u8 *tk_old, *tk_new;
+
+       if (!old || new->conf.keylen != old->conf.keylen)
+               return false;
+
+       tk_old = old->conf.key;
+       tk_new = new->conf.key;
+
+       /*
+        * In station mode, don't compare the TX MIC key, as it's never used
+        * and offloaded rekeying may not care to send it to the host. This
+        * is the case in iwlwifi, for example.
+        */
+       if (sdata->vif.type == NL80211_IFTYPE_STATION &&
+           new->conf.cipher == WLAN_CIPHER_SUITE_TKIP &&
+           new->conf.keylen == WLAN_KEY_LEN_TKIP &&
+           !(new->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
+               memcpy(tkip_old, tk_old, WLAN_KEY_LEN_TKIP);
+               memcpy(tkip_new, tk_new, WLAN_KEY_LEN_TKIP);
+               memset(tkip_old + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY, 0, 8);
+               memset(tkip_new + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY, 0, 8);
+               tk_old = tkip_old;
+               tk_new = tkip_new;
+       }
+
+       return !crypto_memneq(tk_old, tk_new, new->conf.keylen);
+}
+
 int ieee80211_key_link(struct ieee80211_key *key,
                       struct ieee80211_sub_if_data *sdata,
                       struct sta_info *sta)
@@ -485,9 +520,6 @@ int ieee80211_key_link(struct ieee80211_key *key,
 
        pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE;
        idx = key->conf.keyidx;
-       key->local = sdata->local;
-       key->sdata = sdata;
-       key->sta = sta;
 
        mutex_lock(&sdata->local->key_mtx);
 
@@ -498,6 +530,20 @@ int ieee80211_key_link(struct ieee80211_key *key,
        else
                old_key = key_mtx_dereference(sdata->local, sdata->keys[idx]);
 
+       /*
+        * Silently accept key re-installation without really installing the
+        * new version of the key to avoid nonce reuse or replay issues.
+        */
+       if (ieee80211_key_identical(sdata, old_key, key)) {
+               ieee80211_key_free_unused(key);
+               ret = 0;
+               goto out;
+       }
+
+       key->local = sdata->local;
+       key->sdata = sdata;
+       key->sta = sta;
+
        increment_tailroom_need_count(sdata);
 
        ieee80211_key_replace(sdata, sta, pairwise, old_key, key);
@@ -513,6 +559,7 @@ int ieee80211_key_link(struct ieee80211_key *key,
                ret = 0;
        }
 
+ out:
        mutex_unlock(&sdata->local->key_mtx);
 
        return ret;
diff --git a/net/sctp/input.c b/net/sctp/input.c
index 2d7859c03fd2..71c2ef84c5b0 100644
--- a/net/sctp/input.c
+++ b/net/sctp/input.c
@@ -420,7 +420,7 @@ void sctp_icmp_redirect(struct sock *sk, struct 
sctp_transport *t,
 {
        struct dst_entry *dst;
 
-       if (!t)
+       if (sock_owned_by_user(sk) || !t)
                return;
        dst = sctp_transport_dst_check(t);
        if (dst)
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 92c6eac72ea6..07324ca1df1d 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -173,6 +173,36 @@ static inline void sctp_set_owner_w(struct sctp_chunk 
*chunk)
        sk_mem_charge(sk, chunk->skb->truesize);
 }
 
+static void sctp_clear_owner_w(struct sctp_chunk *chunk)
+{
+       skb_orphan(chunk->skb);
+}
+
+static void sctp_for_each_tx_datachunk(struct sctp_association *asoc,
+                                      void (*cb)(struct sctp_chunk *))
+
+{
+       struct sctp_outq *q = &asoc->outqueue;
+       struct sctp_transport *t;
+       struct sctp_chunk *chunk;
+
+       list_for_each_entry(t, &asoc->peer.transport_addr_list, transports)
+               list_for_each_entry(chunk, &t->transmitted, transmitted_list)
+                       cb(chunk);
+
+       list_for_each_entry(chunk, &q->retransmit, list)
+               cb(chunk);
+
+       list_for_each_entry(chunk, &q->sacked, list)
+               cb(chunk);
+
+       list_for_each_entry(chunk, &q->abandoned, list)
+               cb(chunk);
+
+       list_for_each_entry(chunk, &q->out_chunk_list, list)
+               cb(chunk);
+}
+
 /* Verify that this is a valid address. */
 static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr,
                                   int len)
@@ -7367,7 +7397,9 @@ static void sctp_sock_migrate(struct sock *oldsk, struct 
sock *newsk,
         * paths won't try to lock it and then oldsk.
         */
        lock_sock_nested(newsk, SINGLE_DEPTH_NESTING);
+       sctp_for_each_tx_datachunk(assoc, sctp_clear_owner_w);
        sctp_assoc_migrate(assoc, newsk);
+       sctp_for_each_tx_datachunk(assoc, sctp_set_owner_w);
 
        /* If the association on the newsk is already closed before accept()
         * is called, set RCV_SHUTDOWN flag.
diff --git a/net/unix/diag.c b/net/unix/diag.c
index 9d4218fc0a61..c4e4e2f664e8 100644
--- a/net/unix/diag.c
+++ b/net/unix/diag.c
@@ -256,6 +256,8 @@ static int unix_diag_get_exact(struct sk_buff *in_skb,
        err = -ENOENT;
        if (sk == NULL)
                goto out_nosk;
+       if (!net_eq(sock_net(sk), net))
+               goto out;
 
        err = sock_diag_check_cookie(sk, req->udiag_cookie);
        if (err)
diff --git a/security/keys/Kconfig b/security/keys/Kconfig
index a4f3f8c48d6e..d7734b53b3a8 100644
--- a/security/keys/Kconfig
+++ b/security/keys/Kconfig
@@ -20,6 +20,10 @@ config KEYS
 
          If you are unsure as to whether this is required, answer N.
 
+config KEYS_COMPAT
+       def_bool y
+       depends on COMPAT && KEYS
+
 config PERSISTENT_KEYRINGS
        bool "Enable register of persistent per-UID keyrings"
        depends on KEYS

Reply via email to