Commit 46b3b620 authored by Nick Mathewson's avatar Nick Mathewson 🤹
Browse files

Avoid double-free on failure to dump_descriptor() a cached md

This is a fix for 10423, which was introducd in caa0d15c in 0.2.4.13-alpha.

Spotted by bobnomnom.
parent 59f50c80
Loading
Loading
Loading
Loading

changes/bug10423

0 → 100644
+4 −0
Original line number Diff line number Diff line
  o Minor bugfixes:
    - If we fail to dump a previously cached microdescriptor to disk, avoid
      freeing duplicate data later on. Fix for bug 10423; bugfix on
      0.2.4.13-alpha. Spotted by "bobnomnom".
+22 −11
Original line number Diff line number Diff line
@@ -407,6 +407,26 @@ should_rebuild_md_cache(microdesc_cache_t *cache)
    return 0;
}

/**
 * Mark <b>md</b> as having no body, and release any storage previously held
 * by its body.
 */
static void
microdesc_wipe_body(microdesc_t *md)
{
  if (!md)
    return;

  if (md->saved_location != SAVED_IN_CACHE)
    tor_free(md->body);

  md->off = 0;
  md->saved_location = SAVED_NOWHERE;
  md->body = NULL;
  md->bodylen = 0;
  md->no_save = 1;
}

/** Regenerate the main cache file for <b>cache</b>, clear the journal file,
 * and update every microdesc_t in the cache with pointers to its new
 * location.  If <b>force</b> is true, do this unconditionally.  If
@@ -455,12 +475,7 @@ microdesc_cache_rebuild(microdesc_cache_t *cache, int force)

    size = dump_microdescriptor(fd, md, &annotation_len);
    if (size < 0) {
      if (md->saved_location != SAVED_IN_CACHE)
        tor_free(md->body);
      md->saved_location = SAVED_NOWHERE;
      md->off = 0;
      md->bodylen = 0;
      md->no_save = 1;
      microdesc_wipe_body(md);

      /* rewind, in case it was a partial write. */
      tor_fd_setpos(fd, off);
@@ -497,11 +512,7 @@ microdesc_cache_rebuild(microdesc_cache_t *cache, int force)
    HT_FOREACH(mdp, microdesc_map, &cache->map) {
      microdesc_t *md = *mdp;
      if (md->saved_location == SAVED_IN_CACHE) {
        md->off = 0;
        md->saved_location = SAVED_NOWHERE;
        md->body = NULL;
        md->bodylen = 0;
        md->no_save = 1;
        microdesc_wipe_body(md);
      }
    }
    return -1;