diff options
author | Ryan Lortie <desrt@desrt.ca> | 2012-07-06 21:42:04 -0400 |
---|---|---|
committer | Ryan Lortie <desrt@desrt.ca> | 2012-07-06 21:42:04 -0400 |
commit | 374cb1bc87a64efe48f3aac2b0c71c395792d42d (patch) | |
tree | d529d3fad6ef5e740d0f8971451f437a812a76dc | |
parent | a9551ccf92fb046a92573fb4a5b42a4d43e2abec (diff) | |
download | gvdb-374cb1bc87a64efe48f3aac2b0c71c395792d42d.tar.gz |
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.
-rw-r--r-- | gvdb-reader.c | 49 |
1 files changed, 36 insertions, 13 deletions
diff --git a/gvdb-reader.c b/gvdb-reader.c index c04630d..b41fb5d 100644 --- a/gvdb-reader.c +++ b/gvdb-reader.c @@ -457,7 +457,15 @@ gboolean gvdb_table_has_value (GvdbTable *file, 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 * @@ -699,23 +707,38 @@ gvdb_table_walk (GvdbTable *table, item = gvdb_table_get_item (table, *pointers[index]++); start_here: - if (item != NULL && - (name = gvdb_table_item_get_key (table, item, &name_len))) + if (item != NULL && (name = gvdb_table_item_get_key (table, item, &name_len))) { if (item->type == 'L') { - if (open_func (name, name_len, user_data)) - { - guint length; + const guint32_le *dir; + guint length; - index++; - g_assert (index < 64); + 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++; + 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') |