diff options
author | Dimitri Staessens <dimitri@ouroboros.rocks> | 2022-02-20 21:56:17 +0100 |
---|---|---|
committer | Sander Vrijders <sander@ouroboros.rocks> | 2022-02-21 09:05:27 +0100 |
commit | 21f6b43ed597999deda967ea6baf0b2859c517da (patch) | |
tree | d7239fa18f28385c661e09aab487d0f2b6fcc4a0 /src/ipcpd/eth/eth.c | |
parent | d30154086afa32df203606817ed4d614cbe37b31 (diff) | |
download | ouroboros-21f6b43ed597999deda967ea6baf0b2859c517da.tar.gz ouroboros-21f6b43ed597999deda967ea6baf0b2859c517da.zip |
ipcpd: Fix potential double unlock in eth
When handling management frames, there was a cancellation point after
the unlock, which would cause the cleanup handler to attempt a double
unlock if the thread was cancelled at that point.
Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks>
Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
Diffstat (limited to 'src/ipcpd/eth/eth.c')
-rw-r--r-- | src/ipcpd/eth/eth.c | 38 |
1 files changed, 15 insertions, 23 deletions
diff --git a/src/ipcpd/eth/eth.c b/src/ipcpd/eth/eth.c index 932034d5..e22dd7bc 100644 --- a/src/ipcpd/eth/eth.c +++ b/src/ipcpd/eth/eth.c @@ -799,51 +799,43 @@ static int eth_ipcp_mgmt_frame(const uint8_t * buf, static void * eth_ipcp_mgmt_handler(void * o) { - int ret; - struct timespec timeout = {(MGMT_TIMEO / 1000), - (MGMT_TIMEO % 1000) * MILLION}; - struct timespec abstime; - struct mgmt_frame * frame; - (void) o; - pthread_cleanup_push(__cleanup_mutex_unlock, ð_data.mgmt_lock); - while (true) { - ret = 0; + int ret = 0; + struct timespec timeout = {(MGMT_TIMEO / 1000), + (MGMT_TIMEO % 1000) * MILLION}; + struct timespec abstime; + struct mgmt_frame * frame = NULL; clock_gettime(PTHREAD_COND_CLOCK, &abstime); ts_add(&abstime, &timeout, &abstime); pthread_mutex_lock(ð_data.mgmt_lock); + pthread_cleanup_push(__cleanup_mutex_unlock, + ð_data.mgmt_lock); while (list_is_empty(ð_data.mgmt_frames) && ret != -ETIMEDOUT) ret = -pthread_cond_timedwait(ð_data.mgmt_cond, ð_data.mgmt_lock, &abstime); + if (ret != -ETIMEDOUT) + frame = list_first_entry((ð_data.mgmt_frames), + struct mgmt_frame, next); + if (frame != NULL) + list_del(&frame->next); - if (ret == -ETIMEDOUT) { - pthread_mutex_unlock(ð_data.mgmt_lock); - continue; - } + pthread_cleanup_pop(true); - frame = list_first_entry((ð_data.mgmt_frames), - struct mgmt_frame, next); - if (frame == NULL) { - pthread_mutex_unlock(ð_data.mgmt_lock); + if (frame == NULL) continue; - } - - list_del(&frame->next); - pthread_mutex_unlock(ð_data.mgmt_lock); eth_ipcp_mgmt_frame(frame->buf, frame->len, frame->r_addr); + free(frame); } - pthread_cleanup_pop(false); - return (void *) 0; } |