From 492341db77302730aab9d47a2581bb575ca6465d Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Thu, 14 Jun 2012 18:31:51 +0100 Subject: [PATCH] oggdemux: fix quadratic search for last page A crafted file with invalid pages will cause repeated searches from earlier offsets in steps of 8500 bytes, but reading till the end of the stream. Since we know the maximum size of an Ogg page, we can bound the search for next page, to get a linear behavior (though still not good enough as it will read the entire file backwards if there's no valid page till then). --- ext/ogg/gstoggdemux.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/ext/ogg/gstoggdemux.c b/ext/ogg/gstoggdemux.c index 031c25d860..e50db334dc 100644 --- a/ext/ogg/gstoggdemux.c +++ b/ext/ogg/gstoggdemux.c @@ -56,6 +56,10 @@ /* stop duration checks within this much of EOS */ #define EOS_AVOIDANCE_THRESHOLD 8192 +/* An Ogg page can not be larger than 255 segments of 255 bytes, plus + 26 bytes of header */ +#define MAX_OGG_PAGE_SIZE (255 * 255 + 26) + #define GST_FLOW_LIMIT GST_FLOW_CUSTOM_ERROR #define GST_FLOW_SKIP_PUSH GST_FLOW_CUSTOM_SUCCESS_1 @@ -2397,10 +2401,18 @@ gst_ogg_demux_get_prev_page (GstOggDemux * ogg, ogg_page * og, gint64 * offset) * start, we save it. It might not be the final page as there could be * another page after this one. */ while (ogg->offset < end) { - gint64 new_offset; + gint64 new_offset, boundary; - ret = - gst_ogg_demux_get_next_page (ogg, og, end - ogg->offset, &new_offset); + /* An Ogg page cannot be more than a bit less than 64 KB, so we can + bound the boundary to that size when searching backwards if we + haven't found a page yet. So the most we have to look at is twice + the max page size, which is the worst case if we start scanning + just after a large page, after which also lies a large page. */ + boundary = end - ogg->offset; + if (boundary > 2 * MAX_OGG_PAGE_SIZE) + boundary = 2 * MAX_OGG_PAGE_SIZE; + + ret = gst_ogg_demux_get_next_page (ogg, og, boundary, &new_offset); /* we hit the upper limit, offset contains the last page start */ if (ret == GST_FLOW_LIMIT) { GST_LOG_OBJECT (ogg, "hit limit");