diff options
author | Jason A. Donenfeld <Jason@zx2c4.com> | 2021-05-03 16:31:25 +0200 |
---|---|---|
committer | Jason A. Donenfeld <Jason@zx2c4.com> | 2021-05-03 19:54:39 +0200 |
commit | 561f3a8f930cf2e44f493fa04d932ba9a2362cc5 (patch) | |
tree | 0adc4943df4c61f0f0e2c8a92673b590a742cc22 | |
parent | if_wg: put event notifiers in main loop (diff) | |
download | wireguard-freebsd-561f3a8f930cf2e44f493fa04d932ba9a2362cc5.tar.xz wireguard-freebsd-561f3a8f930cf2e44f493fa04d932ba9a2362cc5.zip |
wg_noise: set handshake to dead before removing keypair
Otherwise CK_LIST_REMOVE might be called twice on the same element.
Running the following trigger will reproduce the bug that Manojav
reported:
#!/usr/local/bin/bash
NUM_PEER=50
peer_args=( )
for ((i=0; i<NUM_PEER; i++)); do
port="$RANDOM"
private="$(wg genkey)"
ifconfig "wg$i" create
wg set "wg$i" listen-port "$port" private-key <(echo "$private")
peer_args+=( peer "$(wg pubkey <<<"$private")" endpoint "127.0.0.1:$port" persistent-keepalive 1 )
done
for ((i=0; i<NUM_PEER; i++)); do
wg set "wg$i" "${peer_args[@]}"
ifconfig "wg$i" up
done
wg
while true; do
for ((i=0; i<NUM_PEER; i++)); do
ifconfig "wg$i" down
ifconfig "wg$i" up
done
done
Reported-by: Manojav Sridhar <manojav@manojav.com>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
-rw-r--r-- | src/wg_noise.c | 5 |
1 files changed, 3 insertions, 2 deletions
diff --git a/src/wg_noise.c b/src/wg_noise.c index cb9f525..41f7f50 100644 --- a/src/wg_noise.c +++ b/src/wg_noise.c @@ -445,9 +445,9 @@ noise_remote_index_remove(struct noise_local *l, struct noise_remote *r) rw_assert(&r->r_handshake_lock, RA_WLOCKED); if (r->r_handshake_state != HANDSHAKE_DEAD) { rw_wlock(&l->l_index_lock); + r->r_handshake_state = HANDSHAKE_DEAD; CK_LIST_REMOVE(&r->r_index, i_entry); rw_wunlock(&l->l_index_lock); - r->r_handshake_state = HANDSHAKE_DEAD; return (1); } return (0); @@ -634,6 +634,7 @@ noise_add_new_keypair(struct noise_local *l, struct noise_remote *r, rw_wlock(&l->l_index_lock); CK_LIST_INSERT_BEFORE(r_i, &kp->kp_index, i_entry); + r->r_handshake_state = HANDSHAKE_DEAD; CK_LIST_REMOVE(r_i, i_entry); rw_wunlock(&l->l_index_lock); @@ -1346,7 +1347,7 @@ noise_tai64n_now(uint8_t output[NOISE_TIMESTAMP_LEN]) memcpy(output + sizeof(sec), &nsec, sizeof(nsec)); } -static __inline int +static inline int noise_timer_expired(sbintime_t timer, uint32_t sec, uint32_t nsec) { sbintime_t now = getsbinuptime(); |