Commit 87760fec authored by Natanael Copa's avatar Natanael Copa

main/linux-grsec: upgrade to 3.9.4 and use reworked arp and frag patches

fixes #1782

(cherry picked from commit a43c9a40)
parent 4d918a90
From 1225b1090991bdcab819bdab96be329397563f1c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi>
Date: Thu, 23 May 2013 11:30:23 +0300
Subject: [PATCH 1/6] net: inform NETDEV_CHANGE callbacks which flags were
changed
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
In certain cases (like the follow up commit to arp.c) will need to
check which flags actually changed to avoid excessive work.
Ben Hutchings nicely worded why to put these transient flags to
struct net_device for the time being:
> It's inelegant to put transient data associated with an event in a
> persistent data structure. On the other hand, having every user cache
> the old state is pretty awful as well.
>
> Really, netdev notifiers should be changed to accept a structure that
> encapsulates the changes rather than just a pointer to the net_device.
> But making such a change would be an enormous pain and error-prone
> because notifier functions aren't type-safe.
>
> As an interim solution, I think either the general flags_changed or
> old_flags would be preferable to defining extra transient flags.
Signed-off-by: Timo Teräs <timo.teras@iki.fi>
Acked-by: Ben Hutchings <bhutchings@solarflare.com>
---
include/linux/netdevice.h | 4 +++-
net/core/dev.c | 5 ++++-
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 6151e90..8b3c649 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1112,7 +1112,9 @@ struct net_device {
/* Hardware header description */
const struct header_ops *header_ops;
- unsigned int flags; /* interface flags (a la BSD) */
+ unsigned int flags; /* interface flags (a la BSD) */
+ unsigned int flags_changed; /* flags that are being changed
+ * valid during NETDEV_CHANGE notifier */
unsigned int priv_flags; /* Like 'flags' but invisible to userspace.
* See if.h for definitions. */
unsigned short gflags;
diff --git a/net/core/dev.c b/net/core/dev.c
index 9a278e9..2f3feae 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4683,8 +4683,11 @@ void __dev_notify_flags(struct net_device *dev, unsigned int old_flags)
}
if (dev->flags & IFF_UP &&
- (changes & ~(IFF_UP | IFF_PROMISC | IFF_ALLMULTI | IFF_VOLATILE)))
+ (changes & ~(IFF_UP | IFF_PROMISC | IFF_ALLMULTI | IFF_VOLATILE))) {
+ dev->flags_changed = changes;
call_netdevice_notifiers(NETDEV_CHANGE, dev);
+ dev->flags_changed = 0;
+ }
}
/**
--
1.8.2.3
From 36fbd62c47d800705d9989c69994359711514165 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi>
Date: Thu, 23 May 2013 11:43:55 +0300
Subject: [PATCH 2/6] arp: flush arp cache on IFF_NOARP change
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
IFF_NOARP affects what kind of neighbor entries are created
(nud NOARP or nud INCOMPLETE). If the flag changes, flush the arp
cache to refresh all entries.
Signed-off-by: Timo Teräs <timo.teras@iki.fi>
---
net/ipv4/arp.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index fea4929..2a06ecf 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -1226,6 +1226,10 @@ static int arp_netdev_event(struct notifier_block *this, unsigned long event,
neigh_changeaddr(&arp_tbl, dev);
rt_cache_flush(dev_net(dev));
break;
+ case NETDEV_CHANGE:
+ if (dev->flags_changed & IFF_NOARP)
+ neigh_changeaddr(&arp_tbl, dev);
+ break;
default:
break;
}
--
1.8.2.3
From 777eadba40c19bcfdb48807e7b0547ef30555671 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi>
Date: Sat, 25 May 2013 15:42:30 +0300
Subject: [PATCH 3/6] ipv4: properly refresh rtable entries on pmtu/redirect
events
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This reverts commit 05ab86c5 (xfrm4: Invalidate all ipv4 routes on
IPsec pmtu events). Flushing all cached entries is not needed.
Instead, invalidate only the related next hop dsts to recheck for
the added next hop exception where needed. This also fixes a subtle
race due to bumping generation id's before updating the pmtu.
Cc: Steffen Klassert <steffen.klassert@secunet.com>
Signed-off-by: Timo Teräs <timo.teras@iki.fi>
---
net/ipv4/ah4.c | 7 ++-----
net/ipv4/esp4.c | 7 ++-----
net/ipv4/ipcomp.c | 7 ++-----
net/ipv4/route.c | 63 ++++++++++++++++++++++++++++++++-----------------------
4 files changed, 43 insertions(+), 41 deletions(-)
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
index 2e7f194..7179026 100644
--- a/net/ipv4/ah4.c
+++ b/net/ipv4/ah4.c
@@ -419,12 +419,9 @@ static void ah4_err(struct sk_buff *skb, u32 info)
if (!x)
return;
- if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) {
- atomic_inc_unchecked(&flow_cache_genid);
- rt_genid_bump(net);
-
+ if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH)
ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_AH, 0);
- } else
+ else
ipv4_redirect(skb, net, 0, 0, IPPROTO_AH, 0);
xfrm_state_put(x);
}
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index 4cfe34d..ab3d814 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -502,12 +502,9 @@ static void esp4_err(struct sk_buff *skb, u32 info)
if (!x)
return;
- if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) {
- atomic_inc_unchecked(&flow_cache_genid);
- rt_genid_bump(net);
-
+ if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH)
ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_ESP, 0);
- } else
+ else
ipv4_redirect(skb, net, 0, 0, IPPROTO_ESP, 0);
xfrm_state_put(x);
}
diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c
index f01d1b1..48b3f0b 100644
--- a/net/ipv4/ipcomp.c
+++ b/net/ipv4/ipcomp.c
@@ -47,12 +47,9 @@ static void ipcomp4_err(struct sk_buff *skb, u32 info)
if (!x)
return;
- if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) {
- atomic_inc_unchecked(&flow_cache_genid);
- rt_genid_bump(net);
-
+ if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH)
ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_COMP, 0);
- } else
+ else
ipv4_redirect(skb, net, 0, 0, IPPROTO_COMP, 0);
xfrm_state_put(x);
}
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 6e28514..8dedfeb 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -594,11 +594,25 @@ static inline u32 fnhe_hashfun(__be32 daddr)
return hval & (FNHE_HASH_SIZE - 1);
}
+static void fill_route_from_fnhe(struct rtable *rt, struct fib_nh_exception *fnhe)
+{
+ rt->rt_pmtu = fnhe->fnhe_pmtu;
+ rt->dst.expires = fnhe->fnhe_expires;
+
+ if (fnhe->fnhe_gw) {
+ rt->rt_flags |= RTCF_REDIRECTED;
+ rt->rt_gateway = fnhe->fnhe_gw;
+ rt->rt_uses_gateway = 1;
+ }
+}
+
static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw,
u32 pmtu, unsigned long expires)
{
struct fnhe_hash_bucket *hash;
struct fib_nh_exception *fnhe;
+ struct rtable *rt;
+ unsigned int i;
int depth;
u32 hval = fnhe_hashfun(daddr);
@@ -627,8 +641,12 @@ static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw,
fnhe->fnhe_gw = gw;
if (pmtu) {
fnhe->fnhe_pmtu = pmtu;
- fnhe->fnhe_expires = expires;
+ fnhe->fnhe_expires = max(1UL, expires);
}
+ /* Update all cached dsts too */
+ rt = rcu_dereference(fnhe->fnhe_rth);
+ if (rt)
+ fill_route_from_fnhe(rt, fnhe);
} else {
if (depth > FNHE_RECLAIM_DEPTH)
fnhe = fnhe_oldest(hash);
@@ -644,6 +662,18 @@ static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw,
fnhe->fnhe_gw = gw;
fnhe->fnhe_pmtu = pmtu;
fnhe->fnhe_expires = expires;
+
+ /* Exception created; mark the cached routes for the nexthop
+ * stale, so anyone caching it rechecks if this exception
+ * applies to them.
+ */
+ for_each_possible_cpu(i) {
+ struct rtable __rcu **prt;
+ prt = per_cpu_ptr(nh->nh_pcpu_rth_output, i);
+ rt = rcu_dereference(*prt);
+ if (rt)
+ rt->dst.obsolete = DST_OBSOLETE_KILL;
+ }
}
fnhe->fnhe_stamp = jiffies;
@@ -917,13 +947,6 @@ static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu)
if (mtu < ip_rt_min_pmtu)
mtu = ip_rt_min_pmtu;
- if (!rt->rt_pmtu) {
- dst->obsolete = DST_OBSOLETE_KILL;
- } else {
- rt->rt_pmtu = mtu;
- dst->expires = max(1UL, jiffies + ip_rt_mtu_expires);
- }
-
rcu_read_lock();
if (fib_lookup(dev_net(dst->dev), fl4, &res) == 0) {
struct fib_nh *nh = &FIB_RES_NH(res);
@@ -1063,11 +1086,11 @@ static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie)
* DST_OBSOLETE_FORCE_CHK which forces validation calls down
* into this function always.
*
- * When a PMTU/redirect information update invalidates a
- * route, this is indicated by setting obsolete to
- * DST_OBSOLETE_KILL.
+ * When a PMTU/redirect information update invalidates a route,
+ * this is indicated by setting obsolete to DST_OBSOLETE_KILL or
+ * DST_OBSOLETE_DEAD by dst_free().
*/
- if (dst->obsolete == DST_OBSOLETE_KILL || rt_is_expired(rt))
+ if (dst->obsolete != DST_OBSOLETE_FORCE_CHK || rt_is_expired(rt))
return NULL;
return dst;
}
@@ -1215,20 +1238,8 @@ static bool rt_bind_exception(struct rtable *rt, struct fib_nh_exception *fnhe,
fnhe->fnhe_pmtu = 0;
fnhe->fnhe_expires = 0;
}
- if (fnhe->fnhe_pmtu) {
- unsigned long expires = fnhe->fnhe_expires;
- unsigned long diff = expires - jiffies;
-
- if (time_before(jiffies, expires)) {
- rt->rt_pmtu = fnhe->fnhe_pmtu;
- dst_set_expires(&rt->dst, diff);
- }
- }
- if (fnhe->fnhe_gw) {
- rt->rt_flags |= RTCF_REDIRECTED;
- rt->rt_gateway = fnhe->fnhe_gw;
- rt->rt_uses_gateway = 1;
- } else if (!rt->rt_gateway)
+ fill_route_from_fnhe(rt, fnhe);
+ if (!rt->rt_gateway)
rt->rt_gateway = daddr;
rcu_assign_pointer(fnhe->fnhe_rth, rt);
--
1.8.2.3
From 90f586dba1465a73295d752abe2451e924ba1888 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi>
Date: Mon, 27 May 2013 08:33:10 +0300
Subject: [PATCH 4/6] ipv4: rate limit updating of next hop exceptions with
same pmtu
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The tunnel devices call update_pmtu for each packet sent, this causes
contention on the fnhe_lock. Ignore the pmtu update if pmtu is not
actually changed, and there is still plenty of time before the entry
expires.
Signed-off-by: Timo Teräs <timo.teras@iki.fi>
---
net/ipv4/route.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 8dedfeb..85b9c07 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -947,6 +947,10 @@ static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu)
if (mtu < ip_rt_min_pmtu)
mtu = ip_rt_min_pmtu;
+ if (rt->rt_pmtu == mtu &&
+ time_before(jiffies, dst->expires - ip_rt_mtu_expires / 2))
+ return;
+
rcu_read_lock();
if (fib_lookup(dev_net(dst->dev), fl4, &res) == 0) {
struct fib_nh *nh = &FIB_RES_NH(res);
--
1.8.2.3
From 4a7dbb238480fac2b1ad02a74240efcf225c1f45 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi>
Date: Mon, 27 May 2013 10:55:52 +0300
Subject: [PATCH 5/6] ipv4: use separate genid for next hop exceptions
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
commit 13d82bf5 (ipv4: Fix flushing of cached routing informations)
added the support to flush learned pmtu information.
However, using rt_genid is quite heavy as it is bumped on route
add/change and multicast events amongst other places. These can
happen quote often, especially if using dynamic routing protocols.
While this is ok with routes (as they are just recreated locally),
the pmtu information is learned from remote systems and the icmp
notification can come with long delays. It is worthy to have separate
genid to avoid excessive pmtu resets.
Cc: Steffen Klassert <steffen.klassert@secunet.com>
Signed-off-by: Timo Teräs <timo.teras@iki.fi>
---
include/net/ip_fib.h | 1 +
include/net/net_namespace.h | 11 +++++++++++
net/ipv4/route.c | 12 ++++++++++--
3 files changed, 22 insertions(+), 2 deletions(-)
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index e49db91..44424e9 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -51,6 +51,7 @@ struct rtable;
struct fib_nh_exception {
struct fib_nh_exception __rcu *fnhe_next;
+ int fnhe_genid;
__be32 fnhe_daddr;
u32 fnhe_pmtu;
__be32 fnhe_gw;
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index de644bc..b5a5baf 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -116,6 +116,7 @@ struct net {
struct netns_ipvs *ipvs;
struct sock *diag_nlsk;
atomic_unchecked_t rt_genid;
+ atomic_unchecked_t fnhe_genid;
};
/*
@@ -338,4 +339,14 @@ static inline void rt_genid_bump(struct net *net)
atomic_inc_unchecked(&net->rt_genid);
}
+static inline int fnhe_genid(struct net *net)
+{
+ return atomic_read_unchecked(&net->fnhe_genid);
+}
+
+static inline void fnhe_genid_bump(struct net *net)
+{
+ atomic_inc_unchecked(&net->fnhe_genid);
+}
+
#endif /* __NET_NET_NAMESPACE_H */
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 85b9c07..f44a4bb 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -658,6 +658,7 @@ static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw,
fnhe->fnhe_next = hash->chain;
rcu_assign_pointer(hash->chain, fnhe);
}
+ fnhe->fnhe_genid = fnhe_genid(dev_net(nh->nh_dev));
fnhe->fnhe_daddr = daddr;
fnhe->fnhe_gw = gw;
fnhe->fnhe_pmtu = pmtu;
@@ -1236,8 +1237,11 @@ static bool rt_bind_exception(struct rtable *rt, struct fib_nh_exception *fnhe,
spin_lock_bh(&fnhe_lock);
if (daddr == fnhe->fnhe_daddr) {
+ int genid = fnhe_genid(dev_net(rt->dst.dev));
struct rtable *orig = rcu_dereference(fnhe->fnhe_rth);
- if (orig && rt_is_expired(orig)) {
+
+ if (fnhe->fnhe_genid != genid) {
+ fnhe->fnhe_genid = genid;
fnhe->fnhe_gw = 0;
fnhe->fnhe_pmtu = 0;
fnhe->fnhe_expires = 0;
@@ -2443,8 +2447,11 @@ static int ipv4_sysctl_rtcache_flush(ctl_table *__ctl, int write,
void __user *buffer,
size_t *lenp, loff_t *ppos)
{
+ struct net *net = (struct net *)__ctl->extra1;
+
if (write) {
- rt_cache_flush((struct net *)__ctl->extra1);
+ rt_cache_flush(net);
+ fnhe_genid_bump(net);
return 0;
}
@@ -2619,6 +2626,7 @@ static __net_initdata struct pernet_operations sysctl_route_ops = {
static __net_init int rt_genid_init(struct net *net)
{
atomic_set_unchecked(&net->rt_genid, 0);
+ atomic_set_unchecked(&net->fnhe_genid, 0);
get_random_bytes(&net->ipv4.dev_addr_genid,
sizeof(net->ipv4.dev_addr_genid));
return 0;
--
1.8.2.3
From patchwork Thu May 23 13:15:46 2013
Content-Type: text/plain; charset="utf-8"
From 87151ab93a08bcc4abe23aa2e87fbc2b956ae2cc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi>
Date: Mon, 27 May 2013 08:40:22 +0300
Subject: [PATCH 6/6] ipv4: use next hop exceptions also for input routes
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Subject: [RFC] net/ipv4: Use next hop exceptions also for input routes
Date: Thu, 23 May 2013 03:15:46 -0000
From: =?utf-8?q?Timo_Ter=C3=A4s?= <timo.teras@iki.fi>
X-Patchwork-Id: 245949
Message-Id: <1369314946-12692-1-git-send-email-timo.teras@iki.fi>
To: netdev@vger.kernel.org
Cc: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi>
Commit d2d68ba9 (ipv4: Cache input routes in fib_info nexthops)
assmued that "locally destined, and routed packets, never trigger
......@@ -22,39 +18,23 @@ next hop exceptions are not consulted for pmtu, IP fragmentation will
not be done properly for these routes.
It also seems that we really need to have the PMTU information always
for netfilter TCPMSS' clamp-to-pmtu feature to work properly.
for netfilter TCPMSS clamp-to-pmtu feature to work properly.
So for the time being, cache separate copies of input routes for
each next hop exception.
Signed-off-by: Timo Teräs <timo.teras@iki.fi>
---
I had ideas to make optimizations where pmtu information would not
be needed. This includes:
- Target devices with IFF_XMIT_DST_RELEASE set (practically all devices
except tunnels). If skb_dst() is early freed the target device cannot
generate PMTU events
- Add flag for input route generation if pmtu info is needed for
fragmentation. Basically a flag saying if DF bit was set in ip_hdr.
However, TCPMSS clamp-to-pmtu prevents both optimizations.
I'm not yet all familiar with the recent changes in routing caching,
so there might be caveats that I missed. Basic testing shows this fixes
the fragmentation issues I'm seeing, and I have not yet found any ill
side effects either.
include/net/ip_fib.h | 3 ++-
net/ipv4/fib_semantics.c | 3 ++-
net/ipv4/route.c | 41 +++++++++++++++++++++++++++++++----------
3 files changed, 35 insertions(+), 12 deletions(-)
net/ipv4/route.c | 65 +++++++++++++++++++++++++++++++++++++-----------
3 files changed, 54 insertions(+), 17 deletions(-)
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index e49db91..20529a6 100644
index 44424e9..aac8553 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -55,7 +55,8 @@ struct fib_nh_exception {
@@ -56,7 +56,8 @@ struct fib_nh_exception {
u32 fnhe_pmtu;
__be32 fnhe_gw;
unsigned long fnhe_expires;
......@@ -79,45 +59,97 @@ index 8f6cb7a..d5dbca5 100644
kfree(fnhe);
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 550781a..073df96 100644
index f44a4bb..a7a36f7 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -576,9 +576,14 @@ static struct fib_nh_exception *fnhe_oldest(struct fnhe_hash_bucket *hash)
@@ -565,10 +565,25 @@ static inline void rt_free(struct rtable *rt)
static DEFINE_SPINLOCK(fnhe_lock);
+static void fnhe_flush_routes(struct fib_nh_exception *fnhe)
+{
+ struct rtable *rt;
+
+ rt = rcu_dereference(fnhe->fnhe_rth_input);
+ if (rt) {
+ RCU_INIT_POINTER(fnhe->fnhe_rth_input, NULL);
+ rt_free(rt);
+ }
+ rt = rcu_dereference(fnhe->fnhe_rth_output);
+ if (rt) {
+ RCU_INIT_POINTER(fnhe->fnhe_rth_output, NULL);
+ rt_free(rt);
+ }
+}
+
static struct fib_nh_exception *fnhe_oldest(struct fnhe_hash_bucket *hash)
{
struct fib_nh_exception *fnhe, *oldest;
- struct rtable *orig;
oldest = rcu_dereference(hash->chain);
for (fnhe = rcu_dereference(oldest->fnhe_next); fnhe;
@@ -576,11 +591,7 @@ static struct fib_nh_exception *fnhe_oldest(struct fnhe_hash_bucket *hash)
if (time_before(fnhe->fnhe_stamp, oldest->fnhe_stamp))
oldest = fnhe;
}
- orig = rcu_dereference(oldest->fnhe_rth);
+ orig = rcu_dereference(oldest->fnhe_rth_input);
if (orig) {
- if (orig) {
- RCU_INIT_POINTER(oldest->fnhe_rth, NULL);
+ RCU_INIT_POINTER(oldest->fnhe_rth_input, NULL);
+ rt_free(orig);
+ }
+ orig = rcu_dereference(oldest->fnhe_rth_output);
+ if (orig) {
+ RCU_INIT_POINTER(oldest->fnhe_rth_output, NULL);
rt_free(orig);
}
- rt_free(orig);
- }
+ fnhe_flush_routes(oldest);
return oldest;
@@ -1209,7 +1214,15 @@ static bool rt_bind_exception(struct rtable *rt, struct fib_nh_exception *fnhe,
}
@@ -644,7 +655,10 @@ static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw,
fnhe->fnhe_expires = max(1UL, expires);
}
/* Update all cached dsts too */
- rt = rcu_dereference(fnhe->fnhe_rth);
+ rt = rcu_dereference(fnhe->fnhe_rth_input);
+ if (rt)
+ fill_route_from_fnhe(rt, fnhe);
+ rt = rcu_dereference(fnhe->fnhe_rth_output);
if (rt)
fill_route_from_fnhe(rt, fnhe);
} else {
@@ -668,6 +682,10 @@ static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw,
* stale, so anyone caching it rechecks if this exception
* applies to them.
*/
+ rt = rcu_dereference(nh->nh_rth_input);
+ if (rt)
+ rt->dst.obsolete = DST_OBSOLETE_KILL;
+
for_each_possible_cpu(i) {
struct rtable __rcu **prt;
prt = per_cpu_ptr(nh->nh_pcpu_rth_output, i);
@@ -1237,25 +1255,36 @@ static bool rt_bind_exception(struct rtable *rt, struct fib_nh_exception *fnhe,
spin_lock_bh(&fnhe_lock);
if (daddr == fnhe->fnhe_daddr) {
- struct rtable *orig = rcu_dereference(fnhe->fnhe_rth);
+ struct rtable __rcu **porig;
+ struct rtable *orig;
int genid = fnhe_genid(dev_net(rt->dst.dev));
- struct rtable *orig = rcu_dereference(fnhe->fnhe_rth);
+
+ if (rt_is_input_route(rt))
+ porig = &fnhe->fnhe_rth_input;
+ else
+ porig = &fnhe->fnhe_rth_output;
+
+ orig = rcu_dereference(*porig);
if (orig && rt_is_expired(orig)) {
if (fnhe->fnhe_genid != genid) {
fnhe->fnhe_genid = genid;
fnhe->fnhe_gw = 0;
fnhe->fnhe_pmtu = 0;
@@ -1231,12 +1244,14 @@ static bool rt_bind_exception(struct rtable *rt, struct fib_nh_exception *fnhe,
} else if (!rt->rt_gateway)
fnhe->fnhe_expires = 0;
+ fnhe_flush_routes(fnhe);
+ orig = NULL;
}
fill_route_from_fnhe(rt, fnhe);
if (!rt->rt_gateway)
rt->rt_gateway = daddr;
- rcu_assign_pointer(fnhe->fnhe_rth, rt);
......@@ -135,7 +167,7 @@ index 550781a..073df96 100644
}
spin_unlock_bh(&fnhe_lock);
@@ -1468,6 +1483,7 @@ static int __mkroute_input(struct sk_buff *skb,
@@ -1487,6 +1516,7 @@ static int __mkroute_input(struct sk_buff *skb,
struct in_device *in_dev,
__be32 daddr, __be32 saddr, u32 tos)
{
......@@ -143,7 +175,7 @@ index 550781a..073df96 100644
struct rtable *rth;
int err;
struct in_device *out_dev;
@@ -1514,8 +1530,13 @@ static int __mkroute_input(struct sk_buff *skb,
@@ -1533,8 +1563,13 @@ static int __mkroute_input(struct sk_buff *skb,
}
}
......@@ -158,7 +190,7 @@ index 550781a..073df96 100644
if (rt_cache_valid(rth)) {
skb_dst_set_noref(skb, &rth->dst);
goto out;
@@ -1543,7 +1564,7 @@ static int __mkroute_input(struct sk_buff *skb,
@@ -1562,7 +1597,7 @@ static int __mkroute_input(struct sk_buff *skb,
rth->dst.input = ip_forward;
rth->dst.output = ip_output;
......@@ -167,7 +199,7 @@ index 550781a..073df96 100644
skb_dst_set(skb, &rth->dst);
out:
err = 0;
@@ -1858,7 +1879,7 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
@@ -1877,7 +1912,7 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
fnhe = find_exception(nh, fl4->daddr);
if (fnhe)
......@@ -176,3 +208,6 @@ index 550781a..073df96 100644
else {
if (unlikely(fl4->flowi4_flags &
FLOWI_FLAG_KNOWN_NH &&
--
1.8.2.3
......@@ -2,12 +2,12 @@
_flavor=grsec
pkgname=linux-${_flavor}
pkgver=3.9.3
pkgver=3.9.4
case $pkgver in
*.*.*) _kernver=${pkgver%.*};;
*.*) _kernver=${pkgver};;
esac
pkgrel=2
pkgrel=0
pkgdesc="Linux kernel with grsecurity"
url=http://grsecurity.net
depends="mkinitfs linux-firmware"
......@@ -17,12 +17,17 @@ _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.3-201305201732.patch
grsecurity-2.9.1-3.9.4-201305251009.patch
v2-net-next-arp-flush-arp-cache-on-IFF_NOARP-change.patch
leds-leds-gpio-reserve-gpio-before-using-it.patch
ipsec-xfrm-properly-handle-invalid-states-as-an-error.patch
RFC-net-ipv4-Use-next-hop-exceptions-also-for-input-routes.patch
0001-net-inform-NETDEV_CHANGE-callbacks-which-flags-were-.patch
0002-arp-flush-arp-cache-on-IFF_NOARP-change.patch
0003-ipv4-properly-refresh-rtable-entries-on-pmtu-redirec.patch
0004-ipv4-rate-limit-updating-of-next-hop-exceptions-with.patch
0005-ipv4-use-separate-genid-for-next-hop-exceptions.patch
0006-ipv4-use-next-hop-exceptions-also-for-input-routes.patch
kernelconfig.x86
kernelconfig.x86_64
......@@ -147,29 +152,41 @@ dev() {
}
md5sums="4348c9b6b2eb3144d601e87c19d5d909 linux-3.9.tar.xz
71b31e29e0cb437a27017c781293b6f4 patch-3.9.3.xz