]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Don't read from a disarmed or invalid timerfd
authorTerry Wilson <twilson@digium.com>
Wed, 17 Aug 2011 17:35:27 +0000 (17:35 +0000)
committerTerry Wilson <twilson@digium.com>
Wed, 17 Aug 2011 17:35:27 +0000 (17:35 +0000)
Numerous isues have been reported for deadlocks that are caused by
a blocking read in res_timing_timerfd on a file descriptor that will
never be written to. This patch adds some checks to make sure that
the timerfd is both valid and armed before calling read().

Should fix: ASTERISK-18142, ASTERISK-18197, ASTERISK-18166, AST-486
AST-495, AST-507 and possibly others.

Review: https://reviewboard.asterisk.org/r/1361/

git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.8@332320 65c4cc65-6c06-0410-ace0-fbb531ad65f3

res/res_timing_timerfd.c

index 80e5ca8a59ecd49234436c16862aa9302ca63547..81331a99faef515fd17a92ccab9c319583241006 100644 (file)
@@ -162,8 +162,32 @@ static void timerfd_timer_ack(int handle, unsigned int quantity)
 {
        uint64_t expirations;
        int read_result = 0;
+       struct timerfd_timer *our_timer, find_helper = {
+               .handle = handle,
+       };
+
+       if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) {
+               ast_log(LOG_ERROR, "Couldn't find a timer with handle %d\n", handle);
+               return;
+       }
+
+       ao2_lock(our_timer);
 
        do {
+               struct itimerspec timer_status;
+
+               if (timerfd_gettime(handle, &timer_status)) {
+                       ast_log(LOG_ERROR, "Call to timerfd_gettime() error: %s\n", strerror(errno));
+                       expirations = 0;
+                       break;
+               }
+
+               if (timer_status.it_value.tv_sec == 0 && timer_status.it_value.tv_nsec == 0) {
+                       ast_debug(1, "Avoiding read on disarmed timerfd %d\n", handle);
+                       expirations = 0;
+                       break;
+               }
+
                read_result = read(handle, &expirations, sizeof(expirations));
                if (read_result == -1) {
                        if (errno == EINTR || errno == EAGAIN) {
@@ -175,6 +199,9 @@ static void timerfd_timer_ack(int handle, unsigned int quantity)
                }
        } while (read_result != sizeof(expirations));
 
+       ao2_unlock(our_timer);
+       ao2_ref(our_timer, -1);
+
        if (expirations != quantity) {
                ast_debug(2, "Expected to acknowledge %u ticks but got %llu instead\n", quantity, (unsigned long long) expirations);
        }