Skip to content

Commit cbd92e7

Browse files
committed
Merge branch 'wireguard-siphash-patches-for-5-16-rc6'
Jason A. Donenfeld says: ==================== wireguard/siphash patches for 5.16-rc Here's quite a largeish set of stable patches I've had queued up and testing for a number of months now: - Patch (1) squelches a sparse warning by fixing an annotation. - Patches (2), (3), and (5) are minor improvements and fixes to the test suite. - Patch (4) is part of a tree-wide cleanup to have module-specific init and exit functions. - Patch (6) fixes a an issue with dangling dst references, by having a function to release references immediately rather than deferring, and adds an associated test case to prevent this from regressing. - Patches (7) and (8) help mitigate somewhat a potential DoS on the ingress path due to the use of skb_list's locking hitting contention on multiple cores by switching to using a ring buffer and dropping packets on contention rather than locking up another core spinning. - Patch (9) switches kvzalloc to kvcalloc for better form. - Patch (10) fixes alignment traps in siphash with clang-13 (and maybe other compilers) on armv6, by switching to using the unaligned functions by default instead of the aligned functions by default. ==================== Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents cdef485 + f7e5b9b commit cbd92e7

File tree

16 files changed

+129
-71
lines changed

16 files changed

+129
-71
lines changed

drivers/net/wireguard/allowedips.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ static bool node_placement(struct allowedips_node __rcu *trie, const u8 *key,
163163
return exact;
164164
}
165165

166-
static inline void connect_node(struct allowedips_node **parent, u8 bit, struct allowedips_node *node)
166+
static inline void connect_node(struct allowedips_node __rcu **parent, u8 bit, struct allowedips_node *node)
167167
{
168168
node->parent_bit_packed = (unsigned long)parent | bit;
169169
rcu_assign_pointer(*parent, node);

drivers/net/wireguard/device.c

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ static int wg_stop(struct net_device *dev)
9898
{
9999
struct wg_device *wg = netdev_priv(dev);
100100
struct wg_peer *peer;
101+
struct sk_buff *skb;
101102

102103
mutex_lock(&wg->device_update_lock);
103104
list_for_each_entry(peer, &wg->peer_list, peer_list) {
@@ -108,7 +109,9 @@ static int wg_stop(struct net_device *dev)
108109
wg_noise_reset_last_sent_handshake(&peer->last_sent_handshake);
109110
}
110111
mutex_unlock(&wg->device_update_lock);
111-
skb_queue_purge(&wg->incoming_handshakes);
112+
while ((skb = ptr_ring_consume(&wg->handshake_queue.ring)) != NULL)
113+
kfree_skb(skb);
114+
atomic_set(&wg->handshake_queue_len, 0);
112115
wg_socket_reinit(wg, NULL, NULL);
113116
return 0;
114117
}
@@ -235,14 +238,13 @@ static void wg_destruct(struct net_device *dev)
235238
destroy_workqueue(wg->handshake_receive_wq);
236239
destroy_workqueue(wg->handshake_send_wq);
237240
destroy_workqueue(wg->packet_crypt_wq);
238-
wg_packet_queue_free(&wg->decrypt_queue);
239-
wg_packet_queue_free(&wg->encrypt_queue);
241+
wg_packet_queue_free(&wg->handshake_queue, true);
242+
wg_packet_queue_free(&wg->decrypt_queue, false);
243+
wg_packet_queue_free(&wg->encrypt_queue, false);
240244
rcu_barrier(); /* Wait for all the peers to be actually freed. */
241245
wg_ratelimiter_uninit();
242246
memzero_explicit(&wg->static_identity, sizeof(wg->static_identity));
243-
skb_queue_purge(&wg->incoming_handshakes);
244247
free_percpu(dev->tstats);
245-
free_percpu(wg->incoming_handshakes_worker);
246248
kvfree(wg->index_hashtable);
247249
kvfree(wg->peer_hashtable);
248250
mutex_unlock(&wg->device_update_lock);
@@ -298,7 +300,6 @@ static int wg_newlink(struct net *src_net, struct net_device *dev,
298300
init_rwsem(&wg->static_identity.lock);
299301
mutex_init(&wg->socket_update_lock);
300302
mutex_init(&wg->device_update_lock);
301-
skb_queue_head_init(&wg->incoming_handshakes);
302303
wg_allowedips_init(&wg->peer_allowedips);
303304
wg_cookie_checker_init(&wg->cookie_checker, wg);
304305
INIT_LIST_HEAD(&wg->peer_list);
@@ -316,16 +317,10 @@ static int wg_newlink(struct net *src_net, struct net_device *dev,
316317
if (!dev->tstats)
317318
goto err_free_index_hashtable;
318319

319-
wg->incoming_handshakes_worker =
320-
wg_packet_percpu_multicore_worker_alloc(
321-
wg_packet_handshake_receive_worker, wg);
322-
if (!wg->incoming_handshakes_worker)
323-
goto err_free_tstats;
324-
325320
wg->handshake_receive_wq = alloc_workqueue("wg-kex-%s",
326321
WQ_CPU_INTENSIVE | WQ_FREEZABLE, 0, dev->name);
327322
if (!wg->handshake_receive_wq)
328-
goto err_free_incoming_handshakes;
323+
goto err_free_tstats;
329324

330325
wg->handshake_send_wq = alloc_workqueue("wg-kex-%s",
331326
WQ_UNBOUND | WQ_FREEZABLE, 0, dev->name);
@@ -347,10 +342,15 @@ static int wg_newlink(struct net *src_net, struct net_device *dev,
347342
if (ret < 0)
348343
goto err_free_encrypt_queue;
349344

350-
ret = wg_ratelimiter_init();
345+
ret = wg_packet_queue_init(&wg->handshake_queue, wg_packet_handshake_receive_worker,
346+
MAX_QUEUED_INCOMING_HANDSHAKES);
351347
if (ret < 0)
352348
goto err_free_decrypt_queue;
353349

350+
ret = wg_ratelimiter_init();
351+
if (ret < 0)
352+
goto err_free_handshake_queue;
353+
354354
ret = register_netdevice(dev);
355355
if (ret < 0)
356356
goto err_uninit_ratelimiter;
@@ -367,18 +367,18 @@ static int wg_newlink(struct net *src_net, struct net_device *dev,
367367

368368
err_uninit_ratelimiter:
369369
wg_ratelimiter_uninit();
370+
err_free_handshake_queue:
371+
wg_packet_queue_free(&wg->handshake_queue, false);
370372
err_free_decrypt_queue:
371-
wg_packet_queue_free(&wg->decrypt_queue);
373+
wg_packet_queue_free(&wg->decrypt_queue, false);
372374
err_free_encrypt_queue:
373-
wg_packet_queue_free(&wg->encrypt_queue);
375+
wg_packet_queue_free(&wg->encrypt_queue, false);
374376
err_destroy_packet_crypt:
375377
destroy_workqueue(wg->packet_crypt_wq);
376378
err_destroy_handshake_send:
377379
destroy_workqueue(wg->handshake_send_wq);
378380
err_destroy_handshake_receive:
379381
destroy_workqueue(wg->handshake_receive_wq);
380-
err_free_incoming_handshakes:
381-
free_percpu(wg->incoming_handshakes_worker);
382382
err_free_tstats:
383383
free_percpu(dev->tstats);
384384
err_free_index_hashtable:
@@ -398,6 +398,7 @@ static struct rtnl_link_ops link_ops __read_mostly = {
398398
static void wg_netns_pre_exit(struct net *net)
399399
{
400400
struct wg_device *wg;
401+
struct wg_peer *peer;
401402

402403
rtnl_lock();
403404
list_for_each_entry(wg, &device_list, device_list) {
@@ -407,6 +408,8 @@ static void wg_netns_pre_exit(struct net *net)
407408
mutex_lock(&wg->device_update_lock);
408409
rcu_assign_pointer(wg->creating_net, NULL);
409410
wg_socket_reinit(wg, NULL, NULL);
411+
list_for_each_entry(peer, &wg->peer_list, peer_list)
412+
wg_socket_clear_peer_endpoint_src(peer);
410413
mutex_unlock(&wg->device_update_lock);
411414
}
412415
}

drivers/net/wireguard/device.h

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,21 +39,18 @@ struct prev_queue {
3939

4040
struct wg_device {
4141
struct net_device *dev;
42-
struct crypt_queue encrypt_queue, decrypt_queue;
42+
struct crypt_queue encrypt_queue, decrypt_queue, handshake_queue;
4343
struct sock __rcu *sock4, *sock6;
4444
struct net __rcu *creating_net;
4545
struct noise_static_identity static_identity;
46-
struct workqueue_struct *handshake_receive_wq, *handshake_send_wq;
47-
struct workqueue_struct *packet_crypt_wq;
48-
struct sk_buff_head incoming_handshakes;
49-
int incoming_handshake_cpu;
50-
struct multicore_worker __percpu *incoming_handshakes_worker;
46+
struct workqueue_struct *packet_crypt_wq,*handshake_receive_wq, *handshake_send_wq;
5147
struct cookie_checker cookie_checker;
5248
struct pubkey_hashtable *peer_hashtable;
5349
struct index_hashtable *index_hashtable;
5450
struct allowedips peer_allowedips;
5551
struct mutex device_update_lock, socket_update_lock;
5652
struct list_head device_list, peer_list;
53+
atomic_t handshake_queue_len;
5754
unsigned int num_peers, device_update_gen;
5855
u32 fwmark;
5956
u16 incoming_port;

drivers/net/wireguard/main.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
#include <linux/genetlink.h>
1818
#include <net/rtnetlink.h>
1919

20-
static int __init mod_init(void)
20+
static int __init wg_mod_init(void)
2121
{
2222
int ret;
2323

@@ -60,16 +60,16 @@ static int __init mod_init(void)
6060
return ret;
6161
}
6262

63-
static void __exit mod_exit(void)
63+
static void __exit wg_mod_exit(void)
6464
{
6565
wg_genetlink_uninit();
6666
wg_device_uninit();
6767
wg_peer_uninit();
6868
wg_allowedips_slab_uninit();
6969
}
7070

71-
module_init(mod_init);
72-
module_exit(mod_exit);
71+
module_init(wg_mod_init);
72+
module_exit(wg_mod_exit);
7373
MODULE_LICENSE("GPL v2");
7474
MODULE_DESCRIPTION("WireGuard secure network tunnel");
7575
MODULE_AUTHOR("Jason A. Donenfeld <[email protected]>");

drivers/net/wireguard/queueing.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,11 @@ int wg_packet_queue_init(struct crypt_queue *queue, work_func_t function,
3838
return 0;
3939
}
4040

41-
void wg_packet_queue_free(struct crypt_queue *queue)
41+
void wg_packet_queue_free(struct crypt_queue *queue, bool purge)
4242
{
4343
free_percpu(queue->worker);
44-
WARN_ON(!__ptr_ring_empty(&queue->ring));
45-
ptr_ring_cleanup(&queue->ring, NULL);
44+
WARN_ON(!purge && !__ptr_ring_empty(&queue->ring));
45+
ptr_ring_cleanup(&queue->ring, purge ? (void(*)(void*))kfree_skb : NULL);
4646
}
4747

4848
#define NEXT(skb) ((skb)->prev)

drivers/net/wireguard/queueing.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ struct sk_buff;
2323
/* queueing.c APIs: */
2424
int wg_packet_queue_init(struct crypt_queue *queue, work_func_t function,
2525
unsigned int len);
26-
void wg_packet_queue_free(struct crypt_queue *queue);
26+
void wg_packet_queue_free(struct crypt_queue *queue, bool purge);
2727
struct multicore_worker __percpu *
2828
wg_packet_percpu_multicore_worker_alloc(work_func_t function, void *ptr);
2929

drivers/net/wireguard/ratelimiter.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,12 +176,12 @@ int wg_ratelimiter_init(void)
176176
(1U << 14) / sizeof(struct hlist_head)));
177177
max_entries = table_size * 8;
178178

179-
table_v4 = kvzalloc(table_size * sizeof(*table_v4), GFP_KERNEL);
179+
table_v4 = kvcalloc(table_size, sizeof(*table_v4), GFP_KERNEL);
180180
if (unlikely(!table_v4))
181181
goto err_kmemcache;
182182

183183
#if IS_ENABLED(CONFIG_IPV6)
184-
table_v6 = kvzalloc(table_size * sizeof(*table_v6), GFP_KERNEL);
184+
table_v6 = kvcalloc(table_size, sizeof(*table_v6), GFP_KERNEL);
185185
if (unlikely(!table_v6)) {
186186
kvfree(table_v4);
187187
goto err_kmemcache;

drivers/net/wireguard/receive.c

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,8 @@ static void wg_receive_handshake_packet(struct wg_device *wg,
116116
return;
117117
}
118118

119-
under_load = skb_queue_len(&wg->incoming_handshakes) >=
120-
MAX_QUEUED_INCOMING_HANDSHAKES / 8;
119+
under_load = atomic_read(&wg->handshake_queue_len) >=
120+
MAX_QUEUED_INCOMING_HANDSHAKES / 8;
121121
if (under_load) {
122122
last_under_load = ktime_get_coarse_boottime_ns();
123123
} else if (last_under_load) {
@@ -212,13 +212,14 @@ static void wg_receive_handshake_packet(struct wg_device *wg,
212212

213213
void wg_packet_handshake_receive_worker(struct work_struct *work)
214214
{
215-
struct wg_device *wg = container_of(work, struct multicore_worker,
216-
work)->ptr;
215+
struct crypt_queue *queue = container_of(work, struct multicore_worker, work)->ptr;
216+
struct wg_device *wg = container_of(queue, struct wg_device, handshake_queue);
217217
struct sk_buff *skb;
218218

219-
while ((skb = skb_dequeue(&wg->incoming_handshakes)) != NULL) {
219+
while ((skb = ptr_ring_consume_bh(&queue->ring)) != NULL) {
220220
wg_receive_handshake_packet(wg, skb);
221221
dev_kfree_skb(skb);
222+
atomic_dec(&wg->handshake_queue_len);
222223
cond_resched();
223224
}
224225
}
@@ -553,22 +554,28 @@ void wg_packet_receive(struct wg_device *wg, struct sk_buff *skb)
553554
case cpu_to_le32(MESSAGE_HANDSHAKE_INITIATION):
554555
case cpu_to_le32(MESSAGE_HANDSHAKE_RESPONSE):
555556
case cpu_to_le32(MESSAGE_HANDSHAKE_COOKIE): {
556-
int cpu;
557-
558-
if (skb_queue_len(&wg->incoming_handshakes) >
559-
MAX_QUEUED_INCOMING_HANDSHAKES ||
560-
unlikely(!rng_is_initialized())) {
557+
int cpu, ret = -EBUSY;
558+
559+
if (unlikely(!rng_is_initialized()))
560+
goto drop;
561+
if (atomic_read(&wg->handshake_queue_len) > MAX_QUEUED_INCOMING_HANDSHAKES / 2) {
562+
if (spin_trylock_bh(&wg->handshake_queue.ring.producer_lock)) {
563+
ret = __ptr_ring_produce(&wg->handshake_queue.ring, skb);
564+
spin_unlock_bh(&wg->handshake_queue.ring.producer_lock);
565+
}
566+
} else
567+
ret = ptr_ring_produce_bh(&wg->handshake_queue.ring, skb);
568+
if (ret) {
569+
drop:
561570
net_dbg_skb_ratelimited("%s: Dropping handshake packet from %pISpfsc\n",
562571
wg->dev->name, skb);
563572
goto err;
564573
}
565-
skb_queue_tail(&wg->incoming_handshakes, skb);
566-
/* Queues up a call to packet_process_queued_handshake_
567-
* packets(skb):
568-
*/
569-
cpu = wg_cpumask_next_online(&wg->incoming_handshake_cpu);
574+
atomic_inc(&wg->handshake_queue_len);
575+
cpu = wg_cpumask_next_online(&wg->handshake_queue.last_cpu);
576+
/* Queues up a call to packet_process_queued_handshake_packets(skb): */
570577
queue_work_on(cpu, wg->handshake_receive_wq,
571-
&per_cpu_ptr(wg->incoming_handshakes_worker, cpu)->work);
578+
&per_cpu_ptr(wg->handshake_queue.worker, cpu)->work);
572579
break;
573580
}
574581
case cpu_to_le32(MESSAGE_DATA):

drivers/net/wireguard/socket.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ void wg_socket_clear_peer_endpoint_src(struct wg_peer *peer)
308308
{
309309
write_lock_bh(&peer->endpoint_lock);
310310
memset(&peer->endpoint.src6, 0, sizeof(peer->endpoint.src6));
311-
dst_cache_reset(&peer->endpoint_cache);
311+
dst_cache_reset_now(&peer->endpoint_cache);
312312
write_unlock_bh(&peer->endpoint_lock);
313313
}
314314

include/linux/siphash.h

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,7 @@ static inline bool siphash_key_is_zero(const siphash_key_t *key)
2727
}
2828

2929
u64 __siphash_aligned(const void *data, size_t len, const siphash_key_t *key);
30-
#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
3130
u64 __siphash_unaligned(const void *data, size_t len, const siphash_key_t *key);
32-
#endif
3331

3432
u64 siphash_1u64(const u64 a, const siphash_key_t *key);
3533
u64 siphash_2u64(const u64 a, const u64 b, const siphash_key_t *key);
@@ -82,10 +80,9 @@ static inline u64 ___siphash_aligned(const __le64 *data, size_t len,
8280
static inline u64 siphash(const void *data, size_t len,
8381
const siphash_key_t *key)
8482
{
85-
#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
86-
if (!IS_ALIGNED((unsigned long)data, SIPHASH_ALIGNMENT))
83+
if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) ||
84+
!IS_ALIGNED((unsigned long)data, SIPHASH_ALIGNMENT))
8785
return __siphash_unaligned(data, len, key);
88-
#endif
8986
return ___siphash_aligned(data, len, key);
9087
}
9188

@@ -96,10 +93,8 @@ typedef struct {
9693

9794
u32 __hsiphash_aligned(const void *data, size_t len,
9895
const hsiphash_key_t *key);
99-
#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
10096
u32 __hsiphash_unaligned(const void *data, size_t len,
10197
const hsiphash_key_t *key);
102-
#endif
10398

10499
u32 hsiphash_1u32(const u32 a, const hsiphash_key_t *key);
105100
u32 hsiphash_2u32(const u32 a, const u32 b, const hsiphash_key_t *key);
@@ -135,10 +130,9 @@ static inline u32 ___hsiphash_aligned(const __le32 *data, size_t len,
135130
static inline u32 hsiphash(const void *data, size_t len,
136131
const hsiphash_key_t *key)
137132
{
138-
#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
139-
if (!IS_ALIGNED((unsigned long)data, HSIPHASH_ALIGNMENT))
133+
if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) ||
134+
!IS_ALIGNED((unsigned long)data, HSIPHASH_ALIGNMENT))
140135
return __hsiphash_unaligned(data, len, key);
141-
#endif
142136
return ___hsiphash_aligned(data, len, key);
143137
}
144138

0 commit comments

Comments
 (0)