[pulseaudio-discuss] Remotely triggerable crash in module-rtp-recv

Alexander E. Patrakov patrakov at gmail.com
Sat May 31 10:03:25 PDT 2014


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
  * A system with PulseAudio 5.0 and microphone, with IP address
  * 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


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 

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.


Alexander E. Patrakov

More information about the pulseaudio-discuss mailing list