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 | |
| 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')
| -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;  }  | 
