diff options
author | Wim Taymans <wim.taymans@collabora.co.uk> | 2010-09-07 13:51:37 +0200 |
---|---|---|
committer | Wim Taymans <wim.taymans@collabora.co.uk> | 2010-09-07 13:56:53 +0200 |
commit | 6be0c7b7626a30ef3479e2032599271f0f3f17ab (patch) | |
tree | 6226b8b3f369c9717c234474cfe242a5050840c3 | |
parent | f604e20499901bdaf3cf136b9cf383d66c422d9a (diff) |
vrawdepay: handle invalid payload better
Make sure we don't read more data than available in the input buffer.
Clip the input data into the output buffer.
-rw-r--r-- | gst/rtp/gstrtpvrawdepay.c | 147 |
1 files changed, 102 insertions, 45 deletions
diff --git a/gst/rtp/gstrtpvrawdepay.c b/gst/rtp/gstrtpvrawdepay.c index 77ca7979f..70d5f8118 100644 --- a/gst/rtp/gstrtpvrawdepay.c +++ b/gst/rtp/gstrtpvrawdepay.c @@ -266,9 +266,10 @@ static GstBuffer * gst_rtp_vraw_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { GstRtpVRawDepay *rtpvrawdepay; - guint8 *payload, *data, *yp, *up, *vp, *headers; + guint8 *payload, *data, *dataend, *yp, *up, *vp, *headers; guint32 timestamp; - guint cont, ystride, uvstride, pgroup; + guint cont, ystride, uvstride, pgroup, payload_len, size; + gint width, height, xinc, yinc; rtpvrawdepay = GST_RTP_VRAW_DEPAY (depayload); @@ -299,6 +300,8 @@ gst_rtp_vraw_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) } data = GST_BUFFER_DATA (rtpvrawdepay->outbuf); + size = GST_BUFFER_SIZE (rtpvrawdepay->outbuf); + dataend = data + size; /* get pointer and strides of the planes */ yp = data + rtpvrawdepay->yp; @@ -308,41 +311,79 @@ gst_rtp_vraw_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) ystride = rtpvrawdepay->ystride; uvstride = rtpvrawdepay->uvstride; pgroup = rtpvrawdepay->pgroup; + width = rtpvrawdepay->width; + height = rtpvrawdepay->height; + xinc = rtpvrawdepay->xinc; + yinc = rtpvrawdepay->yinc; payload = gst_rtp_buffer_get_payload (buf); + payload_len = gst_rtp_buffer_get_payload_len (buf); + + if (payload_len < 3) + goto short_packet; /* skip extended seqnum */ - payload++; - payload++; + payload += 2; + payload_len -= 2; /* remember header position */ headers = payload; /* find data start */ do { + if (payload_len < 6) + goto short_packet; + cont = payload[4] & 0x80; + payload += 6; + payload_len -= 6; } while (cont); while (TRUE) { - guint length, line, offs; + guint length, line, offs, plen; guint8 *datap; - /* read length and cont */ + /* stop when we run out of data */ + if (payload_len == 0) + break; + + /* read length and cont. This should work because we iterated the headers + * above. */ length = (headers[0] << 8) | headers[1]; line = ((headers[2] & 0x7f) << 8) | headers[3]; offs = ((headers[4] & 0x7f) << 8) | headers[5]; cont = headers[4] & 0x80; headers += 6; + /* length must be a multiple of pgroup */ + if (length % pgroup != 0) + goto wrong_length; + + if (length > payload_len) + length = payload_len; + /* sanity check */ - if (line > (rtpvrawdepay->height - rtpvrawdepay->yinc)) - continue; - if (offs > (rtpvrawdepay->width - rtpvrawdepay->xinc)) - continue; + if (line > (height - yinc)) { + GST_WARNING_OBJECT (depayload, "skipping line %d: out of range", line); + goto next; + } + if (offs > (width - xinc)) { + GST_WARNING_OBJECT (depayload, "skipping offset %d: out of range", offs); + goto next; + } + + /* calculate the maximim amount of bytes we can use per line */ + if (offs + ((length / pgroup) * xinc) > (width - xinc)) { + plen = ((width - offs) * pgroup) / xinc; + GST_WARNING_OBJECT (depayload, "clipping length %d, offset %d", length, + offs); + } else + plen = length; - GST_LOG_OBJECT (depayload, "writing length %u, line %u, offset %u", length, - line, offs); + GST_LOG_OBJECT (depayload, + "writing length %u/%u, line %u, offset %u, remaining %u", plen, length, + line, offs, payload_len); switch (rtpvrawdepay->format) { case GST_VIDEO_FORMAT_RGB: @@ -351,25 +392,27 @@ gst_rtp_vraw_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) case GST_VIDEO_FORMAT_BGRA: case GST_VIDEO_FORMAT_UYVY: /* samples are packed just like gstreamer packs them */ - offs /= rtpvrawdepay->xinc; + offs /= xinc; datap = yp + (line * ystride) + (offs * pgroup); - memcpy (datap, payload, length); - payload += length; + + memcpy (datap, payload, plen); break; case GST_VIDEO_FORMAT_AYUV: { gint i; + guint8 *p; datap = yp + (line * ystride) + (offs * 4); + p = payload; /* samples are packed in order Cb-Y-Cr for both interlaced and * progressive frames */ - for (i = 0; i < length; i += pgroup) { + for (i = 0; i < plen; i += pgroup) { *datap++ = 0; - *datap++ = payload[1]; - *datap++ = payload[0]; - *datap++ = payload[2]; - payload += pgroup; + *datap++ = p[1]; + *datap++ = p[0]; + *datap++ = p[2]; + p += pgroup; } break; } @@ -377,25 +420,25 @@ gst_rtp_vraw_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { gint i; guint uvoff; - guint8 *yd1p, *yd2p, *udp, *vdp; + guint8 *yd1p, *yd2p, *udp, *vdp, *p; yd1p = yp + (line * ystride) + (offs); yd2p = yd1p + ystride; - uvoff = - (line / rtpvrawdepay->yinc * uvstride) + - (offs / rtpvrawdepay->xinc); + uvoff = (line / yinc * uvstride) + (offs / xinc); + udp = up + uvoff; vdp = vp + uvoff; + p = payload; /* line 0/1: Y00-Y01-Y10-Y11-Cb00-Cr00 Y02-Y03-Y12-Y13-Cb01-Cr01 ... */ - for (i = 0; i < length; i += pgroup) { - *yd1p++ = payload[0]; - *yd1p++ = payload[1]; - *yd2p++ = payload[2]; - *yd2p++ = payload[3]; - *udp++ = payload[4]; - *vdp++ = payload[5]; - payload += pgroup; + for (i = 0; i < plen; i += pgroup) { + *yd1p++ = p[0]; + *yd1p++ = p[1]; + *yd2p++ = p[2]; + *yd2p++ = p[3]; + *udp++ = p[4]; + *vdp++ = p[5]; + p += pgroup; } break; } @@ -403,25 +446,25 @@ gst_rtp_vraw_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { gint i; guint uvoff; - guint8 *ydp, *udp, *vdp; + guint8 *ydp, *udp, *vdp, *p; ydp = yp + (line * ystride) + (offs); - uvoff = - (line / rtpvrawdepay->yinc * uvstride) + - (offs / rtpvrawdepay->xinc); + uvoff = (line / yinc * uvstride) + (offs / xinc); + udp = up + uvoff; vdp = vp + uvoff; + p = payload; /* Samples are packed in order Cb0-Y0-Y1-Cr0-Y2-Y3 for both interlaced * and progressive scan lines */ - for (i = 0; i < length; i += pgroup) { - *udp++ = payload[0]; - *ydp++ = payload[1]; - *ydp++ = payload[2]; - *vdp++ = payload[3]; - *ydp++ = payload[4]; - *ydp++ = payload[5]; - payload += pgroup; + for (i = 0; i < plen; i += pgroup) { + *udp++ = p[0]; + *ydp++ = p[1]; + *ydp++ = p[2]; + *vdp++ = p[3]; + *ydp++ = p[4]; + *ydp++ = p[5]; + p += pgroup; } break; } @@ -429,8 +472,12 @@ gst_rtp_vraw_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) goto unknown_sampling; } + next: if (!cont) break; + + payload += length; + payload_len -= length; } if (gst_rtp_buffer_get_marker (buf)) { @@ -453,7 +500,17 @@ unknown_sampling: } alloc_failed: { - GST_DEBUG_OBJECT (depayload, "failed to alloc output buffer"); + GST_WARNING_OBJECT (depayload, "failed to alloc output buffer"); + return NULL; + } +wrong_length: + { + GST_WARNING_OBJECT (depayload, "length not multiple of pgroup"); + return NULL; + } +short_packet: + { + GST_WARNING_OBJECT (depayload, "short packet"); return NULL; } } |