Checkpoint skip logic reads before ckpt array when no checkpoints exist

XMLWordPrintableJSON

    • Type: Bug
    • Resolution: Fixed
    • Priority: Major - P3
    • WT12.0.0, 9.0.0-rc0
    • Affects Version/s: None
    • Component/s: Checkpoints
    • None
    • Environment:
      Windows host with WSL (Ubuntu 24.04), GCC 13.3.0, AddressSanitizer enabled for repro
    • Storage Engines - Persistence
    • 485.899
    • None
    • 1
    • v8.3, v8.0, v7.0

      Problem:
      In __checkpoint_mark_skip the code reads (ckpt - 1)->name before checking
      that the checkpoint list has at least two entries. When the list is empty (only
      the NULL sentinel), ckpt == ckptbase after WT_CKPT_FOREACH, so (ckpt - 1)
      is an out-of-bounds read. This is undefined behavior and is caught by ASan in a
      minimal repro.

      Root Cause
      The unconditional dereference (ckpt - 1)->name appears before the guard
      ckpt > ckptbase + 1 that would make it safe:

      /* Bug */
      const char *name = (ckpt - 1)->name;  // evaluated unconditionally
      if (ckpt > ckptbase + 1 && deleted < 2 &&   // guard comes too late
        (strcmp(name, (ckpt - 2)->name) == 0 || ...

      In the current production call path __checkpoint_lock_dirty_tree always
      appends a new entry before calling __checkpoint_mark_skip so the list is
      never empty at runtime. The bug is therefore latent the code is fragile
      and will become immediately exploitable if the call-site guarantee is ever
      relaxed by a refactor.

      Move the dereference inside the bounds-checked branch:
      /* Fix */
      if (ckpt > ckptbase + 1 && deleted < 2) {
          const char *name = (ckpt - 1)->name;  // list has ≥ 2 entries
          if (strcmp(name, (ckpt - 2)->name) == 0 ||
            (WT_PREFIX_MATCH(name, WT_CHECKPOINT) &&
              WT_PREFIX_MATCH((ckpt - 2)->name, WT_CHECKPOINT)))

      {         F_SET(btree, WT_BTREE_SKIP_CKPT);         ...     }

      }

      A minimal C repro compiled with ASan confirms the out-of-bounds read pattern
      when __checkpoint_mark_skip receives an empty list

            Assignee:
            Etienne Petrel
            Reporter:
            Tuna KARABACAK
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              Resolved: