Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix SetConsoleWindowInfo being able to crash ConPTY #13212

Merged
2 commits merged into from
Jun 1, 2022

Conversation

lhecker
Copy link
Member

@lhecker lhecker commented May 31, 2022

MSFT-33471786 is one of the most common crashes we have right now.
Memory dumps suggest that VtEngine::UpdateViewport is called with a rectangle
like (0, 46, 119, 29) (left, top, right, bottom), which is a rectangle of
negative height. When the _invalidMap is resized the negative size gets
turned into a very large unsigned integer, which results in an OOM exception,
crashing OpenConsole.

VtEngine::UpdateViewport is called by Renderer::_CheckViewportAndScroll
which holds a (cached) old and a new viewport. The old viewport was
(0, 46, 119, 75) which is exceedingly similar to the invalid, new viewport.
It's bottom coordinate is also coincidentally larger by exactly 46 (top).

The viewport comes from the SCREEN_INFORMATION class whose SetViewport
function was highly suspicious as it has a branch which updates the bottom
to be the buffer height, but leaves the top unmodified.

SCREEN_INFORMATION::SetViewport is called by SetConsoleWindowInfo which
processes user-provided data. A repro of the crash can be constructed with:

SMALL_RECT rect{0, 46, 119, 75};
SetConsoleWindowInfo(GetStdHandle(STD_OUTPUT_HANDLE), TRUE, &rect);

Closes #13193
Closes MSFT-33471786

Validation Steps Performed

Ensured the following code doesn't crash when run under Windows Terminal:

SMALL_RECT rect{0, 46, 119, 75};
SetConsoleWindowInfo(GetStdHandle(STD_OUTPUT_HANDLE), TRUE, &rect);

@ghost ghost added Issue-Bug It either shouldn't be doing this or needs an investigation. Priority-1 A description (P1) Severity-Crash Crashes are real bad news. labels May 31, 2022
Comment on lines +2277 to +2280
const auto cx = gsl::narrow_cast<SHORT>(std::clamp(viewportRect.width(), 1, coordScreenBufferSize.width));
const auto cy = gsl::narrow_cast<SHORT>(std::clamp(viewportRect.height(), 1, coordScreenBufferSize.height));
const auto x = gsl::narrow_cast<SHORT>(std::clamp(viewportRect.left, 0, coordScreenBufferSize.width - cx));
const auto y = gsl::narrow_cast<SHORT>(std::clamp(viewportRect.top, 0, coordScreenBufferSize.height - cy));
Copy link
Member Author

@lhecker lhecker May 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function needs to correct the newViewport argument to be within the valid bounds, while retaining the given size as much as possible. If you pass a newViewport with the top/bottom coordinates -130 and -100, it should still result in a viewport that's 30 high, but with a top/bottom of 0 and 30.

I feel like this change increases the robustness of the code by splitting the viewport into its size (cx/cy) and origin (x/y). That way we can first ensure that the size doesn't exceed our limits (just like the old code seemingly intended) and then adjust the origin to be within the smaller rectangle of valid coordinates.

The gsl::narrow_cast<SHORT>s will be removed once my 32-bit coord PR has been merged, but it shouldn't pose a problem here either, as GetBufferSize().Dimensions() is a COORD which can't exceed a SHORT.

@lhecker lhecker force-pushed the user/lhecker/13193-fail-fast-crash branch from 35deadc to 02ab51d Compare May 31, 2022 23:45
Comment on lines +2277 to +2278
const auto cx = gsl::narrow_cast<SHORT>(std::clamp(viewportRect.width(), 1, coordScreenBufferSize.width));
const auto cy = gsl::narrow_cast<SHORT>(std::clamp(viewportRect.height(), 1, coordScreenBufferSize.height));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const auto cx = gsl::narrow_cast<SHORT>(std::clamp(viewportRect.width(), 1, coordScreenBufferSize.width));
const auto cy = gsl::narrow_cast<SHORT>(std::clamp(viewportRect.height(), 1, coordScreenBufferSize.height));
const auto cx = gsl::narrow_cast<SHORT>(std::clamp(viewportRect.width(), 0, coordScreenBufferSize.width));
const auto cy = gsl::narrow_cast<SHORT>(std::clamp(viewportRect.height(), 0, coordScreenBufferSize.height));

curious, why not allow a width/height of 0?

Copy link
Member Author

@lhecker lhecker Jun 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The minimum size the TextBuffer allows is (1,1), so I thought it'd be reasonable if we did the same here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A text buffer with a zero dimension would not be a particularly useful text buffer :)

@carlos-zamora carlos-zamora added the Needs-Second It's a PR that needs another sign-off label Jun 1, 2022
@ghost ghost requested review from zadjii-msft, PankajBhojwani and DHowett June 1, 2022 17:36
@DHowett DHowett added the AutoMerge Marked for automatic merge by the bot when requirements are met label Jun 1, 2022
@ghost
Copy link

ghost commented Jun 1, 2022

Hello @DHowett!

Because this pull request has the AutoMerge label, I will be glad to assist with helping to merge this pull request once all check-in policies pass.

p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (@msftbot) and give me an instruction to get started! Learn more here.

@ghost ghost merged commit 7dbe741 into main Jun 1, 2022
@ghost ghost deleted the user/lhecker/13193-fail-fast-crash branch June 1, 2022 17:47
DHowett pushed a commit that referenced this pull request Jun 30, 2022
MSFT-33471786 is one of the most common crashes we have right now.
Memory dumps suggest that `VtEngine::UpdateViewport` is called with a rectangle
like `(0, 46, 119, 29)` (left, top, right, bottom), which is a rectangle of
negative height. When the `_invalidMap` is resized the negative size gets
turned into a very large unsigned integer, which results in an OOM exception,
crashing OpenConsole.

`VtEngine::UpdateViewport` is called by `Renderer::_CheckViewportAndScroll`
which holds a (cached) old and a new viewport. The old viewport was
`(0, 46, 119, 75)` which is exceedingly similar to the invalid, new viewport.
It's bottom coordinate is also coincidentally larger by exactly 46 (top).

The viewport comes from the `SCREEN_INFORMATION` class whose `SetViewport`
function was highly suspicious as it has a branch which updates the bottom
to be the buffer height, but leaves the top unmodified.

`SCREEN_INFORMATION::SetViewport` is called by `SetConsoleWindowInfo` which
processes user-provided data. A repro of the crash can be constructed with:
```
SMALL_RECT rect{0, 46, 119, 75};
SetConsoleWindowInfo(GetStdHandle(STD_OUTPUT_HANDLE), TRUE, &rect);
```

Closes #13193
Closes MSFT-33471786

## Validation Steps Performed
Ensured the following code doesn't crash when run under Windows Terminal:
```
SMALL_RECT rect{0, 46, 119, 75};
SetConsoleWindowInfo(GetStdHandle(STD_OUTPUT_HANDLE), TRUE, &rect);
```

(cherry picked from commit 7dbe741)
Service-Card-Id: 82642053
Service-Version: 1.14
@ghost
Copy link

ghost commented Jul 6, 2022

🎉Windows Terminal v1.14.186 has been released which incorporates this pull request.:tada:

Handy links:

@ghost ghost mentioned this pull request Jul 6, 2022
@ghost
Copy link

ghost commented Jul 6, 2022

🎉Windows Terminal Preview v1.15.186 has been released which incorporates this pull request.:tada:

Handy links:

This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
AutoMerge Marked for automatic merge by the bot when requirements are met Issue-Bug It either shouldn't be doing this or needs an investigation. Needs-Second It's a PR that needs another sign-off Priority-1 A description (P1) Severity-Crash Crashes are real bad news.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Exception 0xc0000409 in ucrtbase.dll
3 participants