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-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <lsq.1510009382.912497330@decadent.org.uk>
Date:   Mon, 06 Nov 2017 23:03:02 +0000
From:   Ben Hutchings <ben@...adent.org.uk>
To:     linux-kernel@...r.kernel.org, stable@...r.kernel.org
CC:     akpm@...ux-foundation.org
Subject: [PATCH 3.16 114/294] dst: Increase alignment of metrics to allow
 extra flag on pointers

3.16.50-rc1 review patch.  If anyone has any objections, please let me know.

------------------

From: Ben Hutchings <ben@...adent.org.uk>

For the backport of "ipv4: add reference counting to metrics", we will
need a third flag on metrics pointers.  This was not needed upstream
as the DST_METRICS_FORCE_OVERWRITE flag has been eliminated there.
In order to use three flag bits we need to increase the alignment of
metrics from 4 to 8 bytes.

Signed-off-by: Ben Hutchings <ben@...adent.org.uk>
---
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -105,12 +105,15 @@ struct dst_entry {
 	};
 };
 
+void *dst_alloc_metrics(gfp_t flags);
+void dst_free_metrics(void *metrics);
 u32 *dst_cow_metrics_generic(struct dst_entry *dst, unsigned long old);
 extern const u32 dst_default_metrics[];
 
 #define DST_METRICS_READ_ONLY		0x1UL
 #define DST_METRICS_FORCE_OVERWRITE	0x2UL
-#define DST_METRICS_FLAGS		0x3UL
+#define DST_METRICS_FLAGS		0x7UL
+#define DST_METRICS_ALIGNMENT		0x8UL
 #define __DST_METRICS_PTR(Y)	\
 	((u32 *)((Y) & ~DST_METRICS_FLAGS))
 #define DST_METRICS_PTR(X)	__DST_METRICS_PTR((X)->_metrics)
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -155,7 +155,7 @@ static struct dst_ops fake_dst_ops = {
  * ipt_REJECT needs it.  Future netfilter modules might
  * require us to fill additional fields.
  */
-static const u32 br_dst_default_metrics[RTAX_MAX] = {
+static const u32 br_dst_default_metrics[RTAX_MAX] __aligned(DST_METRICS_ALIGNMENT) = {
 	[RTAX_MTU - 1] = 1500,
 };
 
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@ -149,7 +149,7 @@ int dst_discard_sk(struct sock *sk, stru
 }
 EXPORT_SYMBOL(dst_discard_sk);
 
-const u32 dst_default_metrics[RTAX_MAX + 1] = {
+const u32 dst_default_metrics[RTAX_MAX + 1] __aligned(DST_METRICS_ALIGNMENT) = {
 	/* This initializer is needed to force linker to place this variable
 	 * into const section. Otherwise it might end into bss section.
 	 * We really want to avoid false sharing on this variable, and catch
@@ -292,9 +292,23 @@ void dst_release(struct dst_entry *dst)
 }
 EXPORT_SYMBOL(dst_release);
 
+static struct kmem_cache *metrics_cache;
+
+void *dst_alloc_metrics(gfp_t flags)
+{
+	return kmem_cache_alloc(metrics_cache, flags);
+}
+EXPORT_SYMBOL(dst_alloc_metrics);
+
+void dst_free_metrics(void *metrics)
+{
+	kmem_cache_free(metrics_cache, metrics);
+}
+EXPORT_SYMBOL(dst_free_metrics);
+
 u32 *dst_cow_metrics_generic(struct dst_entry *dst, unsigned long old)
 {
-	u32 *p = kmalloc(sizeof(u32) * RTAX_MAX, GFP_ATOMIC);
+	u32 *p = dst_alloc_metrics(GFP_ATOMIC);
 
 	if (p) {
 		u32 *old_p = __DST_METRICS_PTR(old);
@@ -306,7 +320,7 @@ u32 *dst_cow_metrics_generic(struct dst_
 		prev = cmpxchg(&dst->_metrics, old, new);
 
 		if (prev != old) {
-			kfree(p);
+			dst_free_metrics(p);
 			p = __DST_METRICS_PTR(prev);
 			if (prev & DST_METRICS_READ_ONLY)
 				p = NULL;
@@ -324,7 +338,7 @@ void __dst_destroy_metrics_generic(struc
 	new = ((unsigned long) dst_default_metrics) | DST_METRICS_READ_ONLY;
 	prev = cmpxchg(&dst->_metrics, old, new);
 	if (prev == old)
-		kfree(__DST_METRICS_PTR(old));
+		dst_free_metrics(__DST_METRICS_PTR(old));
 }
 EXPORT_SYMBOL(__dst_destroy_metrics_generic);
 
@@ -419,4 +433,8 @@ static struct notifier_block dst_dev_not
 void __init dst_init(void)
 {
 	register_netdevice_notifier(&dst_dev_notifier);
+	metrics_cache = kmem_cache_create("dst_metrics",
+					  sizeof(u32) * RTAX_MAX,
+					  DST_METRICS_ALIGNMENT,
+					  SLAB_PANIC, NULL);
 }
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -2502,7 +2502,7 @@ static void mod_cur_headers(struct pktge
 
 
 #ifdef CONFIG_XFRM
-static u32 pktgen_dst_metrics[RTAX_MAX + 1] = {
+static u32 pktgen_dst_metrics[RTAX_MAX + 1] __aligned(DST_METRICS_ALIGNMENT) = {
 
 	[RTAX_HOPLIMIT] = 0x5, /* Set a static hoplimit */
 };
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -213,7 +213,7 @@ static void free_fib_info_rcu(struct rcu
 
 	release_net(fi->fib_net);
 	if (fi->fib_metrics != (u32 *) dst_default_metrics)
-		kfree(fi->fib_metrics);
+		dst_free_metrics(fi->fib_metrics);
 	kfree(fi);
 }
 
@@ -823,7 +823,7 @@ struct fib_info *fib_create_info(struct
 		goto failure;
 	fib_info_cnt++;
 	if (cfg->fc_mx) {
-		fi->fib_metrics = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL);
+		fi->fib_metrics = dst_alloc_metrics(GFP_KERNEL | __GFP_ZERO);
 		if (!fi->fib_metrics)
 			goto failure;
 	} else
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -247,7 +247,7 @@ static struct dst_ops ip6_dst_blackhole_
 	.neigh_lookup		=	ip6_neigh_lookup,
 };
 
-static const u32 ip6_template_metrics[RTAX_MAX] = {
+static const u32 ip6_template_metrics[RTAX_MAX] __aligned(DST_METRICS_ALIGNMENT) = {
 	[RTAX_HOPLIMIT - 1] = 0,
 };
 
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -643,7 +643,7 @@ static int fib6_commit_metrics(struct ds
 	if (dst->flags & DST_HOST) {
 		mp = dst_metrics_write_ptr(dst);
 	} else {
-		mp = kzalloc(sizeof(u32) * RTAX_MAX, GFP_ATOMIC);
+		mp = dst_alloc_metrics(GFP_ATOMIC | __GFP_ZERO);
 		if (!mp)
 			return -ENOMEM;
 		dst_init_metrics(dst, mp, 0);

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ