[pulseaudio-discuss] Remotely triggerable crash in module-rtp-recv
Alexander E. Patrakov
patrakov at gmail.com
Sat May 31 10:03:25 PDT 2014
Hello.
While looking at module-rtp-recv source, I found some suspicious use of
the FIONREAD ioctl (see below). I was going to test this bug, expecting
to find an infinite loop (as it would be common for such FIONREAD
misuse), but found an assertion failure instead. So there may be two bugs.
Assume that you have this kind of network:
* A system with PulseAudio 5.0 and speakers, with the IP address
169.254.7.181.
* A system with PulseAudio 5.0 and microphone, with IP address
169.254.10.194.
* Avahi running on both systems, not sure if this is relevant.
On the system with the microphone: pacmd load-module module-rtp-send
On the system with speakers: pacmd load-module module-rtp-recv
As a result, some multicast packets will flow from the system with
microphone to the system with speakers.
And now an attacker can crash PulseAudio on the system with speakers
from the third host. All he needs to do is to figure out the correct
source and destination ports (trivially done with tcpdump, let's suppose
they are 59405 and 46402), and then to send an empty UDP packet to the
multicast address:
# nping --udp --dest-port 46402 --source-port 59405 --data-string ''
--privileged --send-ip --source-ip 169.254.10.194 224.0.0.56
Result:
E: [alsa-sink-ALC275 Analog] memblock.c: Assertion 'b' failed at
.../pulseaudio-5.0/src/pulsecore/memblock.c:596, function
pa_memblock_unref(). Aborting.
And here is what I expected and why.
Please see src/modules/rtp/rtp.c, function pa_rtp_recv.
The first thing it does with the socket is to call the FIONREAD ioctl in
order to see the size of the next incoming datagram (presumably after
getting the rtpoll notification that there is, in fact, something to
read). Then it looks whether there was an error. Then it compares: size
<= 0. And if size is indeed <= 0, it just returns, without doing
anything more with the socket or the memblock. Not even the same cleanup
as after the "fail:" label (but I am not sure what cleanup is needed at
this point).
And comparison of the FIONREAD output with 0 is a very dangerous thing
on UDP sockets, because it could mean two completely different things.
1. There is in fact nothing to read - e.g. there was a badly-checksummed
packet.
2. There is in fact a packet to read! A well-formed zero-sized packet.
You have to receive it for the poll/epoll to stop bothering you about it
again and again.
PulseAudio does not attempt to distinguish between these two cases, and
does not attempt to receive the resulting packet. See CVE-2011-1002 for
a similar bug in Avahi.
http://xorl.wordpress.com/2011/02/20/cve-2011-1002-avahi-daemon-remote-denial-of-service/
--
Alexander E. Patrakov
More information about the pulseaudio-discuss
mailing list