Skip to content

Env-cleanup hooks can miss a descriptor mid-close/mid-reopen (registry reachability + dangling entry reference) #695

Description

@kriszyp

Follow-up from the #694 cross-model review (adjudicated significant-narrow; shared with the pre-existing listener cleanup path, not introduced by #694).

The module env-cleanup hooks (DBRegistry::RemoveListenersByEnv, DBRegistry::ReleaseCommitCompletionsByEnv) find shared descriptors by walking instance->databases[*].descriptor. Two windows make a live descriptor unreachable from that map:

  1. OpenDB's wait predicate does entry.descriptor.reset() when it observes a closing descriptor (db_registry.cpp), dropping the registry's ref while the closer is still inside finishClose(). A worker env tearing down in that window is not scrubbed from the descriptor; the backstop is finishClose()'s own release pass (which runs after the commit thread is joined), but that pass can then call napi_release_threadsafe_function on a tsfn whose creating env has concurrently finished teardown — a narrow UAF.
  2. Related pre-existing hazard in the same protocol: OpenDB's waiting thread holds auto& entry = entryIterator->second (a reference into the map node) across the condition wait, while the closer's guarded erase can erase that node (the guard erases when !eraseIt->second.descriptor, which is exactly the state OpenDB's predicate creates). The woken waiter then evaluates its predicate against freed node storage.

Candidate categorical fix: give the registry a secondary set of all live descriptors (weak_ptr), maintained under databasesMutex, that the env-cleanup hooks walk instead of the entry map — descriptor reachability then no longer depends on entry-map lifecycle. The entry dangling reference wants a re-find-after-wake (or shared_ptr'd entry values) in OpenDB.

#694 already narrowed the surface: DestroyDB now closes before unlinking (CloseDB's discipline).

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions