terminal/src/host/writeData.hpp
Dustin Howett c0ab9cb5b5 Merged PR 6034984: Fix a crash caused by improper buffer management w/ multiple clients
Until there's a "Wait", there's usually only one API message inflight at
a time.

In our quest for performance, we put that single API message in charge
of its own buffer management: instead of allocating buffers on the heap
and deleting them later (storing pointers to them at the far corners of
the earth), it would instead allocate them from small internal pools (if
possible) and only heap allocate (transparently) if necessary. The
pointers flung to the corners of the earth would be pointers (1) back
into the API_MSG or (2) to a heap block owned by boost::small_vector.

It took us months to realize that those bare pointers were being held by
COOKED_READ and RAW_READ and not actually being updated when the API
message was _copied_ as it was shuffled off to the background to become
a "Wait" message.

It turns out that it's trivially possible to crash the console by
sending two API calls--one that waits and one that completes
immediately--when the waiting message or the "wait completer" has a
bunch of dangling pointers in it. It further turns out that some
accessibility software (like JAWS) attaches directly to the console
session, much like winpty and ConEmu and friends. They're trying to read
out the buffer (API call!) and sometimes there's a shell waiting for
input (API call!). Oops.

In this commit, we fix up the message's internal pointers (in lieu of
giving it a proper copy constructor; see GH-10076) and then tell the
wait completion routine (which is going to be a COOKED_READ, RAW_READ,
DirectRead or WriteData) about the new buffer location.

This is a scoped fix that should be replaced (TODO GH-10076) with a
final one after Ask mode.

Retrieved from https://microsoft.visualstudio.com os.2020 OS official/rs_wdx_dxp_windev eca0875950fd3a9735662474613405e2dc06f485

References GH-10076

Fixes MSFT-33127449
Fixes GH-9692
2021-05-11 16:56:43 +00:00

57 lines
1.7 KiB
C++

/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- writeData.hpp
Abstract:
- This file defines the interface for write data structures.
- This is used not only within the write call, but also to hold context in case a wait condition is required
because writing to the buffer is blocked for some reason.
Author:
- Michael Niksa (MiNiksa) 9-Mar-2017
Revision History:
--*/
#pragma once
#include "../server/IWaitRoutine.h"
#include "../server/WaitTerminationReason.h"
class WriteData : public IWaitRoutine
{
public:
WriteData(SCREEN_INFORMATION& siContext,
_In_reads_bytes_(cbContext) wchar_t* const pwchContext,
const size_t cbContext,
const UINT uiOutputCodepage,
const bool requiresVtQuirk);
~WriteData();
void SetLeadByteAdjustmentStatus(const bool fLeadByteCaptured,
const bool fLeadByteConsumed);
void SetUtf8ConsumedCharacters(const size_t cchUtf8Consumed);
void MigrateUserBuffersOnTransitionToBackgroundWait(const void* oldBuffer, void* newBuffer) override;
bool Notify(const WaitTerminationReason TerminationReason,
const bool fIsUnicode,
_Out_ NTSTATUS* const pReplyStatus,
_Out_ size_t* const pNumBytes,
_Out_ DWORD* const pControlKeyState,
_Out_ void* const pOutputData);
private:
SCREEN_INFORMATION& _siContext;
wchar_t* const _pwchContext;
size_t const _cbContext;
UINT const _uiOutputCodepage;
bool _requiresVtQuirk;
bool _fLeadByteCaptured;
bool _fLeadByteConsumed;
size_t _cchUtf8Consumed;
};