stable.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* FAILED: patch "[PATCH] net/flow_dissector: switch to siphash" failed to apply to 4.4-stable tree
@ 2019-11-06 15:42 gregkh
  2019-11-06 15:48 ` Eric Dumazet
  0 siblings, 1 reply; 3+ messages in thread
From: gregkh @ 2019-11-06 15:42 UTC (permalink / raw)
  To: edumazet, aksecurity, benny, davem, jonathann1, tom; +Cc: stable


The patch below does not apply to the 4.4-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable@vger.kernel.org>.

thanks,

greg k-h

------------------ original commit in Linus's tree ------------------

From 55667441c84fa5e0911a0aac44fb059c15ba6da2 Mon Sep 17 00:00:00 2001
From: Eric Dumazet <edumazet@google.com>
Date: Tue, 22 Oct 2019 07:57:46 -0700
Subject: [PATCH] net/flow_dissector: switch to siphash

UDP IPv6 packets auto flowlabels are using a 32bit secret
(static u32 hashrnd in net/core/flow_dissector.c) and
apply jhash() over fields known by the receivers.

Attackers can easily infer the 32bit secret and use this information
to identify a device and/or user, since this 32bit secret is only
set at boot time.

Really, using jhash() to generate cookies sent on the wire
is a serious security concern.

Trying to change the rol32(hash, 16) in ip6_make_flowlabel() would be
a dead end. Trying to periodically change the secret (like in sch_sfq.c)
could change paths taken in the network for long lived flows.

Let's switch to siphash, as we did in commit df453700e8d8
("inet: switch IP ID generator to siphash")

Using a cryptographically strong pseudo random function will solve this
privacy issue and more generally remove other weak points in the stack.

Packet schedulers using skb_get_hash_perturb() benefit from this change.

Fixes: b56774163f99 ("ipv6: Enable auto flow labels by default")
Fixes: 42240901f7c4 ("ipv6: Implement different admin modes for automatic flow labels")
Fixes: 67800f9b1f4e ("ipv6: Call skb_get_hash_flowi6 to get skb->hash in ip6_make_flowlabel")
Fixes: cb1ce2ef387b ("ipv6: Implement automatic flow label generation on transmit")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reported-by: Jonathan Berger <jonathann1@walla.com>
Reported-by: Amit Klein <aksecurity@gmail.com>
Reported-by: Benny Pinkas <benny@pinkas.net>
Cc: Tom Herbert <tom@herbertland.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 7914fdaf4226..a391147c03d4 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -1354,7 +1354,8 @@ static inline __u32 skb_get_hash_flowi6(struct sk_buff *skb, const struct flowi6
 	return skb->hash;
 }
 
-__u32 skb_get_hash_perturb(const struct sk_buff *skb, u32 perturb);
+__u32 skb_get_hash_perturb(const struct sk_buff *skb,
+			   const siphash_key_t *perturb);
 
 static inline __u32 skb_get_hash_raw(const struct sk_buff *skb)
 {
diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h
index 90bd210be060..5cd12276ae21 100644
--- a/include/net/flow_dissector.h
+++ b/include/net/flow_dissector.h
@@ -4,6 +4,7 @@
 
 #include <linux/types.h>
 #include <linux/in6.h>
+#include <linux/siphash.h>
 #include <uapi/linux/if_ether.h>
 
 /**
@@ -276,7 +277,7 @@ struct flow_keys_basic {
 struct flow_keys {
 	struct flow_dissector_key_control control;
 #define FLOW_KEYS_HASH_START_FIELD basic
-	struct flow_dissector_key_basic basic;
+	struct flow_dissector_key_basic basic __aligned(SIPHASH_ALIGNMENT);
 	struct flow_dissector_key_tags tags;
 	struct flow_dissector_key_vlan vlan;
 	struct flow_dissector_key_vlan cvlan;
diff --git a/include/net/fq.h b/include/net/fq.h
index d126b5d20261..2ad85e683041 100644
--- a/include/net/fq.h
+++ b/include/net/fq.h
@@ -69,7 +69,7 @@ struct fq {
 	struct list_head backlogs;
 	spinlock_t lock;
 	u32 flows_cnt;
-	u32 perturbation;
+	siphash_key_t	perturbation;
 	u32 limit;
 	u32 memory_limit;
 	u32 memory_usage;
diff --git a/include/net/fq_impl.h b/include/net/fq_impl.h
index be40a4b327e3..107c0d700ed6 100644
--- a/include/net/fq_impl.h
+++ b/include/net/fq_impl.h
@@ -108,7 +108,7 @@ static struct sk_buff *fq_tin_dequeue(struct fq *fq,
 
 static u32 fq_flow_idx(struct fq *fq, struct sk_buff *skb)
 {
-	u32 hash = skb_get_hash_perturb(skb, fq->perturbation);
+	u32 hash = skb_get_hash_perturb(skb, &fq->perturbation);
 
 	return reciprocal_scale(hash, fq->flows_cnt);
 }
@@ -308,7 +308,7 @@ static int fq_init(struct fq *fq, int flows_cnt)
 	INIT_LIST_HEAD(&fq->backlogs);
 	spin_lock_init(&fq->lock);
 	fq->flows_cnt = max_t(u32, flows_cnt, 1);
-	fq->perturbation = prandom_u32();
+	get_random_bytes(&fq->perturbation, sizeof(fq->perturbation));
 	fq->quantum = 300;
 	fq->limit = 8192;
 	fq->memory_limit = 16 << 20; /* 16 MBytes */
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
index 7c09d87d3269..68eda10d0680 100644
--- a/net/core/flow_dissector.c
+++ b/net/core/flow_dissector.c
@@ -1350,30 +1350,21 @@ bool __skb_flow_dissect(const struct net *net,
 }
 EXPORT_SYMBOL(__skb_flow_dissect);
 
-static u32 hashrnd __read_mostly;
+static siphash_key_t hashrnd __read_mostly;
 static __always_inline void __flow_hash_secret_init(void)
 {
 	net_get_random_once(&hashrnd, sizeof(hashrnd));
 }
 
-static __always_inline u32 __flow_hash_words(const u32 *words, u32 length,
-					     u32 keyval)
+static const void *flow_keys_hash_start(const struct flow_keys *flow)
 {
-	return jhash2(words, length, keyval);
-}
-
-static inline const u32 *flow_keys_hash_start(const struct flow_keys *flow)
-{
-	const void *p = flow;
-
-	BUILD_BUG_ON(FLOW_KEYS_HASH_OFFSET % sizeof(u32));
-	return (const u32 *)(p + FLOW_KEYS_HASH_OFFSET);
+	BUILD_BUG_ON(FLOW_KEYS_HASH_OFFSET % SIPHASH_ALIGNMENT);
+	return &flow->FLOW_KEYS_HASH_START_FIELD;
 }
 
 static inline size_t flow_keys_hash_length(const struct flow_keys *flow)
 {
 	size_t diff = FLOW_KEYS_HASH_OFFSET + sizeof(flow->addrs);
-	BUILD_BUG_ON((sizeof(*flow) - FLOW_KEYS_HASH_OFFSET) % sizeof(u32));
 	BUILD_BUG_ON(offsetof(typeof(*flow), addrs) !=
 		     sizeof(*flow) - sizeof(flow->addrs));
 
@@ -1388,7 +1379,7 @@ static inline size_t flow_keys_hash_length(const struct flow_keys *flow)
 		diff -= sizeof(flow->addrs.tipckey);
 		break;
 	}
-	return (sizeof(*flow) - diff) / sizeof(u32);
+	return sizeof(*flow) - diff;
 }
 
 __be32 flow_get_u32_src(const struct flow_keys *flow)
@@ -1454,14 +1445,15 @@ static inline void __flow_hash_consistentify(struct flow_keys *keys)
 	}
 }
 
-static inline u32 __flow_hash_from_keys(struct flow_keys *keys, u32 keyval)
+static inline u32 __flow_hash_from_keys(struct flow_keys *keys,
+					const siphash_key_t *keyval)
 {
 	u32 hash;
 
 	__flow_hash_consistentify(keys);
 
-	hash = __flow_hash_words(flow_keys_hash_start(keys),
-				 flow_keys_hash_length(keys), keyval);
+	hash = siphash(flow_keys_hash_start(keys),
+		       flow_keys_hash_length(keys), keyval);
 	if (!hash)
 		hash = 1;
 
@@ -1471,12 +1463,13 @@ static inline u32 __flow_hash_from_keys(struct flow_keys *keys, u32 keyval)
 u32 flow_hash_from_keys(struct flow_keys *keys)
 {
 	__flow_hash_secret_init();
-	return __flow_hash_from_keys(keys, hashrnd);
+	return __flow_hash_from_keys(keys, &hashrnd);
 }
 EXPORT_SYMBOL(flow_hash_from_keys);
 
 static inline u32 ___skb_get_hash(const struct sk_buff *skb,
-				  struct flow_keys *keys, u32 keyval)
+				  struct flow_keys *keys,
+				  const siphash_key_t *keyval)
 {
 	skb_flow_dissect_flow_keys(skb, keys,
 				   FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL);
@@ -1524,7 +1517,7 @@ u32 __skb_get_hash_symmetric(const struct sk_buff *skb)
 			   &keys, NULL, 0, 0, 0,
 			   FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL);
 
-	return __flow_hash_from_keys(&keys, hashrnd);
+	return __flow_hash_from_keys(&keys, &hashrnd);
 }
 EXPORT_SYMBOL_GPL(__skb_get_hash_symmetric);
 
@@ -1544,13 +1537,14 @@ void __skb_get_hash(struct sk_buff *skb)
 
 	__flow_hash_secret_init();
 
-	hash = ___skb_get_hash(skb, &keys, hashrnd);
+	hash = ___skb_get_hash(skb, &keys, &hashrnd);
 
 	__skb_set_sw_hash(skb, hash, flow_keys_have_l4(&keys));
 }
 EXPORT_SYMBOL(__skb_get_hash);
 
-__u32 skb_get_hash_perturb(const struct sk_buff *skb, u32 perturb)
+__u32 skb_get_hash_perturb(const struct sk_buff *skb,
+			   const siphash_key_t *perturb)
 {
 	struct flow_keys keys;
 
diff --git a/net/sched/sch_hhf.c b/net/sched/sch_hhf.c
index 23cd1c873a2c..be35f03b657b 100644
--- a/net/sched/sch_hhf.c
+++ b/net/sched/sch_hhf.c
@@ -5,11 +5,11 @@
  * Copyright (C) 2013 Nandita Dukkipati <nanditad@google.com>
  */
 
-#include <linux/jhash.h>
 #include <linux/jiffies.h>
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/vmalloc.h>
+#include <linux/siphash.h>
 #include <net/pkt_sched.h>
 #include <net/sock.h>
 
@@ -126,7 +126,7 @@ struct wdrr_bucket {
 
 struct hhf_sched_data {
 	struct wdrr_bucket buckets[WDRR_BUCKET_CNT];
-	u32		   perturbation;   /* hash perturbation */
+	siphash_key_t	   perturbation;   /* hash perturbation */
 	u32		   quantum;        /* psched_mtu(qdisc_dev(sch)); */
 	u32		   drop_overlimit; /* number of times max qdisc packet
 					    * limit was hit
@@ -264,7 +264,7 @@ static enum wdrr_bucket_idx hhf_classify(struct sk_buff *skb, struct Qdisc *sch)
 	}
 
 	/* Get hashed flow-id of the skb. */
-	hash = skb_get_hash_perturb(skb, q->perturbation);
+	hash = skb_get_hash_perturb(skb, &q->perturbation);
 
 	/* Check if this packet belongs to an already established HH flow. */
 	flow_pos = hash & HHF_BIT_MASK;
@@ -582,7 +582,7 @@ static int hhf_init(struct Qdisc *sch, struct nlattr *opt,
 
 	sch->limit = 1000;
 	q->quantum = psched_mtu(qdisc_dev(sch));
-	q->perturbation = prandom_u32();
+	get_random_bytes(&q->perturbation, sizeof(q->perturbation));
 	INIT_LIST_HEAD(&q->new_buckets);
 	INIT_LIST_HEAD(&q->old_buckets);
 
diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c
index d448fe3068e5..4074c50ac3d7 100644
--- a/net/sched/sch_sfb.c
+++ b/net/sched/sch_sfb.c
@@ -18,7 +18,7 @@
 #include <linux/errno.h>
 #include <linux/skbuff.h>
 #include <linux/random.h>
-#include <linux/jhash.h>
+#include <linux/siphash.h>
 #include <net/ip.h>
 #include <net/pkt_sched.h>
 #include <net/pkt_cls.h>
@@ -45,7 +45,7 @@ struct sfb_bucket {
  * (Section 4.4 of SFB reference : moving hash functions)
  */
 struct sfb_bins {
-	u32		  perturbation; /* jhash perturbation */
+	siphash_key_t	  perturbation; /* siphash key */
 	struct sfb_bucket bins[SFB_LEVELS][SFB_NUMBUCKETS];
 };
 
@@ -217,7 +217,8 @@ static u32 sfb_compute_qlen(u32 *prob_r, u32 *avgpm_r, const struct sfb_sched_da
 
 static void sfb_init_perturbation(u32 slot, struct sfb_sched_data *q)
 {
-	q->bins[slot].perturbation = prandom_u32();
+	get_random_bytes(&q->bins[slot].perturbation,
+			 sizeof(q->bins[slot].perturbation));
 }
 
 static void sfb_swap_slot(struct sfb_sched_data *q)
@@ -314,9 +315,9 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch,
 		/* If using external classifiers, get result and record it. */
 		if (!sfb_classify(skb, fl, &ret, &salt))
 			goto other_drop;
-		sfbhash = jhash_1word(salt, q->bins[slot].perturbation);
+		sfbhash = siphash_1u32(salt, &q->bins[slot].perturbation);
 	} else {
-		sfbhash = skb_get_hash_perturb(skb, q->bins[slot].perturbation);
+		sfbhash = skb_get_hash_perturb(skb, &q->bins[slot].perturbation);
 	}
 
 
@@ -352,7 +353,7 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch,
 		/* Inelastic flow */
 		if (q->double_buffering) {
 			sfbhash = skb_get_hash_perturb(skb,
-			    q->bins[slot].perturbation);
+			    &q->bins[slot].perturbation);
 			if (!sfbhash)
 				sfbhash = 1;
 			sfb_skb_cb(skb)->hashes[slot] = sfbhash;
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index 68404a9d2ce4..c787d4d46017 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -14,7 +14,7 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/skbuff.h>
-#include <linux/jhash.h>
+#include <linux/siphash.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <net/netlink.h>
@@ -117,7 +117,7 @@ struct sfq_sched_data {
 	u8		headdrop;
 	u8		maxdepth;	/* limit of packets per flow */
 
-	u32		perturbation;
+	siphash_key_t 	perturbation;
 	u8		cur_depth;	/* depth of longest slot */
 	u8		flags;
 	unsigned short  scaled_quantum; /* SFQ_ALLOT_SIZE(quantum) */
@@ -157,7 +157,7 @@ static inline struct sfq_head *sfq_dep_head(struct sfq_sched_data *q, sfq_index
 static unsigned int sfq_hash(const struct sfq_sched_data *q,
 			     const struct sk_buff *skb)
 {
-	return skb_get_hash_perturb(skb, q->perturbation) & (q->divisor - 1);
+	return skb_get_hash_perturb(skb, &q->perturbation) & (q->divisor - 1);
 }
 
 static unsigned int sfq_classify(struct sk_buff *skb, struct Qdisc *sch,
@@ -607,9 +607,11 @@ static void sfq_perturbation(struct timer_list *t)
 	struct sfq_sched_data *q = from_timer(q, t, perturb_timer);
 	struct Qdisc *sch = q->sch;
 	spinlock_t *root_lock = qdisc_lock(qdisc_root_sleeping(sch));
+	siphash_key_t nkey;
 
+	get_random_bytes(&nkey, sizeof(nkey));
 	spin_lock(root_lock);
-	q->perturbation = prandom_u32();
+	q->perturbation = nkey;
 	if (!q->filter_list && q->tail)
 		sfq_rehash(sch);
 	spin_unlock(root_lock);
@@ -688,7 +690,7 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt)
 	del_timer(&q->perturb_timer);
 	if (q->perturb_period) {
 		mod_timer(&q->perturb_timer, jiffies + q->perturb_period);
-		q->perturbation = prandom_u32();
+		get_random_bytes(&q->perturbation, sizeof(q->perturbation));
 	}
 	sch_tree_unlock(sch);
 	kfree(p);
@@ -745,7 +747,7 @@ static int sfq_init(struct Qdisc *sch, struct nlattr *opt,
 	q->quantum = psched_mtu(qdisc_dev(sch));
 	q->scaled_quantum = SFQ_ALLOT_SIZE(q->quantum);
 	q->perturb_period = 0;
-	q->perturbation = prandom_u32();
+	get_random_bytes(&q->perturbation, sizeof(q->perturbation));
 
 	if (opt) {
 		int err = sfq_change(sch, opt);


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: FAILED: patch "[PATCH] net/flow_dissector: switch to siphash" failed to apply to 4.4-stable tree
  2019-11-06 15:42 FAILED: patch "[PATCH] net/flow_dissector: switch to siphash" failed to apply to 4.4-stable tree gregkh
@ 2019-11-06 15:48 ` Eric Dumazet
  2019-11-06 15:58   ` Greg Kroah-Hartman
  0 siblings, 1 reply; 3+ messages in thread
From: Eric Dumazet @ 2019-11-06 15:48 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Amit Klein, Benny Pinkas, David Miller, jonathann1, Tom Herbert, stable

Thanks Greg.

We definitely want to backport this fix to all relevant kernels, I
will work on these backports soon.

Thanks.

On Wed, Nov 6, 2019 at 7:42 AM <gregkh@linuxfoundation.org> wrote:
>
>
> The patch below does not apply to the 4.4-stable tree.
> If someone wants it applied there, or to any other stable or longterm
> tree, then please email the backport, including the original git commit
> id to <stable@vger.kernel.org>.
>
> thanks,
>
> greg k-h
>
> ------------------ original commit in Linus's tree ------------------
>
> From 55667441c84fa5e0911a0aac44fb059c15ba6da2 Mon Sep 17 00:00:00 2001
> From: Eric Dumazet <edumazet@google.com>
> Date: Tue, 22 Oct 2019 07:57:46 -0700
> Subject: [PATCH] net/flow_dissector: switch to siphash
>
> UDP IPv6 packets auto flowlabels are using a 32bit secret
> (static u32 hashrnd in net/core/flow_dissector.c) and
> apply jhash() over fields known by the receivers.
>
> Attackers can easily infer the 32bit secret and use this information
> to identify a device and/or user, since this 32bit secret is only
> set at boot time.
>
> Really, using jhash() to generate cookies sent on the wire
> is a serious security concern.
>
> Trying to change the rol32(hash, 16) in ip6_make_flowlabel() would be
> a dead end. Trying to periodically change the secret (like in sch_sfq.c)
> could change paths taken in the network for long lived flows.
>
> Let's switch to siphash, as we did in commit df453700e8d8
> ("inet: switch IP ID generator to siphash")
>
> Using a cryptographically strong pseudo random function will solve this
> privacy issue and more generally remove other weak points in the stack.
>
> Packet schedulers using skb_get_hash_perturb() benefit from this change.
>
> Fixes: b56774163f99 ("ipv6: Enable auto flow labels by default")
> Fixes: 42240901f7c4 ("ipv6: Implement different admin modes for automatic flow labels")
> Fixes: 67800f9b1f4e ("ipv6: Call skb_get_hash_flowi6 to get skb->hash in ip6_make_flowlabel")
> Fixes: cb1ce2ef387b ("ipv6: Implement automatic flow label generation on transmit")
> Signed-off-by: Eric Dumazet <edumazet@google.com>
> Reported-by: Jonathan Berger <jonathann1@walla.com>
> Reported-by: Amit Klein <aksecurity@gmail.com>
> Reported-by: Benny Pinkas <benny@pinkas.net>
> Cc: Tom Herbert <tom@herbertland.com>
> Signed-off-by: David S. Miller <davem@davemloft.net>
>
> diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
> index 7914fdaf4226..a391147c03d4 100644
> --- a/include/linux/skbuff.h
> +++ b/include/linux/skbuff.h
> @@ -1354,7 +1354,8 @@ static inline __u32 skb_get_hash_flowi6(struct sk_buff *skb, const struct flowi6
>         return skb->hash;
>  }
>
> -__u32 skb_get_hash_perturb(const struct sk_buff *skb, u32 perturb);
> +__u32 skb_get_hash_perturb(const struct sk_buff *skb,
> +                          const siphash_key_t *perturb);
>
>  static inline __u32 skb_get_hash_raw(const struct sk_buff *skb)
>  {
> diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h
> index 90bd210be060..5cd12276ae21 100644
> --- a/include/net/flow_dissector.h
> +++ b/include/net/flow_dissector.h
> @@ -4,6 +4,7 @@
>
>  #include <linux/types.h>
>  #include <linux/in6.h>
> +#include <linux/siphash.h>
>  #include <uapi/linux/if_ether.h>
>
>  /**
> @@ -276,7 +277,7 @@ struct flow_keys_basic {
>  struct flow_keys {
>         struct flow_dissector_key_control control;
>  #define FLOW_KEYS_HASH_START_FIELD basic
> -       struct flow_dissector_key_basic basic;
> +       struct flow_dissector_key_basic basic __aligned(SIPHASH_ALIGNMENT);
>         struct flow_dissector_key_tags tags;
>         struct flow_dissector_key_vlan vlan;
>         struct flow_dissector_key_vlan cvlan;
> diff --git a/include/net/fq.h b/include/net/fq.h
> index d126b5d20261..2ad85e683041 100644
> --- a/include/net/fq.h
> +++ b/include/net/fq.h
> @@ -69,7 +69,7 @@ struct fq {
>         struct list_head backlogs;
>         spinlock_t lock;
>         u32 flows_cnt;
> -       u32 perturbation;
> +       siphash_key_t   perturbation;
>         u32 limit;
>         u32 memory_limit;
>         u32 memory_usage;
> diff --git a/include/net/fq_impl.h b/include/net/fq_impl.h
> index be40a4b327e3..107c0d700ed6 100644
> --- a/include/net/fq_impl.h
> +++ b/include/net/fq_impl.h
> @@ -108,7 +108,7 @@ static struct sk_buff *fq_tin_dequeue(struct fq *fq,
>
>  static u32 fq_flow_idx(struct fq *fq, struct sk_buff *skb)
>  {
> -       u32 hash = skb_get_hash_perturb(skb, fq->perturbation);
> +       u32 hash = skb_get_hash_perturb(skb, &fq->perturbation);
>
>         return reciprocal_scale(hash, fq->flows_cnt);
>  }
> @@ -308,7 +308,7 @@ static int fq_init(struct fq *fq, int flows_cnt)
>         INIT_LIST_HEAD(&fq->backlogs);
>         spin_lock_init(&fq->lock);
>         fq->flows_cnt = max_t(u32, flows_cnt, 1);
> -       fq->perturbation = prandom_u32();
> +       get_random_bytes(&fq->perturbation, sizeof(fq->perturbation));
>         fq->quantum = 300;
>         fq->limit = 8192;
>         fq->memory_limit = 16 << 20; /* 16 MBytes */
> diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
> index 7c09d87d3269..68eda10d0680 100644
> --- a/net/core/flow_dissector.c
> +++ b/net/core/flow_dissector.c
> @@ -1350,30 +1350,21 @@ bool __skb_flow_dissect(const struct net *net,
>  }
>  EXPORT_SYMBOL(__skb_flow_dissect);
>
> -static u32 hashrnd __read_mostly;
> +static siphash_key_t hashrnd __read_mostly;
>  static __always_inline void __flow_hash_secret_init(void)
>  {
>         net_get_random_once(&hashrnd, sizeof(hashrnd));
>  }
>
> -static __always_inline u32 __flow_hash_words(const u32 *words, u32 length,
> -                                            u32 keyval)
> +static const void *flow_keys_hash_start(const struct flow_keys *flow)
>  {
> -       return jhash2(words, length, keyval);
> -}
> -
> -static inline const u32 *flow_keys_hash_start(const struct flow_keys *flow)
> -{
> -       const void *p = flow;
> -
> -       BUILD_BUG_ON(FLOW_KEYS_HASH_OFFSET % sizeof(u32));
> -       return (const u32 *)(p + FLOW_KEYS_HASH_OFFSET);
> +       BUILD_BUG_ON(FLOW_KEYS_HASH_OFFSET % SIPHASH_ALIGNMENT);
> +       return &flow->FLOW_KEYS_HASH_START_FIELD;
>  }
>
>  static inline size_t flow_keys_hash_length(const struct flow_keys *flow)
>  {
>         size_t diff = FLOW_KEYS_HASH_OFFSET + sizeof(flow->addrs);
> -       BUILD_BUG_ON((sizeof(*flow) - FLOW_KEYS_HASH_OFFSET) % sizeof(u32));
>         BUILD_BUG_ON(offsetof(typeof(*flow), addrs) !=
>                      sizeof(*flow) - sizeof(flow->addrs));
>
> @@ -1388,7 +1379,7 @@ static inline size_t flow_keys_hash_length(const struct flow_keys *flow)
>                 diff -= sizeof(flow->addrs.tipckey);
>                 break;
>         }
> -       return (sizeof(*flow) - diff) / sizeof(u32);
> +       return sizeof(*flow) - diff;
>  }
>
>  __be32 flow_get_u32_src(const struct flow_keys *flow)
> @@ -1454,14 +1445,15 @@ static inline void __flow_hash_consistentify(struct flow_keys *keys)
>         }
>  }
>
> -static inline u32 __flow_hash_from_keys(struct flow_keys *keys, u32 keyval)
> +static inline u32 __flow_hash_from_keys(struct flow_keys *keys,
> +                                       const siphash_key_t *keyval)
>  {
>         u32 hash;
>
>         __flow_hash_consistentify(keys);
>
> -       hash = __flow_hash_words(flow_keys_hash_start(keys),
> -                                flow_keys_hash_length(keys), keyval);
> +       hash = siphash(flow_keys_hash_start(keys),
> +                      flow_keys_hash_length(keys), keyval);
>         if (!hash)
>                 hash = 1;
>
> @@ -1471,12 +1463,13 @@ static inline u32 __flow_hash_from_keys(struct flow_keys *keys, u32 keyval)
>  u32 flow_hash_from_keys(struct flow_keys *keys)
>  {
>         __flow_hash_secret_init();
> -       return __flow_hash_from_keys(keys, hashrnd);
> +       return __flow_hash_from_keys(keys, &hashrnd);
>  }
>  EXPORT_SYMBOL(flow_hash_from_keys);
>
>  static inline u32 ___skb_get_hash(const struct sk_buff *skb,
> -                                 struct flow_keys *keys, u32 keyval)
> +                                 struct flow_keys *keys,
> +                                 const siphash_key_t *keyval)
>  {
>         skb_flow_dissect_flow_keys(skb, keys,
>                                    FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL);
> @@ -1524,7 +1517,7 @@ u32 __skb_get_hash_symmetric(const struct sk_buff *skb)
>                            &keys, NULL, 0, 0, 0,
>                            FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL);
>
> -       return __flow_hash_from_keys(&keys, hashrnd);
> +       return __flow_hash_from_keys(&keys, &hashrnd);
>  }
>  EXPORT_SYMBOL_GPL(__skb_get_hash_symmetric);
>
> @@ -1544,13 +1537,14 @@ void __skb_get_hash(struct sk_buff *skb)
>
>         __flow_hash_secret_init();
>
> -       hash = ___skb_get_hash(skb, &keys, hashrnd);
> +       hash = ___skb_get_hash(skb, &keys, &hashrnd);
>
>         __skb_set_sw_hash(skb, hash, flow_keys_have_l4(&keys));
>  }
>  EXPORT_SYMBOL(__skb_get_hash);
>
> -__u32 skb_get_hash_perturb(const struct sk_buff *skb, u32 perturb)
> +__u32 skb_get_hash_perturb(const struct sk_buff *skb,
> +                          const siphash_key_t *perturb)
>  {
>         struct flow_keys keys;
>
> diff --git a/net/sched/sch_hhf.c b/net/sched/sch_hhf.c
> index 23cd1c873a2c..be35f03b657b 100644
> --- a/net/sched/sch_hhf.c
> +++ b/net/sched/sch_hhf.c
> @@ -5,11 +5,11 @@
>   * Copyright (C) 2013 Nandita Dukkipati <nanditad@google.com>
>   */
>
> -#include <linux/jhash.h>
>  #include <linux/jiffies.h>
>  #include <linux/module.h>
>  #include <linux/skbuff.h>
>  #include <linux/vmalloc.h>
> +#include <linux/siphash.h>
>  #include <net/pkt_sched.h>
>  #include <net/sock.h>
>
> @@ -126,7 +126,7 @@ struct wdrr_bucket {
>
>  struct hhf_sched_data {
>         struct wdrr_bucket buckets[WDRR_BUCKET_CNT];
> -       u32                perturbation;   /* hash perturbation */
> +       siphash_key_t      perturbation;   /* hash perturbation */
>         u32                quantum;        /* psched_mtu(qdisc_dev(sch)); */
>         u32                drop_overlimit; /* number of times max qdisc packet
>                                             * limit was hit
> @@ -264,7 +264,7 @@ static enum wdrr_bucket_idx hhf_classify(struct sk_buff *skb, struct Qdisc *sch)
>         }
>
>         /* Get hashed flow-id of the skb. */
> -       hash = skb_get_hash_perturb(skb, q->perturbation);
> +       hash = skb_get_hash_perturb(skb, &q->perturbation);
>
>         /* Check if this packet belongs to an already established HH flow. */
>         flow_pos = hash & HHF_BIT_MASK;
> @@ -582,7 +582,7 @@ static int hhf_init(struct Qdisc *sch, struct nlattr *opt,
>
>         sch->limit = 1000;
>         q->quantum = psched_mtu(qdisc_dev(sch));
> -       q->perturbation = prandom_u32();
> +       get_random_bytes(&q->perturbation, sizeof(q->perturbation));
>         INIT_LIST_HEAD(&q->new_buckets);
>         INIT_LIST_HEAD(&q->old_buckets);
>
> diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c
> index d448fe3068e5..4074c50ac3d7 100644
> --- a/net/sched/sch_sfb.c
> +++ b/net/sched/sch_sfb.c
> @@ -18,7 +18,7 @@
>  #include <linux/errno.h>
>  #include <linux/skbuff.h>
>  #include <linux/random.h>
> -#include <linux/jhash.h>
> +#include <linux/siphash.h>
>  #include <net/ip.h>
>  #include <net/pkt_sched.h>
>  #include <net/pkt_cls.h>
> @@ -45,7 +45,7 @@ struct sfb_bucket {
>   * (Section 4.4 of SFB reference : moving hash functions)
>   */
>  struct sfb_bins {
> -       u32               perturbation; /* jhash perturbation */
> +       siphash_key_t     perturbation; /* siphash key */
>         struct sfb_bucket bins[SFB_LEVELS][SFB_NUMBUCKETS];
>  };
>
> @@ -217,7 +217,8 @@ static u32 sfb_compute_qlen(u32 *prob_r, u32 *avgpm_r, const struct sfb_sched_da
>
>  static void sfb_init_perturbation(u32 slot, struct sfb_sched_data *q)
>  {
> -       q->bins[slot].perturbation = prandom_u32();
> +       get_random_bytes(&q->bins[slot].perturbation,
> +                        sizeof(q->bins[slot].perturbation));
>  }
>
>  static void sfb_swap_slot(struct sfb_sched_data *q)
> @@ -314,9 +315,9 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch,
>                 /* If using external classifiers, get result and record it. */
>                 if (!sfb_classify(skb, fl, &ret, &salt))
>                         goto other_drop;
> -               sfbhash = jhash_1word(salt, q->bins[slot].perturbation);
> +               sfbhash = siphash_1u32(salt, &q->bins[slot].perturbation);
>         } else {
> -               sfbhash = skb_get_hash_perturb(skb, q->bins[slot].perturbation);
> +               sfbhash = skb_get_hash_perturb(skb, &q->bins[slot].perturbation);
>         }
>
>
> @@ -352,7 +353,7 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch,
>                 /* Inelastic flow */
>                 if (q->double_buffering) {
>                         sfbhash = skb_get_hash_perturb(skb,
> -                           q->bins[slot].perturbation);
> +                           &q->bins[slot].perturbation);
>                         if (!sfbhash)
>                                 sfbhash = 1;
>                         sfb_skb_cb(skb)->hashes[slot] = sfbhash;
> diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
> index 68404a9d2ce4..c787d4d46017 100644
> --- a/net/sched/sch_sfq.c
> +++ b/net/sched/sch_sfq.c
> @@ -14,7 +14,7 @@
>  #include <linux/errno.h>
>  #include <linux/init.h>
>  #include <linux/skbuff.h>
> -#include <linux/jhash.h>
> +#include <linux/siphash.h>
>  #include <linux/slab.h>
>  #include <linux/vmalloc.h>
>  #include <net/netlink.h>
> @@ -117,7 +117,7 @@ struct sfq_sched_data {
>         u8              headdrop;
>         u8              maxdepth;       /* limit of packets per flow */
>
> -       u32             perturbation;
> +       siphash_key_t   perturbation;
>         u8              cur_depth;      /* depth of longest slot */
>         u8              flags;
>         unsigned short  scaled_quantum; /* SFQ_ALLOT_SIZE(quantum) */
> @@ -157,7 +157,7 @@ static inline struct sfq_head *sfq_dep_head(struct sfq_sched_data *q, sfq_index
>  static unsigned int sfq_hash(const struct sfq_sched_data *q,
>                              const struct sk_buff *skb)
>  {
> -       return skb_get_hash_perturb(skb, q->perturbation) & (q->divisor - 1);
> +       return skb_get_hash_perturb(skb, &q->perturbation) & (q->divisor - 1);
>  }
>
>  static unsigned int sfq_classify(struct sk_buff *skb, struct Qdisc *sch,
> @@ -607,9 +607,11 @@ static void sfq_perturbation(struct timer_list *t)
>         struct sfq_sched_data *q = from_timer(q, t, perturb_timer);
>         struct Qdisc *sch = q->sch;
>         spinlock_t *root_lock = qdisc_lock(qdisc_root_sleeping(sch));
> +       siphash_key_t nkey;
>
> +       get_random_bytes(&nkey, sizeof(nkey));
>         spin_lock(root_lock);
> -       q->perturbation = prandom_u32();
> +       q->perturbation = nkey;
>         if (!q->filter_list && q->tail)
>                 sfq_rehash(sch);
>         spin_unlock(root_lock);
> @@ -688,7 +690,7 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt)
>         del_timer(&q->perturb_timer);
>         if (q->perturb_period) {
>                 mod_timer(&q->perturb_timer, jiffies + q->perturb_period);
> -               q->perturbation = prandom_u32();
> +               get_random_bytes(&q->perturbation, sizeof(q->perturbation));
>         }
>         sch_tree_unlock(sch);
>         kfree(p);
> @@ -745,7 +747,7 @@ static int sfq_init(struct Qdisc *sch, struct nlattr *opt,
>         q->quantum = psched_mtu(qdisc_dev(sch));
>         q->scaled_quantum = SFQ_ALLOT_SIZE(q->quantum);
>         q->perturb_period = 0;
> -       q->perturbation = prandom_u32();
> +       get_random_bytes(&q->perturbation, sizeof(q->perturbation));
>
>         if (opt) {
>                 int err = sfq_change(sch, opt);
>

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: FAILED: patch "[PATCH] net/flow_dissector: switch to siphash" failed to apply to 4.4-stable tree
  2019-11-06 15:48 ` Eric Dumazet
@ 2019-11-06 15:58   ` Greg Kroah-Hartman
  0 siblings, 0 replies; 3+ messages in thread
From: Greg Kroah-Hartman @ 2019-11-06 15:58 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: Amit Klein, Benny Pinkas, David Miller, jonathann1, Tom Herbert, stable

On Wed, Nov 06, 2019 at 07:48:00AM -0800, Eric Dumazet wrote:
> Thanks Greg.
> 
> We definitely want to backport this fix to all relevant kernels, I
> will work on these backports soon.

Wonderful, thanks!

greg k-h

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2019-11-06 15:58 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-06 15:42 FAILED: patch "[PATCH] net/flow_dissector: switch to siphash" failed to apply to 4.4-stable tree gregkh
2019-11-06 15:48 ` Eric Dumazet
2019-11-06 15:58   ` Greg Kroah-Hartman

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).