lib: fix memory error in notmuch_config_list_value

The documentation for notmuch_config_list_key warns that that the
returned value will be destroyed by the next call to
notmuch_config_list_key, but it neglected to mention that calling
notmuch_config_list_value would also destroy it (by calling
notmuch_config_list_key). This is surprising, and caused a use after
free bug in _setup_user_query_fields (first noticed by an OpenBSD
porter, so kudos to the OpenBSD malloc implementation).  This change
fixes that use-after-free bug.
This commit is contained in:
David Bremner 2019-11-24 22:31:34 -04:00
parent 2a003f0f50
commit 8e22514842

View file

@ -150,13 +150,17 @@ notmuch_config_list_valid (notmuch_config_list_t *metadata)
return true; return true;
} }
static inline char * _key_from_iterator (notmuch_config_list_t *list) {
return talloc_strdup (list, (*list->iterator).c_str () + CONFIG_PREFIX.length ());
}
const char * const char *
notmuch_config_list_key (notmuch_config_list_t *list) notmuch_config_list_key (notmuch_config_list_t *list)
{ {
if (list->current_key) if (list->current_key)
talloc_free (list->current_key); talloc_free (list->current_key);
list->current_key = talloc_strdup (list, (*list->iterator).c_str () + CONFIG_PREFIX.length ()); list->current_key = _key_from_iterator (list);
return list->current_key; return list->current_key;
} }
@ -166,7 +170,7 @@ notmuch_config_list_value (notmuch_config_list_t *list)
{ {
std::string strval; std::string strval;
notmuch_status_t status; notmuch_status_t status;
const char *key = notmuch_config_list_key (list); char *key = _key_from_iterator (list);
/* TODO: better error reporting?? */ /* TODO: better error reporting?? */
status = _metadata_value (list->notmuch, key, strval); status = _metadata_value (list->notmuch, key, strval);
@ -177,6 +181,7 @@ notmuch_config_list_value (notmuch_config_list_t *list)
talloc_free (list->current_val); talloc_free (list->current_val);
list->current_val = talloc_strdup (list, strval.c_str ()); list->current_val = talloc_strdup (list, strval.c_str ());
talloc_free (key);
return list->current_val; return list->current_val;
} }