Skip to content

Commit 9357281

Browse files
lheckerDHowett
authored andcommitted
Fix use-after-free when disabling the ASB (microsoft#19186)
Closes microsoft#17515 ## Validation Steps Performed * Disable the ASB while there's a pending cooked read * Type some text * No crash ✅ (cherry picked from commit dfcc8f3) Service-Card-Id: PVTI_lADOAF3p4s4AxadtzgdFoBM Service-Version: 1.23
1 parent edcd042 commit 9357281

File tree

8 files changed

+37
-0
lines changed

8 files changed

+37
-0
lines changed

src/host/readDataCooked.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,11 @@ COOKED_READ_DATA::COOKED_READ_DATA(_In_ InputBuffer* const pInputBuffer,
176176
}
177177
}
178178

179+
const SCREEN_INFORMATION* COOKED_READ_DATA::GetScreenBuffer() const noexcept
180+
{
181+
return &_screenInfo;
182+
}
183+
179184
// Routine Description:
180185
// - This routine is called to complete a cooked read that blocked in ReadInputBuffer.
181186
// - The context of the read was saved in the CookedReadData structure.

src/host/readDataCooked.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ class COOKED_READ_DATA final : public ReadData
1919
_In_ std::wstring_view initialData,
2020
_In_ ConsoleProcessHandle* pClientProcess);
2121

22+
const SCREEN_INFORMATION* GetScreenBuffer() const noexcept override;
2223
void MigrateUserBuffersOnTransitionToBackgroundWait(const void* oldBuffer, void* newBuffer) noexcept override;
2324

2425
bool Notify(WaitTerminationReason TerminationReason,

src/host/screenInfo.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,9 @@ void SCREEN_INFORMATION::s_InsertScreenBuffer(_In_ SCREEN_INFORMATION* const pSc
192192
void SCREEN_INFORMATION::s_RemoveScreenBuffer(_In_ SCREEN_INFORMATION* const pScreenInfo)
193193
{
194194
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
195+
196+
gci.GetActiveInputBuffer()->WaitQueue.CancelWaitersForScreenBuffer(pScreenInfo);
197+
195198
if (pScreenInfo == gci.ScreenBuffers)
196199
{
197200
gci.ScreenBuffers = pScreenInfo->Next;

src/server/IWaitRoutine.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ class IWaitRoutine
4242
IWaitRoutine& operator=(const IWaitRoutine&) & = delete;
4343
IWaitRoutine& operator=(IWaitRoutine&&) & = delete;
4444

45+
virtual const SCREEN_INFORMATION* GetScreenBuffer() const noexcept
46+
{
47+
return nullptr;
48+
}
4549
virtual void MigrateUserBuffersOnTransitionToBackgroundWait(const void* oldBuffer, void* newBuffer) = 0;
4650

4751
virtual bool Notify(const WaitTerminationReason TerminationReason,

src/server/WaitBlock.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,11 @@ ConsoleWaitBlock::~ConsoleWaitBlock()
7575
delete _pWaiter;
7676
}
7777

78+
const SCREEN_INFORMATION* ConsoleWaitBlock::GetScreenBuffer() const noexcept
79+
{
80+
return _pWaiter->GetScreenBuffer();
81+
}
82+
7883
// Routine Description:
7984
// - Creates and enqueues a new wait for later callback when a routine cannot be serviced at this time.
8085
// - Will extract the process ID and the target object, enqueuing in both to know when to callback

src/server/WaitBlock.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class ConsoleWaitBlock
3030
public:
3131
~ConsoleWaitBlock();
3232

33+
const SCREEN_INFORMATION* GetScreenBuffer() const noexcept;
3334
bool Notify(const WaitTerminationReason TerminationReason);
3435

3536
[[nodiscard]] static HRESULT s_CreateWait(_Inout_ CONSOLE_API_MSG* const pWaitReplymessage,

src/server/WaitQueue.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,22 @@ bool ConsoleWaitQueue::NotifyWaiters(const bool fNotifyAll,
103103
return fResult;
104104
}
105105

106+
void ConsoleWaitQueue::CancelWaitersForScreenBuffer(const SCREEN_INFORMATION* pScreenInfo)
107+
{
108+
for (auto it = _blocks.begin(); it != _blocks.end();)
109+
{
110+
const auto nextIt = std::next(it); // we have to capture next before it is potentially erased
111+
auto* pWaitBlock = *it;
112+
113+
if (pWaitBlock->GetScreenBuffer() == pScreenInfo)
114+
{
115+
_NotifyBlock(pWaitBlock, WaitTerminationReason::HandleClosing);
116+
}
117+
118+
it = nextIt;
119+
}
120+
}
121+
106122
// Routine Description:
107123
// - A helper to delete successfully notified callbacks
108124
// Arguments:

src/server/WaitQueue.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ class ConsoleWaitQueue
3737
bool NotifyWaiters(const bool fNotifyAll,
3838
const WaitTerminationReason TerminationReason);
3939

40+
void CancelWaitersForScreenBuffer(const SCREEN_INFORMATION* pScreenInfo);
41+
4042
[[nodiscard]] static HRESULT s_CreateWait(_Inout_ CONSOLE_API_MSG* const pWaitReplyMessage,
4143
_In_ IWaitRoutine* const pWaiter);
4244

0 commit comments

Comments
 (0)