July 31st, 2023

Misinterpreting the misleadingly-named STATUS_STACK_BUFFER_OVERRUN

I noted some time ago that STATUS_STACK_BUFFER_OVERRUN doesn’t mean that there was a stack buffer overrun, although that’s what it meant at first. Later, the status code was broadened to mean “Program self-triggered abnormal termination”, but it was too late to change the name.

A security vulnerability report came in that went like this:

I have found a stack overflow bug in Explorer. This stack overflow occurs in ucrtbase.dll and Windows.UI.FileExplorer.dll. Since it occurs in Explorer, this can be exploited to escalate privileges. To reproduce, download the attached ZIP file and right-click it. I have also attached Explorer crash dumps for analysis.

EXCEPTION_RECORD: (.exr -1)
ExceptionAddress: 00007ffcaa19dd7e (ucrtbase!abort+0x000000000000004e)
ExceptionCode: c0000409 (Security check failure or stack buffer overrun)
ExceptionFlags: 00000001
NumberParameters: 1
Parameter[0]: 0000000000000007
Subcode: 0x7 FAST_FAIL_FATAL_APP_EXIT

STACK_TEXT:
ucrtbase!abort+0x4e
ucrtbase!terminate+0x29
ucrtbase!__crt_state_management::wrapped_invoke<void (__cdecl*)(void) noexcept,void>+0xf
explorer!_scrt_unhandled_exception_filter+0x5a
KERNELBASE!UnhandledExceptionFilter+0x1f1
ntdll!LdrpLogFatalUserCallbackException+0xa2
ntdll!KiUserCallbackDispatcherHandler+0x20
ntdll!RtlpExecuteHandlerForException+0xf
ntdll!RtlDispatchException+0x25a
ntdll!RtlRaiseException+0x163
KERNELBASE!RaiseException+0x6c
msvcr90!_CxxThrowException+0x86
contoso+0x104d
contososhellext!OnInvokeCommand+0x548
contososhellext!OnInvokeCommand+0x24d2a
contososhellext!OnGetCommandString+0x4f
contoso+0x2abd
contoso+0x27f0
shell32!CDefFolderMenu::GetCommandString+0x1f6
shell32!CDefFolderMenu::_UnduplicateVerbs+0x31f
shell32!CDefFolderMenu::QueryContextMenu+0x7d2
shell32!CDefView::_DoContextMenuPopup+0x2f7
shell32!CDefView::OnSelectionContextMenu+0x85
explorerframe!UIItemsView::ShowContextMenu+0x378
explorerframe!CItemsView::ShowContextMenu+0x17
shell32!CDefView::_DoContextMenu+0x92
shell32!CDefView::_OnContextMenu+0xec
shell32!CDefView::WndProc+0x718
shell32!CDefView::s_WndProc+0x5c
user32!UserCallWinProcCheckWow+0x33c
user32!CallWindowProcW+0x8e

From the exception record, we see that this was a fast-fail: FAST_FAIL_FATAL_APP_EXIT.

From the stack trace we can see that this was due to an unhandled C++ exception thrown by Contoso: Contoso called _CxxThrowException, and this ended up reaching the _scrt_unhandled_exception_filter, which decided to terminate the process.

The problem is therefore with the Contoso shell extension: When you right-click this file, the Contoso shell extension throws a C++ exception which it does not handle.

C++ exceptions cannot be thrown across the ABI boundary because there’s no requirement in the ABI that the calling code even be written in C++ at all!¹ And certainly unhandled C++ exceptions are really bad ideas.

There is a bug here, but the bug is in the Contoso shell extension, not in Explorer. Such is the punishment for allowing third party extensibility: Any bug in a third party extension manifests itself as a bug in Explorer.

¹ For example, the Windows 95 shell was written in C.

Topics
Code

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

4 comments

Discussion is closed. Login to edit/delete existing comments.

  • Melissa P

    “Since it occurs in Explorer, this can be exploited to escalate privileges.” .. err, what? Why does that “bug reporter” talk about privilege escalation? I don’t see any.

    The stack trace is kinda straight forward, and the 409 is STATUS_FAIL_FAST_EXCEPTION. I did not know that it was once called STATUS_STACK_BUFFER_OVERRUN. Interesting.

    • Gavin Lambert

      > Why does that “bug reporter” talk about privilege escalation? I don’t see any.

      Because to people looking for “hacker clout” without actually knowing what they’re talking about, a buffer overrun always means privilege escalation. Ignoring that this case isn’t actually a buffer overrun, and that even if it was, Explorer does not (typically) run with elevated privileges. At most it might be “arbitrary code execution”, but it’s not even that.

    • Chris Iverson

      > and the 409 is STATUS_FAIL_FAST_EXCEPTION

      What? No it’s not. “STATUS_FAIL_FAST_EXCEPTION” is 0xC0000602.

      0xC0000409 is still defined as “STATUS_STACK_BUFFER_OVERRUN”.

      The subcode of the exception indicates that it’s a fast-fail. But it’s not returning the “STATUS_FAIL_FAST_EXCEPTION” NTSTATUS error code.

  • Larry Osterman

    Another reason that C++ exceptions can’t cross the ABI boundary is that there is no binary contract for C++ exceptions. Even if the calling code WAS written in C++, there’s no guarantee that the same compiler was used for both sides of the binary. Or the same version of the same compiler. Or with the same compiler switches.