summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Pagano <mpagano@gentoo.org>2015-02-27 13:23:46 -0500
committerMike Pagano <mpagano@gentoo.org>2015-02-27 13:23:46 -0500
commit67b9d04ff69ca7c7a8be3fefb3247bd81d2241cc (patch)
tree3b9e2fb298486b87d09f310431122772291e36c6
parentEnable link security restrictions by default (diff)
downloadlinux-patches-3.10-78.tar.gz
linux-patches-3.10-78.tar.bz2
linux-patches-3.10-78.zip
Linux patch 3.10.70. Enable link security restrictions by default.3.10-78
-rw-r--r--0000_README4
-rw-r--r--1069_linux-3.10.70.patch569
2 files changed, 573 insertions, 0 deletions
diff --git a/0000_README b/0000_README
index 1791ea52..59f86bb1 100644
--- a/0000_README
+++ b/0000_README
@@ -318,6 +318,10 @@ Patch: 1068_linux-3.10.69.patch
From: http://www.kernel.org
Desc: Linux 3.10.69
+Patch: 1069_linux-3.10.70.patch
+From: http://www.kernel.org
+Desc: Linux 3.10.70
+
Patch: 1500_XATTR_USER_PREFIX.patch
From: https://bugs.gentoo.org/show_bug.cgi?id=470644
Desc: Support for namespace user.pax.* on tmpfs.
diff --git a/1069_linux-3.10.70.patch b/1069_linux-3.10.70.patch
new file mode 100644
index 00000000..eb0b7000
--- /dev/null
+++ b/1069_linux-3.10.70.patch
@@ -0,0 +1,569 @@
+diff --git a/Makefile b/Makefile
+index 81ede20061cf..402cbb7c27f1 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,6 +1,6 @@
+ VERSION = 3
+ PATCHLEVEL = 10
+-SUBLEVEL = 69
++SUBLEVEL = 70
+ EXTRAVERSION =
+ NAME = TOSSUG Baby Fish
+
+diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
+index 9951e66b8502..7e3f45105f11 100644
+--- a/drivers/block/rbd.c
++++ b/drivers/block/rbd.c
+@@ -2149,7 +2149,6 @@ static void rbd_img_obj_callback(struct rbd_obj_request *obj_request)
+ rbd_assert(img_request->obj_request_count > 0);
+ rbd_assert(which != BAD_WHICH);
+ rbd_assert(which < img_request->obj_request_count);
+- rbd_assert(which >= img_request->next_completion);
+
+ spin_lock_irq(&img_request->completion_lock);
+ if (which != img_request->next_completion)
+diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
+index e4561264e124..a895ed02da86 100644
+--- a/drivers/media/rc/ir-lirc-codec.c
++++ b/drivers/media/rc/ir-lirc-codec.c
+@@ -42,11 +42,17 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev)
+ return -EINVAL;
+
+ /* Packet start */
+- if (ev.reset)
+- return 0;
++ if (ev.reset) {
++ /* Userspace expects a long space event before the start of
++ * the signal to use as a sync. This may be done with repeat
++ * packets and normal samples. But if a reset has been sent
++ * then we assume that a long time has passed, so we send a
++ * space with the maximum time value. */
++ sample = LIRC_SPACE(LIRC_VALUE_MASK);
++ IR_dprintk(2, "delivering reset sync space to lirc_dev\n");
+
+ /* Carrier reports */
+- if (ev.carrier_report) {
++ } else if (ev.carrier_report) {
+ sample = LIRC_FREQUENCY(ev.carrier);
+ IR_dprintk(2, "carrier report (freq: %d)\n", sample);
+
+diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
+index af951f343ff6..50104a7e963f 100644
+--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
++++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
+@@ -2315,7 +2315,10 @@ static int netxen_nic_poll(struct napi_struct *napi, int budget)
+
+ work_done = netxen_process_rcv_ring(sds_ring, budget);
+
+- if ((work_done < budget) && tx_complete) {
++ if (!tx_complete)
++ work_done = budget;
++
++ if (work_done < budget) {
+ napi_complete(&sds_ring->napi);
+ if (test_bit(__NX_DEV_UP, &adapter->state))
+ netxen_nic_enable_int(sds_ring);
+diff --git a/drivers/net/ppp/ppp_deflate.c b/drivers/net/ppp/ppp_deflate.c
+index 602c625d95d5..b5edc7f96a39 100644
+--- a/drivers/net/ppp/ppp_deflate.c
++++ b/drivers/net/ppp/ppp_deflate.c
+@@ -246,7 +246,7 @@ static int z_compress(void *arg, unsigned char *rptr, unsigned char *obuf,
+ /*
+ * See if we managed to reduce the size of the packet.
+ */
+- if (olen < isize) {
++ if (olen < isize && olen <= osize) {
+ state->stats.comp_bytes += olen;
+ state->stats.comp_packets++;
+ } else {
+diff --git a/include/net/ip.h b/include/net/ip.h
+index 8695359982d1..0a62365149e2 100644
+--- a/include/net/ip.h
++++ b/include/net/ip.h
+@@ -37,11 +37,12 @@ struct inet_skb_parm {
+ struct ip_options opt; /* Compiled IP options */
+ unsigned char flags;
+
+-#define IPSKB_FORWARDED 1
+-#define IPSKB_XFRM_TUNNEL_SIZE 2
+-#define IPSKB_XFRM_TRANSFORMED 4
+-#define IPSKB_FRAG_COMPLETE 8
+-#define IPSKB_REROUTED 16
++#define IPSKB_FORWARDED BIT(0)
++#define IPSKB_XFRM_TUNNEL_SIZE BIT(1)
++#define IPSKB_XFRM_TRANSFORMED BIT(2)
++#define IPSKB_FRAG_COMPLETE BIT(3)
++#define IPSKB_REROUTED BIT(4)
++#define IPSKB_DOREDIRECT BIT(5)
+
+ u16 frag_max_size;
+ };
+@@ -162,7 +163,7 @@ static inline __u8 ip_reply_arg_flowi_flags(const struct ip_reply_arg *arg)
+ return (arg->flags & IP_REPLY_ARG_NOSRCCHECK) ? FLOWI_FLAG_ANYSRC : 0;
+ }
+
+-void ip_send_unicast_reply(struct net *net, struct sk_buff *skb, __be32 daddr,
++void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb, __be32 daddr,
+ __be32 saddr, const struct ip_reply_arg *arg,
+ unsigned int len);
+
+diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h
+index 2ba9de89e8ec..03e6378d5353 100644
+--- a/include/net/netns/ipv4.h
++++ b/include/net/netns/ipv4.h
+@@ -43,6 +43,7 @@ struct netns_ipv4 {
+ struct inet_peer_base *peers;
+ struct tcpm_hash_bucket *tcp_metrics_hash;
+ unsigned int tcp_metrics_hash_log;
++ struct sock * __percpu *tcp_sk;
+ struct netns_frags frags;
+ #ifdef CONFIG_NETFILTER
+ struct xt_table *iptable_filter;
+diff --git a/net/core/dev.c b/net/core/dev.c
+index cca7ae0ba915..c310440309bb 100644
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -6015,10 +6015,20 @@ static int dev_cpu_callback(struct notifier_block *nfb,
+ oldsd->output_queue = NULL;
+ oldsd->output_queue_tailp = &oldsd->output_queue;
+ }
+- /* Append NAPI poll list from offline CPU. */
+- if (!list_empty(&oldsd->poll_list)) {
+- list_splice_init(&oldsd->poll_list, &sd->poll_list);
+- raise_softirq_irqoff(NET_RX_SOFTIRQ);
++ /* Append NAPI poll list from offline CPU, with one exception :
++ * process_backlog() must be called by cpu owning percpu backlog.
++ * We properly handle process_queue & input_pkt_queue later.
++ */
++ while (!list_empty(&oldsd->poll_list)) {
++ struct napi_struct *napi = list_first_entry(&oldsd->poll_list,
++ struct napi_struct,
++ poll_list);
++
++ list_del_init(&napi->poll_list);
++ if (napi->poll == process_backlog)
++ napi->state = 0;
++ else
++ ____napi_schedule(sd, napi);
+ }
+
+ raise_softirq_irqoff(NET_TX_SOFTIRQ);
+@@ -6029,7 +6039,7 @@ static int dev_cpu_callback(struct notifier_block *nfb,
+ netif_rx(skb);
+ input_queue_head_incr(oldsd);
+ }
+- while ((skb = __skb_dequeue(&oldsd->input_pkt_queue))) {
++ while ((skb = skb_dequeue(&oldsd->input_pkt_queue))) {
+ netif_rx(skb);
+ input_queue_head_incr(oldsd);
+ }
+diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
+index 25c4dd563a79..279b5dcf09ae 100644
+--- a/net/core/rtnetlink.c
++++ b/net/core/rtnetlink.c
+@@ -2477,12 +2477,16 @@ static int rtnl_bridge_notify(struct net_device *dev, u16 flags)
+ goto errout;
+ }
+
++ if (!skb->len)
++ goto errout;
++
+ rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
+ return 0;
+ errout:
+ WARN_ON(err == -EMSGSIZE);
+ kfree_skb(skb);
+- rtnl_set_sk_err(net, RTNLGRP_LINK, err);
++ if (err)
++ rtnl_set_sk_err(net, RTNLGRP_LINK, err);
+ return err;
+ }
+
+diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c
+index bd1c5baf69be..31ee5c6033df 100644
+--- a/net/ipv4/ip_forward.c
++++ b/net/ipv4/ip_forward.c
+@@ -175,7 +175,8 @@ int ip_forward(struct sk_buff *skb)
+ * We now generate an ICMP HOST REDIRECT giving the route
+ * we calculated.
+ */
+- if (rt->rt_flags&RTCF_DOREDIRECT && !opt->srr && !skb_sec_path(skb))
++ if (IPCB(skb)->flags & IPSKB_DOREDIRECT && !opt->srr &&
++ !skb_sec_path(skb))
+ ip_rt_send_redirect(skb);
+
+ skb->priority = rt_tos2priority(iph->tos);
+diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
+index 22fa05e041ea..def18547748e 100644
+--- a/net/ipv4/ip_output.c
++++ b/net/ipv4/ip_output.c
+@@ -1454,23 +1454,8 @@ static int ip_reply_glue_bits(void *dptr, char *to, int offset,
+ /*
+ * Generic function to send a packet as reply to another packet.
+ * Used to send some TCP resets/acks so far.
+- *
+- * Use a fake percpu inet socket to avoid false sharing and contention.
+ */
+-static DEFINE_PER_CPU(struct inet_sock, unicast_sock) = {
+- .sk = {
+- .__sk_common = {
+- .skc_refcnt = ATOMIC_INIT(1),
+- },
+- .sk_wmem_alloc = ATOMIC_INIT(1),
+- .sk_allocation = GFP_ATOMIC,
+- .sk_flags = (1UL << SOCK_USE_WRITE_QUEUE),
+- },
+- .pmtudisc = IP_PMTUDISC_WANT,
+- .uc_ttl = -1,
+-};
+-
+-void ip_send_unicast_reply(struct net *net, struct sk_buff *skb, __be32 daddr,
++void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb, __be32 daddr,
+ __be32 saddr, const struct ip_reply_arg *arg,
+ unsigned int len)
+ {
+@@ -1478,9 +1463,8 @@ void ip_send_unicast_reply(struct net *net, struct sk_buff *skb, __be32 daddr,
+ struct ipcm_cookie ipc;
+ struct flowi4 fl4;
+ struct rtable *rt = skb_rtable(skb);
++ struct net *net = sock_net(sk);
+ struct sk_buff *nskb;
+- struct sock *sk;
+- struct inet_sock *inet;
+ int err;
+
+ if (ip_options_echo(&replyopts.opt.opt, skb))
+@@ -1508,15 +1492,11 @@ void ip_send_unicast_reply(struct net *net, struct sk_buff *skb, __be32 daddr,
+ if (IS_ERR(rt))
+ return;
+
+- inet = &get_cpu_var(unicast_sock);
++ inet_sk(sk)->tos = arg->tos;
+
+- inet->tos = arg->tos;
+- sk = &inet->sk;
+ sk->sk_priority = skb->priority;
+ sk->sk_protocol = ip_hdr(skb)->protocol;
+ sk->sk_bound_dev_if = arg->bound_dev_if;
+- sock_net_set(sk, net);
+- __skb_queue_head_init(&sk->sk_write_queue);
+ sk->sk_sndbuf = sysctl_wmem_default;
+ err = ip_append_data(sk, &fl4, ip_reply_glue_bits, arg->iov->iov_base,
+ len, 0, &ipc, &rt, MSG_DONTWAIT);
+@@ -1532,13 +1512,10 @@ void ip_send_unicast_reply(struct net *net, struct sk_buff *skb, __be32 daddr,
+ arg->csumoffset) = csum_fold(csum_add(nskb->csum,
+ arg->csum));
+ nskb->ip_summed = CHECKSUM_NONE;
+- skb_orphan(nskb);
+ skb_set_queue_mapping(nskb, skb_get_queue_mapping(skb));
+ ip_push_pending_frames(sk, &fl4);
+ }
+ out:
+- put_cpu_var(unicast_sock);
+-
+ ip_rt_put(rt);
+ }
+
+diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
+index 23e6ab0a2dc0..f6603142cb33 100644
+--- a/net/ipv4/ip_sockglue.c
++++ b/net/ipv4/ip_sockglue.c
+@@ -410,15 +410,11 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
+
+ memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err));
+ sin = &errhdr.offender;
+- sin->sin_family = AF_UNSPEC;
++ memset(sin, 0, sizeof(*sin));
+ if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP) {
+- struct inet_sock *inet = inet_sk(sk);
+-
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
+- sin->sin_port = 0;
+- memset(&sin->sin_zero, 0, sizeof(sin->sin_zero));
+- if (inet->cmsg_flags)
++ if (inet_sk(sk)->cmsg_flags)
+ ip_cmsg_recv(msg, skb);
+ }
+
+diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
+index aa857a4a06a8..698f3a2ac5ae 100644
+--- a/net/ipv4/ping.c
++++ b/net/ipv4/ping.c
+@@ -720,8 +720,11 @@ void ping_rcv(struct sk_buff *skb)
+ sk = ping_v4_lookup(net, saddr, daddr, ntohs(icmph->un.echo.id),
+ skb->dev->ifindex);
+ if (sk != NULL) {
++ struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
++
+ pr_debug("rcv on socket %p\n", sk);
+- ping_queue_rcv_skb(sk, skb_get(skb));
++ if (skb2)
++ ping_queue_rcv_skb(sk, skb2);
+ sock_put(sk);
+ return;
+ }
+diff --git a/net/ipv4/route.c b/net/ipv4/route.c
+index d4d162eac4df..e23c5f64286b 100644
+--- a/net/ipv4/route.c
++++ b/net/ipv4/route.c
+@@ -1514,11 +1514,10 @@ static int __mkroute_input(struct sk_buff *skb,
+
+ do_cache = res->fi && !itag;
+ if (out_dev == in_dev && err && IN_DEV_TX_REDIRECTS(out_dev) &&
++ skb->protocol == htons(ETH_P_IP) &&
+ (IN_DEV_SHARED_MEDIA(out_dev) ||
+- inet_addr_onlink(out_dev, saddr, FIB_RES_GW(*res)))) {
+- flags |= RTCF_DOREDIRECT;
+- do_cache = false;
+- }
++ inet_addr_onlink(out_dev, saddr, FIB_RES_GW(*res))))
++ IPCB(skb)->flags |= IPSKB_DOREDIRECT;
+
+ if (skb->protocol != htons(ETH_P_IP)) {
+ /* Not IP (i.e. ARP). Do not create route, if it is
+@@ -2255,6 +2254,8 @@ static int rt_fill_info(struct net *net, __be32 dst, __be32 src,
+ r->rtm_flags = (rt->rt_flags & ~0xFFFF) | RTM_F_CLONED;
+ if (rt->rt_flags & RTCF_NOTIFY)
+ r->rtm_flags |= RTM_F_NOTIFY;
++ if (IPCB(skb)->flags & IPSKB_DOREDIRECT)
++ r->rtm_flags |= RTCF_DOREDIRECT;
+
+ if (nla_put_be32(skb, RTA_DST, dst))
+ goto nla_put_failure;
+diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
+index e025c1c788a1..cce35e5a7ee6 100644
+--- a/net/ipv4/tcp_ipv4.c
++++ b/net/ipv4/tcp_ipv4.c
+@@ -707,7 +707,8 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb)
+
+ net = dev_net(skb_dst(skb)->dev);
+ arg.tos = ip_hdr(skb)->tos;
+- ip_send_unicast_reply(net, skb, ip_hdr(skb)->saddr,
++ ip_send_unicast_reply(*this_cpu_ptr(net->ipv4.tcp_sk),
++ skb, ip_hdr(skb)->saddr,
+ ip_hdr(skb)->daddr, &arg, arg.iov[0].iov_len);
+
+ TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS);
+@@ -790,7 +791,8 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack,
+ if (oif)
+ arg.bound_dev_if = oif;
+ arg.tos = tos;
+- ip_send_unicast_reply(net, skb, ip_hdr(skb)->saddr,
++ ip_send_unicast_reply(*this_cpu_ptr(net->ipv4.tcp_sk),
++ skb, ip_hdr(skb)->saddr,
+ ip_hdr(skb)->daddr, &arg, arg.iov[0].iov_len);
+
+ TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS);
+@@ -2898,14 +2900,39 @@ struct proto tcp_prot = {
+ };
+ EXPORT_SYMBOL(tcp_prot);
+
++static void __net_exit tcp_sk_exit(struct net *net)
++{
++ int cpu;
++
++ for_each_possible_cpu(cpu)
++ inet_ctl_sock_destroy(*per_cpu_ptr(net->ipv4.tcp_sk, cpu));
++ free_percpu(net->ipv4.tcp_sk);
++}
++
+ static int __net_init tcp_sk_init(struct net *net)
+ {
++ int res, cpu;
++
++ net->ipv4.tcp_sk = alloc_percpu(struct sock *);
++ if (!net->ipv4.tcp_sk)
++ return -ENOMEM;
++
++ for_each_possible_cpu(cpu) {
++ struct sock *sk;
++
++ res = inet_ctl_sock_create(&sk, PF_INET, SOCK_RAW,
++ IPPROTO_TCP, net);
++ if (res)
++ goto fail;
++ *per_cpu_ptr(net->ipv4.tcp_sk, cpu) = sk;
++ }
+ net->ipv4.sysctl_tcp_ecn = 2;
+ return 0;
+-}
+
+-static void __net_exit tcp_sk_exit(struct net *net)
+-{
++fail:
++ tcp_sk_exit(net);
++
++ return res;
+ }
+
+ static void __net_exit tcp_sk_exit_batch(struct list_head *net_exit_list)
+diff --git a/net/ipv4/udp_diag.c b/net/ipv4/udp_diag.c
+index 7927db0a9279..4a000f1dd757 100644
+--- a/net/ipv4/udp_diag.c
++++ b/net/ipv4/udp_diag.c
+@@ -99,11 +99,13 @@ static void udp_dump(struct udp_table *table, struct sk_buff *skb, struct netlin
+ s_slot = cb->args[0];
+ num = s_num = cb->args[1];
+
+- for (slot = s_slot; slot <= table->mask; num = s_num = 0, slot++) {
++ for (slot = s_slot; slot <= table->mask; s_num = 0, slot++) {
+ struct sock *sk;
+ struct hlist_nulls_node *node;
+ struct udp_hslot *hslot = &table->hash[slot];
+
++ num = 0;
++
+ if (hlist_nulls_empty(&hslot->head))
+ continue;
+
+diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
+index 8997340e3742..ce17d3da9b2b 100644
+--- a/net/ipv6/datagram.c
++++ b/net/ipv6/datagram.c
+@@ -374,11 +374,10 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
+
+ memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err));
+ sin = &errhdr.offender;
+- sin->sin6_family = AF_UNSPEC;
++ memset(sin, 0, sizeof(*sin));
++
+ if (serr->ee.ee_origin != SO_EE_ORIGIN_LOCAL) {
+ sin->sin6_family = AF_INET6;
+- sin->sin6_flowinfo = 0;
+- sin->sin6_port = 0;
+ if (skb->protocol == htons(ETH_P_IPV6)) {
+ sin->sin6_addr = ipv6_hdr(skb)->saddr;
+ if (np->rxopt.all)
+@@ -387,12 +386,9 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
+ ipv6_iface_scope_id(&sin->sin6_addr,
+ IP6CB(skb)->iif);
+ } else {
+- struct inet_sock *inet = inet_sk(sk);
+-
+ ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr,
+ &sin->sin6_addr);
+- sin->sin6_scope_id = 0;
+- if (inet->cmsg_flags)
++ if (inet_sk(sk)->cmsg_flags)
+ ip_cmsg_recv(msg, skb);
+ }
+ }
+diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
+index 009c9620f442..ceeb9458bb60 100644
+--- a/net/ipv6/ip6_fib.c
++++ b/net/ipv6/ip6_fib.c
+@@ -638,6 +638,29 @@ static inline bool rt6_qualify_for_ecmp(struct rt6_info *rt)
+ RTF_GATEWAY;
+ }
+
++static void fib6_purge_rt(struct rt6_info *rt, struct fib6_node *fn,
++ struct net *net)
++{
++ if (atomic_read(&rt->rt6i_ref) != 1) {
++ /* This route is used as dummy address holder in some split
++ * nodes. It is not leaked, but it still holds other resources,
++ * which must be released in time. So, scan ascendant nodes
++ * and replace dummy references to this route with references
++ * to still alive ones.
++ */
++ while (fn) {
++ if (!(fn->fn_flags & RTN_RTINFO) && fn->leaf == rt) {
++ fn->leaf = fib6_find_prefix(net, fn);
++ atomic_inc(&fn->leaf->rt6i_ref);
++ rt6_release(rt);
++ }
++ fn = fn->parent;
++ }
++ /* No more references are possible at this point. */
++ BUG_ON(atomic_read(&rt->rt6i_ref) != 1);
++ }
++}
++
+ /*
+ * Insert routing information in a node.
+ */
+@@ -775,11 +798,12 @@ add:
+ rt->dst.rt6_next = iter->dst.rt6_next;
+ atomic_inc(&rt->rt6i_ref);
+ inet6_rt_notify(RTM_NEWROUTE, rt, info);
+- rt6_release(iter);
+ if (!(fn->fn_flags & RTN_RTINFO)) {
+ info->nl_net->ipv6.rt6_stats->fib_route_nodes++;
+ fn->fn_flags |= RTN_RTINFO;
+ }
++ fib6_purge_rt(iter, fn, info->nl_net);
++ rt6_release(iter);
+ }
+
+ return 0;
+@@ -1284,24 +1308,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
+ fn = fib6_repair_tree(net, fn);
+ }
+
+- if (atomic_read(&rt->rt6i_ref) != 1) {
+- /* This route is used as dummy address holder in some split
+- * nodes. It is not leaked, but it still holds other resources,
+- * which must be released in time. So, scan ascendant nodes
+- * and replace dummy references to this route with references
+- * to still alive ones.
+- */
+- while (fn) {
+- if (!(fn->fn_flags & RTN_RTINFO) && fn->leaf == rt) {
+- fn->leaf = fib6_find_prefix(net, fn);
+- atomic_inc(&fn->leaf->rt6i_ref);
+- rt6_release(rt);
+- }
+- fn = fn->parent;
+- }
+- /* No more references are possible at this point. */
+- BUG_ON(atomic_read(&rt->rt6i_ref) != 1);
+- }
++ fib6_purge_rt(rt, fn, net);
+
+ inet6_rt_notify(RTM_DELROUTE, rt, info);
+ rt6_release(rt);
+diff --git a/net/ipv6/route.c b/net/ipv6/route.c
+index b2614b22622b..92274796eb71 100644
+--- a/net/ipv6/route.c
++++ b/net/ipv6/route.c
+@@ -1141,12 +1141,9 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
+ struct net *net = dev_net(dst->dev);
+
+ rt6->rt6i_flags |= RTF_MODIFIED;
+- if (mtu < IPV6_MIN_MTU) {
+- u32 features = dst_metric(dst, RTAX_FEATURES);
++ if (mtu < IPV6_MIN_MTU)
+ mtu = IPV6_MIN_MTU;
+- features |= RTAX_FEATURE_ALLFRAG;
+- dst_metric_set(dst, RTAX_FEATURES, features);
+- }
++
+ dst_metric_set(dst, RTAX_MTU, mtu);
+ rt6_update_expires(rt6, net->ipv6.sysctl.ip6_rt_mtu_expires);
+ }
+diff --git a/net/sctp/associola.c b/net/sctp/associola.c
+index ca4a1a1b8e69..6360a14edeab 100644
+--- a/net/sctp/associola.c
++++ b/net/sctp/associola.c
+@@ -1297,7 +1297,6 @@ void sctp_assoc_update(struct sctp_association *asoc,
+ asoc->peer.peer_hmacs = new->peer.peer_hmacs;
+ new->peer.peer_hmacs = NULL;
+
+- sctp_auth_key_put(asoc->asoc_shared_key);
+ sctp_auth_asoc_init_active_key(asoc, GFP_ATOMIC);
+ }
+
+diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
+index 29fc16f3633f..beedadf62f6c 100644
+--- a/net/sctp/sm_make_chunk.c
++++ b/net/sctp/sm_make_chunk.c
+@@ -2595,7 +2595,7 @@ do_addr_param:
+
+ addr_param = param.v + sizeof(sctp_addip_param_t);
+
+- af = sctp_get_af_specific(param_type2af(param.p->type));
++ af = sctp_get_af_specific(param_type2af(addr_param->p.type));
+ if (af == NULL)
+ break;
+