mpdparse: Validate format strings before using them

Using format strings from an untrusted source without validation is
calling for problems, and at least allows to remotely crash your application.
If not worse.
This commit is contained in:
Sebastian Dröge 2015-06-04 10:47:07 +02:00
parent 53a149f5d4
commit 1be223fdc3

View file

@ -2536,6 +2536,45 @@ gst_mpdparser_get_initializationURL (GstActiveStream * stream,
return url_prefix; return url_prefix;
} }
/* ISO/IEC 23009-1:2004 5.3.9.4.4 */
static gboolean
validate_format (const gchar * format)
{
gchar *p;
/* Check if there is a % at all */
p = strchr (format, '%');
if (!p)
return TRUE;
p++;
/* Following the % must be a 0, or any of d, x or u.
* x and u are not part of the spec, but don't hurt us
*/
if (p[0] == '0') {
p++;
while (g_ascii_isdigit (*p))
p++;
}
/* After any 0 and alphanumeric values, there must be
* an d, x or u.
*/
if (p[0] != 'd' && p[0] != 'x' && p[0] != 'u')
return FALSE;
p++;
/* And then potentially more characters without any
* further %, even if the spec does not mention this
*/
p = strchr (p, '%');
if (p)
return FALSE;
return TRUE;
}
static gchar * static gchar *
gst_mpdparser_build_URL_from_template (const gchar * url_template, gst_mpdparser_build_URL_from_template (const gchar * url_template,
const gchar * id, guint number, guint bandwidth, guint64 time) const gchar * id, guint number, guint bandwidth, guint64 time)
@ -2566,6 +2605,9 @@ gst_mpdparser_build_URL_from_template (const gchar * url_template,
if (strlen (token) > 6) { if (strlen (token) > 6) {
format = token + 6; /* format tag */ format = token + 6; /* format tag */
} }
if (!validate_format (format))
goto invalid_format;
tokens[i] = g_strdup_printf (format, number); tokens[i] = g_strdup_printf (format, number);
g_free (token); g_free (token);
last_token_par = TRUE; last_token_par = TRUE;
@ -2573,6 +2615,9 @@ gst_mpdparser_build_URL_from_template (const gchar * url_template,
if (strlen (token) > 9) { if (strlen (token) > 9) {
format = token + 9; /* format tag */ format = token + 9; /* format tag */
} }
if (!validate_format (format))
goto invalid_format;
tokens[i] = g_strdup_printf (format, bandwidth); tokens[i] = g_strdup_printf (format, bandwidth);
g_free (token); g_free (token);
last_token_par = TRUE; last_token_par = TRUE;
@ -2582,6 +2627,9 @@ gst_mpdparser_build_URL_from_template (const gchar * url_template,
} else { } else {
format = "%" G_GUINT64_FORMAT; format = "%" G_GUINT64_FORMAT;
} }
if (!validate_format (format))
goto invalid_format;
tokens[i] = g_strdup_printf (format, time); tokens[i] = g_strdup_printf (format, time);
g_free (token); g_free (token);
last_token_par = TRUE; last_token_par = TRUE;
@ -2597,9 +2645,19 @@ gst_mpdparser_build_URL_from_template (const gchar * url_template,
} }
ret = g_strjoinv (NULL, tokens); ret = g_strjoinv (NULL, tokens);
g_strfreev (tokens); g_strfreev (tokens);
return ret; return ret;
invalid_format:
{
GST_ERROR ("Invalid format '%s' in '%s'", format, token);
g_strfreev (tokens);
return NULL;
}
} }
guint guint