FAILED: patch "[PATCH] net/flow_dissector: switch to siphash" failed to apply to 4.4-stable tree
Subsystems (3)
[email protected]
maintainerThe 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 <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 55667441c84fa5e0911a0aac44fb059c15ba6da2 Mon Sep 17 00:00:00 2001
From: Eric Dumazet <[email protected]>
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.
include/linux/skbuff.h +2 -1
@@ -1354,7 +1354,8 @@ static inline __u32 skb_get_hash_flowi6(struct sk_buff *skb, const struct flowi6return 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) {
include/net/flow_dissector.h +2 -1
@@ -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;
include/net/fq.h +1 -1
@@ -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;
include/net/fq_impl.h +2 -2
@@ -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 */
net/core/flow_dissector.c +16 -22
@@ -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;
net/sched/sch_hhf.c +4 -4
@@ -5,11 +5,11 @@* Copyright (C) 2013 Nandita Dukkipati <[email protected]> */ -#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);
net/sched/sch_sfb.c +7 -6
@@ -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_dastatic 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;
net/sched/sch_sfq.c +8 -6
@@ -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_indexstatic 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);
Thanks Greg.
We definitely want to backport this fix to all relevant kernels, I will work on these backports soon.
Thanks.
Quoted 391 lines · On Wed, Nov 6, 2019 at 7:42 AM <[email protected]> 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 <[email protected]>.thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From
55667441c84fa5e0911a0aac44fb059c15ba6da2Mon Sep 17 00:00:00 2001
From: Eric Dumazet <[email protected]>
Date: Tue, 22 Oct 2019 07:57:46 -0700
Subject: [PATCH]net/flow_dissector: switch to siphashUDP IPv6 packets auto flowlabels are using a 32bit secret (static u32 hashrnd in
net/core/flow_dissector.c) and applyjhash()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)inip6_make_flowlabel()would be a dead end. Trying to periodically change the secret (like insch_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 <[email protected]>Reported-by Jonathan Berger <[email protected]>Reported-by Amit Klein <[email protected]>Reported-by Benny Pinkas <[email protected]>Cc Tom Herbert <[email protected]>Signed-off-by David S. Miller <[email protected]>include/linux/skbuff.h +2
-1@@ -1354,7 +1354,8 @@ static inline __u32 skb_get_hash_flowi6(struct sk_buff *skb, const struct flowi6return 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) {include/net/flow_dissector.h +2
-1@@ -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;include/net/fq.h +1
-1@@ -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;include/net/fq_impl.h +2
-2@@ -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 */ net/core/flow_dissector.c +16
-22@@ -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;net/sched/sch_hhf.c +4
-4@@ -5,11 +5,11 @@* Copyright (C) 2013 Nandita Dukkipati <[email protected]> */ -#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);net/sched/sch_sfb.c +7
-6@@ -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_dastatic 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;net/sched/sch_sfq.c +8
-6@@ -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_indexstatic 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);
Greg Kroah-Hartman
maintainerQuoted 4 lines · Eric Dumazet
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