From d28fbbb186b9b6e8572f89d0e3f3ab5f0c783bc5 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Sun, 4 Jul 2010 17:30:33 +0200 Subject: [PATCH] Fix race in io_output() that can lead to double-free Move call of ioq_makeiov() to its use, because calling it before empth_select() is racy, as follows. Player thread flushes output by calling io_output(player->iop, 1). io_output() sets up iov[] to point to queued output. empth_select() blocks on output. Another thread sends a C_FLASH or C_INFORM message to this player. This calls io_output(p->iop, 0). The output file descriptor has become writable since the player thread blocked on it, so some output gets written and dequeued. The player thread resumes, writes out iov[] and dequeues. Any output already written by the other thread gets duplicated. If the other thread's dequeue operation freed struct io buffers, there's use after free followed by double-free. --- src/lib/empthread/io.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib/empthread/io.c b/src/lib/empthread/io.c index 67c60520..1d78504d 100644 --- a/src/lib/empthread/io.c +++ b/src/lib/empthread/io.c @@ -209,8 +209,6 @@ io_output(struct iop *iop, int wait) if (iop->flags & IO_ERROR) return -1; - n = ioq_makeiov(iop->output, iov, IO_BUFSIZE); - if (wait) { res = empth_select(iop->fd, EMPTH_FD_WRITE, NULL); if (res == 0) @@ -221,6 +219,7 @@ io_output(struct iop *iop, int wait) } } + n = ioq_makeiov(iop->output, iov, IO_BUFSIZE); cc = writev(iop->fd, iov, n); if (cc < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK)