lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date:	Sun, 11 Mar 2012 00:49:05 +1100
From:	Herbert Xu <herbert@...dor.apana.org.au>
To:	"David S. Miller" <davem@...emloft.net>, netdev@...r.kernel.org
Subject: ipv4: Allow administrative updates of inetpeer cache metrics

Hi:

Sorry, I totally forgot about this issue that we talked about
previously.

ipv4: Allow administrative updates of inetpeer cache metrics

As it stands we only ever copy the metrics from fib table once
for a given inetpeer cache entry.  This means that if the fib
table is subsequently changed by the administrator then that
will never make it into the existing inetpeer cache entry.

This patch fixes this by recording the genid and checking it
every time we use the inetpeer entry.

I have no idea why we still have this code in IPv6 when we no
longer store metrics in the inetpeer cache.  The changes to
IPv6 should result in exactly the same semantics as before.

Signed-off-by: Herbert Xu <herbert@...dor.apana.org.au>

diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h
index 06b795d..b4a7694 100644
--- a/include/net/inetpeer.h
+++ b/include/net/inetpeer.h
@@ -40,6 +40,7 @@ struct inet_peer {
 	unsigned long		pmtu_expires;
 	u32			pmtu_orig;
 	u32			pmtu_learned;
+	int			metrics_genid;
 	struct inetpeer_addr_base redirect_learned;
 	/*
 	 * Once inet_peer is queued for deletion (refcnt == -1), following fields
@@ -66,9 +67,16 @@ void			inet_initpeers(void) __init;
 
 #define INETPEER_METRICS_NEW	(~(u32) 0)
 
-static inline bool inet_metrics_new(const struct inet_peer *p)
+static inline void inet_metrics_init(struct inet_peer *p, u32 *metrics,
+				     int genid)
 {
-	return p->metrics[RTAX_LOCK-1] == INETPEER_METRICS_NEW;
+	if (p->metrics[RTAX_LOCK-1] != INETPEER_METRICS_NEW &&
+	    p->metrics_genid == genid)
+
+		return;
+
+	p->metrics_genid = genid;
+	memcpy(p->metrics, metrics, sizeof(u32) * RTAX_MAX);
 }
 
 /* can be called with or without local BH being disabled */
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index bcacf54..896b95f 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -150,6 +150,11 @@ static void		 ipv4_link_failure(struct sk_buff *skb);
 static void		 ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu);
 static int rt_garbage_collect(struct dst_ops *ops);
 
+static inline int rt_genid(struct net *net)
+{
+	return atomic_read(&net->ipv4.rt_genid);
+}
+
 static void ipv4_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
 			    int how)
 {
@@ -170,8 +175,7 @@ static u32 *ipv4_cow_metrics(struct dst_entry *dst, unsigned long old)
 		unsigned long prev, new;
 
 		p = peer->metrics;
-		if (inet_metrics_new(peer))
-			memcpy(p, old_p, sizeof(u32) * RTAX_MAX);
+		inet_metrics_init(peer, old_p, rt_genid(dev_net(rt->dst.dev)));
 
 		new = (unsigned long) p;
 		prev = cmpxchg(&dst->_metrics, old, new);
@@ -310,11 +314,6 @@ static inline unsigned int rt_hash(__be32 daddr, __be32 saddr, int idx,
 		& rt_hash_mask;
 }
 
-static inline int rt_genid(struct net *net)
-{
-	return atomic_read(&net->ipv4.rt_genid);
-}
-
 #ifdef CONFIG_PROC_FS
 struct rt_cache_iter_state {
 	struct seq_net_private p;
@@ -1952,9 +1951,8 @@ static void rt_init_metrics(struct rtable *rt, const struct flowi4 *fl4,
 	rt->peer = peer = inet_getpeer_v4(rt->rt_dst, create);
 	if (peer) {
 		rt->rt_peer_genid = rt_peer_genid();
-		if (inet_metrics_new(peer))
-			memcpy(peer->metrics, fi->fib_metrics,
-			       sizeof(u32) * RTAX_MAX);
+		inet_metrics_init(peer, fi->fib_metrics,
+				  rt_genid(dev_net(rt->dst.dev)));
 		dst_init_metrics(&rt->dst, peer->metrics, false);
 
 		check_peer_pmtu(&rt->dst, peer);
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 8c2e3ab..580b20b 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -106,8 +106,7 @@ static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old)
 		unsigned long prev, new;
 
 		p = peer->metrics;
-		if (inet_metrics_new(peer))
-			memcpy(p, old_p, sizeof(u32) * RTAX_MAX);
+		inet_metrics_init(peer, old_p, 0);
 
 		new = (unsigned long) p;
 		prev = cmpxchg(&dst->_metrics, old, new);

Thanks,
-- 
Email: Herbert Xu <herbert@...dor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ