[girepository] Actually verify header of loaded typelibs in g_irepository_require

Take a GError * for typelib loading code, validate the header.  This
fixes bizarre errors from gjs where g_irepository_require would happily
load old typelibs.
This commit is contained in:
Colin Walters 2010-07-14 11:59:11 -04:00
parent 3a310fd242
commit 1b8bf7a4dc
4 changed files with 71 additions and 25 deletions

View File

@ -1221,7 +1221,9 @@ g_irepository_require (GIRepository *repository,
goto out; goto out;
} }
typelib = g_typelib_new_from_mapped_file (mfile); typelib = g_typelib_new_from_mapped_file (mfile, error);
if (!typelib)
goto out;
header = (Header *) typelib->data; header = (Header *) typelib->data;
typelib_namespace = g_typelib_get_string (typelib, header->namespace); typelib_namespace = g_typelib_get_string (typelib, header->namespace);
typelib_version = g_typelib_get_string (typelib, header->nsversion); typelib_version = g_typelib_get_string (typelib, header->nsversion);

View File

@ -206,6 +206,7 @@ GTypelib *
g_ir_module_build_typelib (GIrModule *module, g_ir_module_build_typelib (GIrModule *module,
GList *modules) GList *modules)
{ {
GError *error = NULL;
GTypelib *typelib; GTypelib *typelib;
gsize length; gsize length;
guint i; guint i;
@ -434,7 +435,12 @@ g_ir_module_build_typelib (GIrModule *module,
data = g_realloc (data, offset2); data = g_realloc (data, offset2);
header = (Header*) data; header = (Header*) data;
length = header->size = offset2; length = header->size = offset2;
typelib = g_typelib_new_from_memory (data, length); typelib = g_typelib_new_from_memory (data, length, &error);
if (!typelib)
{
g_error ("error building typelib: %s",
error->message);
}
g_hash_table_destroy (strings); g_hash_table_destroy (strings);
g_hash_table_destroy (types); g_hash_table_destroy (types);

View File

@ -260,30 +260,30 @@ validate_name (GTypelib *typelib,
return TRUE; return TRUE;
} }
/* Fast path sanity check, operates on a memory blob */
static gboolean static gboolean
validate_header (ValidateContext *ctx, validate_header_basic (const guint8 *memory,
GError **error) gsize len,
GError **error)
{ {
GTypelib *typelib = ctx->typelib; Header *header = (Header *)memory;
Header *header;
if (typelib->len < sizeof (Header)) if (len < sizeof (Header))
{ {
g_set_error (error, g_set_error (error,
G_TYPELIB_ERROR, G_TYPELIB_ERROR,
G_TYPELIB_ERROR_INVALID, G_TYPELIB_ERROR_INVALID,
"The buffer is too short"); "The specified typelib length %" G_GSIZE_FORMAT " is too short",
len);
return FALSE; return FALSE;
} }
header = (Header *)typelib->data;
if (strncmp (header->magic, G_IR_MAGIC, 16) != 0) if (strncmp (header->magic, G_IR_MAGIC, 16) != 0)
{ {
g_set_error (error, g_set_error (error,
G_TYPELIB_ERROR, G_TYPELIB_ERROR,
G_TYPELIB_ERROR_INVALID_HEADER, G_TYPELIB_ERROR_INVALID_HEADER,
"Magic string not found"); "Invalid magic header");
return FALSE; return FALSE;
} }
@ -293,7 +293,7 @@ validate_header (ValidateContext *ctx,
g_set_error (error, g_set_error (error,
G_TYPELIB_ERROR, G_TYPELIB_ERROR,
G_TYPELIB_ERROR_INVALID_HEADER, G_TYPELIB_ERROR_INVALID_HEADER,
"Version mismatch; expected 3, found %d", "Typelib version mismatch; expected 3, found %d",
header->major_version); header->major_version);
return FALSE; return FALSE;
@ -308,12 +308,13 @@ validate_header (ValidateContext *ctx,
return FALSE; return FALSE;
} }
if (header->size != typelib->len) if (header->size != len)
{ {
g_set_error (error, g_set_error (error,
G_TYPELIB_ERROR, G_TYPELIB_ERROR,
G_TYPELIB_ERROR_INVALID_HEADER, G_TYPELIB_ERROR_INVALID_HEADER,
"Typelib size mismatch"); "Typelib size %" G_GSIZE_FORMAT " does not match %" G_GSIZE_FORMAT,
header->size, len);
return FALSE; return FALSE;
} }
@ -378,9 +379,24 @@ validate_header (ValidateContext *ctx,
return FALSE; return FALSE;
} }
if (!validate_name (typelib, "namespace", typelib->data, header->namespace, error)) return TRUE;
}
static gboolean
validate_header (ValidateContext *ctx,
GError **error)
{
GTypelib *typelib = ctx->typelib;
if (!validate_header_basic (typelib->data, typelib->len, error))
return FALSE; return FALSE;
{
Header *header = (Header*)typelib->data;
if (!validate_name (typelib, "namespace", typelib->data, header->namespace, error))
return FALSE;
}
return TRUE; return TRUE;
} }
@ -2056,6 +2072,7 @@ _g_typelib_ensure_open (GTypelib *typelib)
* g_typelib_new_from_memory: * g_typelib_new_from_memory:
* @memory: address of memory chunk containing the typelib * @memory: address of memory chunk containing the typelib
* @len: length of memory chunk containing the typelib * @len: length of memory chunk containing the typelib
* @error: a #GError
* *
* Creates a new #GTypelib from a memory location. The memory block * Creates a new #GTypelib from a memory location. The memory block
* pointed to by @typelib will be automatically g_free()d when the * pointed to by @typelib will be automatically g_free()d when the
@ -2064,10 +2081,15 @@ _g_typelib_ensure_open (GTypelib *typelib)
* Return value: the new #GTypelib * Return value: the new #GTypelib
**/ **/
GTypelib * GTypelib *
g_typelib_new_from_memory (guchar *memory, gsize len) g_typelib_new_from_memory (guint8 *memory,
gsize len,
GError **error)
{ {
GTypelib *meta; GTypelib *meta;
if (!validate_header_basic (memory, len, error))
return NULL;
meta = g_slice_new0 (GTypelib); meta = g_slice_new0 (GTypelib);
meta->data = memory; meta->data = memory;
meta->len = len; meta->len = len;
@ -2081,16 +2103,22 @@ g_typelib_new_from_memory (guchar *memory, gsize len)
* g_typelib_new_from_const_memory: * g_typelib_new_from_const_memory:
* @memory: address of memory chunk containing the typelib * @memory: address of memory chunk containing the typelib
* @len: length of memory chunk containing the typelib * @len: length of memory chunk containing the typelib
* @error: A #GError
* *
* Creates a new #GTypelib from a memory location. * Creates a new #GTypelib from a memory location.
* *
* Return value: the new #GTypelib * Return value: the new #GTypelib
**/ **/
GTypelib * GTypelib *
g_typelib_new_from_const_memory (const guchar *memory, gsize len) g_typelib_new_from_const_memory (const guchar *memory,
gsize len,
GError **error)
{ {
GTypelib *meta; GTypelib *meta;
if (!validate_header_basic (memory, len, error))
return NULL;
meta = g_slice_new0 (GTypelib); meta = g_slice_new0 (GTypelib);
meta->data = (guchar *) memory; meta->data = (guchar *) memory;
meta->len = len; meta->len = len;
@ -2103,21 +2131,28 @@ g_typelib_new_from_const_memory (const guchar *memory, gsize len)
/** /**
* g_typelib_new_from_mapped_file: * g_typelib_new_from_mapped_file:
* @mfile: a #GMappedFile, that will be free'd when the repository is destroyed * @mfile: a #GMappedFile, that will be free'd when the repository is destroyed
* @error: a #GError
* *
* Creates a new #GTypelib from a #GMappedFile. * Creates a new #GTypelib from a #GMappedFile.
* *
* Return value: the new #GTypelib * Return value: the new #GTypelib
**/ **/
GTypelib * GTypelib *
g_typelib_new_from_mapped_file (GMappedFile *mfile) g_typelib_new_from_mapped_file (GMappedFile *mfile,
GError **error)
{ {
GTypelib *meta; GTypelib *meta;
guint8 *data = (guint8 *) g_mapped_file_get_contents (mfile);
gsize len = g_mapped_file_get_length (mfile);
if (!validate_header_basic (data, len, error))
return NULL;
meta = g_slice_new0 (GTypelib); meta = g_slice_new0 (GTypelib);
meta->mfile = mfile; meta->mfile = mfile;
meta->owns_memory = FALSE; meta->owns_memory = FALSE;
meta->data = (guchar *) g_mapped_file_get_contents (mfile); meta->data = data;
meta->len = g_mapped_file_get_length (mfile); meta->len = len;
return meta; return meta;
} }

View File

@ -34,11 +34,14 @@ G_BEGIN_DECLS
typedef struct _GTypelib GTypelib; typedef struct _GTypelib GTypelib;
GTypelib * g_typelib_new_from_memory (guchar *memory, GTypelib * g_typelib_new_from_memory (guint8 *memory,
gsize len); gsize len,
GTypelib * g_typelib_new_from_const_memory (const guchar *memory, GError **error);
gsize len); GTypelib * g_typelib_new_from_const_memory (const guint8 *memory,
GTypelib * g_typelib_new_from_mapped_file (GMappedFile *mfile); gsize len,
GError **error);
GTypelib * g_typelib_new_from_mapped_file (GMappedFile *mfile,
GError **error);
void g_typelib_free (GTypelib *typelib); void g_typelib_free (GTypelib *typelib);
gboolean g_typelib_symbol (GTypelib *typelib, gboolean g_typelib_symbol (GTypelib *typelib,