Skip to content

Foundation: make Logger::shutdown() channel-detach instead of map-reset (fix UAF)#5326

Closed
SAY-5 wants to merge 1 commit intopocoproject:mainfrom
SAY-5:fix/logger-shutdown-uaf-5324
Closed

Foundation: make Logger::shutdown() channel-detach instead of map-reset (fix UAF)#5326
SAY-5 wants to merge 1 commit intopocoproject:mainfrom
SAY-5:fix/logger-shutdown-uaf-5324

Conversation

@SAY-5
Copy link
Copy Markdown

@SAY-5 SAY-5 commented Apr 20, 2026

Fixes #5324.

Logger::shutdown() previously did:

void Logger::shutdown()
{
    Mutex::ScopedLock lock(_mapMtx);
    _pLoggerMap.reset();
}

shutdown() is called from LoggingSubsystem::uninitialize(), which runs before the destruction of static singletons that registered via atexit. Those singletons frequently cache a Logger& obtained from Logger::get() during construction — the canonical pattern recommended in the Poco samples and used widely by downstream code. Once the logger map is torn down, every such cached reference is dangling, and the first log call from a static destructor hits a heap-use-after-free.

This switches shutdown() to detach the channel from every Logger rather than destroying them. logImpl() already short-circuits on if (_pChannel), so once the channel is null all further logging from a Logger is a cheap no-op and the reference stays valid. The map itself is released at real program exit when the static _pLoggerMap is destroyed; no long-lived singleton can touch it between shutdown() and that point.

…et (fix UAF)

Logger::shutdown() previously did:

    void Logger::shutdown()
    {
        Mutex::ScopedLock lock(_mapMtx);
        _pLoggerMap.reset();
    }

shutdown() is called from LoggingSubsystem::uninitialize(), which runs
before the destruction of static singletons that registered via
atexit. Those singletons frequently cache a Logger& obtained from
Logger::get() during construction (the canonical pattern recommended
in the Poco samples and used widely by downstream code). Once the
logger map is torn down, every such cached reference is dangling, and
the first log call from a static destructor hits a heap-use-after-free.

Switch shutdown() to detach the channel from every Logger rather than
destroying them. logImpl() already short-circuits on `if (_pChannel)`,
so once the channel is null all further logging from a Logger is a
cheap no-op and the reference stays valid. The map itself is released
at real program exit when the static _pLoggerMap is destroyed; no
long-lived singleton can touch it between shutdown() and that point.

Fixes pocoproject#5324
@aleks-f
Copy link
Copy Markdown
Member

aleks-f commented Apr 20, 2026

#5325

@aleks-f aleks-f closed this Apr 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Logger::shutdown() use-after-free

2 participants