From e17da4c1150b1f8be9071c7403163ea6fb518c6e Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Thu, 5 Dec 2019 12:15:21 +0100 Subject: Fix pthread data writer interfering with signal handling If a signal is sent to a process, the POSIX spec says that ANY thread could be picked ARBITRARILY to handle the signal. In our case this could be one of the internal worker threads. The problem here is that an unsuspecting user of the library might suddenly have their signal handler run in parallel to their main thread and run into weird concurrency issues, because they didn't expect that to happen. In fact, the libsquashfs API tries to be transparent about whether or not it uses a thread pool internally and does everything other than number crunching (e.g. I/O that may happen through user supplied callbacks) in the same thread as the one that submitts the blocks. Unfortunately, pthread doesn't have a way to set a signal mask for the new thread and setting it inside the thread is racy (i.e. a signal might be delivered before the worker thread sets the mask). The only portable and non-racy way to do this, is to disable all signals in the calling thread that sets up the data writer, create the threads (which will inherit the mask) and then resetore the previous signal mask, hoping for the best. The downside to this is that signals may be lost in that short time. Signed-off-by: David Oberhollenzer --- lib/sqfs/data_writer/internal.h | 1 + lib/sqfs/data_writer/pthread.c | 7 +++++++ 2 files changed, 8 insertions(+) (limited to 'lib') diff --git a/lib/sqfs/data_writer/internal.h b/lib/sqfs/data_writer/internal.h index d6e26cd..7af6ab4 100644 --- a/lib/sqfs/data_writer/internal.h +++ b/lib/sqfs/data_writer/internal.h @@ -24,6 +24,7 @@ #ifdef WITH_PTHREAD #include +#include #endif diff --git a/lib/sqfs/data_writer/pthread.c b/lib/sqfs/data_writer/pthread.c index 3cdf8fb..915ea2a 100644 --- a/lib/sqfs/data_writer/pthread.c +++ b/lib/sqfs/data_writer/pthread.c @@ -45,6 +45,7 @@ sqfs_data_writer_t *sqfs_data_writer_create(size_t max_block_size, sqfs_file_t *file) { sqfs_data_writer_t *proc; + sigset_t set, oldset; unsigned int i; int ret; @@ -79,6 +80,9 @@ sqfs_data_writer_t *sqfs_data_writer_create(size_t max_block_size, goto fail_init; } + sigfillset(&set); + pthread_sigmask(SIG_SETMASK, &set, &oldset); + for (i = 0; i < num_workers; ++i) { ret = pthread_create(&proc->workers[i]->thread, NULL, worker_proc, proc->workers[i]); @@ -87,6 +91,8 @@ sqfs_data_writer_t *sqfs_data_writer_create(size_t max_block_size, goto fail_thread; } + pthread_sigmask(SIG_SETMASK, &oldset, NULL); + return proc; fail_thread: pthread_mutex_lock(&proc->mtx); @@ -99,6 +105,7 @@ fail_thread: pthread_join(proc->workers[i]->thread, NULL); } } + pthread_sigmask(SIG_SETMASK, &oldset, NULL); fail_init: for (i = 0; i < num_workers; ++i) { if (proc->workers[i] != NULL) { -- cgit v1.2.3