aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2022-10-07 18:51:36 -0400
committerRich Felker <dalias@aerifal.cx>2022-10-19 14:01:32 -0400
commitd8f35e29d0e35a90f44c04de585470c211afddf9 (patch)
treea00ce19cc0fe9699ab2ad5baef543a2d621ad276
parent26c76a908b8613ea8a77d40f3bd51b02f984501c (diff)
downloadmusl-d8f35e29d0e35a90f44c04de585470c211afddf9.zip
musl-d8f35e29d0e35a90f44c04de585470c211afddf9.tar.gz
musl-d8f35e29d0e35a90f44c04de585470c211afddf9.tar.bz2
fix AS-safety of close when aio is in use and fd map is expanded
the aio operations that lead to calling __aio_get_queue with the possibility to expand the fd map are not AS-safe, but if they are interrupted by a signal handler, the signal handler may call close, which is required to be AS-safe. due to __aio_get_queue taking the write lock without blocking signals, such a call to close from a signal handler could deadlock. change __aio_get_queue to block signals if it needs to obtain a write lock, and restore when finished.
-rw-r--r--src/aio/aio.c6
1 files changed, 6 insertions, 0 deletions
diff --git a/src/aio/aio.c b/src/aio/aio.c
index 82f8ecc..d7e063b 100644
--- a/src/aio/aio.c
+++ b/src/aio/aio.c
@@ -82,6 +82,8 @@ static size_t io_thread_stack_size;
static struct aio_queue *__aio_get_queue(int fd, int need)
{
+ sigset_t allmask, origmask;
+ int masked = 0;
if (fd < 0) {
errno = EBADF;
return 0;
@@ -93,6 +95,9 @@ static struct aio_queue *__aio_get_queue(int fd, int need)
if ((!map || !map[a] || !map[a][b] || !map[a][b][c] || !(q=map[a][b][c][d])) && need) {
pthread_rwlock_unlock(&maplock);
if (fcntl(fd, F_GETFD) < 0) return 0;
+ sigfillset(&allmask);
+ masked = 1;
+ pthread_sigmask(SIG_BLOCK, &allmask, &origmask);
pthread_rwlock_wrlock(&maplock);
if (!io_thread_stack_size) {
unsigned long val = __getauxval(AT_MINSIGSTKSZ);
@@ -119,6 +124,7 @@ static struct aio_queue *__aio_get_queue(int fd, int need)
if (q) pthread_mutex_lock(&q->lock);
out:
pthread_rwlock_unlock(&maplock);
+ if (masked) pthread_sigmask(SIG_SETMASK, &origmask, 0);
return q;
}