Commit 3c025b63 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'wireguard-fixes'



Jason A. Donenfeld says:

====================
wireguard fixes for 5.6-rc7

I originally intended to spend this cycle working on fun optimizations
and architecture for WireGuard for 5.7, but I've been a bit neurotic
about having 5.6 ship without any show stopper bugs. WireGuard has been
stable for a long time now, but that doesn't make me any less nervous
about the real deal in 5.6. To that end, I've been doing code reviews
and having discussions, and we also had a security firm audit the code.
That audit didn't turn up any vulnerabilities, but they did make a good
defense-in-depth suggestion. This series contains:

1) Removal of a duplicated header, from YueHaibing.
2) Testing with 64-bit time in our test suite.
3) Account for skb->protocol==0 due to AF_PACKET sockets, suggested
   by Florian Fainelli.
4) Clean up some code in an unreachable switch/case branch, suggested
   by Florian Fainelli.
5) Better handling of low-order points, discussed with Mathias
   Hall-Andersen.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 384d91c2 11a7686a
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -122,7 +122,7 @@ static netdev_tx_t wg_xmit(struct sk_buff *skb, struct net_device *dev)
	u32 mtu;
	int ret;

	if (unlikely(wg_skb_examine_untrusted_ip_hdr(skb) != skb->protocol)) {
	if (unlikely(!wg_check_packet_protocol(skb))) {
		ret = -EPROTONOSUPPORT;
		net_dbg_ratelimited("%s: Invalid IP packet\n", dev->name);
		goto err;
+2 −6
Original line number Diff line number Diff line
@@ -411,11 +411,7 @@ static int set_peer(struct wg_device *wg, struct nlattr **attrs)

		peer = wg_peer_create(wg, public_key, preshared_key);
		if (IS_ERR(peer)) {
			/* Similar to the above, if the key is invalid, we skip
			 * it without fanfare, so that services don't need to
			 * worry about doing key validation themselves.
			 */
			ret = PTR_ERR(peer) == -EKEYREJECTED ? 0 : PTR_ERR(peer);
			ret = PTR_ERR(peer);
			peer = NULL;
			goto out;
		}
@@ -569,7 +565,7 @@ static int wg_set_device(struct sk_buff *skb, struct genl_info *info)
							 private_key);
		list_for_each_entry_safe(peer, temp, &wg->peer_list,
					 peer_list) {
			BUG_ON(!wg_noise_precompute_static_static(peer));
			wg_noise_precompute_static_static(peer);
			wg_noise_expire_current_peer_keypairs(peer);
		}
		wg_cookie_checker_precompute_device_keys(&wg->cookie_checker);
+29 −26
Original line number Diff line number Diff line
@@ -44,28 +44,19 @@ void __init wg_noise_init(void)
}

/* Must hold peer->handshake.static_identity->lock */
bool wg_noise_precompute_static_static(struct wg_peer *peer)
void wg_noise_precompute_static_static(struct wg_peer *peer)
{
	bool ret;

	down_write(&peer->handshake.lock);
	if (peer->handshake.static_identity->has_identity) {
		ret = curve25519(
			peer->handshake.precomputed_static_static,
	if (!peer->handshake.static_identity->has_identity ||
	    !curve25519(peer->handshake.precomputed_static_static,
			peer->handshake.static_identity->static_private,
			peer->handshake.remote_static);
	} else {
		u8 empty[NOISE_PUBLIC_KEY_LEN] = { 0 };

		ret = curve25519(empty, empty, peer->handshake.remote_static);
			peer->handshake.remote_static))
		memset(peer->handshake.precomputed_static_static, 0,
		       NOISE_PUBLIC_KEY_LEN);
	}
	up_write(&peer->handshake.lock);
	return ret;
}

bool wg_noise_handshake_init(struct noise_handshake *handshake,
void wg_noise_handshake_init(struct noise_handshake *handshake,
			     struct noise_static_identity *static_identity,
			     const u8 peer_public_key[NOISE_PUBLIC_KEY_LEN],
			     const u8 peer_preshared_key[NOISE_SYMMETRIC_KEY_LEN],
@@ -81,7 +72,7 @@ bool wg_noise_handshake_init(struct noise_handshake *handshake,
		       NOISE_SYMMETRIC_KEY_LEN);
	handshake->static_identity = static_identity;
	handshake->state = HANDSHAKE_ZEROED;
	return wg_noise_precompute_static_static(peer);
	wg_noise_precompute_static_static(peer);
}

static void handshake_zero(struct noise_handshake *handshake)
@@ -403,6 +394,19 @@ static bool __must_check mix_dh(u8 chaining_key[NOISE_HASH_LEN],
	return true;
}

static bool __must_check mix_precomputed_dh(u8 chaining_key[NOISE_HASH_LEN],
					    u8 key[NOISE_SYMMETRIC_KEY_LEN],
					    const u8 precomputed[NOISE_PUBLIC_KEY_LEN])
{
	static u8 zero_point[NOISE_PUBLIC_KEY_LEN];
	if (unlikely(!crypto_memneq(precomputed, zero_point, NOISE_PUBLIC_KEY_LEN)))
		return false;
	kdf(chaining_key, key, NULL, precomputed, NOISE_HASH_LEN,
	    NOISE_SYMMETRIC_KEY_LEN, 0, NOISE_PUBLIC_KEY_LEN,
	    chaining_key);
	return true;
}

static void mix_hash(u8 hash[NOISE_HASH_LEN], const u8 *src, size_t src_len)
{
	struct blake2s_state blake;
@@ -531,10 +535,9 @@ wg_noise_handshake_create_initiation(struct message_handshake_initiation *dst,
			NOISE_PUBLIC_KEY_LEN, key, handshake->hash);

	/* ss */
	kdf(handshake->chaining_key, key, NULL,
	    handshake->precomputed_static_static, NOISE_HASH_LEN,
	    NOISE_SYMMETRIC_KEY_LEN, 0, NOISE_PUBLIC_KEY_LEN,
	    handshake->chaining_key);
	if (!mix_precomputed_dh(handshake->chaining_key, key,
				handshake->precomputed_static_static))
		goto out;

	/* {t} */
	tai64n_now(timestamp);
@@ -595,9 +598,9 @@ wg_noise_handshake_consume_initiation(struct message_handshake_initiation *src,
	handshake = &peer->handshake;

	/* ss */
	kdf(chaining_key, key, NULL, handshake->precomputed_static_static,
	    NOISE_HASH_LEN, NOISE_SYMMETRIC_KEY_LEN, 0, NOISE_PUBLIC_KEY_LEN,
	    chaining_key);
	if (!mix_precomputed_dh(chaining_key, key,
				handshake->precomputed_static_static))
	    goto out;

	/* {t} */
	if (!message_decrypt(t, src->encrypted_timestamp,
+6 −6
Original line number Diff line number Diff line
@@ -94,7 +94,7 @@ struct noise_handshake {
struct wg_device;

void wg_noise_init(void);
bool wg_noise_handshake_init(struct noise_handshake *handshake,
void wg_noise_handshake_init(struct noise_handshake *handshake,
			     struct noise_static_identity *static_identity,
			     const u8 peer_public_key[NOISE_PUBLIC_KEY_LEN],
			     const u8 peer_preshared_key[NOISE_SYMMETRIC_KEY_LEN],
@@ -116,7 +116,7 @@ void wg_noise_expire_current_peer_keypairs(struct wg_peer *peer);
void wg_noise_set_static_identity_private_key(
	struct noise_static_identity *static_identity,
	const u8 private_key[NOISE_PUBLIC_KEY_LEN]);
bool wg_noise_precompute_static_static(struct wg_peer *peer);
void wg_noise_precompute_static_static(struct wg_peer *peer);

bool
wg_noise_handshake_create_initiation(struct message_handshake_initiation *dst,
+2 −5
Original line number Diff line number Diff line
@@ -34,11 +34,8 @@ struct wg_peer *wg_peer_create(struct wg_device *wg,
		return ERR_PTR(ret);
	peer->device = wg;

	if (!wg_noise_handshake_init(&peer->handshake, &wg->static_identity,
				     public_key, preshared_key, peer)) {
		ret = -EKEYREJECTED;
		goto err_1;
	}
	wg_noise_handshake_init(&peer->handshake, &wg->static_identity,
				public_key, preshared_key, peer);
	if (dst_cache_init(&peer->endpoint_cache, GFP_KERNEL))
		goto err_1;
	if (wg_packet_queue_init(&peer->tx_queue, wg_packet_tx_worker, false,
Loading