Skip to content

Commit c78a0b4

Browse files
zx2c4davem330
authored andcommitted
wireguard: queueing: preserve flow hash across packet scrubbing
It's important that we clear most header fields during encapsulation and decapsulation, because the packet is substantially changed, and we don't want any info leak or logic bug due to an accidental correlation. But, for encapsulation, it's wrong to clear skb->hash, since it's used by fq_codel and flow dissection in general. Without it, classification does not proceed as usual. This change might make it easier to estimate the number of innerflows by examining clustering of out of order packets, but this shouldn't open up anything that can't already be inferred otherwise (e.g. syn packet size inference), and fq_codel can be disabled anyway. Furthermore, it might be the case that the hash isn't used or queried at all until after wireguard transmits the encrypted UDP packet, which means skb->hash might still be zero at this point, and thus no hash taken over the inner packet data. In order to address this situation, we force a calculation of skb->hash before encrypting packet data. Of course this means that fq_codel might transmit packets slightly more out of order than usual. Toke did some testing on beefy machines with high quantities of parallel flows and found that increasing the reply-attack counter to 8192 takes care of the most pathological cases pretty well. Reported-by: Dave Taht <[email protected]> Reviewed-and-tested-by: Toke Høiland-Jørgensen <[email protected]> Fixes: e7096c1 ("net: WireGuard secure network tunnel") Signed-off-by: Jason A. Donenfeld <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent bc67d37 commit c78a0b4

File tree

4 files changed

+17
-4
lines changed

4 files changed

+17
-4
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/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: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,7 @@ int wg_packet_rx_poll(struct napi_struct *napi, int budget)
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

drivers/net/wireguard/send.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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;

0 commit comments

Comments
 (0)