Skip to content

Commit 53cb099

Browse files
committed
Merge branch 'wireguard-fixes'
Jason A. Donenfeld says: ==================== wireguard fixes for 5.7-rc7 Hopefully these are the last fixes for 5.7: 1) A trivial bump in the selftest harness to support gcc-10. build.wireguard.com is still on gcc-9 but I'll probably switch to gcc-10 in the coming weeks. 2) A concurrency fix regarding userspace modifying the pre-shared key at the same time as packets are being processed, reported by Matt Dunwoodie. 3) We were previously clearing skb->hash on egress, which broke fq_codel, cake, and other things that actually make use of the flow hash for queueing, reported by Dave Taht and Toke Høiland-Jørgensen. 4) A fix for the increased memory usage caused by (3). This can be thought of as part of patch (3), but because of the separate reasoning and breadth of it I thought made it a bit cleaner to put in a standalone commit. Fixes (2), (3), and (4) are -stable material. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 20a785a + a9e90d9 commit 53cb099

File tree

8 files changed

+71
-59
lines changed

8 files changed

+71
-59
lines changed

drivers/net/wireguard/messages.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ enum cookie_values {
3232
};
3333

3434
enum counter_values {
35-
COUNTER_BITS_TOTAL = 2048,
35+
COUNTER_BITS_TOTAL = 8192,
3636
COUNTER_REDUNDANT_BITS = BITS_PER_LONG,
3737
COUNTER_WINDOW_SIZE = COUNTER_BITS_TOTAL - COUNTER_REDUNDANT_BITS
3838
};

drivers/net/wireguard/noise.c

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ static struct noise_keypair *keypair_create(struct wg_peer *peer)
104104

105105
if (unlikely(!keypair))
106106
return NULL;
107+
spin_lock_init(&keypair->receiving_counter.lock);
107108
keypair->internal_id = atomic64_inc_return(&keypair_counter);
108109
keypair->entry.type = INDEX_HASHTABLE_KEYPAIR;
109110
keypair->entry.peer = peer;
@@ -358,25 +359,16 @@ static void kdf(u8 *first_dst, u8 *second_dst, u8 *third_dst, const u8 *data,
358359
memzero_explicit(output, BLAKE2S_HASH_SIZE + 1);
359360
}
360361

361-
static void symmetric_key_init(struct noise_symmetric_key *key)
362-
{
363-
spin_lock_init(&key->counter.receive.lock);
364-
atomic64_set(&key->counter.counter, 0);
365-
memset(key->counter.receive.backtrack, 0,
366-
sizeof(key->counter.receive.backtrack));
367-
key->birthdate = ktime_get_coarse_boottime_ns();
368-
key->is_valid = true;
369-
}
370-
371362
static void derive_keys(struct noise_symmetric_key *first_dst,
372363
struct noise_symmetric_key *second_dst,
373364
const u8 chaining_key[NOISE_HASH_LEN])
374365
{
366+
u64 birthdate = ktime_get_coarse_boottime_ns();
375367
kdf(first_dst->key, second_dst->key, NULL, NULL,
376368
NOISE_SYMMETRIC_KEY_LEN, NOISE_SYMMETRIC_KEY_LEN, 0, 0,
377369
chaining_key);
378-
symmetric_key_init(first_dst);
379-
symmetric_key_init(second_dst);
370+
first_dst->birthdate = second_dst->birthdate = birthdate;
371+
first_dst->is_valid = second_dst->is_valid = true;
380372
}
381373

382374
static bool __must_check mix_dh(u8 chaining_key[NOISE_HASH_LEN],
@@ -715,6 +707,7 @@ wg_noise_handshake_consume_response(struct message_handshake_response *src,
715707
u8 e[NOISE_PUBLIC_KEY_LEN];
716708
u8 ephemeral_private[NOISE_PUBLIC_KEY_LEN];
717709
u8 static_private[NOISE_PUBLIC_KEY_LEN];
710+
u8 preshared_key[NOISE_SYMMETRIC_KEY_LEN];
718711

719712
down_read(&wg->static_identity.lock);
720713

@@ -733,6 +726,8 @@ wg_noise_handshake_consume_response(struct message_handshake_response *src,
733726
memcpy(chaining_key, handshake->chaining_key, NOISE_HASH_LEN);
734727
memcpy(ephemeral_private, handshake->ephemeral_private,
735728
NOISE_PUBLIC_KEY_LEN);
729+
memcpy(preshared_key, handshake->preshared_key,
730+
NOISE_SYMMETRIC_KEY_LEN);
736731
up_read(&handshake->lock);
737732

738733
if (state != HANDSHAKE_CREATED_INITIATION)
@@ -750,7 +745,7 @@ wg_noise_handshake_consume_response(struct message_handshake_response *src,
750745
goto fail;
751746

752747
/* psk */
753-
mix_psk(chaining_key, hash, key, handshake->preshared_key);
748+
mix_psk(chaining_key, hash, key, preshared_key);
754749

755750
/* {} */
756751
if (!message_decrypt(NULL, src->encrypted_nothing,
@@ -783,6 +778,7 @@ wg_noise_handshake_consume_response(struct message_handshake_response *src,
783778
memzero_explicit(chaining_key, NOISE_HASH_LEN);
784779
memzero_explicit(ephemeral_private, NOISE_PUBLIC_KEY_LEN);
785780
memzero_explicit(static_private, NOISE_PUBLIC_KEY_LEN);
781+
memzero_explicit(preshared_key, NOISE_SYMMETRIC_KEY_LEN);
786782
up_read(&wg->static_identity.lock);
787783
return ret_peer;
788784
}

drivers/net/wireguard/noise.h

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,24 @@
1515
#include <linux/mutex.h>
1616
#include <linux/kref.h>
1717

18-
union noise_counter {
19-
struct {
20-
u64 counter;
21-
unsigned long backtrack[COUNTER_BITS_TOTAL / BITS_PER_LONG];
22-
spinlock_t lock;
23-
} receive;
24-
atomic64_t counter;
18+
struct noise_replay_counter {
19+
u64 counter;
20+
spinlock_t lock;
21+
unsigned long backtrack[COUNTER_BITS_TOTAL / BITS_PER_LONG];
2522
};
2623

2724
struct noise_symmetric_key {
2825
u8 key[NOISE_SYMMETRIC_KEY_LEN];
29-
union noise_counter counter;
3026
u64 birthdate;
3127
bool is_valid;
3228
};
3329

3430
struct noise_keypair {
3531
struct index_hashtable_entry entry;
3632
struct noise_symmetric_key sending;
33+
atomic64_t sending_counter;
3734
struct noise_symmetric_key receiving;
35+
struct noise_replay_counter receiving_counter;
3836
__le32 remote_index;
3937
bool i_am_the_initiator;
4038
struct kref refcount;

drivers/net/wireguard/queueing.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,12 +87,20 @@ static inline bool wg_check_packet_protocol(struct sk_buff *skb)
8787
return real_protocol && skb->protocol == real_protocol;
8888
}
8989

90-
static inline void wg_reset_packet(struct sk_buff *skb)
90+
static inline void wg_reset_packet(struct sk_buff *skb, bool encapsulating)
9191
{
92+
u8 l4_hash = skb->l4_hash;
93+
u8 sw_hash = skb->sw_hash;
94+
u32 hash = skb->hash;
9295
skb_scrub_packet(skb, true);
9396
memset(&skb->headers_start, 0,
9497
offsetof(struct sk_buff, headers_end) -
9598
offsetof(struct sk_buff, headers_start));
99+
if (encapsulating) {
100+
skb->l4_hash = l4_hash;
101+
skb->sw_hash = sw_hash;
102+
skb->hash = hash;
103+
}
96104
skb->queue_mapping = 0;
97105
skb->nohdr = 0;
98106
skb->peeked = 0;

drivers/net/wireguard/receive.c

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -245,20 +245,20 @@ static void keep_key_fresh(struct wg_peer *peer)
245245
}
246246
}
247247

248-
static bool decrypt_packet(struct sk_buff *skb, struct noise_symmetric_key *key)
248+
static bool decrypt_packet(struct sk_buff *skb, struct noise_keypair *keypair)
249249
{
250250
struct scatterlist sg[MAX_SKB_FRAGS + 8];
251251
struct sk_buff *trailer;
252252
unsigned int offset;
253253
int num_frags;
254254

255-
if (unlikely(!key))
255+
if (unlikely(!keypair))
256256
return false;
257257

258-
if (unlikely(!READ_ONCE(key->is_valid) ||
259-
wg_birthdate_has_expired(key->birthdate, REJECT_AFTER_TIME) ||
260-
key->counter.receive.counter >= REJECT_AFTER_MESSAGES)) {
261-
WRITE_ONCE(key->is_valid, false);
258+
if (unlikely(!READ_ONCE(keypair->receiving.is_valid) ||
259+
wg_birthdate_has_expired(keypair->receiving.birthdate, REJECT_AFTER_TIME) ||
260+
keypair->receiving_counter.counter >= REJECT_AFTER_MESSAGES)) {
261+
WRITE_ONCE(keypair->receiving.is_valid, false);
262262
return false;
263263
}
264264

@@ -283,7 +283,7 @@ static bool decrypt_packet(struct sk_buff *skb, struct noise_symmetric_key *key)
283283

284284
if (!chacha20poly1305_decrypt_sg_inplace(sg, skb->len, NULL, 0,
285285
PACKET_CB(skb)->nonce,
286-
key->key))
286+
keypair->receiving.key))
287287
return false;
288288

289289
/* Another ugly situation of pushing and pulling the header so as to
@@ -298,41 +298,41 @@ static bool decrypt_packet(struct sk_buff *skb, struct noise_symmetric_key *key)
298298
}
299299

300300
/* This is RFC6479, a replay detection bitmap algorithm that avoids bitshifts */
301-
static bool counter_validate(union noise_counter *counter, u64 their_counter)
301+
static bool counter_validate(struct noise_replay_counter *counter, u64 their_counter)
302302
{
303303
unsigned long index, index_current, top, i;
304304
bool ret = false;
305305

306-
spin_lock_bh(&counter->receive.lock);
306+
spin_lock_bh(&counter->lock);
307307

308-
if (unlikely(counter->receive.counter >= REJECT_AFTER_MESSAGES + 1 ||
308+
if (unlikely(counter->counter >= REJECT_AFTER_MESSAGES + 1 ||
309309
their_counter >= REJECT_AFTER_MESSAGES))
310310
goto out;
311311

312312
++their_counter;
313313

314314
if (unlikely((COUNTER_WINDOW_SIZE + their_counter) <
315-
counter->receive.counter))
315+
counter->counter))
316316
goto out;
317317

318318
index = their_counter >> ilog2(BITS_PER_LONG);
319319

320-
if (likely(their_counter > counter->receive.counter)) {
321-
index_current = counter->receive.counter >> ilog2(BITS_PER_LONG);
320+
if (likely(their_counter > counter->counter)) {
321+
index_current = counter->counter >> ilog2(BITS_PER_LONG);
322322
top = min_t(unsigned long, index - index_current,
323323
COUNTER_BITS_TOTAL / BITS_PER_LONG);
324324
for (i = 1; i <= top; ++i)
325-
counter->receive.backtrack[(i + index_current) &
325+
counter->backtrack[(i + index_current) &
326326
((COUNTER_BITS_TOTAL / BITS_PER_LONG) - 1)] = 0;
327-
counter->receive.counter = their_counter;
327+
counter->counter = their_counter;
328328
}
329329

330330
index &= (COUNTER_BITS_TOTAL / BITS_PER_LONG) - 1;
331331
ret = !test_and_set_bit(their_counter & (BITS_PER_LONG - 1),
332-
&counter->receive.backtrack[index]);
332+
&counter->backtrack[index]);
333333

334334
out:
335-
spin_unlock_bh(&counter->receive.lock);
335+
spin_unlock_bh(&counter->lock);
336336
return ret;
337337
}
338338

@@ -472,19 +472,19 @@ int wg_packet_rx_poll(struct napi_struct *napi, int budget)
472472
if (unlikely(state != PACKET_STATE_CRYPTED))
473473
goto next;
474474

475-
if (unlikely(!counter_validate(&keypair->receiving.counter,
475+
if (unlikely(!counter_validate(&keypair->receiving_counter,
476476
PACKET_CB(skb)->nonce))) {
477477
net_dbg_ratelimited("%s: Packet has invalid nonce %llu (max %llu)\n",
478478
peer->device->dev->name,
479479
PACKET_CB(skb)->nonce,
480-
keypair->receiving.counter.receive.counter);
480+
keypair->receiving_counter.counter);
481481
goto next;
482482
}
483483

484484
if (unlikely(wg_socket_endpoint_from_skb(&endpoint, skb)))
485485
goto next;
486486

487-
wg_reset_packet(skb);
487+
wg_reset_packet(skb, false);
488488
wg_packet_consume_data_done(peer, skb, &endpoint);
489489
free = false;
490490

@@ -511,8 +511,8 @@ void wg_packet_decrypt_worker(struct work_struct *work)
511511
struct sk_buff *skb;
512512

513513
while ((skb = ptr_ring_consume_bh(&queue->ring)) != NULL) {
514-
enum packet_state state = likely(decrypt_packet(skb,
515-
&PACKET_CB(skb)->keypair->receiving)) ?
514+
enum packet_state state =
515+
likely(decrypt_packet(skb, PACKET_CB(skb)->keypair)) ?
516516
PACKET_STATE_CRYPTED : PACKET_STATE_DEAD;
517517
wg_queue_enqueue_per_peer_napi(skb, state);
518518
if (need_resched())

drivers/net/wireguard/selftest/counter.c

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,24 @@
66
#ifdef DEBUG
77
bool __init wg_packet_counter_selftest(void)
88
{
9+
struct noise_replay_counter *counter;
910
unsigned int test_num = 0, i;
10-
union noise_counter counter;
1111
bool success = true;
1212

13-
#define T_INIT do { \
14-
memset(&counter, 0, sizeof(union noise_counter)); \
15-
spin_lock_init(&counter.receive.lock); \
13+
counter = kmalloc(sizeof(*counter), GFP_KERNEL);
14+
if (unlikely(!counter)) {
15+
pr_err("nonce counter self-test malloc: FAIL\n");
16+
return false;
17+
}
18+
19+
#define T_INIT do { \
20+
memset(counter, 0, sizeof(*counter)); \
21+
spin_lock_init(&counter->lock); \
1622
} while (0)
1723
#define T_LIM (COUNTER_WINDOW_SIZE + 1)
1824
#define T(n, v) do { \
1925
++test_num; \
20-
if (counter_validate(&counter, n) != (v)) { \
26+
if (counter_validate(counter, n) != (v)) { \
2127
pr_err("nonce counter self-test %u: FAIL\n", \
2228
test_num); \
2329
success = false; \
@@ -99,6 +105,7 @@ bool __init wg_packet_counter_selftest(void)
99105

100106
if (success)
101107
pr_info("nonce counter self-tests: pass\n");
108+
kfree(counter);
102109
return success;
103110
}
104111
#endif

drivers/net/wireguard/send.c

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ static void keep_key_fresh(struct wg_peer *peer)
129129
rcu_read_lock_bh();
130130
keypair = rcu_dereference_bh(peer->keypairs.current_keypair);
131131
send = keypair && READ_ONCE(keypair->sending.is_valid) &&
132-
(atomic64_read(&keypair->sending.counter.counter) > REKEY_AFTER_MESSAGES ||
132+
(atomic64_read(&keypair->sending_counter) > REKEY_AFTER_MESSAGES ||
133133
(keypair->i_am_the_initiator &&
134134
wg_birthdate_has_expired(keypair->sending.birthdate, REKEY_AFTER_TIME)));
135135
rcu_read_unlock_bh();
@@ -167,6 +167,11 @@ static bool encrypt_packet(struct sk_buff *skb, struct noise_keypair *keypair)
167167
struct sk_buff *trailer;
168168
int num_frags;
169169

170+
/* Force hash calculation before encryption so that flow analysis is
171+
* consistent over the inner packet.
172+
*/
173+
skb_get_hash(skb);
174+
170175
/* Calculate lengths. */
171176
padding_len = calculate_skb_padding(skb);
172177
trailer_len = padding_len + noise_encrypted_len(0);
@@ -295,7 +300,7 @@ void wg_packet_encrypt_worker(struct work_struct *work)
295300
skb_list_walk_safe(first, skb, next) {
296301
if (likely(encrypt_packet(skb,
297302
PACKET_CB(first)->keypair))) {
298-
wg_reset_packet(skb);
303+
wg_reset_packet(skb, true);
299304
} else {
300305
state = PACKET_STATE_DEAD;
301306
break;
@@ -344,7 +349,6 @@ void wg_packet_purge_staged_packets(struct wg_peer *peer)
344349

345350
void wg_packet_send_staged_packets(struct wg_peer *peer)
346351
{
347-
struct noise_symmetric_key *key;
348352
struct noise_keypair *keypair;
349353
struct sk_buff_head packets;
350354
struct sk_buff *skb;
@@ -364,10 +368,9 @@ void wg_packet_send_staged_packets(struct wg_peer *peer)
364368
rcu_read_unlock_bh();
365369
if (unlikely(!keypair))
366370
goto out_nokey;
367-
key = &keypair->sending;
368-
if (unlikely(!READ_ONCE(key->is_valid)))
371+
if (unlikely(!READ_ONCE(keypair->sending.is_valid)))
369372
goto out_nokey;
370-
if (unlikely(wg_birthdate_has_expired(key->birthdate,
373+
if (unlikely(wg_birthdate_has_expired(keypair->sending.birthdate,
371374
REJECT_AFTER_TIME)))
372375
goto out_invalid;
373376

@@ -382,7 +385,7 @@ void wg_packet_send_staged_packets(struct wg_peer *peer)
382385
*/
383386
PACKET_CB(skb)->ds = ip_tunnel_ecn_encap(0, ip_hdr(skb), skb);
384387
PACKET_CB(skb)->nonce =
385-
atomic64_inc_return(&key->counter.counter) - 1;
388+
atomic64_inc_return(&keypair->sending_counter) - 1;
386389
if (unlikely(PACKET_CB(skb)->nonce >= REJECT_AFTER_MESSAGES))
387390
goto out_invalid;
388391
}
@@ -394,7 +397,7 @@ void wg_packet_send_staged_packets(struct wg_peer *peer)
394397
return;
395398

396399
out_invalid:
397-
WRITE_ONCE(key->is_valid, false);
400+
WRITE_ONCE(keypair->sending.is_valid, false);
398401
out_nokey:
399402
wg_noise_keypair_put(keypair, false);
400403

tools/testing/selftests/wireguard/qemu/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ endef
4444
$(eval $(call tar_download,MUSL,musl,1.2.0,.tar.gz,https://musl.libc.org/releases/,c6de7b191139142d3f9a7b5b702c9cae1b5ee6e7f57e582da9328629408fd4e8))
4545
$(eval $(call tar_download,IPERF,iperf,3.7,.tar.gz,https://downloads.es.net/pub/iperf/,d846040224317caf2f75c843d309a950a7db23f9b44b94688ccbe557d6d1710c))
4646
$(eval $(call tar_download,BASH,bash,5.0,.tar.gz,https://ftp.gnu.org/gnu/bash/,b4a80f2ac66170b2913efbfb9f2594f1f76c7b1afd11f799e22035d63077fb4d))
47-
$(eval $(call tar_download,IPROUTE2,iproute2,5.4.0,.tar.xz,https://www.kernel.org/pub/linux/utils/net/iproute2/,fe97aa60a0d4c5ac830be18937e18dc3400ca713a33a89ad896ff1e3d46086ae))
47+
$(eval $(call tar_download,IPROUTE2,iproute2,5.6.0,.tar.xz,https://www.kernel.org/pub/linux/utils/net/iproute2/,1b5b0e25ce6e23da7526ea1da044e814ad85ba761b10dd29c2b027c056b04692))
4848
$(eval $(call tar_download,IPTABLES,iptables,1.8.4,.tar.bz2,https://www.netfilter.org/projects/iptables/files/,993a3a5490a544c2cbf2ef15cf7e7ed21af1845baf228318d5c36ef8827e157c))
4949
$(eval $(call tar_download,NMAP,nmap,7.80,.tar.bz2,https://nmap.org/dist/,fcfa5a0e42099e12e4bf7a68ebe6fde05553383a682e816a7ec9256ab4773faa))
5050
$(eval $(call tar_download,IPUTILS,iputils,s20190709,.tar.gz,https://github.com/iputils/iputils/archive/s20190709.tar.gz/#,a15720dd741d7538dd2645f9f516d193636ae4300ff7dbc8bfca757bf166490a))

0 commit comments

Comments
 (0)