gvdb-reader: robustness improvements

Improve the robustness of gvdb-reader in two ways.

First: ensure that the result of gvdb_table_has_value() always agrees
with gvdb_table_get_value().  Those two could disagree in the case that
the value was recorded as existing but pointed to an out-of-bounds
region.

Second: prevent gvdb_table_walk() from getting stuck in finite loops due
to self-referential directories.
This commit is contained in:
Ryan Lortie 2012-07-06 21:42:04 -04:00
parent a9551ccf92
commit 374cb1bc87

View File

@ -457,7 +457,15 @@ gboolean
gvdb_table_has_value (GvdbTable *file, gvdb_table_has_value (GvdbTable *file,
const gchar *key) const gchar *key)
{ {
return gvdb_table_lookup (file, key, 'v') != NULL; static const struct gvdb_hash_item *item;
gsize size;
item = gvdb_table_lookup (file, key, 'v');
if (item == NULL)
return FALSE;
return gvdb_table_dereference (file, &item->value.pointer, 8, &size) != NULL;
} }
static GVariant * static GVariant *
@ -699,23 +707,38 @@ gvdb_table_walk (GvdbTable *table,
item = gvdb_table_get_item (table, *pointers[index]++); item = gvdb_table_get_item (table, *pointers[index]++);
start_here: start_here:
if (item != NULL && if (item != NULL && (name = gvdb_table_item_get_key (table, item, &name_len)))
(name = gvdb_table_item_get_key (table, item, &name_len)))
{ {
if (item->type == 'L') if (item->type == 'L')
{ {
if (open_func (name, name_len, user_data)) const guint32_le *dir;
{
guint length; guint length;
if (gvdb_table_list_from_item (table, item, &dir, &length))
{
gint i;
/* In order to avoid files with recursive contents
* we impose the rule that a directory's data must
* follow the data of any directory pointing to
* it.
*
* If we discover that our newly-discovered
* directory follows the one we're traversing now
* then bail out.
*/
if (dir <= pointers[index])
continue;
if (open_func (name, name_len, user_data))
{
index++; index++;
g_assert (index < 64); g_assert (index < 64);
gvdb_table_list_from_item (table, item,
&pointers[index],
&length);
enders[index] = pointers[index] + length;
name_lengths[index] = name_len; name_lengths[index] = name_len;
pointers[index] = dir;
enders[index] = pointers[index] + length;
}
} }
} }
else if (item->type == 'v') else if (item->type == 'v')