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

sizeof vs. ARRAYSIZE mismatches in SystemConfigurationProvider::GetSettingsFromLink #11761

Closed
KalleOlaviNiemitalo opened this issue Nov 15, 2021 · 9 comments
Labels
Area-CodeHealth Issues related to code cleanliness, linting, rules, warnings, errors, static analysis, etc. good first issue This is a fix that might be easier for someone to do as a first contribution Help Wanted We encourage anyone to jump in on these. Issue-Bug It either shouldn't be doing this or needs an investigation. Needs-Tag-Fix Doesn't match tag requirements Priority-3 A description (P3) Product-Conhost For issues in the Console codebase
Milestone

Comments

@KalleOlaviNiemitalo
Copy link

Windows Terminal version (or Windows build number)

1.12.2931.0

Other Software

No response

Steps to reproduce

Both sizeof(wszIconLocation) expressions in the following part of SystemConfigurationProvider::GetSettingsFromLink should be ARRAYSIZE(wszIconLocation), instead.

// search for the application along the path so that we can load its icons (if we didn't find one explicitly in
// the shortcut)
const DWORD dwLinkLen = SearchPathW(pwszCurrDir, pwszAppName, nullptr, ARRAYSIZE(wszIconLocation), wszIconLocation, nullptr);
// If we cannot find the application in the path, then try to fall back and see if the window title is a valid path and use that.
if (dwLinkLen <= 0 || dwLinkLen > sizeof(wszIconLocation))
{
if (PathFileExistsW(pwszTitle) && (wcslen(pwszTitle) < sizeof(wszIconLocation)))

wszIconLocation is a local variable here:

WCHAR wszIconLocation[MAX_PATH] = { 0 };

Expected Behavior

No response

Actual Behavior

In the dwLinkLen > sizeof(wszIconLocation) comparison, dwLinkLen comes from SearchPathW, which returns the number of WCHARs. sizeof(wszIconLocation) however is the number of bytes. The effect of this mismatch is that, if the string from SearchPathW does not fit in wszIconLocation, then SystemConfigurationProvider::GetSettingsFromLink might not notice the problem. In principle, the content of the wszIconLocation array is then undefined, but the array was filled with zeroes initially and it seems likely that at least one of them is still there and prevents any out-of-bounds read.

In the wcslen(pwszTitle) < sizeof(wszIconLocation) comparison, wcslen returns the number of wchar_t values, but sizeof(wszIconLocation) is the number of bytes. The effect of this mismatch is that, if pwszTitle is too long, SystemConfigurationProvider::GetSettingsFromLink might call StringCchCopyW(wszIconLocation, ARRAYSIZE(wszIconLocation), pwszTitle) regardless. StringCchCopyW would then fail with STRSAFE_E_INSUFFICIENT_BUFFER and truncate the string, and SystemConfigurationProvider::GetSettingsFromLink would attempt to load icons from the truncated path. This does not seem exploitable because anyone providing the overlong pwszTitle could have provided the truncated string instead.

@ghost ghost added Needs-Triage It's a new issue that the core contributor team needs to triage at the next triage meeting Needs-Tag-Fix Doesn't match tag requirements labels Nov 15, 2021
@KalleOlaviNiemitalo
Copy link
Author

The initial release of the source code had the same bugs already:

// search for the application along the path so that we can load its icons (if we didn't find one explicitly in
// the shortcut)
const DWORD dwLinkLen = SearchPathW(pwszCurrDir, pwszAppName, nullptr, ARRAYSIZE(wszIconLocation), wszIconLocation, nullptr);
// If we cannot find the application in the path, then try to fall back and see if the window title is a valid path and use that.
if (dwLinkLen <= 0 || dwLinkLen > sizeof(wszIconLocation))
{
if (PathFileExistsW(pwszTitle) && (wcslen(pwszTitle) < sizeof(wszIconLocation)))

@zadjii-msft
Copy link
Member

Classic - there were tons of these in the codebase when we first inherited the console code. Seems we didn't find all of them. I suspect this isn't the only bug like this.

@zadjii-msft zadjii-msft added Area-CodeHealth Issues related to code cleanliness, linting, rules, warnings, errors, static analysis, etc. good first issue This is a fix that might be easier for someone to do as a first contribution Help Wanted We encourage anyone to jump in on these. Issue-Bug It either shouldn't be doing this or needs an investigation. Priority-3 A description (P3) Product-Conhost For issues in the Console codebase labels Nov 15, 2021
@ghost ghost removed the Needs-Tag-Fix Doesn't match tag requirements label Nov 15, 2021
@zadjii-msft zadjii-msft added this to the Terminal Backlog milestone Nov 15, 2021
@KalleOlaviNiemitalo
Copy link
Author

Did the codebase use ANSI functions originally?

@zadjii-msft
Copy link
Member

I believe it did, but then like, half of it was also surrounded by #ifdef CJK or something, which was a total mess, so a lot of the ANSI and wchar support all got merged into one codebase when we first inherited it.

@malxau
Copy link
Contributor

malxau commented Nov 16, 2021

As a rough rule, code that came from Win9x started life as ANSI; code from NT started life as Unicode. The consoles are completely different - this one was Unicode from the start.

Looking back at history, what happened here is the code was prepared for the open source release, which involved replacing undocumented NT calls with documented Win32 APIs. One of the differences is the underlying NT APIs often use bytes for buffer size, even for WCHARs. So it looks like the initial change to use SearchPathW still used sizeof, which failed tests, and this was changed to ARRAYSIZE a week later. Unfortunately the return value also needed to be changed. SearchPathW is multiplying the value by sizeof(WCHAR), calling NT, and dividing the result by sizeof(WCHAR), so sizeof was correct for both cases before that change.

@DHowett DHowett removed the Needs-Triage It's a new issue that the core contributor team needs to triage at the next triage meeting label Nov 17, 2021
@KalleOlaviNiemitalo
Copy link
Author

Is there something that can detect bugs like this automatically? The SearchPathW function has a parameter annotated as _Out_writes_to_opt_(nBufferLength,return + 1) LPWSTR lpBuffer, from which an analyzer could deduce that the return value counts WCHARs and does not make sense to compare to sizeof a WCHAR array.

@zadjii-msft zadjii-msft modified the milestones: Terminal Backlog, Backlog Jan 4, 2022
@abdoulkkonate
Copy link
Contributor

Hello guys, i just submitted the fix for this issue. I did this for a class assignment now it would be great if someone can tell how to find the function wszIconLocation. Thank you

@KalleOlaviNiemitalo
Copy link
Author

wszIconLocation is a local variable, not a function. I already posted a link to its definition.

The wsz prefix is Microsoft's traditional "Hungarian notation" and means it is a null-terminated string of wide characters.

@KalleOlaviNiemitalo
Copy link
Author

Closed this because #12273 was merged and released.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-CodeHealth Issues related to code cleanliness, linting, rules, warnings, errors, static analysis, etc. good first issue This is a fix that might be easier for someone to do as a first contribution Help Wanted We encourage anyone to jump in on these. Issue-Bug It either shouldn't be doing this or needs an investigation. Needs-Tag-Fix Doesn't match tag requirements Priority-3 A description (P3) Product-Conhost For issues in the Console codebase
Projects
None yet
Development

No branches or pull requests

5 participants