Commit cbd92e7d authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

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/20211129153929.3457-1-Jason@zx2c4.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents cdef4852 f7e5b9bf
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -163,7 +163,7 @@ static bool node_placement(struct allowedips_node __rcu *trie, const u8 *key,
	return exact;
}

static inline void connect_node(struct allowedips_node **parent, u8 bit, struct allowedips_node *node)
static inline void connect_node(struct allowedips_node __rcu **parent, u8 bit, struct allowedips_node *node)
{
	node->parent_bit_packed = (unsigned long)parent | bit;
	rcu_assign_pointer(*parent, node);
+21 −18
Original line number Diff line number Diff line
@@ -98,6 +98,7 @@ static int wg_stop(struct net_device *dev)
{
	struct wg_device *wg = netdev_priv(dev);
	struct wg_peer *peer;
	struct sk_buff *skb;

	mutex_lock(&wg->device_update_lock);
	list_for_each_entry(peer, &wg->peer_list, peer_list) {
@@ -108,7 +109,9 @@ static int wg_stop(struct net_device *dev)
		wg_noise_reset_last_sent_handshake(&peer->last_sent_handshake);
	}
	mutex_unlock(&wg->device_update_lock);
	skb_queue_purge(&wg->incoming_handshakes);
	while ((skb = ptr_ring_consume(&wg->handshake_queue.ring)) != NULL)
		kfree_skb(skb);
	atomic_set(&wg->handshake_queue_len, 0);
	wg_socket_reinit(wg, NULL, NULL);
	return 0;
}
@@ -235,14 +238,13 @@ static void wg_destruct(struct net_device *dev)
	destroy_workqueue(wg->handshake_receive_wq);
	destroy_workqueue(wg->handshake_send_wq);
	destroy_workqueue(wg->packet_crypt_wq);
	wg_packet_queue_free(&wg->decrypt_queue);
	wg_packet_queue_free(&wg->encrypt_queue);
	wg_packet_queue_free(&wg->handshake_queue, true);
	wg_packet_queue_free(&wg->decrypt_queue, false);
	wg_packet_queue_free(&wg->encrypt_queue, false);
	rcu_barrier(); /* Wait for all the peers to be actually freed. */
	wg_ratelimiter_uninit();
	memzero_explicit(&wg->static_identity, sizeof(wg->static_identity));
	skb_queue_purge(&wg->incoming_handshakes);
	free_percpu(dev->tstats);
	free_percpu(wg->incoming_handshakes_worker);
	kvfree(wg->index_hashtable);
	kvfree(wg->peer_hashtable);
	mutex_unlock(&wg->device_update_lock);
@@ -298,7 +300,6 @@ static int wg_newlink(struct net *src_net, struct net_device *dev,
	init_rwsem(&wg->static_identity.lock);
	mutex_init(&wg->socket_update_lock);
	mutex_init(&wg->device_update_lock);
	skb_queue_head_init(&wg->incoming_handshakes);
	wg_allowedips_init(&wg->peer_allowedips);
	wg_cookie_checker_init(&wg->cookie_checker, wg);
	INIT_LIST_HEAD(&wg->peer_list);
@@ -316,16 +317,10 @@ static int wg_newlink(struct net *src_net, struct net_device *dev,
	if (!dev->tstats)
		goto err_free_index_hashtable;

	wg->incoming_handshakes_worker =
		wg_packet_percpu_multicore_worker_alloc(
				wg_packet_handshake_receive_worker, wg);
	if (!wg->incoming_handshakes_worker)
		goto err_free_tstats;

	wg->handshake_receive_wq = alloc_workqueue("wg-kex-%s",
			WQ_CPU_INTENSIVE | WQ_FREEZABLE, 0, dev->name);
	if (!wg->handshake_receive_wq)
		goto err_free_incoming_handshakes;
		goto err_free_tstats;

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

	ret = wg_ratelimiter_init();
	ret = wg_packet_queue_init(&wg->handshake_queue, wg_packet_handshake_receive_worker,
				   MAX_QUEUED_INCOMING_HANDSHAKES);
	if (ret < 0)
		goto err_free_decrypt_queue;

	ret = wg_ratelimiter_init();
	if (ret < 0)
		goto err_free_handshake_queue;

	ret = register_netdevice(dev);
	if (ret < 0)
		goto err_uninit_ratelimiter;
@@ -367,18 +367,18 @@ static int wg_newlink(struct net *src_net, struct net_device *dev,

err_uninit_ratelimiter:
	wg_ratelimiter_uninit();
err_free_handshake_queue:
	wg_packet_queue_free(&wg->handshake_queue, false);
err_free_decrypt_queue:
	wg_packet_queue_free(&wg->decrypt_queue);
	wg_packet_queue_free(&wg->decrypt_queue, false);
err_free_encrypt_queue:
	wg_packet_queue_free(&wg->encrypt_queue);
	wg_packet_queue_free(&wg->encrypt_queue, false);
err_destroy_packet_crypt:
	destroy_workqueue(wg->packet_crypt_wq);
err_destroy_handshake_send:
	destroy_workqueue(wg->handshake_send_wq);
err_destroy_handshake_receive:
	destroy_workqueue(wg->handshake_receive_wq);
err_free_incoming_handshakes:
	free_percpu(wg->incoming_handshakes_worker);
err_free_tstats:
	free_percpu(dev->tstats);
err_free_index_hashtable:
@@ -398,6 +398,7 @@ static struct rtnl_link_ops link_ops __read_mostly = {
static void wg_netns_pre_exit(struct net *net)
{
	struct wg_device *wg;
	struct wg_peer *peer;

	rtnl_lock();
	list_for_each_entry(wg, &device_list, device_list) {
@@ -407,6 +408,8 @@ static void wg_netns_pre_exit(struct net *net)
			mutex_lock(&wg->device_update_lock);
			rcu_assign_pointer(wg->creating_net, NULL);
			wg_socket_reinit(wg, NULL, NULL);
			list_for_each_entry(peer, &wg->peer_list, peer_list)
				wg_socket_clear_peer_endpoint_src(peer);
			mutex_unlock(&wg->device_update_lock);
		}
	}
+3 −6
Original line number Diff line number Diff line
@@ -39,21 +39,18 @@ struct prev_queue {

struct wg_device {
	struct net_device *dev;
	struct crypt_queue encrypt_queue, decrypt_queue;
	struct crypt_queue encrypt_queue, decrypt_queue, handshake_queue;
	struct sock __rcu *sock4, *sock6;
	struct net __rcu *creating_net;
	struct noise_static_identity static_identity;
	struct workqueue_struct *handshake_receive_wq, *handshake_send_wq;
	struct workqueue_struct *packet_crypt_wq;
	struct sk_buff_head incoming_handshakes;
	int incoming_handshake_cpu;
	struct multicore_worker __percpu *incoming_handshakes_worker;
	struct workqueue_struct *packet_crypt_wq,*handshake_receive_wq, *handshake_send_wq;
	struct cookie_checker cookie_checker;
	struct pubkey_hashtable *peer_hashtable;
	struct index_hashtable *index_hashtable;
	struct allowedips peer_allowedips;
	struct mutex device_update_lock, socket_update_lock;
	struct list_head device_list, peer_list;
	atomic_t handshake_queue_len;
	unsigned int num_peers, device_update_gen;
	u32 fwmark;
	u16 incoming_port;
+4 −4
Original line number Diff line number Diff line
@@ -17,7 +17,7 @@
#include <linux/genetlink.h>
#include <net/rtnetlink.h>

static int __init mod_init(void)
static int __init wg_mod_init(void)
{
	int ret;

@@ -60,7 +60,7 @@ static int __init mod_init(void)
	return ret;
}

static void __exit mod_exit(void)
static void __exit wg_mod_exit(void)
{
	wg_genetlink_uninit();
	wg_device_uninit();
@@ -68,8 +68,8 @@ static void __exit mod_exit(void)
	wg_allowedips_slab_uninit();
}

module_init(mod_init);
module_exit(mod_exit);
module_init(wg_mod_init);
module_exit(wg_mod_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("WireGuard secure network tunnel");
MODULE_AUTHOR("Jason A. Donenfeld <Jason@zx2c4.com>");
+3 −3
Original line number Diff line number Diff line
@@ -38,11 +38,11 @@ int wg_packet_queue_init(struct crypt_queue *queue, work_func_t function,
	return 0;
}

void wg_packet_queue_free(struct crypt_queue *queue)
void wg_packet_queue_free(struct crypt_queue *queue, bool purge)
{
	free_percpu(queue->worker);
	WARN_ON(!__ptr_ring_empty(&queue->ring));
	ptr_ring_cleanup(&queue->ring, NULL);
	WARN_ON(!purge && !__ptr_ring_empty(&queue->ring));
	ptr_ring_cleanup(&queue->ring, purge ? (void(*)(void*))kfree_skb : NULL);
}

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