mpdparser: add some checks to duration parsing

https://bugzilla.gnome.org/show_bug.cgi?id=752336
This commit is contained in:
Vincent Penquerc'h 2015-11-02 10:25:38 +00:00
parent 7dca9fb3f4
commit 045a03c14a

View File

@ -940,36 +940,50 @@ convert_to_millisecs (guint decimals, gint pos)
} }
static gboolean static gboolean
gst_mpdparser_get_xml_prop_duration (xmlNode * a_node, accumulate (guint64 * v, guint64 mul, guint64 add)
const gchar * property_name, guint64 default_value, {
guint64 * property_value) guint64 tmp;
if (*v > G_MAXUINT64 / mul)
return FALSE;
tmp = *v * mul;
if (tmp > G_MAXUINT64 - add)
return FALSE;
*v = tmp + add;
return TRUE;
}
static gboolean
gst_mpdparser_parse_duration (const char *str, guint64 * value)
{ {
xmlChar *prop_string;
gchar *str;
gint ret, len, pos, posT; gint ret, len, pos, posT;
gint years = -1, months = -1, days = -1, hours = -1, minutes = -1, seconds = gint years = -1, months = -1, days = -1, hours = -1, minutes = -1, seconds =
-1, decimals = -1, read; -1, decimals = -1, read;
gboolean have_ms = FALSE; gboolean have_ms = FALSE;
gboolean exists = FALSE; guint64 tmp_value;
*property_value = default_value; len = strlen (str);
prop_string = xmlGetProp (a_node, (const xmlChar *) property_name);
if (prop_string) {
len = xmlStrlen (prop_string);
str = (gchar *) prop_string;
GST_TRACE ("duration: %s, len %d", str, len); GST_TRACE ("duration: %s, len %d", str, len);
if (strchr (str, '-') != NULL) { if (strspn (str, "PT0123456789., \tHMDSY") < len) {
GST_WARNING ("'-' sign found while parsing unsigned duration"); GST_WARNING ("Invalid character found: '%s'", str);
goto error; goto error;
} }
/* skip leading/trailing whitespace */
while (strchr (" \t", str[0])) {
str++;
len--;
}
while (len > 0 && strchr (" \t", str[len - 1]))
--len;
/* read "P" for period */ /* read "P" for period */
pos = strcspn (str, "P"); if (str[0] != 'P') {
if (pos != 0) {
GST_WARNING ("P not found at the beginning of the string!"); GST_WARNING ("P not found at the beginning of the string!");
goto error; goto error;
} }
str++; str++;
len--; len--;
/* read "T" for time (if present) */ /* read "T" for time (if present) */
posT = strcspn (str, "T"); posT = strcspn (str, "T");
len -= posT; len -= posT;
@ -998,6 +1012,10 @@ gst_mpdparser_get_xml_prop_duration (xmlNode * a_node,
goto error; goto error;
} }
months = read; months = read;
if (months >= 12) {
GST_WARNING ("Month out of range");
goto error;
}
break; break;
case 'D': case 'D':
if (days != -1) { if (days != -1) {
@ -1005,6 +1023,10 @@ gst_mpdparser_get_xml_prop_duration (xmlNode * a_node,
goto error; goto error;
} }
days = read; days = read;
if (days >= 31) {
GST_WARNING ("Day out of range");
goto error;
}
break; break;
default: default:
GST_WARNING ("unexpected char %c!", str[pos]); GST_WARNING ("unexpected char %c!", str[pos]);
@ -1033,7 +1055,7 @@ gst_mpdparser_get_xml_prop_duration (xmlNode * a_node,
pos = 0; pos = 0;
if (pos < len) { if (pos < len) {
/* T found, there is a time section */ /* T found, there is a time section */
/* read hours, minutes, seconds, cents of second */ /* read hours, minutes, seconds, hundredths of second */
do { do {
GST_TRACE ("parsing substring %s", str); GST_TRACE ("parsing substring %s", str);
pos = strcspn (str, "HMS,."); pos = strcspn (str, "HMS,.");
@ -1049,6 +1071,10 @@ gst_mpdparser_get_xml_prop_duration (xmlNode * a_node,
goto error; goto error;
} }
hours = read; hours = read;
if (hours >= 24) {
GST_WARNING ("Hour out of range");
goto error;
}
break; break;
case 'M': case 'M':
if (minutes != -1 || seconds != -1) { if (minutes != -1 || seconds != -1) {
@ -1056,6 +1082,10 @@ gst_mpdparser_get_xml_prop_duration (xmlNode * a_node,
goto error; goto error;
} }
minutes = read; minutes = read;
if (minutes >= 60) {
GST_WARNING ("Minute out of range");
goto error;
}
break; break;
case 'S': case 'S':
if (have_ms) { if (have_ms) {
@ -1103,14 +1133,46 @@ gst_mpdparser_get_xml_prop_duration (xmlNode * a_node,
decimals = 0; decimals = 0;
GST_TRACE ("H:M:S.MS=%d:%d:%d.%03d", hours, minutes, seconds, decimals); GST_TRACE ("H:M:S.MS=%d:%d:%d.%03d", hours, minutes, seconds, decimals);
xmlFree (prop_string); tmp_value = 0;
exists = TRUE; if (!accumulate (&tmp_value, 1, years)
*property_value = || !accumulate (&tmp_value, 365, months * 30)
(((((guint64) years * 365 + months * 30 + days) * 24 + || !accumulate (&tmp_value, 1, days)
hours) * 60 + minutes) * 60 + seconds) * 1000 + decimals; || !accumulate (&tmp_value, 24, hours)
GST_LOG (" - %s: %" G_GUINT64_FORMAT, property_name, *property_value); || !accumulate (&tmp_value, 60, minutes)
|| !accumulate (&tmp_value, 60, seconds)
|| !accumulate (&tmp_value, 1000, decimals))
goto error;
/* ensure it can be converted from milliseconds to nanoseconds */
if (tmp_value > G_MAXUINT64 / 1000000)
goto error;
*value = tmp_value;
return TRUE;
error:
return FALSE;
} }
static gboolean
gst_mpdparser_get_xml_prop_duration (xmlNode * a_node,
const gchar * property_name, guint64 default_value,
guint64 * property_value)
{
xmlChar *prop_string;
gchar *str;
gboolean exists = FALSE;
*property_value = default_value;
prop_string = xmlGetProp (a_node, (const xmlChar *) property_name);
if (prop_string) {
str = (gchar *) prop_string;
if (!gst_mpdparser_parse_duration (str, property_value))
goto error;
GST_LOG (" - %s: %" G_GUINT64_FORMAT, property_name, *property_value);
xmlFree (prop_string);
exists = TRUE;
}
return exists; return exists;
error: error: