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>
This commit is contained in:
Jason A. Donenfeld 2021-05-03 16:31:25 +02:00
parent 280bee380d
commit 561f3a8f93
1 changed files with 3 additions and 2 deletions

View File

@ -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();