diff options
author | Eric Dumazet <edumazet@google.com> | 2019-10-22 10:57:46 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-10-23 23:13:22 -0400 |
commit | 55667441c84fa5e0911a0aac44fb059c15ba6da2 (patch) | |
tree | 83d3fb8a5acbfbb3f9766f30a1e2343f0f19a90b | |
parent | 6c5d9c2a6bedbb3c3c14253776320c0ee564f064 (diff) |
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>
-rw-r--r-- | include/linux/skbuff.h | 3 | ||||
-rw-r--r-- | include/net/flow_dissector.h | 3 | ||||
-rw-r--r-- | include/net/fq.h | 2 | ||||
-rw-r--r-- | include/net/fq_impl.h | 4 | ||||
-rw-r--r-- | net/core/flow_dissector.c | 38 | ||||
-rw-r--r-- | net/sched/sch_hhf.c | 8 | ||||
-rw-r--r-- | net/sched/sch_sfb.c | 13 | ||||
-rw-r--r-- | net/sched/sch_sfq.c | 14 |
8 files changed, 42 insertions, 43 deletions
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 | |||
1354 | return skb->hash; | 1354 | return skb->hash; |
1355 | } | 1355 | } |
1356 | 1356 | ||
1357 | __u32 skb_get_hash_perturb(const struct sk_buff *skb, u32 perturb); | 1357 | __u32 skb_get_hash_perturb(const struct sk_buff *skb, |
1358 | const siphash_key_t *perturb); | ||
1358 | 1359 | ||
1359 | static inline __u32 skb_get_hash_raw(const struct sk_buff *skb) | 1360 | static inline __u32 skb_get_hash_raw(const struct sk_buff *skb) |
1360 | { | 1361 | { |
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 @@ | |||
4 | 4 | ||
5 | #include <linux/types.h> | 5 | #include <linux/types.h> |
6 | #include <linux/in6.h> | 6 | #include <linux/in6.h> |
7 | #include <linux/siphash.h> | ||
7 | #include <uapi/linux/if_ether.h> | 8 | #include <uapi/linux/if_ether.h> |
8 | 9 | ||
9 | /** | 10 | /** |
@@ -276,7 +277,7 @@ struct flow_keys_basic { | |||
276 | struct flow_keys { | 277 | struct flow_keys { |
277 | struct flow_dissector_key_control control; | 278 | struct flow_dissector_key_control control; |
278 | #define FLOW_KEYS_HASH_START_FIELD basic | 279 | #define FLOW_KEYS_HASH_START_FIELD basic |
279 | struct flow_dissector_key_basic basic; | 280 | struct flow_dissector_key_basic basic __aligned(SIPHASH_ALIGNMENT); |
280 | struct flow_dissector_key_tags tags; | 281 | struct flow_dissector_key_tags tags; |
281 | struct flow_dissector_key_vlan vlan; | 282 | struct flow_dissector_key_vlan vlan; |
282 | struct flow_dissector_key_vlan cvlan; | 283 | 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 { | |||
69 | struct list_head backlogs; | 69 | struct list_head backlogs; |
70 | spinlock_t lock; | 70 | spinlock_t lock; |
71 | u32 flows_cnt; | 71 | u32 flows_cnt; |
72 | u32 perturbation; | 72 | siphash_key_t perturbation; |
73 | u32 limit; | 73 | u32 limit; |
74 | u32 memory_limit; | 74 | u32 memory_limit; |
75 | u32 memory_usage; | 75 | 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 @@ begin: | |||
108 | 108 | ||
109 | static u32 fq_flow_idx(struct fq *fq, struct sk_buff *skb) | 109 | static u32 fq_flow_idx(struct fq *fq, struct sk_buff *skb) |
110 | { | 110 | { |
111 | u32 hash = skb_get_hash_perturb(skb, fq->perturbation); | 111 | u32 hash = skb_get_hash_perturb(skb, &fq->perturbation); |
112 | 112 | ||
113 | return reciprocal_scale(hash, fq->flows_cnt); | 113 | return reciprocal_scale(hash, fq->flows_cnt); |
114 | } | 114 | } |
@@ -308,7 +308,7 @@ static int fq_init(struct fq *fq, int flows_cnt) | |||
308 | INIT_LIST_HEAD(&fq->backlogs); | 308 | INIT_LIST_HEAD(&fq->backlogs); |
309 | spin_lock_init(&fq->lock); | 309 | spin_lock_init(&fq->lock); |
310 | fq->flows_cnt = max_t(u32, flows_cnt, 1); | 310 | fq->flows_cnt = max_t(u32, flows_cnt, 1); |
311 | fq->perturbation = prandom_u32(); | 311 | get_random_bytes(&fq->perturbation, sizeof(fq->perturbation)); |
312 | fq->quantum = 300; | 312 | fq->quantum = 300; |
313 | fq->limit = 8192; | 313 | fq->limit = 8192; |
314 | fq->memory_limit = 16 << 20; /* 16 MBytes */ | 314 | 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 @@ out_bad: | |||
1350 | } | 1350 | } |
1351 | EXPORT_SYMBOL(__skb_flow_dissect); | 1351 | EXPORT_SYMBOL(__skb_flow_dissect); |
1352 | 1352 | ||
1353 | static u32 hashrnd __read_mostly; | 1353 | static siphash_key_t hashrnd __read_mostly; |
1354 | static __always_inline void __flow_hash_secret_init(void) | 1354 | static __always_inline void __flow_hash_secret_init(void) |
1355 | { | 1355 | { |
1356 | net_get_random_once(&hashrnd, sizeof(hashrnd)); | 1356 | net_get_random_once(&hashrnd, sizeof(hashrnd)); |
1357 | } | 1357 | } |
1358 | 1358 | ||
1359 | static __always_inline u32 __flow_hash_words(const u32 *words, u32 length, | 1359 | static const void *flow_keys_hash_start(const struct flow_keys *flow) |
1360 | u32 keyval) | ||
1361 | { | 1360 | { |
1362 | return jhash2(words, length, keyval); | 1361 | BUILD_BUG_ON(FLOW_KEYS_HASH_OFFSET % SIPHASH_ALIGNMENT); |
1363 | } | 1362 | return &flow->FLOW_KEYS_HASH_START_FIELD; |
1364 | |||
1365 | static inline const u32 *flow_keys_hash_start(const struct flow_keys *flow) | ||
1366 | { | ||
1367 | const void *p = flow; | ||
1368 | |||
1369 | BUILD_BUG_ON(FLOW_KEYS_HASH_OFFSET % sizeof(u32)); | ||
1370 | return (const u32 *)(p + FLOW_KEYS_HASH_OFFSET); | ||
1371 | } | 1363 | } |
1372 | 1364 | ||
1373 | static inline size_t flow_keys_hash_length(const struct flow_keys *flow) | 1365 | static inline size_t flow_keys_hash_length(const struct flow_keys *flow) |
1374 | { | 1366 | { |
1375 | size_t diff = FLOW_KEYS_HASH_OFFSET + sizeof(flow->addrs); | 1367 | size_t diff = FLOW_KEYS_HASH_OFFSET + sizeof(flow->addrs); |
1376 | BUILD_BUG_ON((sizeof(*flow) - FLOW_KEYS_HASH_OFFSET) % sizeof(u32)); | ||
1377 | BUILD_BUG_ON(offsetof(typeof(*flow), addrs) != | 1368 | BUILD_BUG_ON(offsetof(typeof(*flow), addrs) != |
1378 | sizeof(*flow) - sizeof(flow->addrs)); | 1369 | sizeof(*flow) - sizeof(flow->addrs)); |
1379 | 1370 | ||
@@ -1388,7 +1379,7 @@ static inline size_t flow_keys_hash_length(const struct flow_keys *flow) | |||
1388 | diff -= sizeof(flow->addrs.tipckey); | 1379 | diff -= sizeof(flow->addrs.tipckey); |
1389 | break; | 1380 | break; |
1390 | } | 1381 | } |
1391 | return (sizeof(*flow) - diff) / sizeof(u32); | 1382 | return sizeof(*flow) - diff; |
1392 | } | 1383 | } |
1393 | 1384 | ||
1394 | __be32 flow_get_u32_src(const struct flow_keys *flow) | 1385 | __be32 flow_get_u32_src(const struct flow_keys *flow) |
@@ -1454,14 +1445,15 @@ static inline void __flow_hash_consistentify(struct flow_keys *keys) | |||
1454 | } | 1445 | } |
1455 | } | 1446 | } |
1456 | 1447 | ||
1457 | static inline u32 __flow_hash_from_keys(struct flow_keys *keys, u32 keyval) | 1448 | static inline u32 __flow_hash_from_keys(struct flow_keys *keys, |
1449 | const siphash_key_t *keyval) | ||
1458 | { | 1450 | { |
1459 | u32 hash; | 1451 | u32 hash; |
1460 | 1452 | ||
1461 | __flow_hash_consistentify(keys); | 1453 | __flow_hash_consistentify(keys); |
1462 | 1454 | ||
1463 | hash = __flow_hash_words(flow_keys_hash_start(keys), | 1455 | hash = siphash(flow_keys_hash_start(keys), |
1464 | flow_keys_hash_length(keys), keyval); | 1456 | flow_keys_hash_length(keys), keyval); |
1465 | if (!hash) | 1457 | if (!hash) |
1466 | hash = 1; | 1458 | hash = 1; |
1467 | 1459 | ||
@@ -1471,12 +1463,13 @@ static inline u32 __flow_hash_from_keys(struct flow_keys *keys, u32 keyval) | |||
1471 | u32 flow_hash_from_keys(struct flow_keys *keys) | 1463 | u32 flow_hash_from_keys(struct flow_keys *keys) |
1472 | { | 1464 | { |
1473 | __flow_hash_secret_init(); | 1465 | __flow_hash_secret_init(); |
1474 | return __flow_hash_from_keys(keys, hashrnd); | 1466 | return __flow_hash_from_keys(keys, &hashrnd); |
1475 | } | 1467 | } |
1476 | EXPORT_SYMBOL(flow_hash_from_keys); | 1468 | EXPORT_SYMBOL(flow_hash_from_keys); |
1477 | 1469 | ||
1478 | static inline u32 ___skb_get_hash(const struct sk_buff *skb, | 1470 | static inline u32 ___skb_get_hash(const struct sk_buff *skb, |
1479 | struct flow_keys *keys, u32 keyval) | 1471 | struct flow_keys *keys, |
1472 | const siphash_key_t *keyval) | ||
1480 | { | 1473 | { |
1481 | skb_flow_dissect_flow_keys(skb, keys, | 1474 | skb_flow_dissect_flow_keys(skb, keys, |
1482 | FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL); | 1475 | FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL); |
@@ -1524,7 +1517,7 @@ u32 __skb_get_hash_symmetric(const struct sk_buff *skb) | |||
1524 | &keys, NULL, 0, 0, 0, | 1517 | &keys, NULL, 0, 0, 0, |
1525 | FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL); | 1518 | FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL); |
1526 | 1519 | ||
1527 | return __flow_hash_from_keys(&keys, hashrnd); | 1520 | return __flow_hash_from_keys(&keys, &hashrnd); |
1528 | } | 1521 | } |
1529 | EXPORT_SYMBOL_GPL(__skb_get_hash_symmetric); | 1522 | EXPORT_SYMBOL_GPL(__skb_get_hash_symmetric); |
1530 | 1523 | ||
@@ -1544,13 +1537,14 @@ void __skb_get_hash(struct sk_buff *skb) | |||
1544 | 1537 | ||
1545 | __flow_hash_secret_init(); | 1538 | __flow_hash_secret_init(); |
1546 | 1539 | ||
1547 | hash = ___skb_get_hash(skb, &keys, hashrnd); | 1540 | hash = ___skb_get_hash(skb, &keys, &hashrnd); |
1548 | 1541 | ||
1549 | __skb_set_sw_hash(skb, hash, flow_keys_have_l4(&keys)); | 1542 | __skb_set_sw_hash(skb, hash, flow_keys_have_l4(&keys)); |
1550 | } | 1543 | } |
1551 | EXPORT_SYMBOL(__skb_get_hash); | 1544 | EXPORT_SYMBOL(__skb_get_hash); |
1552 | 1545 | ||
1553 | __u32 skb_get_hash_perturb(const struct sk_buff *skb, u32 perturb) | 1546 | __u32 skb_get_hash_perturb(const struct sk_buff *skb, |
1547 | const siphash_key_t *perturb) | ||
1554 | { | 1548 | { |
1555 | struct flow_keys keys; | 1549 | struct flow_keys keys; |
1556 | 1550 | ||
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 @@ | |||
5 | * Copyright (C) 2013 Nandita Dukkipati <nanditad@google.com> | 5 | * Copyright (C) 2013 Nandita Dukkipati <nanditad@google.com> |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <linux/jhash.h> | ||
9 | #include <linux/jiffies.h> | 8 | #include <linux/jiffies.h> |
10 | #include <linux/module.h> | 9 | #include <linux/module.h> |
11 | #include <linux/skbuff.h> | 10 | #include <linux/skbuff.h> |
12 | #include <linux/vmalloc.h> | 11 | #include <linux/vmalloc.h> |
12 | #include <linux/siphash.h> | ||
13 | #include <net/pkt_sched.h> | 13 | #include <net/pkt_sched.h> |
14 | #include <net/sock.h> | 14 | #include <net/sock.h> |
15 | 15 | ||
@@ -126,7 +126,7 @@ struct wdrr_bucket { | |||
126 | 126 | ||
127 | struct hhf_sched_data { | 127 | struct hhf_sched_data { |
128 | struct wdrr_bucket buckets[WDRR_BUCKET_CNT]; | 128 | struct wdrr_bucket buckets[WDRR_BUCKET_CNT]; |
129 | u32 perturbation; /* hash perturbation */ | 129 | siphash_key_t perturbation; /* hash perturbation */ |
130 | u32 quantum; /* psched_mtu(qdisc_dev(sch)); */ | 130 | u32 quantum; /* psched_mtu(qdisc_dev(sch)); */ |
131 | u32 drop_overlimit; /* number of times max qdisc packet | 131 | u32 drop_overlimit; /* number of times max qdisc packet |
132 | * limit was hit | 132 | * limit was hit |
@@ -264,7 +264,7 @@ static enum wdrr_bucket_idx hhf_classify(struct sk_buff *skb, struct Qdisc *sch) | |||
264 | } | 264 | } |
265 | 265 | ||
266 | /* Get hashed flow-id of the skb. */ | 266 | /* Get hashed flow-id of the skb. */ |
267 | hash = skb_get_hash_perturb(skb, q->perturbation); | 267 | hash = skb_get_hash_perturb(skb, &q->perturbation); |
268 | 268 | ||
269 | /* Check if this packet belongs to an already established HH flow. */ | 269 | /* Check if this packet belongs to an already established HH flow. */ |
270 | flow_pos = hash & HHF_BIT_MASK; | 270 | flow_pos = hash & HHF_BIT_MASK; |
@@ -582,7 +582,7 @@ static int hhf_init(struct Qdisc *sch, struct nlattr *opt, | |||
582 | 582 | ||
583 | sch->limit = 1000; | 583 | sch->limit = 1000; |
584 | q->quantum = psched_mtu(qdisc_dev(sch)); | 584 | q->quantum = psched_mtu(qdisc_dev(sch)); |
585 | q->perturbation = prandom_u32(); | 585 | get_random_bytes(&q->perturbation, sizeof(q->perturbation)); |
586 | INIT_LIST_HEAD(&q->new_buckets); | 586 | INIT_LIST_HEAD(&q->new_buckets); |
587 | INIT_LIST_HEAD(&q->old_buckets); | 587 | INIT_LIST_HEAD(&q->old_buckets); |
588 | 588 | ||
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 @@ | |||
18 | #include <linux/errno.h> | 18 | #include <linux/errno.h> |
19 | #include <linux/skbuff.h> | 19 | #include <linux/skbuff.h> |
20 | #include <linux/random.h> | 20 | #include <linux/random.h> |
21 | #include <linux/jhash.h> | 21 | #include <linux/siphash.h> |
22 | #include <net/ip.h> | 22 | #include <net/ip.h> |
23 | #include <net/pkt_sched.h> | 23 | #include <net/pkt_sched.h> |
24 | #include <net/pkt_cls.h> | 24 | #include <net/pkt_cls.h> |
@@ -45,7 +45,7 @@ struct sfb_bucket { | |||
45 | * (Section 4.4 of SFB reference : moving hash functions) | 45 | * (Section 4.4 of SFB reference : moving hash functions) |
46 | */ | 46 | */ |
47 | struct sfb_bins { | 47 | struct sfb_bins { |
48 | u32 perturbation; /* jhash perturbation */ | 48 | siphash_key_t perturbation; /* siphash key */ |
49 | struct sfb_bucket bins[SFB_LEVELS][SFB_NUMBUCKETS]; | 49 | struct sfb_bucket bins[SFB_LEVELS][SFB_NUMBUCKETS]; |
50 | }; | 50 | }; |
51 | 51 | ||
@@ -217,7 +217,8 @@ static u32 sfb_compute_qlen(u32 *prob_r, u32 *avgpm_r, const struct sfb_sched_da | |||
217 | 217 | ||
218 | static void sfb_init_perturbation(u32 slot, struct sfb_sched_data *q) | 218 | static void sfb_init_perturbation(u32 slot, struct sfb_sched_data *q) |
219 | { | 219 | { |
220 | q->bins[slot].perturbation = prandom_u32(); | 220 | get_random_bytes(&q->bins[slot].perturbation, |
221 | sizeof(q->bins[slot].perturbation)); | ||
221 | } | 222 | } |
222 | 223 | ||
223 | static void sfb_swap_slot(struct sfb_sched_data *q) | 224 | 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, | |||
314 | /* If using external classifiers, get result and record it. */ | 315 | /* If using external classifiers, get result and record it. */ |
315 | if (!sfb_classify(skb, fl, &ret, &salt)) | 316 | if (!sfb_classify(skb, fl, &ret, &salt)) |
316 | goto other_drop; | 317 | goto other_drop; |
317 | sfbhash = jhash_1word(salt, q->bins[slot].perturbation); | 318 | sfbhash = siphash_1u32(salt, &q->bins[slot].perturbation); |
318 | } else { | 319 | } else { |
319 | sfbhash = skb_get_hash_perturb(skb, q->bins[slot].perturbation); | 320 | sfbhash = skb_get_hash_perturb(skb, &q->bins[slot].perturbation); |
320 | } | 321 | } |
321 | 322 | ||
322 | 323 | ||
@@ -352,7 +353,7 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, | |||
352 | /* Inelastic flow */ | 353 | /* Inelastic flow */ |
353 | if (q->double_buffering) { | 354 | if (q->double_buffering) { |
354 | sfbhash = skb_get_hash_perturb(skb, | 355 | sfbhash = skb_get_hash_perturb(skb, |
355 | q->bins[slot].perturbation); | 356 | &q->bins[slot].perturbation); |
356 | if (!sfbhash) | 357 | if (!sfbhash) |
357 | sfbhash = 1; | 358 | sfbhash = 1; |
358 | sfb_skb_cb(skb)->hashes[slot] = sfbhash; | 359 | 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 @@ | |||
14 | #include <linux/errno.h> | 14 | #include <linux/errno.h> |
15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
16 | #include <linux/skbuff.h> | 16 | #include <linux/skbuff.h> |
17 | #include <linux/jhash.h> | 17 | #include <linux/siphash.h> |
18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
19 | #include <linux/vmalloc.h> | 19 | #include <linux/vmalloc.h> |
20 | #include <net/netlink.h> | 20 | #include <net/netlink.h> |
@@ -117,7 +117,7 @@ struct sfq_sched_data { | |||
117 | u8 headdrop; | 117 | u8 headdrop; |
118 | u8 maxdepth; /* limit of packets per flow */ | 118 | u8 maxdepth; /* limit of packets per flow */ |
119 | 119 | ||
120 | u32 perturbation; | 120 | siphash_key_t perturbation; |
121 | u8 cur_depth; /* depth of longest slot */ | 121 | u8 cur_depth; /* depth of longest slot */ |
122 | u8 flags; | 122 | u8 flags; |
123 | unsigned short scaled_quantum; /* SFQ_ALLOT_SIZE(quantum) */ | 123 | 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 | |||
157 | static unsigned int sfq_hash(const struct sfq_sched_data *q, | 157 | static unsigned int sfq_hash(const struct sfq_sched_data *q, |
158 | const struct sk_buff *skb) | 158 | const struct sk_buff *skb) |
159 | { | 159 | { |
160 | return skb_get_hash_perturb(skb, q->perturbation) & (q->divisor - 1); | 160 | return skb_get_hash_perturb(skb, &q->perturbation) & (q->divisor - 1); |
161 | } | 161 | } |
162 | 162 | ||
163 | static unsigned int sfq_classify(struct sk_buff *skb, struct Qdisc *sch, | 163 | static unsigned int sfq_classify(struct sk_buff *skb, struct Qdisc *sch, |
@@ -607,9 +607,11 @@ static void sfq_perturbation(struct timer_list *t) | |||
607 | struct sfq_sched_data *q = from_timer(q, t, perturb_timer); | 607 | struct sfq_sched_data *q = from_timer(q, t, perturb_timer); |
608 | struct Qdisc *sch = q->sch; | 608 | struct Qdisc *sch = q->sch; |
609 | spinlock_t *root_lock = qdisc_lock(qdisc_root_sleeping(sch)); | 609 | spinlock_t *root_lock = qdisc_lock(qdisc_root_sleeping(sch)); |
610 | siphash_key_t nkey; | ||
610 | 611 | ||
612 | get_random_bytes(&nkey, sizeof(nkey)); | ||
611 | spin_lock(root_lock); | 613 | spin_lock(root_lock); |
612 | q->perturbation = prandom_u32(); | 614 | q->perturbation = nkey; |
613 | if (!q->filter_list && q->tail) | 615 | if (!q->filter_list && q->tail) |
614 | sfq_rehash(sch); | 616 | sfq_rehash(sch); |
615 | spin_unlock(root_lock); | 617 | spin_unlock(root_lock); |
@@ -688,7 +690,7 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt) | |||
688 | del_timer(&q->perturb_timer); | 690 | del_timer(&q->perturb_timer); |
689 | if (q->perturb_period) { | 691 | if (q->perturb_period) { |
690 | mod_timer(&q->perturb_timer, jiffies + q->perturb_period); | 692 | mod_timer(&q->perturb_timer, jiffies + q->perturb_period); |
691 | q->perturbation = prandom_u32(); | 693 | get_random_bytes(&q->perturbation, sizeof(q->perturbation)); |
692 | } | 694 | } |
693 | sch_tree_unlock(sch); | 695 | sch_tree_unlock(sch); |
694 | kfree(p); | 696 | kfree(p); |
@@ -745,7 +747,7 @@ static int sfq_init(struct Qdisc *sch, struct nlattr *opt, | |||
745 | q->quantum = psched_mtu(qdisc_dev(sch)); | 747 | q->quantum = psched_mtu(qdisc_dev(sch)); |
746 | q->scaled_quantum = SFQ_ALLOT_SIZE(q->quantum); | 748 | q->scaled_quantum = SFQ_ALLOT_SIZE(q->quantum); |
747 | q->perturb_period = 0; | 749 | q->perturb_period = 0; |
748 | q->perturbation = prandom_u32(); | 750 | get_random_bytes(&q->perturbation, sizeof(q->perturbation)); |
749 | 751 | ||
750 | if (opt) { | 752 | if (opt) { |
751 | int err = sfq_change(sch, opt); | 753 | int err = sfq_change(sch, opt); |