summaryrefslogtreecommitdiffstats
path: root/agent
diff options
context:
space:
mode:
authorJustus Winter <justus@g10code.com>2017-01-25 13:51:57 +0100
committerJustus Winter <justus@g10code.com>2017-01-25 13:51:57 +0100
commite175152ef7515921635bf1e00383e812668d13fc (patch)
treebc2d9520a5bc0c3b9cef80bad8e8c677bab5b0be /agent
parenttests: Skip GPGME tests that are not built. (diff)
downloadgnupg2-e175152ef7515921635bf1e00383e812668d13fc.tar.xz
gnupg2-e175152ef7515921635bf1e00383e812668d13fc.zip
agent: Fix double free.
* agent/cache.c (agent_store_cache_hit): Make sure the update is atomic. -- Previously, the function freed the last key, and duplicated the new key after doing that. There is a chance, however, that calling the allocator surrenders control to a different thread, causing a double free if a different thread also calls this function. To make sure the update is atomic under the non-preemptive thread model, we must make sure not to surrender control to a different thread. Therefore, we avoid calling the allocator during the update. Signed-off-by: Justus Winter <justus@g10code.com>
Diffstat (limited to 'agent')
-rw-r--r--agent/cache.c17
1 files changed, 15 insertions, 2 deletions
diff --git a/agent/cache.c b/agent/cache.c
index f58eaeaaa..248368277 100644
--- a/agent/cache.c
+++ b/agent/cache.c
@@ -475,6 +475,19 @@ agent_get_cache (const char *key, cache_mode_t cache_mode)
void
agent_store_cache_hit (const char *key)
{
- xfree (last_stored_cache_key);
- last_stored_cache_key = key? xtrystrdup (key) : NULL;
+ char *new;
+ char *old;
+
+ /* To make sure the update is atomic under the non-preemptive thread
+ * model, we must make sure not to surrender control to a different
+ * thread. Therefore, we avoid calling the allocator during the
+ * update. */
+ new = key ? xtrystrdup (key) : NULL;
+
+ /* Atomic update. */
+ old = last_stored_cache_key;
+ last_stored_cache_key = new;
+ /* Done. */
+
+ xfree (old);
}