mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-03-27 11:32:51 +00:00
binaryregistry: check for not reading beyond the data area. Fixes #576842
Check all reads against the end of the data region. Roll back registration of partial reads.
This commit is contained in:
parent
6a15b2b0c5
commit
82c9b78f86
1 changed files with 106 additions and 62 deletions
|
@ -34,8 +34,6 @@
|
|||
* - why do we collect a list of binary chunks and not write immediately
|
||||
* - because we need to process subchunks, before we can set e.g. nr_of_items
|
||||
* in parent chunk
|
||||
* - need more robustness
|
||||
* - don't parse beyond mem-block size
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
|
@ -72,21 +70,46 @@
|
|||
|
||||
#define GST_CAT_DEFAULT GST_CAT_REGISTRY
|
||||
|
||||
/* macros */
|
||||
/* count string length, but return -1 if we hit the eof */
|
||||
static gint
|
||||
_strnlen (const gchar * str, gint maxlen)
|
||||
{
|
||||
gint len = 0;
|
||||
|
||||
#define unpack_element(_inptr, _outptr, _element) G_STMT_START{ \
|
||||
_outptr = (_element *) _inptr; \
|
||||
_inptr += sizeof (_element); \
|
||||
if (len == maxlen)
|
||||
return -1;
|
||||
|
||||
while (*str++ != '\0') {
|
||||
len++;
|
||||
if (len == maxlen)
|
||||
return -1;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/* reading macros */
|
||||
|
||||
#define unpack_element(inptr, outptr, element, endptr, error_label) G_STMT_START{ \
|
||||
if (inptr + sizeof(element) >= endptr) \
|
||||
goto error_label; \
|
||||
outptr = (element *) inptr; \
|
||||
inptr += sizeof (element); \
|
||||
}G_STMT_END
|
||||
|
||||
#define unpack_const_string(_inptr, _outptr) G_STMT_START{\
|
||||
_outptr = g_intern_string ((const gchar *)_inptr); \
|
||||
_inptr += strlen(_outptr) + 1; \
|
||||
#define unpack_const_string(inptr, outptr, endptr, error_label) G_STMT_START{\
|
||||
gint _len = _strnlen (inptr, (endptr-inptr)) + 1; \
|
||||
if (_len == -1) \
|
||||
goto error_label; \
|
||||
outptr = g_intern_string ((const gchar *)inptr); \
|
||||
inptr += _len; \
|
||||
}G_STMT_END
|
||||
|
||||
#define unpack_string(_inptr, _outptr) G_STMT_START{\
|
||||
_outptr = g_strdup ((gchar *)_inptr); \
|
||||
_inptr += strlen(_outptr) + 1; \
|
||||
#define unpack_string(inptr, outptr, endptr, error_label) G_STMT_START{\
|
||||
gint _len = _strnlen (inptr, (endptr-inptr)) + 1; \
|
||||
if (_len == -1) \
|
||||
goto error_label; \
|
||||
outptr = g_memdup ((gconstpointer)inptr, _len); \
|
||||
inptr += _len; \
|
||||
}G_STMT_END
|
||||
|
||||
#define ALIGNMENT (sizeof (void *))
|
||||
|
@ -802,12 +825,7 @@ gst_registry_binary_check_magic (gchar ** in, gsize size)
|
|||
|
||||
align (*in);
|
||||
GST_DEBUG ("Reading/casting for GstBinaryRegistryMagic at address %p", *in);
|
||||
|
||||
if (size < sizeof (GstBinaryRegistryMagic)) {
|
||||
GST_WARNING ("Not enough data for binary registry magic structure");
|
||||
return -1;
|
||||
}
|
||||
unpack_element (*in, m, GstBinaryRegistryMagic);
|
||||
unpack_element (*in, m, GstBinaryRegistryMagic, (*in + size), fail);
|
||||
|
||||
if (strncmp (m->magic, GST_MAGIC_BINARY_REGISTRY_STR,
|
||||
GST_MAGIC_BINARY_REGISTRY_LEN) != 0) {
|
||||
|
@ -828,6 +846,10 @@ gst_registry_binary_check_magic (gchar ** in, gsize size)
|
|||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
GST_WARNING ("Not enough data for binary registry magic structure");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
@ -839,27 +861,32 @@ gst_registry_binary_check_magic (gchar ** in, gsize size)
|
|||
* Returns: new GstStaticPadTemplate
|
||||
*/
|
||||
static gboolean
|
||||
gst_registry_binary_load_pad_template (GstElementFactory * factory, gchar ** in)
|
||||
gst_registry_binary_load_pad_template (GstElementFactory * factory, gchar ** in,
|
||||
gchar * end)
|
||||
{
|
||||
GstBinaryPadTemplate *pt;
|
||||
GstStaticPadTemplate *template;
|
||||
|
||||
align (*in);
|
||||
GST_DEBUG ("Reading/casting for GstBinaryPadTemplate at address %p", *in);
|
||||
unpack_element (*in, pt, GstBinaryPadTemplate);
|
||||
unpack_element (*in, pt, GstBinaryPadTemplate, end, fail);
|
||||
|
||||
template = g_new0 (GstStaticPadTemplate, 1);
|
||||
template->presence = pt->presence;
|
||||
template->direction = pt->direction;
|
||||
|
||||
/* unpack pad template strings */
|
||||
unpack_const_string (*in, template->name_template);
|
||||
unpack_string (*in, template->static_caps.string);
|
||||
unpack_const_string (*in, template->name_template, end, fail);
|
||||
unpack_string (*in, template->static_caps.string, end, fail);
|
||||
|
||||
__gst_element_factory_add_static_pad_template (factory, template);
|
||||
GST_DEBUG ("Added pad_template %s", template->name_template);
|
||||
|
||||
return TRUE;
|
||||
|
||||
fail:
|
||||
GST_INFO ("Reading pad template failed");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
@ -872,7 +899,7 @@ gst_registry_binary_load_pad_template (GstElementFactory * factory, gchar ** in)
|
|||
*/
|
||||
static gboolean
|
||||
gst_registry_binary_load_feature (GstRegistry * registry, gchar ** in,
|
||||
const gchar * plugin_name)
|
||||
gchar * end, const gchar * plugin_name)
|
||||
{
|
||||
GstBinaryPluginFeature *pf = NULL;
|
||||
GstPluginFeature *feature;
|
||||
|
@ -881,7 +908,7 @@ gst_registry_binary_load_feature (GstRegistry * registry, gchar ** in,
|
|||
guint i;
|
||||
|
||||
/* unpack plugin feature strings */
|
||||
unpack_string (*in, type_name);
|
||||
unpack_string (*in, type_name, end, fail);
|
||||
|
||||
if (!type_name) {
|
||||
GST_ERROR ("No feature type name");
|
||||
|
@ -908,7 +935,7 @@ gst_registry_binary_load_feature (GstRegistry * registry, gchar ** in,
|
|||
}
|
||||
|
||||
/* unpack more plugin feature strings */
|
||||
unpack_string (*in, feature->name);
|
||||
unpack_string (*in, feature->name, end, fail);
|
||||
|
||||
if (GST_IS_ELEMENT_FACTORY (feature)) {
|
||||
GstBinaryElementFactory *ef;
|
||||
|
@ -916,20 +943,20 @@ gst_registry_binary_load_feature (GstRegistry * registry, gchar ** in,
|
|||
|
||||
align (*in);
|
||||
GST_LOG ("Reading/casting for GstBinaryElementFactory at address %p", *in);
|
||||
unpack_element (*in, ef, GstBinaryElementFactory);
|
||||
unpack_element (*in, ef, GstBinaryElementFactory, end, fail);
|
||||
pf = (GstBinaryPluginFeature *) ef;
|
||||
|
||||
/* unpack element factory strings */
|
||||
unpack_string (*in, factory->details.longname);
|
||||
unpack_string (*in, factory->details.klass);
|
||||
unpack_string (*in, factory->details.description);
|
||||
unpack_string (*in, factory->details.author);
|
||||
unpack_string (*in, factory->details.longname, end, fail);
|
||||
unpack_string (*in, factory->details.klass, end, fail);
|
||||
unpack_string (*in, factory->details.description, end, fail);
|
||||
unpack_string (*in, factory->details.author, end, fail);
|
||||
GST_DEBUG ("Element factory : '%s' with npadtemplates=%d",
|
||||
factory->details.longname, ef->npadtemplates);
|
||||
|
||||
/* load pad templates */
|
||||
for (i = 0; i < ef->npadtemplates; i++) {
|
||||
if (!gst_registry_binary_load_pad_template (factory, in)) {
|
||||
if (!gst_registry_binary_load_pad_template (factory, in, end)) {
|
||||
GST_ERROR ("Error while loading binary pad template");
|
||||
goto fail;
|
||||
}
|
||||
|
@ -942,18 +969,18 @@ gst_registry_binary_load_feature (GstRegistry * registry, gchar ** in,
|
|||
align (*in);
|
||||
factory->uri_type = *((guint *) * in);
|
||||
*in += sizeof (factory->uri_type);
|
||||
//unpack_element(*in, &factory->uri_type, factory->uri_type);
|
||||
/*unpack_element(*in, &factory->uri_type, factory->uri_type, end, fail); */
|
||||
|
||||
factory->uri_protocols = g_new0 (gchar *, ef->nuriprotocols + 1);
|
||||
for (i = 0; i < ef->nuriprotocols; i++) {
|
||||
unpack_string (*in, str);
|
||||
unpack_string (*in, str, end, fail);
|
||||
factory->uri_protocols[i] = str;
|
||||
}
|
||||
}
|
||||
/* load interfaces */
|
||||
GST_DEBUG ("Reading %d Interfaces at address %p", ef->ninterfaces, *in);
|
||||
for (i = 0; i < ef->ninterfaces; i++) {
|
||||
unpack_string (*in, str);
|
||||
unpack_string (*in, str, end, fail);
|
||||
__gst_element_factory_add_interface (factory, str);
|
||||
g_free (str);
|
||||
}
|
||||
|
@ -963,11 +990,11 @@ gst_registry_binary_load_feature (GstRegistry * registry, gchar ** in,
|
|||
|
||||
align (*in);
|
||||
GST_DEBUG ("Reading/casting for GstBinaryPluginFeature at address %p", *in);
|
||||
unpack_element (*in, tff, GstBinaryTypeFindFactory);
|
||||
unpack_element (*in, tff, GstBinaryTypeFindFactory, end, fail);
|
||||
pf = (GstBinaryPluginFeature *) tff;
|
||||
|
||||
/* load caps */
|
||||
unpack_string (*in, str);
|
||||
unpack_string (*in, str, end, fail);
|
||||
factory->caps = (str && *str) ? gst_caps_from_string (str) : NULL;
|
||||
g_free (str);
|
||||
/* load extensions */
|
||||
|
@ -976,7 +1003,7 @@ gst_registry_binary_load_feature (GstRegistry * registry, gchar ** in,
|
|||
tff->nextensions, *in);
|
||||
factory->extensions = g_new0 (gchar *, tff->nextensions + 1);
|
||||
for (i = 0; i < tff->nextensions; i++) {
|
||||
unpack_string (*in, str);
|
||||
unpack_string (*in, str, end, fail);
|
||||
factory->extensions[i] = str;
|
||||
}
|
||||
}
|
||||
|
@ -985,10 +1012,10 @@ gst_registry_binary_load_feature (GstRegistry * registry, gchar ** in,
|
|||
|
||||
align (*in);
|
||||
GST_DEBUG ("Reading/casting for GstBinaryPluginFeature at address %p", *in);
|
||||
unpack_element (*in, pf, GstBinaryPluginFeature);
|
||||
unpack_element (*in, pf, GstBinaryPluginFeature, end, fail);
|
||||
|
||||
/* unpack index factory strings */
|
||||
unpack_string (*in, factory->longdesc);
|
||||
unpack_string (*in, factory->longdesc, end, fail);
|
||||
} else {
|
||||
GST_WARNING ("unhandled factory type : %s", G_OBJECT_TYPE_NAME (feature));
|
||||
goto fail;
|
||||
|
@ -1007,6 +1034,7 @@ gst_registry_binary_load_feature (GstRegistry * registry, gchar ** in,
|
|||
|
||||
/* Errors */
|
||||
fail:
|
||||
GST_INFO ("Reading plugin feature failed");
|
||||
g_free (type_name);
|
||||
if (GST_IS_OBJECT (feature))
|
||||
gst_object_unref (feature);
|
||||
|
@ -1016,7 +1044,7 @@ fail:
|
|||
}
|
||||
|
||||
static gchar **
|
||||
gst_registry_binary_load_plugin_dep_strv (gchar ** in, guint n)
|
||||
gst_registry_binary_load_plugin_dep_strv (gchar ** in, gchar * end, guint n)
|
||||
{
|
||||
gchar **arr;
|
||||
|
||||
|
@ -1025,14 +1053,18 @@ gst_registry_binary_load_plugin_dep_strv (gchar ** in, guint n)
|
|||
|
||||
arr = g_new0 (gchar *, n + 1);
|
||||
while (n > 0) {
|
||||
unpack_string (*in, arr[n - 1]);
|
||||
unpack_string (*in, arr[n - 1], end, fail);
|
||||
--n;
|
||||
}
|
||||
return arr;
|
||||
fail:
|
||||
GST_INFO ("Reading plugin dependency strings failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_registry_binary_load_plugin_dep (GstPlugin * plugin, gchar ** in)
|
||||
gst_registry_binary_load_plugin_dep (GstPlugin * plugin, gchar ** in,
|
||||
gchar * end)
|
||||
{
|
||||
GstPluginDep *dep;
|
||||
GstBinaryDep *d;
|
||||
|
@ -1040,7 +1072,7 @@ gst_registry_binary_load_plugin_dep (GstPlugin * plugin, gchar ** in)
|
|||
|
||||
align (*in);
|
||||
GST_LOG_OBJECT (plugin, "Unpacking GstBinaryDep from %p", *in);
|
||||
unpack_element (*in, d, GstBinaryDep);
|
||||
unpack_element (*in, d, GstBinaryDep, end, fail);
|
||||
|
||||
dep = g_new0 (GstPluginDep, 1);
|
||||
|
||||
|
@ -1049,9 +1081,10 @@ gst_registry_binary_load_plugin_dep (GstPlugin * plugin, gchar ** in)
|
|||
|
||||
dep->flags = d->flags;
|
||||
|
||||
dep->names = gst_registry_binary_load_plugin_dep_strv (in, d->n_names);
|
||||
dep->paths = gst_registry_binary_load_plugin_dep_strv (in, d->n_paths);
|
||||
dep->env_vars = gst_registry_binary_load_plugin_dep_strv (in, d->n_env_vars);
|
||||
dep->names = gst_registry_binary_load_plugin_dep_strv (in, end, d->n_names);
|
||||
dep->paths = gst_registry_binary_load_plugin_dep_strv (in, end, d->n_paths);
|
||||
dep->env_vars =
|
||||
gst_registry_binary_load_plugin_dep_strv (in, end, d->n_env_vars);
|
||||
|
||||
plugin->priv->deps = g_list_append (plugin->priv->deps, dep);
|
||||
|
||||
|
@ -1065,6 +1098,9 @@ gst_registry_binary_load_plugin_dep (GstPlugin * plugin, gchar ** in)
|
|||
GST_LOG_OBJECT (plugin, " name: %s", *s);
|
||||
|
||||
return TRUE;
|
||||
fail:
|
||||
GST_INFO ("Reading plugin dependency failed");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1075,7 +1111,8 @@ gst_registry_binary_load_plugin_dep (GstPlugin * plugin, gchar ** in)
|
|||
* GstBinaryPluginElement structure.
|
||||
*/
|
||||
static gboolean
|
||||
gst_registry_binary_load_plugin (GstRegistry * registry, gchar ** in)
|
||||
gst_registry_binary_load_plugin (GstRegistry * registry, gchar ** in,
|
||||
gchar * end)
|
||||
{
|
||||
GstBinaryPluginElement *pe;
|
||||
GstPlugin *plugin = NULL;
|
||||
|
@ -1083,7 +1120,7 @@ gst_registry_binary_load_plugin (GstRegistry * registry, gchar ** in)
|
|||
|
||||
align (*in);
|
||||
GST_LOG ("Reading/casting for GstBinaryPluginElement at address %p", *in);
|
||||
unpack_element (*in, pe, GstBinaryPluginElement);
|
||||
unpack_element (*in, pe, GstBinaryPluginElement, end, fail);
|
||||
|
||||
plugin = g_object_new (GST_TYPE_PLUGIN, NULL);
|
||||
|
||||
|
@ -1093,14 +1130,14 @@ gst_registry_binary_load_plugin (GstRegistry * registry, gchar ** in)
|
|||
plugin->file_size = pe->file_size;
|
||||
|
||||
/* unpack plugin element strings */
|
||||
unpack_const_string (*in, plugin->desc.name);
|
||||
unpack_string (*in, plugin->desc.description);
|
||||
unpack_string (*in, plugin->filename);
|
||||
unpack_const_string (*in, plugin->desc.version);
|
||||
unpack_const_string (*in, plugin->desc.license);
|
||||
unpack_const_string (*in, plugin->desc.source);
|
||||
unpack_const_string (*in, plugin->desc.package);
|
||||
unpack_const_string (*in, plugin->desc.origin);
|
||||
unpack_const_string (*in, plugin->desc.name, end, fail);
|
||||
unpack_string (*in, plugin->desc.description, end, fail);
|
||||
unpack_string (*in, plugin->filename, end, fail);
|
||||
unpack_const_string (*in, plugin->desc.version, end, fail);
|
||||
unpack_const_string (*in, plugin->desc.license, end, fail);
|
||||
unpack_const_string (*in, plugin->desc.source, end, fail);
|
||||
unpack_const_string (*in, plugin->desc.package, end, fail);
|
||||
unpack_const_string (*in, plugin->desc.origin, end, fail);
|
||||
GST_LOG ("read strings for name='%s'", plugin->desc.name);
|
||||
GST_LOG (" desc.description='%s'", plugin->desc.description);
|
||||
GST_LOG (" filename='%s'", plugin->filename);
|
||||
|
@ -1119,16 +1156,19 @@ gst_registry_binary_load_plugin (GstRegistry * registry, gchar ** in)
|
|||
|
||||
/* Load plugin features */
|
||||
for (i = 0; i < pe->nfeatures; i++) {
|
||||
if (!gst_registry_binary_load_feature (registry, in, plugin->desc.name)) {
|
||||
if (!gst_registry_binary_load_feature (registry, in, end,
|
||||
plugin->desc.name)) {
|
||||
GST_ERROR ("Error while loading binary feature");
|
||||
gst_registry_remove_plugin (registry, plugin);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* Load external plugin dependencies */
|
||||
for (i = 0; i < pe->n_deps; ++i) {
|
||||
if (!gst_registry_binary_load_plugin_dep (plugin, in)) {
|
||||
if (!gst_registry_binary_load_plugin_dep (plugin, in, end)) {
|
||||
GST_ERROR_OBJECT (plugin, "Could not read external plugin dependency");
|
||||
gst_registry_remove_plugin (registry, plugin);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
@ -1137,6 +1177,7 @@ gst_registry_binary_load_plugin (GstRegistry * registry, gchar ** in)
|
|||
|
||||
/* Errors */
|
||||
fail:
|
||||
GST_INFO ("Reading plugin failed");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@ -1197,6 +1238,7 @@ gst_registry_binary_read_cache (GstRegistry * registry, const char *location)
|
|||
/* check length for header */
|
||||
size = g_mapped_file_get_length (mapped);
|
||||
}
|
||||
|
||||
/* in is a cursor pointer, we initialize it with the begin of registry and is updated on each read */
|
||||
in = contents;
|
||||
GST_DEBUG ("File data at address %p", in);
|
||||
|
@ -1204,6 +1246,7 @@ gst_registry_binary_read_cache (GstRegistry * registry, const char *location)
|
|||
GST_ERROR ("No or broken registry header");
|
||||
goto Error;
|
||||
}
|
||||
|
||||
/* check if header is valid */
|
||||
if ((check_magic_result = gst_registry_binary_check_magic (&in, size)) < 0) {
|
||||
|
||||
|
@ -1215,20 +1258,21 @@ gst_registry_binary_read_cache (GstRegistry * registry, const char *location)
|
|||
}
|
||||
|
||||
/* check if there are plugins in the file */
|
||||
|
||||
if (!(((gsize) in + sizeof (GstBinaryPluginElement)) <
|
||||
(gsize) contents + size)) {
|
||||
GST_INFO ("No binary plugins structure to read");
|
||||
/* empty file, this is not an error */
|
||||
} else {
|
||||
gchar *end = contents + size;
|
||||
/* read as long as we still have space for a GstBinaryPluginElement */
|
||||
for (;
|
||||
((gsize) in + sizeof (GstBinaryPluginElement)) <
|
||||
(gsize) contents + size;) {
|
||||
GST_DEBUG ("reading binary registry %" G_GSIZE_FORMAT "(%x)/%"
|
||||
G_GSIZE_FORMAT, (gsize) in - (gsize) contents,
|
||||
(guint) ((gsize) in - (gsize) contents), size);
|
||||
if (!gst_registry_binary_load_plugin (registry, &in)) {
|
||||
GST_ERROR ("Problem while reading binary registry");
|
||||
if (!gst_registry_binary_load_plugin (registry, &in, end)) {
|
||||
GST_ERROR ("Problem while reading binary registry %s", location);
|
||||
goto Error;
|
||||
}
|
||||
}
|
||||
|
@ -1242,7 +1286,7 @@ gst_registry_binary_read_cache (GstRegistry * registry, const char *location)
|
|||
GST_INFO ("loaded %s in %lf seconds", location, seconds);
|
||||
|
||||
res = TRUE;
|
||||
/* TODO: once we re-use the pointers to registry contents return here */
|
||||
/* TODO: once we re-use the pointers to registry contents, return here */
|
||||
|
||||
Error:
|
||||
#ifndef GST_DISABLE_GST_DEBUG
|
||||
|
|
Loading…
Reference in a new issue