From: Juergen Perlinger Date: Mon, 18 Apr 2016 04:07:25 +0000 (+0200) Subject: [Bug 2831] Segmentation Fault in DNS lookup during startup. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=89e58c3746f9082ae2dcde13adb4b9ebb618d21b;p=thirdparty%2Fntp.git [Bug 2831] Segmentation Fault in DNS lookup during startup. - fixed yet another race condition in the threaded resolver code. bk: 57145d7dZelIoPAI7f2C_7HLVzESCg --- diff --git a/ChangeLog b/ChangeLog index c70fe8fc5..6b2918084 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ --- +* [Bug 2831] Segmentation Fault in DNS lookup during startup. perlinger@ntp.org + - fixed yet another race condition in the threaded resolver code. * [Bug 2994] Systems with HAVE_SIGNALED_IO fail to compile. perlinger@ntp.org * [Bug 2995] Fixes to compile on Windows diff --git a/include/ntp_worker.h b/include/ntp_worker.h index bc833795b..49ffef4cf 100644 --- a/include/ntp_worker.h +++ b/include/ntp_worker.h @@ -171,6 +171,8 @@ extern void close_all_except(int); extern void kill_asyncio (int); #endif +extern void worker_global_lock(int inOrOut); + # ifdef WORK_PIPE typedef void (*addremove_io_fd_func)(int, int, int); extern addremove_io_fd_func addremove_io_fd; diff --git a/libntp/ntp_intres.c b/libntp/ntp_intres.c index b0f562036..0b5bb7534 100644 --- a/libntp/ntp_intres.c +++ b/libntp/ntp_intres.c @@ -201,8 +201,6 @@ static time_t next_res_init; /* === forward declarations === */ static u_int reserve_dnschild_ctx(void); static u_int get_dnschild_ctx(void); -static void alloc_dnsworker_context(u_int); -/* static void free_dnsworker_context(u_int); */ static dnsworker_ctx * get_worker_context(blocking_child *, u_int); static void scheduled_sleep(time_t, time_t, dnsworker_ctx *); @@ -949,47 +947,41 @@ get_dnschild_ctx(void) } -static void -alloc_dnsworker_context( - u_int idx - ) -{ - const size_t worker_context_sz = sizeof(*dnsworker_contexts[0]); - - REQUIRE(NULL == dnsworker_contexts[idx]); - dnsworker_contexts[idx] = emalloc_zero(worker_context_sz); -} - - static dnsworker_ctx * get_worker_context( blocking_child * c, u_int idx ) { - static size_t ps = sizeof(dnsworker_contexts[0]); - u_int min_new_alloc; - u_int new_alloc; - size_t octets; - size_t new_octets; + u_int min_new_alloc; + u_int new_alloc; + size_t octets; + size_t new_octets; + dnsworker_ctx * retv; + worker_global_lock(TRUE); + if (dnsworker_contexts_alloc <= idx) { min_new_alloc = 1 + idx; /* round new_alloc up to nearest multiple of 4 */ new_alloc = (min_new_alloc + 4) & ~(4 - 1); - new_octets = new_alloc * ps; - octets = dnsworker_contexts_alloc * ps; + new_octets = new_alloc * sizeof(dnsworker_ctx*); + octets = dnsworker_contexts_alloc * sizeof(dnsworker_ctx*); dnsworker_contexts = erealloc_zero(dnsworker_contexts, new_octets, octets); dnsworker_contexts_alloc = new_alloc; + retv = emalloc_zero(sizeof(dnsworker_ctx)); + dnsworker_contexts[idx] = retv; + } else if (NULL == (retv = dnsworker_contexts[idx])) { + retv = emalloc_zero(sizeof(dnsworker_ctx)); + dnsworker_contexts[idx] = retv; } - - if (NULL == dnsworker_contexts[idx]) - alloc_dnsworker_context(idx); - ZERO(*dnsworker_contexts[idx]); - dnsworker_contexts[idx]->c = c; - - return dnsworker_contexts[idx]; + + worker_global_lock(FALSE); + + ZERO(*retv); + retv->c = c; + return retv; } diff --git a/libntp/work_fork.c b/libntp/work_fork.c index 96c550e98..5d72d8ced 100644 --- a/libntp/work_fork.c +++ b/libntp/work_fork.c @@ -540,6 +540,11 @@ fork_blocking_child( } +void worker_global_lock(int inOrOut) +{ + (void)inOrOut; +} + #else /* !WORK_FORK follows */ char work_fork_nonempty_compilation_unit; #endif diff --git a/libntp/work_thread.c b/libntp/work_thread.c index 11e3267d4..82f6064fb 100644 --- a/libntp/work_thread.c +++ b/libntp/work_thread.c @@ -88,7 +88,27 @@ static int ensure_workresp_empty_slot(blocking_child *); static int queue_req_pointer(blocking_child *, blocking_pipe_header *); static void cleanup_after_child(blocking_child *); +static sema_type worker_mmutex; +static sem_ref worker_memlock; +/* -------------------------------------------------------------------- + * locking the global worker state table (and other global stuff) + */ +void +worker_global_lock( + int inOrOut) +{ + if (worker_memlock) { + if (inOrOut) + wait_for_sem(worker_memlock, NULL); + else + tickle_sem(worker_memlock); + } +} + +/* -------------------------------------------------------------------- + * implementation isolation wrapper + */ void exit_worker( int exitcode @@ -724,6 +744,9 @@ prepare_child_sems( blocking_child *c ) { + if (NULL == worker_memlock) + worker_memlock = create_sema(&worker_mmutex, 1, 1); + c->accesslock = create_sema(&c->sem_table[0], 1, 1); c->workitems_pending = create_sema(&c->sem_table[1], 0, 0); c->wake_scheduled_sleep = create_sema(&c->sem_table[2], 0, 1);