Chris Boot [Thu, 23 Nov 2017 14:27:27 +0000 (14:27 +0000)]
tinysvcmdns: fix CVE-2017-12087
This patch incorporates upstream's fixes for a remotely exploitable
buffer overflow bug in the bundled tinysvcmdns library. The following
upstream commits are included:
Belbo [Tue, 15 Aug 2017 20:00:57 +0000 (22:00 +0200)]
Fixed race condition when stopping other threads with SIGUSR1
Many threads have a main loop that checks some exit variable in the loop condition. To stop a thread, another thread sets that exit variable, sends a SIGUSR1 to that thread to get it out of blocking calls like read(), write() or select(), and finally joins it.
There was a race condition though: if the signal arrived after the loop condition was checked but before the blocking system function was entered, the target thread essentially ignored the signal, made the blocking call anyway, and could get stuck forever there.
The only way around this race condition is to block SIGUSR1 in the destination thread during the critical time interval. This requires that the blocking system call and the call to unblock SIGUSR1 be an atomic unit. There is only one system call that makes this possible: pselect(), which takes a signal mask to replace the current signal mask with, but only while pselect() runs. Other functions like read(), recv(), write() and sendto() may only be called if we can be sure that they don't block. For this purpose, the file descriptors must be set to non-blocking mode and we must prepend the call to them with a call to pselect() to block until the socket becomes readable/writable.
Belbo [Tue, 15 Aug 2017 19:51:47 +0000 (21:51 +0200)]
Fixed loop condition in non_blocking_write()
The while loop should be repeated, if the last write attempt was a partial write only. In this case, however, rc is greater than 0 (should be 1), not equal to 0.
Belbo [Mon, 7 Aug 2017 21:49:19 +0000 (23:49 +0200)]
Fixed dangling pointer to random state array
The C library function initstate(), at least in macOS El Capitan, not only sets the state array given to it as the second argument, but also accesses the state array given to it in a previous call! (I don't know why, or if that behaviour is correct, but macOS seems to do that anyhow).
Therefore, we cannot pass a local variable to it. As soon as the player thread stops, it will be a dangling pointer, and when a new player thread is started afterwards, initstate() will dereference that dangling pointer with unforeseeable consequences.
Belbo [Mon, 7 Aug 2017 21:42:51 +0000 (23:42 +0200)]
handle_announce() waits for playing_conn to stop if it's already shutting down
- If playing_conn is already stopping, handle_announce() waits one second for it to stop. This gives the current RTSP connection a better chance to get the player, if it has been started very quickly after the previous RTSP connection had decided to stop. iTunes can sometimes be very quick in starting a new RTSP connection after tearing down the previous one, but shairport_sync unfortunately needs at least 100ms to shut down the old connection.
- cleanup_threads() sets playing_conn to NULL if it points to the removed thread, otherwise playing_conn would be a dangling pointer, which is bad, because handle_announce() dereferences it unless it is NULL.
die(), warn(), debug() and inform() write the string into a limited internal buffer first. They now use vsnprintf() instead of vsprintf() to prevent an overflow of that buffer.
Mike Brady [Tue, 26 Sep 2017 15:03:07 +0000 (16:03 +0100)]
Merge pull request #594 from nbgl/dev-linear-volume
Fix volume bug.
Many thanks for this. I think that in the past the program used to terminate in this case and I changed it to simply continuing and, inadvertently, to failing silently!