summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander E. Patrakov <patrakov@gmail.com>2014-06-05 22:29:25 +0600
committerWim Taymans <wtaymans@redhat.com>2014-06-06 14:38:03 +0200
commit2de05b3485f1fed05a04d6ef868ce2fbbb280fcb (patch)
treec63c8de07c8c231b2275a6fede3c1eedfb5c2f78
parentdfcb4f3a622c3399dc846f281537fb8bec481c38 (diff)
rtp-recv: fix crash on empty UDP packets (CVE-2014-3970)RHEL6-CVE-2014-3970
On FIONREAD returning 0 bytes, we cannot return success, as the caller (rtpoll_work_cb in module-rtp-recv.c) would then try to pa_memblock_unref(chunk.memblock) and, because memblock is NULL, trigger an assertion. Also we have to read out the possible empty packet from the socket, so that the kernel doesn't tell us again and again about it. Signed-off-by: Alexander E. Patrakov <patrakov@gmail.com>
-rw-r--r--src/modules/rtp/rtp.c25
1 files changed, 23 insertions, 2 deletions
diff --git a/src/modules/rtp/rtp.c b/src/modules/rtp/rtp.c
index 6706a10f7..659054294 100644
--- a/src/modules/rtp/rtp.c
+++ b/src/modules/rtp/rtp.c
@@ -183,8 +183,29 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool, struct
goto fail;
}
- if (size <= 0)
- return 0;
+ if (size <= 0) {
+ /* size can be 0 due to any of the following reasons:
+ *
+ * 1. Somebody sent us a perfectly valid zero-length UDP packet.
+ * 2. Somebody sent us a UDP packet with a bad CRC.
+ *
+ * It is unknown whether size can actually be less than zero.
+ *
+ * In the first case, the packet has to be read out, otherwise the
+ * kernel will tell us again and again about it, thus preventing
+ * reception of any further packets. So let's just read it out
+ * now and discard it later, when comparing the number of bytes
+ * received (0) with the number of bytes wanted (1, see below).
+ *
+ * In the second case, recvmsg() will fail, thus allowing us to
+ * return the error.
+ *
+ * Just to avoid passing zero-sized memchunks and NULL pointers to
+ * recvmsg(), let's force allocation of at least one byte by setting
+ * size to 1.
+ */
+ size = 1;
+ }
if (c->memchunk.length < (unsigned) size) {
size_t l;