std: fix stack buffer overflow in Windows junction_point - #158147

Merged
rust-bors[bot] merged 1 commit into
rust-lang:mainfrom
devnexen:windows_fs_oflow_fix
Aug 5, 2026
Merged

std: fix stack buffer overflow in Windows junction_point#158147
rust-bors[bot] merged 1 commit into
rust-lang:mainfrom
devnexen:windows_fs_oflow_fix

Conversation

@devnexen

@devnexendevnexen commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

View all comments

The guard checked data_len > u16::MAX, allowing paths far larger than PathBuffer (a fixed 16384-element array), which the subsequent single copy_from then overflows. Bound against MAXIMUM_REPARSE_DATA_BUFFER_SIZE plus header instead, matching the kernel's limit.

@rustbotrustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Jun 19, 2026
@rustbot

Copy link
Copy Markdown
Collaborator

r? @Darksonn

rustbot has assigned @Darksonn.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: @ChrisDenton, libs
  • @ChrisDenton, libs expanded to 12 candidates
  • Random selection from Darksonn, Mark-Simulacrum, clarfonthey, jhpratt

@DarksonnDarksonn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Comment threadlibrary/std/src/sys/fs/windows.rs Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It sounds like this should be changed to ptr[..abs_path.len()].copy_from_slice(abs_path) or similar so that we actually perform a bounds check here.

Also, it would be really nice with a test that'd catch this (may be easier to check that the test is failing if we insert a bounds check first).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

In fact, maybe the bounds check should be entirely rewritten to

ptr.get(..abs_path.len())
.ok_or_else(|| io::const_error!(io::ErrorKind::InvalidInput, "`original` path is too long"))?
.copy_from_slice(abs_path)

This way there's no risk that the two bounds checks are not kept in sync. For instance, why is there a + 8 in the previous check? I don't understand that part.

Comment threadlibrary/std/src/sys/fs/windows.rs Outdated
Comment on lines 1679 to 1683
PathBuffer: [MaybeUninit<u16>; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize],
}
let data_len = 12 + (abs_path.len() * 2);
if data_len > u16::MAX as usize {
if data_len + 8 > c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize {
return Err(io::const_error!(io::ErrorKind::InvalidInput, "`original` path is too long"));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

data_len counts the number of bytes, but MAXIMUM_REPARSE_DATA_BUFFER_SIZE counts the number of u16s. This doesn't sound right.

@rustbotrustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 19, 2026
@rustbot

Copy link
Copy Markdown
Collaborator

Reminder, once the PR becomes ready for a review, use @rustbot ready.

@rust-log-analyzer

This comment has been minimized.

@devnexen

Copy link
Copy Markdown
ContributorAuthor

@rustbot ready

@rustbotrustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jun 19, 2026

@DarksonnDarksonn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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


#[test]
#[cfg(windows)]
fn junction_point_overlong_path() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd like to see this regression test fail without the change. Do you mind opening a second temporary PR containing just the test so that we can run it through CI? We can close it again when we've confirmed the regression test catches the bug.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Confirmed failure in #158201.

Comment threadlibrary/std/src/sys/fs/windows.rs Outdated
Comment on lines +1694 to +1700
PathBuffer: [MaybeUninit::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize],
PathBuffer: [MaybeUninit::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize / 2],
};
// The path is followed by its null terminator and the (empty) print name's
// null terminator, so the buffer must hold two extra `u16`s. This single
// bounds check keeps the buffer, the copy, and `data_len` below in sync; if
// the path doesn't fit, fail rather than overflow the buffer.
let Some(ptr) = header.PathBuffer.get_mut(..abs_path.len() + 2) else {
return Err(io::const_error!(io::ErrorKind::InvalidInput, "`original` path is too long"));
};
ptr[..abs_path.len()].write_copy_of_slice(&abs_path);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This buffer is uninitialized. Don't you need to set path[abs_path.len()] and path[abs_path.len()+1] to zero?

@ChrisDentonChrisDentonJun 19, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The path has an explicit length so it doesn't need to be null terminated at all. I'm uncertain where that idea came from but it's probably just a misunderstanding? I mean, I guess there's no harm in writing a null but if so it shouldn't be part of the length.

@rustbotrustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 19, 2026
@ChrisDenton

Copy link
Copy Markdown
Member

To give some context here, this was originally a hacky function used only in tests. It's currently publicly exposed as a nightly-only API but it's not considered ready for stabilisation. E.g. 16kb is way too much for a stack buffer (though admittedly using a stack buffer for shorter paths would be useful).

PathBuffer: [MaybeUninit<u16>; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize],
// `MAXIMUM_REPARSE_DATA_BUFFER_SIZE` is a size in bytes; halve it for a
// count of `u16`s (the `readlink` path uses it as a byte buffer).
PathBuffer: [MaybeUninit<u16>; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize / 2],

@ChrisDentonChrisDentonJun 19, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This doesn't sound right at all. What makes you say MAXIMUM_REPARSE_DATA_BUFFER_SIZE is in bytes?

View changes since the review

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Huh, apparently it is.

The protocol docs make no mention of a maximum size, only that it's a 16 bit unsigned integer (hence my surprise at 16kb being a limit). But the public headers for the kernel API do have MAXIMUM_REPARSE_DATA_BUFFER_SIZE in bytes of 16kb.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should it be changed to an u8 array as well?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I would say no. It's the mount-point WCHAR path, and u16 keeps the copy a clean write_copy_of_slice(&abs_path).

@devnexen
devnexenforce-pushed the windows_fs_oflow_fix branch from d842451 to 28748e5CompareJune 21, 2026 06:05
rust-borsBot pushed a commit that referenced this pull request Jun 21, 2026
Temporary CI-verification test for #158147. Without the fix,
a >16 KiB junction target passes the old `> u16::MAX` length check yet
overflows the inline reparse stack buffer. This test must fail on master
and pass once the fix lands.
@DarksonnDarksonn added O-windows Operating system: Windows A-filesystem Area: `std::fs` labels Jun 21, 2026
@devnexen

Copy link
Copy Markdown
ContributorAuthor

@rustbot ready

@rustbotrustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jun 21, 2026

@DarksonnDarksonn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Comment threadlibrary/std/src/sys/fs/windows.rs Outdated
// Size of the reparse data after the 8-byte ReparseTag/ReparseDataLength/
// Reserved header: the four name offset/length `u16` fields (8 bytes) plus
// the path.
let data_len = 8 + abs_path.len() * 2;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Isn't it 16 bytes?

  • ReparseTag is 4 bytes
  • ReparseDataLength is 2 bytes
  • Reserved is 2 bytes
  • SubstituteNameOffset is 2 bytes
  • SubstituteNameLength is 2 bytes
  • PrintNameOffset is 2 bytes
  • PrintNameLength is 2 bytes

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Right, it's 16 bytes. Switched to offset_of! so both lengths derive from the struct.

@rustbotrustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 22, 2026
@devnexen
devnexenforce-pushed the windows_fs_oflow_fix branch from 28748e5 to b7af0d1CompareJune 22, 2026 23:24
@devnexen

Copy link
Copy Markdown
ContributorAuthor

@rustbot ready

@rust-borsrust-borsBot added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Jul 1, 2026
@rust-bors

rust-borsBot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

This pull request was unapproved.

View changes since this unapproval

@rust-borsrust-borsBot removed the S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. label Jul 1, 2026
@Darksonn

Copy link
Copy Markdown
Member

@devnexen Any update on this?

@devnexen
devnexenforce-pushed the windows_fs_oflow_fix branch from b7af0d1 to 74afb0aCompareJuly 25, 2026 15:16
@rustbot

This comment has been minimized.

The guard checked `data_len > u16::MAX`, allowing paths far larger than
`PathBuffer` (a fixed 16384-element array), which the subsequent single
`copy_from` then overflows. Bound against `MAXIMUM_REPARSE_DATA_BUFFER_SIZE`
plus header instead, matching the kernel's limit.
@devnexen
devnexenforce-pushed the windows_fs_oflow_fix branch from 74afb0a to 3313cd6CompareJuly 25, 2026 15:32
@rustbot

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@Darksonn

Copy link
Copy Markdown
Member

Please remember to use @rustbot ready when this is ready for review.

@bors try

@rust-bors

This comment has been minimized.

rust-borsBot pushed a commit that referenced this pull request Aug 5, 2026
std: fix stack buffer overflow in Windows junction_point
@rust-bors

rust-borsBot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

☀️ Try build successful (CI)
Build commit: 409d767 (409d767a80e64b1f76845dfd4cd80eaa8eb67050)
Base parent: 7218ebe (7218ebe93668f51a94a572b690c433dfdbdc2c3d)

@DarksonnDarksonn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@rust-bors

rust-borsBot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

📌 Commit 3313cd6 has been approved by Darksonn

It is now in the queue for this repository.

🌲 The tree is currently closed for pull requests below priority 10. This pull request will be tested once the tree is reopened.

Reason for tree closure: manually handling queue due to backlog

@rust-borsrust-borsBot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Aug 5, 2026
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Aug 5, 2026
…arksonn
std: fix stack buffer overflow in Windows junction_point
The guard checked `data_len > u16::MAX`, allowing paths far larger than `PathBuffer` (a fixed 16384-element array), which the subsequent single `copy_from` then overflows. Bound against `MAXIMUM_REPARSE_DATA_BUFFER_SIZE` plus header instead, matching the kernel's limit.
rust-borsBot pushed a commit that referenced this pull request Aug 5, 2026
…uwer
Rollup of 22 pull requests
Successful merges:
- #158147 (std: fix stack buffer overflow in Windows junction_point)
- #159784 (Hint that memchr returns an in-bounds index)
- #160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- #160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- #160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- #160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- #160422 (move mir-opt miri tests to CI logic)
- #160444 (Avoid resolving path keywords outside `TypeNS`)
- #160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe my unsafe speculative flag)
- #155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- #158726 (std: move futex implementations into sys::sync::futex)
- #159225 (Split IncrCompSession out of Session)
- #159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- #160198 (Rework `smallest_range_containing` to handle duplicates)
- #160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- #160390 (autodiff: Handle slice-tailed DSTs in type trees)
- #160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- #160520 (Add some tests for specialization)
- #160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- #160531 (docs: fix typo in AllowExprMetavar comment)
- #160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- #160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Aug 5, 2026
…arksonn
std: fix stack buffer overflow in Windows junction_point
The guard checked `data_len > u16::MAX`, allowing paths far larger than `PathBuffer` (a fixed 16384-element array), which the subsequent single `copy_from` then overflows. Bound against `MAXIMUM_REPARSE_DATA_BUFFER_SIZE` plus header instead, matching the kernel's limit.
rust-borsBot pushed a commit that referenced this pull request Aug 5, 2026
…uwer
Rollup of 25 pull requests
Successful merges:
- #154585 (treat no_mangle_generic_items as hard error instead of lint warning)
- #158147 (std: fix stack buffer overflow in Windows junction_point)
- #160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- #160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- #160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- #160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- #160422 (move mir-opt miri tests to CI logic)
- #160444 (Avoid resolving path keywords outside `TypeNS`)
- #160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe my unsafe speculative flag)
- #155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- #158726 (std: move futex implementations into sys::sync::futex)
- #158762 (Emit thumb code on VEX V5)
- #159225 (Split IncrCompSession out of Session)
- #159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- #160198 (Rework `smallest_range_containing` to handle duplicates)
- #160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- #160390 (autodiff: Handle slice-tailed DSTs in type trees)
- #160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- #160516 (Add regression test for HRTB projection in closure)
- #160520 (Add some tests for specialization)
- #160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- #160523 (Add regression test for opaque type)
- #160531 (docs: fix typo in AllowExprMetavar comment)
- #160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- #160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
rust-borsBot pushed a commit that referenced this pull request Aug 5, 2026
…uwer
Rollup of 25 pull requests
Successful merges:
- #158147 (std: fix stack buffer overflow in Windows junction_point)
- #160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- #160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- #160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- #160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- #160422 (move mir-opt miri tests to CI logic)
- #160444 (Avoid resolving path keywords outside `TypeNS`)
- #160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe by unsafe speculative flag)
- #155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- #158726 (std: move futex implementations into sys::sync::futex)
- #158762 (Emit thumb code on VEX V5)
- #159225 (Split IncrCompSession out of Session)
- #159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- #160198 (Rework `smallest_range_containing` to handle duplicates)
- #160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- #160390 (autodiff: Handle slice-tailed DSTs in type trees)
- #160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- #160501 (Add bootstrap CLI snapshot test for testing miri)
- #160516 (Add regression test for HRTB projection in closure)
- #160520 (Add some tests for specialization)
- #160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- #160523 (Add regression test for opaque type)
- #160531 (docs: fix typo in AllowExprMetavar comment)
- #160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- #160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
@rust-bors
rust-borsBot merged commit ebab4cf into rust-lang:mainAug 5, 2026
14 checks passed
rust-timer added a commit that referenced this pull request Aug 5, 2026
Rollup merge of #158147 - devnexen:windows_fs_oflow_fix, r=Darksonn
std: fix stack buffer overflow in Windows junction_point
The guard checked `data_len > u16::MAX`, allowing paths far larger than `PathBuffer` (a fixed 16384-element array), which the subsequent single `copy_from` then overflows. Bound against `MAXIMUM_REPARSE_DATA_BUFFER_SIZE` plus header instead, matching the kernel's limit.
@rustbotrustbot added this to the 1.99.0 milestone Aug 5, 2026
github-actionsBot pushed a commit to rust-lang/rustc-dev-guide that referenced this pull request Aug 10, 2026
…uwer
Rollup of 25 pull requests
Successful merges:
- rust-lang/rust#158147 (std: fix stack buffer overflow in Windows junction_point)
- rust-lang/rust#160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- rust-lang/rust#160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- rust-lang/rust#160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- rust-lang/rust#160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- rust-lang/rust#160422 (move mir-opt miri tests to CI logic)
- rust-lang/rust#160444 (Avoid resolving path keywords outside `TypeNS`)
- rust-lang/rust#160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe by unsafe speculative flag)
- rust-lang/rust#155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- rust-lang/rust#158726 (std: move futex implementations into sys::sync::futex)
- rust-lang/rust#158762 (Emit thumb code on VEX V5)
- rust-lang/rust#159225 (Split IncrCompSession out of Session)
- rust-lang/rust#159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- rust-lang/rust#160198 (Rework `smallest_range_containing` to handle duplicates)
- rust-lang/rust#160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- rust-lang/rust#160390 (autodiff: Handle slice-tailed DSTs in type trees)
- rust-lang/rust#160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- rust-lang/rust#160501 (Add bootstrap CLI snapshot test for testing miri)
- rust-lang/rust#160516 (Add regression test for HRTB projection in closure)
- rust-lang/rust#160520 (Add some tests for specialization)
- rust-lang/rust#160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- rust-lang/rust#160523 (Add regression test for opaque type)
- rust-lang/rust#160531 (docs: fix typo in AllowExprMetavar comment)
- rust-lang/rust#160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- rust-lang/rust#160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
flip1995 pushed a commit to flip1995/rust-clippy that referenced this pull request Aug 17, 2026
…uwer
Rollup of 25 pull requests
Successful merges:
- rust-lang/rust#158147 (std: fix stack buffer overflow in Windows junction_point)
- rust-lang/rust#160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- rust-lang/rust#160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- rust-lang/rust#160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- rust-lang/rust#160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- rust-lang/rust#160422 (move mir-opt miri tests to CI logic)
- rust-lang/rust#160444 (Avoid resolving path keywords outside `TypeNS`)
- rust-lang/rust#160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe by unsafe speculative flag)
- rust-lang/rust#155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- rust-lang/rust#158726 (std: move futex implementations into sys::sync::futex)
- rust-lang/rust#158762 (Emit thumb code on VEX V5)
- rust-lang/rust#159225 (Split IncrCompSession out of Session)
- rust-lang/rust#159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- rust-lang/rust#160198 (Rework `smallest_range_containing` to handle duplicates)
- rust-lang/rust#160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- rust-lang/rust#160390 (autodiff: Handle slice-tailed DSTs in type trees)
- rust-lang/rust#160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- rust-lang/rust#160501 (Add bootstrap CLI snapshot test for testing miri)
- rust-lang/rust#160516 (Add regression test for HRTB projection in closure)
- rust-lang/rust#160520 (Add some tests for specialization)
- rust-lang/rust#160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- rust-lang/rust#160523 (Add regression test for opaque type)
- rust-lang/rust#160531 (docs: fix typo in AllowExprMetavar comment)
- rust-lang/rust#160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- rust-lang/rust#160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-filesystemArea: `std::fs`O-windowsOperating system: WindowsS-waiting-on-borsStatus: Waiting on bors to run and complete tests. Bors will change the label on completion.T-libsRelevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@devnexen@rustbot@rust-log-analyzer@ChrisDenton@Darksonn@jhpratt
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

std: fix stack buffer overflow in Windows junction_point - #158147

Merged
rust-bors[bot] merged 1 commit into
rust-lang:mainfrom
devnexen:windows_fs_oflow_fix
Aug 5, 2026
Merged

std: fix stack buffer overflow in Windows junction_point#158147
rust-bors[bot] merged 1 commit into
rust-lang:mainfrom
devnexen:windows_fs_oflow_fix

Conversation

@devnexen

@devnexendevnexen commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

View all comments

The guard checked data_len > u16::MAX, allowing paths far larger than PathBuffer (a fixed 16384-element array), which the subsequent single copy_from then overflows. Bound against MAXIMUM_REPARSE_DATA_BUFFER_SIZE plus header instead, matching the kernel's limit.

@rustbotrustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Jun 19, 2026
@rustbot

Copy link
Copy Markdown
Collaborator

r? @Darksonn

rustbot has assigned @Darksonn.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: @ChrisDenton, libs
  • @ChrisDenton, libs expanded to 12 candidates
  • Random selection from Darksonn, Mark-Simulacrum, clarfonthey, jhpratt

@DarksonnDarksonn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Comment threadlibrary/std/src/sys/fs/windows.rs Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It sounds like this should be changed to ptr[..abs_path.len()].copy_from_slice(abs_path) or similar so that we actually perform a bounds check here.

Also, it would be really nice with a test that'd catch this (may be easier to check that the test is failing if we insert a bounds check first).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

In fact, maybe the bounds check should be entirely rewritten to

ptr.get(..abs_path.len())
.ok_or_else(|| io::const_error!(io::ErrorKind::InvalidInput, "`original` path is too long"))?
.copy_from_slice(abs_path)

This way there's no risk that the two bounds checks are not kept in sync. For instance, why is there a + 8 in the previous check? I don't understand that part.

Comment threadlibrary/std/src/sys/fs/windows.rs Outdated
Comment on lines 1679 to 1683
PathBuffer: [MaybeUninit<u16>; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize],
}
let data_len = 12 + (abs_path.len() * 2);
if data_len > u16::MAX as usize {
if data_len + 8 > c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize {
return Err(io::const_error!(io::ErrorKind::InvalidInput, "`original` path is too long"));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

data_len counts the number of bytes, but MAXIMUM_REPARSE_DATA_BUFFER_SIZE counts the number of u16s. This doesn't sound right.

@rustbotrustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 19, 2026
@rustbot

Copy link
Copy Markdown
Collaborator

Reminder, once the PR becomes ready for a review, use @rustbot ready.

@rust-log-analyzer

This comment has been minimized.

@devnexen

Copy link
Copy Markdown
ContributorAuthor

@rustbot ready

@rustbotrustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jun 19, 2026

@DarksonnDarksonn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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


#[test]
#[cfg(windows)]
fn junction_point_overlong_path() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd like to see this regression test fail without the change. Do you mind opening a second temporary PR containing just the test so that we can run it through CI? We can close it again when we've confirmed the regression test catches the bug.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Confirmed failure in #158201.

Comment threadlibrary/std/src/sys/fs/windows.rs Outdated
Comment on lines +1694 to +1700
PathBuffer: [MaybeUninit::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize],
PathBuffer: [MaybeUninit::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize / 2],
};
// The path is followed by its null terminator and the (empty) print name's
// null terminator, so the buffer must hold two extra `u16`s. This single
// bounds check keeps the buffer, the copy, and `data_len` below in sync; if
// the path doesn't fit, fail rather than overflow the buffer.
let Some(ptr) = header.PathBuffer.get_mut(..abs_path.len() + 2) else {
return Err(io::const_error!(io::ErrorKind::InvalidInput, "`original` path is too long"));
};
ptr[..abs_path.len()].write_copy_of_slice(&abs_path);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This buffer is uninitialized. Don't you need to set path[abs_path.len()] and path[abs_path.len()+1] to zero?

@ChrisDentonChrisDentonJun 19, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The path has an explicit length so it doesn't need to be null terminated at all. I'm uncertain where that idea came from but it's probably just a misunderstanding? I mean, I guess there's no harm in writing a null but if so it shouldn't be part of the length.

@rustbotrustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 19, 2026
@ChrisDenton

Copy link
Copy Markdown
Member

To give some context here, this was originally a hacky function used only in tests. It's currently publicly exposed as a nightly-only API but it's not considered ready for stabilisation. E.g. 16kb is way too much for a stack buffer (though admittedly using a stack buffer for shorter paths would be useful).

PathBuffer: [MaybeUninit<u16>; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize],
// `MAXIMUM_REPARSE_DATA_BUFFER_SIZE` is a size in bytes; halve it for a
// count of `u16`s (the `readlink` path uses it as a byte buffer).
PathBuffer: [MaybeUninit<u16>; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize / 2],

@ChrisDentonChrisDentonJun 19, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This doesn't sound right at all. What makes you say MAXIMUM_REPARSE_DATA_BUFFER_SIZE is in bytes?

View changes since the review

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Huh, apparently it is.

The protocol docs make no mention of a maximum size, only that it's a 16 bit unsigned integer (hence my surprise at 16kb being a limit). But the public headers for the kernel API do have MAXIMUM_REPARSE_DATA_BUFFER_SIZE in bytes of 16kb.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should it be changed to an u8 array as well?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I would say no. It's the mount-point WCHAR path, and u16 keeps the copy a clean write_copy_of_slice(&abs_path).

@devnexen
devnexenforce-pushed the windows_fs_oflow_fix branch from d842451 to 28748e5CompareJune 21, 2026 06:05
rust-borsBot pushed a commit that referenced this pull request Jun 21, 2026
Temporary CI-verification test for #158147. Without the fix,
a >16 KiB junction target passes the old `> u16::MAX` length check yet
overflows the inline reparse stack buffer. This test must fail on master
and pass once the fix lands.
@DarksonnDarksonn added O-windows Operating system: Windows A-filesystem Area: `std::fs` labels Jun 21, 2026
@devnexen

Copy link
Copy Markdown
ContributorAuthor

@rustbot ready

@rustbotrustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jun 21, 2026

@DarksonnDarksonn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Comment threadlibrary/std/src/sys/fs/windows.rs Outdated
// Size of the reparse data after the 8-byte ReparseTag/ReparseDataLength/
// Reserved header: the four name offset/length `u16` fields (8 bytes) plus
// the path.
let data_len = 8 + abs_path.len() * 2;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Isn't it 16 bytes?

  • ReparseTag is 4 bytes
  • ReparseDataLength is 2 bytes
  • Reserved is 2 bytes
  • SubstituteNameOffset is 2 bytes
  • SubstituteNameLength is 2 bytes
  • PrintNameOffset is 2 bytes
  • PrintNameLength is 2 bytes

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Right, it's 16 bytes. Switched to offset_of! so both lengths derive from the struct.

@rustbotrustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 22, 2026
@devnexen
devnexenforce-pushed the windows_fs_oflow_fix branch from 28748e5 to b7af0d1CompareJune 22, 2026 23:24
@devnexen

Copy link
Copy Markdown
ContributorAuthor

@rustbot ready

@rust-borsrust-borsBot added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Jul 1, 2026
@rust-bors

rust-borsBot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

This pull request was unapproved.

View changes since this unapproval

@rust-borsrust-borsBot removed the S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. label Jul 1, 2026
@Darksonn

Copy link
Copy Markdown
Member

@devnexen Any update on this?

@devnexen
devnexenforce-pushed the windows_fs_oflow_fix branch from b7af0d1 to 74afb0aCompareJuly 25, 2026 15:16
@rustbot

This comment has been minimized.

The guard checked `data_len > u16::MAX`, allowing paths far larger than
`PathBuffer` (a fixed 16384-element array), which the subsequent single
`copy_from` then overflows. Bound against `MAXIMUM_REPARSE_DATA_BUFFER_SIZE`
plus header instead, matching the kernel's limit.
@devnexen
devnexenforce-pushed the windows_fs_oflow_fix branch from 74afb0a to 3313cd6CompareJuly 25, 2026 15:32
@rustbot

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@Darksonn

Copy link
Copy Markdown
Member

Please remember to use @rustbot ready when this is ready for review.

@bors try

@rust-bors

This comment has been minimized.

rust-borsBot pushed a commit that referenced this pull request Aug 5, 2026
std: fix stack buffer overflow in Windows junction_point
@rust-bors

rust-borsBot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

☀️ Try build successful (CI)
Build commit: 409d767 (409d767a80e64b1f76845dfd4cd80eaa8eb67050)
Base parent: 7218ebe (7218ebe93668f51a94a572b690c433dfdbdc2c3d)

@DarksonnDarksonn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@rust-bors

rust-borsBot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

📌 Commit 3313cd6 has been approved by Darksonn

It is now in the queue for this repository.

🌲 The tree is currently closed for pull requests below priority 10. This pull request will be tested once the tree is reopened.

Reason for tree closure: manually handling queue due to backlog

@rust-borsrust-borsBot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Aug 5, 2026
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Aug 5, 2026
…arksonn
std: fix stack buffer overflow in Windows junction_point
The guard checked `data_len > u16::MAX`, allowing paths far larger than `PathBuffer` (a fixed 16384-element array), which the subsequent single `copy_from` then overflows. Bound against `MAXIMUM_REPARSE_DATA_BUFFER_SIZE` plus header instead, matching the kernel's limit.
rust-borsBot pushed a commit that referenced this pull request Aug 5, 2026
…uwer
Rollup of 22 pull requests
Successful merges:
- #158147 (std: fix stack buffer overflow in Windows junction_point)
- #159784 (Hint that memchr returns an in-bounds index)
- #160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- #160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- #160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- #160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- #160422 (move mir-opt miri tests to CI logic)
- #160444 (Avoid resolving path keywords outside `TypeNS`)
- #160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe my unsafe speculative flag)
- #155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- #158726 (std: move futex implementations into sys::sync::futex)
- #159225 (Split IncrCompSession out of Session)
- #159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- #160198 (Rework `smallest_range_containing` to handle duplicates)
- #160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- #160390 (autodiff: Handle slice-tailed DSTs in type trees)
- #160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- #160520 (Add some tests for specialization)
- #160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- #160531 (docs: fix typo in AllowExprMetavar comment)
- #160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- #160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Aug 5, 2026
…arksonn
std: fix stack buffer overflow in Windows junction_point
The guard checked `data_len > u16::MAX`, allowing paths far larger than `PathBuffer` (a fixed 16384-element array), which the subsequent single `copy_from` then overflows. Bound against `MAXIMUM_REPARSE_DATA_BUFFER_SIZE` plus header instead, matching the kernel's limit.
rust-borsBot pushed a commit that referenced this pull request Aug 5, 2026
…uwer
Rollup of 25 pull requests
Successful merges:
- #154585 (treat no_mangle_generic_items as hard error instead of lint warning)
- #158147 (std: fix stack buffer overflow in Windows junction_point)
- #160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- #160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- #160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- #160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- #160422 (move mir-opt miri tests to CI logic)
- #160444 (Avoid resolving path keywords outside `TypeNS`)
- #160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe my unsafe speculative flag)
- #155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- #158726 (std: move futex implementations into sys::sync::futex)
- #158762 (Emit thumb code on VEX V5)
- #159225 (Split IncrCompSession out of Session)
- #159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- #160198 (Rework `smallest_range_containing` to handle duplicates)
- #160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- #160390 (autodiff: Handle slice-tailed DSTs in type trees)
- #160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- #160516 (Add regression test for HRTB projection in closure)
- #160520 (Add some tests for specialization)
- #160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- #160523 (Add regression test for opaque type)
- #160531 (docs: fix typo in AllowExprMetavar comment)
- #160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- #160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
rust-borsBot pushed a commit that referenced this pull request Aug 5, 2026
…uwer
Rollup of 25 pull requests
Successful merges:
- #158147 (std: fix stack buffer overflow in Windows junction_point)
- #160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- #160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- #160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- #160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- #160422 (move mir-opt miri tests to CI logic)
- #160444 (Avoid resolving path keywords outside `TypeNS`)
- #160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe by unsafe speculative flag)
- #155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- #158726 (std: move futex implementations into sys::sync::futex)
- #158762 (Emit thumb code on VEX V5)
- #159225 (Split IncrCompSession out of Session)
- #159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- #160198 (Rework `smallest_range_containing` to handle duplicates)
- #160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- #160390 (autodiff: Handle slice-tailed DSTs in type trees)
- #160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- #160501 (Add bootstrap CLI snapshot test for testing miri)
- #160516 (Add regression test for HRTB projection in closure)
- #160520 (Add some tests for specialization)
- #160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- #160523 (Add regression test for opaque type)
- #160531 (docs: fix typo in AllowExprMetavar comment)
- #160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- #160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
@rust-bors
rust-borsBot merged commit ebab4cf into rust-lang:mainAug 5, 2026
14 checks passed
rust-timer added a commit that referenced this pull request Aug 5, 2026
Rollup merge of #158147 - devnexen:windows_fs_oflow_fix, r=Darksonn
std: fix stack buffer overflow in Windows junction_point
The guard checked `data_len > u16::MAX`, allowing paths far larger than `PathBuffer` (a fixed 16384-element array), which the subsequent single `copy_from` then overflows. Bound against `MAXIMUM_REPARSE_DATA_BUFFER_SIZE` plus header instead, matching the kernel's limit.
@rustbotrustbot added this to the 1.99.0 milestone Aug 5, 2026
github-actionsBot pushed a commit to rust-lang/rustc-dev-guide that referenced this pull request Aug 10, 2026
…uwer
Rollup of 25 pull requests
Successful merges:
- rust-lang/rust#158147 (std: fix stack buffer overflow in Windows junction_point)
- rust-lang/rust#160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- rust-lang/rust#160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- rust-lang/rust#160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- rust-lang/rust#160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- rust-lang/rust#160422 (move mir-opt miri tests to CI logic)
- rust-lang/rust#160444 (Avoid resolving path keywords outside `TypeNS`)
- rust-lang/rust#160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe by unsafe speculative flag)
- rust-lang/rust#155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- rust-lang/rust#158726 (std: move futex implementations into sys::sync::futex)
- rust-lang/rust#158762 (Emit thumb code on VEX V5)
- rust-lang/rust#159225 (Split IncrCompSession out of Session)
- rust-lang/rust#159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- rust-lang/rust#160198 (Rework `smallest_range_containing` to handle duplicates)
- rust-lang/rust#160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- rust-lang/rust#160390 (autodiff: Handle slice-tailed DSTs in type trees)
- rust-lang/rust#160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- rust-lang/rust#160501 (Add bootstrap CLI snapshot test for testing miri)
- rust-lang/rust#160516 (Add regression test for HRTB projection in closure)
- rust-lang/rust#160520 (Add some tests for specialization)
- rust-lang/rust#160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- rust-lang/rust#160523 (Add regression test for opaque type)
- rust-lang/rust#160531 (docs: fix typo in AllowExprMetavar comment)
- rust-lang/rust#160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- rust-lang/rust#160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
flip1995 pushed a commit to flip1995/rust-clippy that referenced this pull request Aug 17, 2026
…uwer
Rollup of 25 pull requests
Successful merges:
- rust-lang/rust#158147 (std: fix stack buffer overflow in Windows junction_point)
- rust-lang/rust#160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- rust-lang/rust#160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- rust-lang/rust#160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- rust-lang/rust#160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- rust-lang/rust#160422 (move mir-opt miri tests to CI logic)
- rust-lang/rust#160444 (Avoid resolving path keywords outside `TypeNS`)
- rust-lang/rust#160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe by unsafe speculative flag)
- rust-lang/rust#155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- rust-lang/rust#158726 (std: move futex implementations into sys::sync::futex)
- rust-lang/rust#158762 (Emit thumb code on VEX V5)
- rust-lang/rust#159225 (Split IncrCompSession out of Session)
- rust-lang/rust#159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- rust-lang/rust#160198 (Rework `smallest_range_containing` to handle duplicates)
- rust-lang/rust#160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- rust-lang/rust#160390 (autodiff: Handle slice-tailed DSTs in type trees)
- rust-lang/rust#160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- rust-lang/rust#160501 (Add bootstrap CLI snapshot test for testing miri)
- rust-lang/rust#160516 (Add regression test for HRTB projection in closure)
- rust-lang/rust#160520 (Add some tests for specialization)
- rust-lang/rust#160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- rust-lang/rust#160523 (Add regression test for opaque type)
- rust-lang/rust#160531 (docs: fix typo in AllowExprMetavar comment)
- rust-lang/rust#160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- rust-lang/rust#160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-filesystemArea: `std::fs`O-windowsOperating system: WindowsS-waiting-on-borsStatus: Waiting on bors to run and complete tests. Bors will change the label on completion.T-libsRelevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@devnexen@rustbot@rust-log-analyzer@ChrisDenton@Darksonn@jhpratt
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

std: fix stack buffer overflow in Windows junction_point - #158147

Merged
rust-bors[bot] merged 1 commit into
rust-lang:mainfrom
devnexen:windows_fs_oflow_fix
Aug 5, 2026
Merged

std: fix stack buffer overflow in Windows junction_point#158147
rust-bors[bot] merged 1 commit into
rust-lang:mainfrom
devnexen:windows_fs_oflow_fix

Conversation

@devnexen

@devnexendevnexen commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

View all comments

The guard checked data_len > u16::MAX, allowing paths far larger than PathBuffer (a fixed 16384-element array), which the subsequent single copy_from then overflows. Bound against MAXIMUM_REPARSE_DATA_BUFFER_SIZE plus header instead, matching the kernel's limit.

@rustbotrustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Jun 19, 2026
@rustbot

Copy link
Copy Markdown
Collaborator

r? @Darksonn

rustbot has assigned @Darksonn.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: @ChrisDenton, libs
  • @ChrisDenton, libs expanded to 12 candidates
  • Random selection from Darksonn, Mark-Simulacrum, clarfonthey, jhpratt

@DarksonnDarksonn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Comment threadlibrary/std/src/sys/fs/windows.rs Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It sounds like this should be changed to ptr[..abs_path.len()].copy_from_slice(abs_path) or similar so that we actually perform a bounds check here.

Also, it would be really nice with a test that'd catch this (may be easier to check that the test is failing if we insert a bounds check first).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

In fact, maybe the bounds check should be entirely rewritten to

ptr.get(..abs_path.len())
.ok_or_else(|| io::const_error!(io::ErrorKind::InvalidInput, "`original` path is too long"))?
.copy_from_slice(abs_path)

This way there's no risk that the two bounds checks are not kept in sync. For instance, why is there a + 8 in the previous check? I don't understand that part.

Comment threadlibrary/std/src/sys/fs/windows.rs Outdated
Comment on lines 1679 to 1683
PathBuffer: [MaybeUninit<u16>; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize],
}
let data_len = 12 + (abs_path.len() * 2);
if data_len > u16::MAX as usize {
if data_len + 8 > c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize {
return Err(io::const_error!(io::ErrorKind::InvalidInput, "`original` path is too long"));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

data_len counts the number of bytes, but MAXIMUM_REPARSE_DATA_BUFFER_SIZE counts the number of u16s. This doesn't sound right.

@rustbotrustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 19, 2026
@rustbot

Copy link
Copy Markdown
Collaborator

Reminder, once the PR becomes ready for a review, use @rustbot ready.

@rust-log-analyzer

This comment has been minimized.

@devnexen

Copy link
Copy Markdown
ContributorAuthor

@rustbot ready

@rustbotrustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jun 19, 2026

@DarksonnDarksonn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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


#[test]
#[cfg(windows)]
fn junction_point_overlong_path() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd like to see this regression test fail without the change. Do you mind opening a second temporary PR containing just the test so that we can run it through CI? We can close it again when we've confirmed the regression test catches the bug.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Confirmed failure in #158201.

Comment threadlibrary/std/src/sys/fs/windows.rs Outdated
Comment on lines +1694 to +1700
PathBuffer: [MaybeUninit::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize],
PathBuffer: [MaybeUninit::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize / 2],
};
// The path is followed by its null terminator and the (empty) print name's
// null terminator, so the buffer must hold two extra `u16`s. This single
// bounds check keeps the buffer, the copy, and `data_len` below in sync; if
// the path doesn't fit, fail rather than overflow the buffer.
let Some(ptr) = header.PathBuffer.get_mut(..abs_path.len() + 2) else {
return Err(io::const_error!(io::ErrorKind::InvalidInput, "`original` path is too long"));
};
ptr[..abs_path.len()].write_copy_of_slice(&abs_path);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This buffer is uninitialized. Don't you need to set path[abs_path.len()] and path[abs_path.len()+1] to zero?

@ChrisDentonChrisDentonJun 19, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The path has an explicit length so it doesn't need to be null terminated at all. I'm uncertain where that idea came from but it's probably just a misunderstanding? I mean, I guess there's no harm in writing a null but if so it shouldn't be part of the length.

@rustbotrustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 19, 2026
@ChrisDenton

Copy link
Copy Markdown
Member

To give some context here, this was originally a hacky function used only in tests. It's currently publicly exposed as a nightly-only API but it's not considered ready for stabilisation. E.g. 16kb is way too much for a stack buffer (though admittedly using a stack buffer for shorter paths would be useful).

PathBuffer: [MaybeUninit<u16>; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize],
// `MAXIMUM_REPARSE_DATA_BUFFER_SIZE` is a size in bytes; halve it for a
// count of `u16`s (the `readlink` path uses it as a byte buffer).
PathBuffer: [MaybeUninit<u16>; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize / 2],

@ChrisDentonChrisDentonJun 19, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This doesn't sound right at all. What makes you say MAXIMUM_REPARSE_DATA_BUFFER_SIZE is in bytes?

View changes since the review

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Huh, apparently it is.

The protocol docs make no mention of a maximum size, only that it's a 16 bit unsigned integer (hence my surprise at 16kb being a limit). But the public headers for the kernel API do have MAXIMUM_REPARSE_DATA_BUFFER_SIZE in bytes of 16kb.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should it be changed to an u8 array as well?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I would say no. It's the mount-point WCHAR path, and u16 keeps the copy a clean write_copy_of_slice(&abs_path).

@devnexen
devnexenforce-pushed the windows_fs_oflow_fix branch from d842451 to 28748e5CompareJune 21, 2026 06:05
rust-borsBot pushed a commit that referenced this pull request Jun 21, 2026
Temporary CI-verification test for #158147. Without the fix,
a >16 KiB junction target passes the old `> u16::MAX` length check yet
overflows the inline reparse stack buffer. This test must fail on master
and pass once the fix lands.
@DarksonnDarksonn added O-windows Operating system: Windows A-filesystem Area: `std::fs` labels Jun 21, 2026
@devnexen

Copy link
Copy Markdown
ContributorAuthor

@rustbot ready

@rustbotrustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jun 21, 2026

@DarksonnDarksonn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Comment threadlibrary/std/src/sys/fs/windows.rs Outdated
// Size of the reparse data after the 8-byte ReparseTag/ReparseDataLength/
// Reserved header: the four name offset/length `u16` fields (8 bytes) plus
// the path.
let data_len = 8 + abs_path.len() * 2;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Isn't it 16 bytes?

  • ReparseTag is 4 bytes
  • ReparseDataLength is 2 bytes
  • Reserved is 2 bytes
  • SubstituteNameOffset is 2 bytes
  • SubstituteNameLength is 2 bytes
  • PrintNameOffset is 2 bytes
  • PrintNameLength is 2 bytes

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Right, it's 16 bytes. Switched to offset_of! so both lengths derive from the struct.

@rustbotrustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 22, 2026
@devnexen
devnexenforce-pushed the windows_fs_oflow_fix branch from 28748e5 to b7af0d1CompareJune 22, 2026 23:24
@devnexen

Copy link
Copy Markdown
ContributorAuthor

@rustbot ready

@rust-borsrust-borsBot added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Jul 1, 2026
@rust-bors

rust-borsBot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

This pull request was unapproved.

View changes since this unapproval

@rust-borsrust-borsBot removed the S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. label Jul 1, 2026
@Darksonn

Copy link
Copy Markdown
Member

@devnexen Any update on this?

@devnexen
devnexenforce-pushed the windows_fs_oflow_fix branch from b7af0d1 to 74afb0aCompareJuly 25, 2026 15:16
@rustbot

This comment has been minimized.

The guard checked `data_len > u16::MAX`, allowing paths far larger than
`PathBuffer` (a fixed 16384-element array), which the subsequent single
`copy_from` then overflows. Bound against `MAXIMUM_REPARSE_DATA_BUFFER_SIZE`
plus header instead, matching the kernel's limit.
@devnexen
devnexenforce-pushed the windows_fs_oflow_fix branch from 74afb0a to 3313cd6CompareJuly 25, 2026 15:32
@rustbot

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@Darksonn

Copy link
Copy Markdown
Member

Please remember to use @rustbot ready when this is ready for review.

@bors try

@rust-bors

This comment has been minimized.

rust-borsBot pushed a commit that referenced this pull request Aug 5, 2026
std: fix stack buffer overflow in Windows junction_point
@rust-bors

rust-borsBot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

☀️ Try build successful (CI)
Build commit: 409d767 (409d767a80e64b1f76845dfd4cd80eaa8eb67050)
Base parent: 7218ebe (7218ebe93668f51a94a572b690c433dfdbdc2c3d)

@DarksonnDarksonn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@rust-bors

rust-borsBot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

📌 Commit 3313cd6 has been approved by Darksonn

It is now in the queue for this repository.

🌲 The tree is currently closed for pull requests below priority 10. This pull request will be tested once the tree is reopened.

Reason for tree closure: manually handling queue due to backlog

@rust-borsrust-borsBot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Aug 5, 2026
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Aug 5, 2026
…arksonn
std: fix stack buffer overflow in Windows junction_point
The guard checked `data_len > u16::MAX`, allowing paths far larger than `PathBuffer` (a fixed 16384-element array), which the subsequent single `copy_from` then overflows. Bound against `MAXIMUM_REPARSE_DATA_BUFFER_SIZE` plus header instead, matching the kernel's limit.
rust-borsBot pushed a commit that referenced this pull request Aug 5, 2026
…uwer
Rollup of 22 pull requests
Successful merges:
- #158147 (std: fix stack buffer overflow in Windows junction_point)
- #159784 (Hint that memchr returns an in-bounds index)
- #160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- #160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- #160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- #160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- #160422 (move mir-opt miri tests to CI logic)
- #160444 (Avoid resolving path keywords outside `TypeNS`)
- #160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe my unsafe speculative flag)
- #155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- #158726 (std: move futex implementations into sys::sync::futex)
- #159225 (Split IncrCompSession out of Session)
- #159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- #160198 (Rework `smallest_range_containing` to handle duplicates)
- #160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- #160390 (autodiff: Handle slice-tailed DSTs in type trees)
- #160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- #160520 (Add some tests for specialization)
- #160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- #160531 (docs: fix typo in AllowExprMetavar comment)
- #160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- #160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Aug 5, 2026
…arksonn
std: fix stack buffer overflow in Windows junction_point
The guard checked `data_len > u16::MAX`, allowing paths far larger than `PathBuffer` (a fixed 16384-element array), which the subsequent single `copy_from` then overflows. Bound against `MAXIMUM_REPARSE_DATA_BUFFER_SIZE` plus header instead, matching the kernel's limit.
rust-borsBot pushed a commit that referenced this pull request Aug 5, 2026
…uwer
Rollup of 25 pull requests
Successful merges:
- #154585 (treat no_mangle_generic_items as hard error instead of lint warning)
- #158147 (std: fix stack buffer overflow in Windows junction_point)
- #160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- #160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- #160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- #160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- #160422 (move mir-opt miri tests to CI logic)
- #160444 (Avoid resolving path keywords outside `TypeNS`)
- #160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe my unsafe speculative flag)
- #155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- #158726 (std: move futex implementations into sys::sync::futex)
- #158762 (Emit thumb code on VEX V5)
- #159225 (Split IncrCompSession out of Session)
- #159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- #160198 (Rework `smallest_range_containing` to handle duplicates)
- #160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- #160390 (autodiff: Handle slice-tailed DSTs in type trees)
- #160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- #160516 (Add regression test for HRTB projection in closure)
- #160520 (Add some tests for specialization)
- #160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- #160523 (Add regression test for opaque type)
- #160531 (docs: fix typo in AllowExprMetavar comment)
- #160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- #160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
rust-borsBot pushed a commit that referenced this pull request Aug 5, 2026
…uwer
Rollup of 25 pull requests
Successful merges:
- #158147 (std: fix stack buffer overflow in Windows junction_point)
- #160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- #160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- #160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- #160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- #160422 (move mir-opt miri tests to CI logic)
- #160444 (Avoid resolving path keywords outside `TypeNS`)
- #160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe by unsafe speculative flag)
- #155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- #158726 (std: move futex implementations into sys::sync::futex)
- #158762 (Emit thumb code on VEX V5)
- #159225 (Split IncrCompSession out of Session)
- #159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- #160198 (Rework `smallest_range_containing` to handle duplicates)
- #160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- #160390 (autodiff: Handle slice-tailed DSTs in type trees)
- #160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- #160501 (Add bootstrap CLI snapshot test for testing miri)
- #160516 (Add regression test for HRTB projection in closure)
- #160520 (Add some tests for specialization)
- #160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- #160523 (Add regression test for opaque type)
- #160531 (docs: fix typo in AllowExprMetavar comment)
- #160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- #160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
@rust-bors
rust-borsBot merged commit ebab4cf into rust-lang:mainAug 5, 2026
14 checks passed
rust-timer added a commit that referenced this pull request Aug 5, 2026
Rollup merge of #158147 - devnexen:windows_fs_oflow_fix, r=Darksonn
std: fix stack buffer overflow in Windows junction_point
The guard checked `data_len > u16::MAX`, allowing paths far larger than `PathBuffer` (a fixed 16384-element array), which the subsequent single `copy_from` then overflows. Bound against `MAXIMUM_REPARSE_DATA_BUFFER_SIZE` plus header instead, matching the kernel's limit.
@rustbotrustbot added this to the 1.99.0 milestone Aug 5, 2026
github-actionsBot pushed a commit to rust-lang/rustc-dev-guide that referenced this pull request Aug 10, 2026
…uwer
Rollup of 25 pull requests
Successful merges:
- rust-lang/rust#158147 (std: fix stack buffer overflow in Windows junction_point)
- rust-lang/rust#160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- rust-lang/rust#160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- rust-lang/rust#160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- rust-lang/rust#160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- rust-lang/rust#160422 (move mir-opt miri tests to CI logic)
- rust-lang/rust#160444 (Avoid resolving path keywords outside `TypeNS`)
- rust-lang/rust#160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe by unsafe speculative flag)
- rust-lang/rust#155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- rust-lang/rust#158726 (std: move futex implementations into sys::sync::futex)
- rust-lang/rust#158762 (Emit thumb code on VEX V5)
- rust-lang/rust#159225 (Split IncrCompSession out of Session)
- rust-lang/rust#159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- rust-lang/rust#160198 (Rework `smallest_range_containing` to handle duplicates)
- rust-lang/rust#160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- rust-lang/rust#160390 (autodiff: Handle slice-tailed DSTs in type trees)
- rust-lang/rust#160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- rust-lang/rust#160501 (Add bootstrap CLI snapshot test for testing miri)
- rust-lang/rust#160516 (Add regression test for HRTB projection in closure)
- rust-lang/rust#160520 (Add some tests for specialization)
- rust-lang/rust#160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- rust-lang/rust#160523 (Add regression test for opaque type)
- rust-lang/rust#160531 (docs: fix typo in AllowExprMetavar comment)
- rust-lang/rust#160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- rust-lang/rust#160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
flip1995 pushed a commit to flip1995/rust-clippy that referenced this pull request Aug 17, 2026
…uwer
Rollup of 25 pull requests
Successful merges:
- rust-lang/rust#158147 (std: fix stack buffer overflow in Windows junction_point)
- rust-lang/rust#160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- rust-lang/rust#160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- rust-lang/rust#160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- rust-lang/rust#160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- rust-lang/rust#160422 (move mir-opt miri tests to CI logic)
- rust-lang/rust#160444 (Avoid resolving path keywords outside `TypeNS`)
- rust-lang/rust#160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe by unsafe speculative flag)
- rust-lang/rust#155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- rust-lang/rust#158726 (std: move futex implementations into sys::sync::futex)
- rust-lang/rust#158762 (Emit thumb code on VEX V5)
- rust-lang/rust#159225 (Split IncrCompSession out of Session)
- rust-lang/rust#159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- rust-lang/rust#160198 (Rework `smallest_range_containing` to handle duplicates)
- rust-lang/rust#160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- rust-lang/rust#160390 (autodiff: Handle slice-tailed DSTs in type trees)
- rust-lang/rust#160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- rust-lang/rust#160501 (Add bootstrap CLI snapshot test for testing miri)
- rust-lang/rust#160516 (Add regression test for HRTB projection in closure)
- rust-lang/rust#160520 (Add some tests for specialization)
- rust-lang/rust#160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- rust-lang/rust#160523 (Add regression test for opaque type)
- rust-lang/rust#160531 (docs: fix typo in AllowExprMetavar comment)
- rust-lang/rust#160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- rust-lang/rust#160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-filesystemArea: `std::fs`O-windowsOperating system: WindowsS-waiting-on-borsStatus: Waiting on bors to run and complete tests. Bors will change the label on completion.T-libsRelevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@devnexen@rustbot@rust-log-analyzer@ChrisDenton@Darksonn@jhpratt
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

std: fix stack buffer overflow in Windows junction_point - #158147

Merged
rust-bors[bot] merged 1 commit into
rust-lang:mainfrom
devnexen:windows_fs_oflow_fix
Aug 5, 2026
Merged

std: fix stack buffer overflow in Windows junction_point#158147
rust-bors[bot] merged 1 commit into
rust-lang:mainfrom
devnexen:windows_fs_oflow_fix

Conversation

@devnexen

@devnexendevnexen commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

View all comments

The guard checked data_len > u16::MAX, allowing paths far larger than PathBuffer (a fixed 16384-element array), which the subsequent single copy_from then overflows. Bound against MAXIMUM_REPARSE_DATA_BUFFER_SIZE plus header instead, matching the kernel's limit.

@rustbotrustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Jun 19, 2026
@rustbot

Copy link
Copy Markdown
Collaborator

r? @Darksonn

rustbot has assigned @Darksonn.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: @ChrisDenton, libs
  • @ChrisDenton, libs expanded to 12 candidates
  • Random selection from Darksonn, Mark-Simulacrum, clarfonthey, jhpratt

@DarksonnDarksonn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Comment threadlibrary/std/src/sys/fs/windows.rs Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It sounds like this should be changed to ptr[..abs_path.len()].copy_from_slice(abs_path) or similar so that we actually perform a bounds check here.

Also, it would be really nice with a test that'd catch this (may be easier to check that the test is failing if we insert a bounds check first).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

In fact, maybe the bounds check should be entirely rewritten to

ptr.get(..abs_path.len())
.ok_or_else(|| io::const_error!(io::ErrorKind::InvalidInput, "`original` path is too long"))?
.copy_from_slice(abs_path)

This way there's no risk that the two bounds checks are not kept in sync. For instance, why is there a + 8 in the previous check? I don't understand that part.

Comment threadlibrary/std/src/sys/fs/windows.rs Outdated
Comment on lines 1679 to 1683
PathBuffer: [MaybeUninit<u16>; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize],
}
let data_len = 12 + (abs_path.len() * 2);
if data_len > u16::MAX as usize {
if data_len + 8 > c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize {
return Err(io::const_error!(io::ErrorKind::InvalidInput, "`original` path is too long"));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

data_len counts the number of bytes, but MAXIMUM_REPARSE_DATA_BUFFER_SIZE counts the number of u16s. This doesn't sound right.

@rustbotrustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 19, 2026
@rustbot

Copy link
Copy Markdown
Collaborator

Reminder, once the PR becomes ready for a review, use @rustbot ready.

@rust-log-analyzer

This comment has been minimized.

@devnexen

Copy link
Copy Markdown
ContributorAuthor

@rustbot ready

@rustbotrustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jun 19, 2026

@DarksonnDarksonn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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


#[test]
#[cfg(windows)]
fn junction_point_overlong_path() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd like to see this regression test fail without the change. Do you mind opening a second temporary PR containing just the test so that we can run it through CI? We can close it again when we've confirmed the regression test catches the bug.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Confirmed failure in #158201.

Comment threadlibrary/std/src/sys/fs/windows.rs Outdated
Comment on lines +1694 to +1700
PathBuffer: [MaybeUninit::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize],
PathBuffer: [MaybeUninit::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize / 2],
};
// The path is followed by its null terminator and the (empty) print name's
// null terminator, so the buffer must hold two extra `u16`s. This single
// bounds check keeps the buffer, the copy, and `data_len` below in sync; if
// the path doesn't fit, fail rather than overflow the buffer.
let Some(ptr) = header.PathBuffer.get_mut(..abs_path.len() + 2) else {
return Err(io::const_error!(io::ErrorKind::InvalidInput, "`original` path is too long"));
};
ptr[..abs_path.len()].write_copy_of_slice(&abs_path);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This buffer is uninitialized. Don't you need to set path[abs_path.len()] and path[abs_path.len()+1] to zero?

@ChrisDentonChrisDentonJun 19, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The path has an explicit length so it doesn't need to be null terminated at all. I'm uncertain where that idea came from but it's probably just a misunderstanding? I mean, I guess there's no harm in writing a null but if so it shouldn't be part of the length.

@rustbotrustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 19, 2026
@ChrisDenton

Copy link
Copy Markdown
Member

To give some context here, this was originally a hacky function used only in tests. It's currently publicly exposed as a nightly-only API but it's not considered ready for stabilisation. E.g. 16kb is way too much for a stack buffer (though admittedly using a stack buffer for shorter paths would be useful).

PathBuffer: [MaybeUninit<u16>; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize],
// `MAXIMUM_REPARSE_DATA_BUFFER_SIZE` is a size in bytes; halve it for a
// count of `u16`s (the `readlink` path uses it as a byte buffer).
PathBuffer: [MaybeUninit<u16>; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize / 2],

@ChrisDentonChrisDentonJun 19, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This doesn't sound right at all. What makes you say MAXIMUM_REPARSE_DATA_BUFFER_SIZE is in bytes?

View changes since the review

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Huh, apparently it is.

The protocol docs make no mention of a maximum size, only that it's a 16 bit unsigned integer (hence my surprise at 16kb being a limit). But the public headers for the kernel API do have MAXIMUM_REPARSE_DATA_BUFFER_SIZE in bytes of 16kb.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should it be changed to an u8 array as well?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I would say no. It's the mount-point WCHAR path, and u16 keeps the copy a clean write_copy_of_slice(&abs_path).

@devnexen
devnexenforce-pushed the windows_fs_oflow_fix branch from d842451 to 28748e5CompareJune 21, 2026 06:05
rust-borsBot pushed a commit that referenced this pull request Jun 21, 2026
Temporary CI-verification test for #158147. Without the fix,
a >16 KiB junction target passes the old `> u16::MAX` length check yet
overflows the inline reparse stack buffer. This test must fail on master
and pass once the fix lands.
@DarksonnDarksonn added O-windows Operating system: Windows A-filesystem Area: `std::fs` labels Jun 21, 2026
@devnexen

Copy link
Copy Markdown
ContributorAuthor

@rustbot ready

@rustbotrustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jun 21, 2026

@DarksonnDarksonn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Comment threadlibrary/std/src/sys/fs/windows.rs Outdated
// Size of the reparse data after the 8-byte ReparseTag/ReparseDataLength/
// Reserved header: the four name offset/length `u16` fields (8 bytes) plus
// the path.
let data_len = 8 + abs_path.len() * 2;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Isn't it 16 bytes?

  • ReparseTag is 4 bytes
  • ReparseDataLength is 2 bytes
  • Reserved is 2 bytes
  • SubstituteNameOffset is 2 bytes
  • SubstituteNameLength is 2 bytes
  • PrintNameOffset is 2 bytes
  • PrintNameLength is 2 bytes

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Right, it's 16 bytes. Switched to offset_of! so both lengths derive from the struct.

@rustbotrustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 22, 2026
@devnexen
devnexenforce-pushed the windows_fs_oflow_fix branch from 28748e5 to b7af0d1CompareJune 22, 2026 23:24
@devnexen

Copy link
Copy Markdown
ContributorAuthor

@rustbot ready

@rust-borsrust-borsBot added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Jul 1, 2026
@rust-bors

rust-borsBot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

This pull request was unapproved.

View changes since this unapproval

@rust-borsrust-borsBot removed the S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. label Jul 1, 2026
@Darksonn

Copy link
Copy Markdown
Member

@devnexen Any update on this?

@devnexen
devnexenforce-pushed the windows_fs_oflow_fix branch from b7af0d1 to 74afb0aCompareJuly 25, 2026 15:16
@rustbot

This comment has been minimized.

The guard checked `data_len > u16::MAX`, allowing paths far larger than
`PathBuffer` (a fixed 16384-element array), which the subsequent single
`copy_from` then overflows. Bound against `MAXIMUM_REPARSE_DATA_BUFFER_SIZE`
plus header instead, matching the kernel's limit.
@devnexen
devnexenforce-pushed the windows_fs_oflow_fix branch from 74afb0a to 3313cd6CompareJuly 25, 2026 15:32
@rustbot

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@Darksonn

Copy link
Copy Markdown
Member

Please remember to use @rustbot ready when this is ready for review.

@bors try

@rust-bors

This comment has been minimized.

rust-borsBot pushed a commit that referenced this pull request Aug 5, 2026
std: fix stack buffer overflow in Windows junction_point
@rust-bors

rust-borsBot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

☀️ Try build successful (CI)
Build commit: 409d767 (409d767a80e64b1f76845dfd4cd80eaa8eb67050)
Base parent: 7218ebe (7218ebe93668f51a94a572b690c433dfdbdc2c3d)

@DarksonnDarksonn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@rust-bors

rust-borsBot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

📌 Commit 3313cd6 has been approved by Darksonn

It is now in the queue for this repository.

🌲 The tree is currently closed for pull requests below priority 10. This pull request will be tested once the tree is reopened.

Reason for tree closure: manually handling queue due to backlog

@rust-borsrust-borsBot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Aug 5, 2026
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Aug 5, 2026
…arksonn
std: fix stack buffer overflow in Windows junction_point
The guard checked `data_len > u16::MAX`, allowing paths far larger than `PathBuffer` (a fixed 16384-element array), which the subsequent single `copy_from` then overflows. Bound against `MAXIMUM_REPARSE_DATA_BUFFER_SIZE` plus header instead, matching the kernel's limit.
rust-borsBot pushed a commit that referenced this pull request Aug 5, 2026
…uwer
Rollup of 22 pull requests
Successful merges:
- #158147 (std: fix stack buffer overflow in Windows junction_point)
- #159784 (Hint that memchr returns an in-bounds index)
- #160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- #160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- #160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- #160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- #160422 (move mir-opt miri tests to CI logic)
- #160444 (Avoid resolving path keywords outside `TypeNS`)
- #160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe my unsafe speculative flag)
- #155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- #158726 (std: move futex implementations into sys::sync::futex)
- #159225 (Split IncrCompSession out of Session)
- #159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- #160198 (Rework `smallest_range_containing` to handle duplicates)
- #160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- #160390 (autodiff: Handle slice-tailed DSTs in type trees)
- #160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- #160520 (Add some tests for specialization)
- #160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- #160531 (docs: fix typo in AllowExprMetavar comment)
- #160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- #160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Aug 5, 2026
…arksonn
std: fix stack buffer overflow in Windows junction_point
The guard checked `data_len > u16::MAX`, allowing paths far larger than `PathBuffer` (a fixed 16384-element array), which the subsequent single `copy_from` then overflows. Bound against `MAXIMUM_REPARSE_DATA_BUFFER_SIZE` plus header instead, matching the kernel's limit.
rust-borsBot pushed a commit that referenced this pull request Aug 5, 2026
…uwer
Rollup of 25 pull requests
Successful merges:
- #154585 (treat no_mangle_generic_items as hard error instead of lint warning)
- #158147 (std: fix stack buffer overflow in Windows junction_point)
- #160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- #160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- #160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- #160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- #160422 (move mir-opt miri tests to CI logic)
- #160444 (Avoid resolving path keywords outside `TypeNS`)
- #160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe my unsafe speculative flag)
- #155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- #158726 (std: move futex implementations into sys::sync::futex)
- #158762 (Emit thumb code on VEX V5)
- #159225 (Split IncrCompSession out of Session)
- #159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- #160198 (Rework `smallest_range_containing` to handle duplicates)
- #160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- #160390 (autodiff: Handle slice-tailed DSTs in type trees)
- #160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- #160516 (Add regression test for HRTB projection in closure)
- #160520 (Add some tests for specialization)
- #160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- #160523 (Add regression test for opaque type)
- #160531 (docs: fix typo in AllowExprMetavar comment)
- #160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- #160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
rust-borsBot pushed a commit that referenced this pull request Aug 5, 2026
…uwer
Rollup of 25 pull requests
Successful merges:
- #158147 (std: fix stack buffer overflow in Windows junction_point)
- #160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- #160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- #160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- #160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- #160422 (move mir-opt miri tests to CI logic)
- #160444 (Avoid resolving path keywords outside `TypeNS`)
- #160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe by unsafe speculative flag)
- #155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- #158726 (std: move futex implementations into sys::sync::futex)
- #158762 (Emit thumb code on VEX V5)
- #159225 (Split IncrCompSession out of Session)
- #159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- #160198 (Rework `smallest_range_containing` to handle duplicates)
- #160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- #160390 (autodiff: Handle slice-tailed DSTs in type trees)
- #160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- #160501 (Add bootstrap CLI snapshot test for testing miri)
- #160516 (Add regression test for HRTB projection in closure)
- #160520 (Add some tests for specialization)
- #160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- #160523 (Add regression test for opaque type)
- #160531 (docs: fix typo in AllowExprMetavar comment)
- #160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- #160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
@rust-bors
rust-borsBot merged commit ebab4cf into rust-lang:mainAug 5, 2026
14 checks passed
rust-timer added a commit that referenced this pull request Aug 5, 2026
Rollup merge of #158147 - devnexen:windows_fs_oflow_fix, r=Darksonn
std: fix stack buffer overflow in Windows junction_point
The guard checked `data_len > u16::MAX`, allowing paths far larger than `PathBuffer` (a fixed 16384-element array), which the subsequent single `copy_from` then overflows. Bound against `MAXIMUM_REPARSE_DATA_BUFFER_SIZE` plus header instead, matching the kernel's limit.
@rustbotrustbot added this to the 1.99.0 milestone Aug 5, 2026
github-actionsBot pushed a commit to rust-lang/rustc-dev-guide that referenced this pull request Aug 10, 2026
…uwer
Rollup of 25 pull requests
Successful merges:
- rust-lang/rust#158147 (std: fix stack buffer overflow in Windows junction_point)
- rust-lang/rust#160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- rust-lang/rust#160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- rust-lang/rust#160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- rust-lang/rust#160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- rust-lang/rust#160422 (move mir-opt miri tests to CI logic)
- rust-lang/rust#160444 (Avoid resolving path keywords outside `TypeNS`)
- rust-lang/rust#160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe by unsafe speculative flag)
- rust-lang/rust#155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- rust-lang/rust#158726 (std: move futex implementations into sys::sync::futex)
- rust-lang/rust#158762 (Emit thumb code on VEX V5)
- rust-lang/rust#159225 (Split IncrCompSession out of Session)
- rust-lang/rust#159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- rust-lang/rust#160198 (Rework `smallest_range_containing` to handle duplicates)
- rust-lang/rust#160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- rust-lang/rust#160390 (autodiff: Handle slice-tailed DSTs in type trees)
- rust-lang/rust#160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- rust-lang/rust#160501 (Add bootstrap CLI snapshot test for testing miri)
- rust-lang/rust#160516 (Add regression test for HRTB projection in closure)
- rust-lang/rust#160520 (Add some tests for specialization)
- rust-lang/rust#160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- rust-lang/rust#160523 (Add regression test for opaque type)
- rust-lang/rust#160531 (docs: fix typo in AllowExprMetavar comment)
- rust-lang/rust#160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- rust-lang/rust#160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
flip1995 pushed a commit to flip1995/rust-clippy that referenced this pull request Aug 17, 2026
…uwer
Rollup of 25 pull requests
Successful merges:
- rust-lang/rust#158147 (std: fix stack buffer overflow in Windows junction_point)
- rust-lang/rust#160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- rust-lang/rust#160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- rust-lang/rust#160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- rust-lang/rust#160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- rust-lang/rust#160422 (move mir-opt miri tests to CI logic)
- rust-lang/rust#160444 (Avoid resolving path keywords outside `TypeNS`)
- rust-lang/rust#160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe by unsafe speculative flag)
- rust-lang/rust#155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- rust-lang/rust#158726 (std: move futex implementations into sys::sync::futex)
- rust-lang/rust#158762 (Emit thumb code on VEX V5)
- rust-lang/rust#159225 (Split IncrCompSession out of Session)
- rust-lang/rust#159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- rust-lang/rust#160198 (Rework `smallest_range_containing` to handle duplicates)
- rust-lang/rust#160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- rust-lang/rust#160390 (autodiff: Handle slice-tailed DSTs in type trees)
- rust-lang/rust#160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- rust-lang/rust#160501 (Add bootstrap CLI snapshot test for testing miri)
- rust-lang/rust#160516 (Add regression test for HRTB projection in closure)
- rust-lang/rust#160520 (Add some tests for specialization)
- rust-lang/rust#160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- rust-lang/rust#160523 (Add regression test for opaque type)
- rust-lang/rust#160531 (docs: fix typo in AllowExprMetavar comment)
- rust-lang/rust#160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- rust-lang/rust#160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-filesystemArea: `std::fs`O-windowsOperating system: WindowsS-waiting-on-borsStatus: Waiting on bors to run and complete tests. Bors will change the label on completion.T-libsRelevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@devnexen@rustbot@rust-log-analyzer@ChrisDenton@Darksonn@jhpratt
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

std: fix stack buffer overflow in Windows junction_point - #158147

Merged
rust-bors[bot] merged 1 commit into
rust-lang:mainfrom
devnexen:windows_fs_oflow_fix
Aug 5, 2026
Merged

std: fix stack buffer overflow in Windows junction_point#158147
rust-bors[bot] merged 1 commit into
rust-lang:mainfrom
devnexen:windows_fs_oflow_fix

Conversation

@devnexen

@devnexendevnexen commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

View all comments

The guard checked data_len > u16::MAX, allowing paths far larger than PathBuffer (a fixed 16384-element array), which the subsequent single copy_from then overflows. Bound against MAXIMUM_REPARSE_DATA_BUFFER_SIZE plus header instead, matching the kernel's limit.

@rustbotrustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Jun 19, 2026
@rustbot

Copy link
Copy Markdown
Collaborator

r? @Darksonn

rustbot has assigned @Darksonn.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: @ChrisDenton, libs
  • @ChrisDenton, libs expanded to 12 candidates
  • Random selection from Darksonn, Mark-Simulacrum, clarfonthey, jhpratt

@DarksonnDarksonn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Comment threadlibrary/std/src/sys/fs/windows.rs Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It sounds like this should be changed to ptr[..abs_path.len()].copy_from_slice(abs_path) or similar so that we actually perform a bounds check here.

Also, it would be really nice with a test that'd catch this (may be easier to check that the test is failing if we insert a bounds check first).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

In fact, maybe the bounds check should be entirely rewritten to

ptr.get(..abs_path.len())
.ok_or_else(|| io::const_error!(io::ErrorKind::InvalidInput, "`original` path is too long"))?
.copy_from_slice(abs_path)

This way there's no risk that the two bounds checks are not kept in sync. For instance, why is there a + 8 in the previous check? I don't understand that part.

Comment threadlibrary/std/src/sys/fs/windows.rs Outdated
Comment on lines 1679 to 1683
PathBuffer: [MaybeUninit<u16>; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize],
}
let data_len = 12 + (abs_path.len() * 2);
if data_len > u16::MAX as usize {
if data_len + 8 > c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize {
return Err(io::const_error!(io::ErrorKind::InvalidInput, "`original` path is too long"));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

data_len counts the number of bytes, but MAXIMUM_REPARSE_DATA_BUFFER_SIZE counts the number of u16s. This doesn't sound right.

@rustbotrustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 19, 2026
@rustbot

Copy link
Copy Markdown
Collaborator

Reminder, once the PR becomes ready for a review, use @rustbot ready.

@rust-log-analyzer

This comment has been minimized.

@devnexen

Copy link
Copy Markdown
ContributorAuthor

@rustbot ready

@rustbotrustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jun 19, 2026

@DarksonnDarksonn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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


#[test]
#[cfg(windows)]
fn junction_point_overlong_path() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd like to see this regression test fail without the change. Do you mind opening a second temporary PR containing just the test so that we can run it through CI? We can close it again when we've confirmed the regression test catches the bug.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Confirmed failure in #158201.

Comment threadlibrary/std/src/sys/fs/windows.rs Outdated
Comment on lines +1694 to +1700
PathBuffer: [MaybeUninit::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize],
PathBuffer: [MaybeUninit::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize / 2],
};
// The path is followed by its null terminator and the (empty) print name's
// null terminator, so the buffer must hold two extra `u16`s. This single
// bounds check keeps the buffer, the copy, and `data_len` below in sync; if
// the path doesn't fit, fail rather than overflow the buffer.
let Some(ptr) = header.PathBuffer.get_mut(..abs_path.len() + 2) else {
return Err(io::const_error!(io::ErrorKind::InvalidInput, "`original` path is too long"));
};
ptr[..abs_path.len()].write_copy_of_slice(&abs_path);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This buffer is uninitialized. Don't you need to set path[abs_path.len()] and path[abs_path.len()+1] to zero?

@ChrisDentonChrisDentonJun 19, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The path has an explicit length so it doesn't need to be null terminated at all. I'm uncertain where that idea came from but it's probably just a misunderstanding? I mean, I guess there's no harm in writing a null but if so it shouldn't be part of the length.

@rustbotrustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 19, 2026
@ChrisDenton

Copy link
Copy Markdown
Member

To give some context here, this was originally a hacky function used only in tests. It's currently publicly exposed as a nightly-only API but it's not considered ready for stabilisation. E.g. 16kb is way too much for a stack buffer (though admittedly using a stack buffer for shorter paths would be useful).

PathBuffer: [MaybeUninit<u16>; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize],
// `MAXIMUM_REPARSE_DATA_BUFFER_SIZE` is a size in bytes; halve it for a
// count of `u16`s (the `readlink` path uses it as a byte buffer).
PathBuffer: [MaybeUninit<u16>; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize / 2],

@ChrisDentonChrisDentonJun 19, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This doesn't sound right at all. What makes you say MAXIMUM_REPARSE_DATA_BUFFER_SIZE is in bytes?

View changes since the review

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Huh, apparently it is.

The protocol docs make no mention of a maximum size, only that it's a 16 bit unsigned integer (hence my surprise at 16kb being a limit). But the public headers for the kernel API do have MAXIMUM_REPARSE_DATA_BUFFER_SIZE in bytes of 16kb.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should it be changed to an u8 array as well?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I would say no. It's the mount-point WCHAR path, and u16 keeps the copy a clean write_copy_of_slice(&abs_path).

@devnexen
devnexenforce-pushed the windows_fs_oflow_fix branch from d842451 to 28748e5CompareJune 21, 2026 06:05
rust-borsBot pushed a commit that referenced this pull request Jun 21, 2026
Temporary CI-verification test for #158147. Without the fix,
a >16 KiB junction target passes the old `> u16::MAX` length check yet
overflows the inline reparse stack buffer. This test must fail on master
and pass once the fix lands.
@DarksonnDarksonn added O-windows Operating system: Windows A-filesystem Area: `std::fs` labels Jun 21, 2026
@devnexen

Copy link
Copy Markdown
ContributorAuthor

@rustbot ready

@rustbotrustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jun 21, 2026

@DarksonnDarksonn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Comment threadlibrary/std/src/sys/fs/windows.rs Outdated
// Size of the reparse data after the 8-byte ReparseTag/ReparseDataLength/
// Reserved header: the four name offset/length `u16` fields (8 bytes) plus
// the path.
let data_len = 8 + abs_path.len() * 2;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Isn't it 16 bytes?

  • ReparseTag is 4 bytes
  • ReparseDataLength is 2 bytes
  • Reserved is 2 bytes
  • SubstituteNameOffset is 2 bytes
  • SubstituteNameLength is 2 bytes
  • PrintNameOffset is 2 bytes
  • PrintNameLength is 2 bytes

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Right, it's 16 bytes. Switched to offset_of! so both lengths derive from the struct.

@rustbotrustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 22, 2026
@devnexen
devnexenforce-pushed the windows_fs_oflow_fix branch from 28748e5 to b7af0d1CompareJune 22, 2026 23:24
@devnexen

Copy link
Copy Markdown
ContributorAuthor

@rustbot ready

@rust-borsrust-borsBot added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Jul 1, 2026
@rust-bors

rust-borsBot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

This pull request was unapproved.

View changes since this unapproval

@rust-borsrust-borsBot removed the S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. label Jul 1, 2026
@Darksonn

Copy link
Copy Markdown
Member

@devnexen Any update on this?

@devnexen
devnexenforce-pushed the windows_fs_oflow_fix branch from b7af0d1 to 74afb0aCompareJuly 25, 2026 15:16
@rustbot

This comment has been minimized.

The guard checked `data_len > u16::MAX`, allowing paths far larger than
`PathBuffer` (a fixed 16384-element array), which the subsequent single
`copy_from` then overflows. Bound against `MAXIMUM_REPARSE_DATA_BUFFER_SIZE`
plus header instead, matching the kernel's limit.
@devnexen
devnexenforce-pushed the windows_fs_oflow_fix branch from 74afb0a to 3313cd6CompareJuly 25, 2026 15:32
@rustbot

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@Darksonn

Copy link
Copy Markdown
Member

Please remember to use @rustbot ready when this is ready for review.

@bors try

@rust-bors

This comment has been minimized.

rust-borsBot pushed a commit that referenced this pull request Aug 5, 2026
std: fix stack buffer overflow in Windows junction_point
@rust-bors

rust-borsBot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

☀️ Try build successful (CI)
Build commit: 409d767 (409d767a80e64b1f76845dfd4cd80eaa8eb67050)
Base parent: 7218ebe (7218ebe93668f51a94a572b690c433dfdbdc2c3d)

@DarksonnDarksonn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@rust-bors

rust-borsBot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

📌 Commit 3313cd6 has been approved by Darksonn

It is now in the queue for this repository.

🌲 The tree is currently closed for pull requests below priority 10. This pull request will be tested once the tree is reopened.

Reason for tree closure: manually handling queue due to backlog

@rust-borsrust-borsBot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Aug 5, 2026
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Aug 5, 2026
…arksonn
std: fix stack buffer overflow in Windows junction_point
The guard checked `data_len > u16::MAX`, allowing paths far larger than `PathBuffer` (a fixed 16384-element array), which the subsequent single `copy_from` then overflows. Bound against `MAXIMUM_REPARSE_DATA_BUFFER_SIZE` plus header instead, matching the kernel's limit.
rust-borsBot pushed a commit that referenced this pull request Aug 5, 2026
…uwer
Rollup of 22 pull requests
Successful merges:
- #158147 (std: fix stack buffer overflow in Windows junction_point)
- #159784 (Hint that memchr returns an in-bounds index)
- #160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- #160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- #160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- #160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- #160422 (move mir-opt miri tests to CI logic)
- #160444 (Avoid resolving path keywords outside `TypeNS`)
- #160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe my unsafe speculative flag)
- #155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- #158726 (std: move futex implementations into sys::sync::futex)
- #159225 (Split IncrCompSession out of Session)
- #159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- #160198 (Rework `smallest_range_containing` to handle duplicates)
- #160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- #160390 (autodiff: Handle slice-tailed DSTs in type trees)
- #160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- #160520 (Add some tests for specialization)
- #160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- #160531 (docs: fix typo in AllowExprMetavar comment)
- #160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- #160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Aug 5, 2026
…arksonn
std: fix stack buffer overflow in Windows junction_point
The guard checked `data_len > u16::MAX`, allowing paths far larger than `PathBuffer` (a fixed 16384-element array), which the subsequent single `copy_from` then overflows. Bound against `MAXIMUM_REPARSE_DATA_BUFFER_SIZE` plus header instead, matching the kernel's limit.
rust-borsBot pushed a commit that referenced this pull request Aug 5, 2026
…uwer
Rollup of 25 pull requests
Successful merges:
- #154585 (treat no_mangle_generic_items as hard error instead of lint warning)
- #158147 (std: fix stack buffer overflow in Windows junction_point)
- #160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- #160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- #160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- #160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- #160422 (move mir-opt miri tests to CI logic)
- #160444 (Avoid resolving path keywords outside `TypeNS`)
- #160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe my unsafe speculative flag)
- #155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- #158726 (std: move futex implementations into sys::sync::futex)
- #158762 (Emit thumb code on VEX V5)
- #159225 (Split IncrCompSession out of Session)
- #159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- #160198 (Rework `smallest_range_containing` to handle duplicates)
- #160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- #160390 (autodiff: Handle slice-tailed DSTs in type trees)
- #160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- #160516 (Add regression test for HRTB projection in closure)
- #160520 (Add some tests for specialization)
- #160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- #160523 (Add regression test for opaque type)
- #160531 (docs: fix typo in AllowExprMetavar comment)
- #160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- #160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
rust-borsBot pushed a commit that referenced this pull request Aug 5, 2026
…uwer
Rollup of 25 pull requests
Successful merges:
- #158147 (std: fix stack buffer overflow in Windows junction_point)
- #160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- #160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- #160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- #160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- #160422 (move mir-opt miri tests to CI logic)
- #160444 (Avoid resolving path keywords outside `TypeNS`)
- #160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe by unsafe speculative flag)
- #155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- #158726 (std: move futex implementations into sys::sync::futex)
- #158762 (Emit thumb code on VEX V5)
- #159225 (Split IncrCompSession out of Session)
- #159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- #160198 (Rework `smallest_range_containing` to handle duplicates)
- #160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- #160390 (autodiff: Handle slice-tailed DSTs in type trees)
- #160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- #160501 (Add bootstrap CLI snapshot test for testing miri)
- #160516 (Add regression test for HRTB projection in closure)
- #160520 (Add some tests for specialization)
- #160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- #160523 (Add regression test for opaque type)
- #160531 (docs: fix typo in AllowExprMetavar comment)
- #160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- #160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
@rust-bors
rust-borsBot merged commit ebab4cf into rust-lang:mainAug 5, 2026
14 checks passed
rust-timer added a commit that referenced this pull request Aug 5, 2026
Rollup merge of #158147 - devnexen:windows_fs_oflow_fix, r=Darksonn
std: fix stack buffer overflow in Windows junction_point
The guard checked `data_len > u16::MAX`, allowing paths far larger than `PathBuffer` (a fixed 16384-element array), which the subsequent single `copy_from` then overflows. Bound against `MAXIMUM_REPARSE_DATA_BUFFER_SIZE` plus header instead, matching the kernel's limit.
@rustbotrustbot added this to the 1.99.0 milestone Aug 5, 2026
github-actionsBot pushed a commit to rust-lang/rustc-dev-guide that referenced this pull request Aug 10, 2026
…uwer
Rollup of 25 pull requests
Successful merges:
- rust-lang/rust#158147 (std: fix stack buffer overflow in Windows junction_point)
- rust-lang/rust#160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- rust-lang/rust#160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- rust-lang/rust#160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- rust-lang/rust#160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- rust-lang/rust#160422 (move mir-opt miri tests to CI logic)
- rust-lang/rust#160444 (Avoid resolving path keywords outside `TypeNS`)
- rust-lang/rust#160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe by unsafe speculative flag)
- rust-lang/rust#155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- rust-lang/rust#158726 (std: move futex implementations into sys::sync::futex)
- rust-lang/rust#158762 (Emit thumb code on VEX V5)
- rust-lang/rust#159225 (Split IncrCompSession out of Session)
- rust-lang/rust#159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- rust-lang/rust#160198 (Rework `smallest_range_containing` to handle duplicates)
- rust-lang/rust#160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- rust-lang/rust#160390 (autodiff: Handle slice-tailed DSTs in type trees)
- rust-lang/rust#160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- rust-lang/rust#160501 (Add bootstrap CLI snapshot test for testing miri)
- rust-lang/rust#160516 (Add regression test for HRTB projection in closure)
- rust-lang/rust#160520 (Add some tests for specialization)
- rust-lang/rust#160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- rust-lang/rust#160523 (Add regression test for opaque type)
- rust-lang/rust#160531 (docs: fix typo in AllowExprMetavar comment)
- rust-lang/rust#160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- rust-lang/rust#160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
flip1995 pushed a commit to flip1995/rust-clippy that referenced this pull request Aug 17, 2026
…uwer
Rollup of 25 pull requests
Successful merges:
- rust-lang/rust#158147 (std: fix stack buffer overflow in Windows junction_point)
- rust-lang/rust#160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- rust-lang/rust#160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- rust-lang/rust#160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- rust-lang/rust#160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- rust-lang/rust#160422 (move mir-opt miri tests to CI logic)
- rust-lang/rust#160444 (Avoid resolving path keywords outside `TypeNS`)
- rust-lang/rust#160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe by unsafe speculative flag)
- rust-lang/rust#155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- rust-lang/rust#158726 (std: move futex implementations into sys::sync::futex)
- rust-lang/rust#158762 (Emit thumb code on VEX V5)
- rust-lang/rust#159225 (Split IncrCompSession out of Session)
- rust-lang/rust#159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- rust-lang/rust#160198 (Rework `smallest_range_containing` to handle duplicates)
- rust-lang/rust#160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- rust-lang/rust#160390 (autodiff: Handle slice-tailed DSTs in type trees)
- rust-lang/rust#160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- rust-lang/rust#160501 (Add bootstrap CLI snapshot test for testing miri)
- rust-lang/rust#160516 (Add regression test for HRTB projection in closure)
- rust-lang/rust#160520 (Add some tests for specialization)
- rust-lang/rust#160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- rust-lang/rust#160523 (Add regression test for opaque type)
- rust-lang/rust#160531 (docs: fix typo in AllowExprMetavar comment)
- rust-lang/rust#160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- rust-lang/rust#160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-filesystemArea: `std::fs`O-windowsOperating system: WindowsS-waiting-on-borsStatus: Waiting on bors to run and complete tests. Bors will change the label on completion.T-libsRelevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@devnexen@rustbot@rust-log-analyzer@ChrisDenton@Darksonn@jhpratt
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

std: fix stack buffer overflow in Windows junction_point - #158147

Merged
rust-bors[bot] merged 1 commit into
rust-lang:mainfrom
devnexen:windows_fs_oflow_fix
Aug 5, 2026
Merged

std: fix stack buffer overflow in Windows junction_point#158147
rust-bors[bot] merged 1 commit into
rust-lang:mainfrom
devnexen:windows_fs_oflow_fix

Conversation

@devnexen

@devnexendevnexen commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

View all comments

The guard checked data_len > u16::MAX, allowing paths far larger than PathBuffer (a fixed 16384-element array), which the subsequent single copy_from then overflows. Bound against MAXIMUM_REPARSE_DATA_BUFFER_SIZE plus header instead, matching the kernel's limit.

@rustbotrustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Jun 19, 2026
@rustbot

Copy link
Copy Markdown
Collaborator

r? @Darksonn

rustbot has assigned @Darksonn.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: @ChrisDenton, libs
  • @ChrisDenton, libs expanded to 12 candidates
  • Random selection from Darksonn, Mark-Simulacrum, clarfonthey, jhpratt

@DarksonnDarksonn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Comment threadlibrary/std/src/sys/fs/windows.rs Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It sounds like this should be changed to ptr[..abs_path.len()].copy_from_slice(abs_path) or similar so that we actually perform a bounds check here.

Also, it would be really nice with a test that'd catch this (may be easier to check that the test is failing if we insert a bounds check first).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

In fact, maybe the bounds check should be entirely rewritten to

ptr.get(..abs_path.len())
.ok_or_else(|| io::const_error!(io::ErrorKind::InvalidInput, "`original` path is too long"))?
.copy_from_slice(abs_path)

This way there's no risk that the two bounds checks are not kept in sync. For instance, why is there a + 8 in the previous check? I don't understand that part.

Comment threadlibrary/std/src/sys/fs/windows.rs Outdated
Comment on lines 1679 to 1683
PathBuffer: [MaybeUninit<u16>; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize],
}
let data_len = 12 + (abs_path.len() * 2);
if data_len > u16::MAX as usize {
if data_len + 8 > c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize {
return Err(io::const_error!(io::ErrorKind::InvalidInput, "`original` path is too long"));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

data_len counts the number of bytes, but MAXIMUM_REPARSE_DATA_BUFFER_SIZE counts the number of u16s. This doesn't sound right.

@rustbotrustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 19, 2026
@rustbot

Copy link
Copy Markdown
Collaborator

Reminder, once the PR becomes ready for a review, use @rustbot ready.

@rust-log-analyzer

This comment has been minimized.

@devnexen

Copy link
Copy Markdown
ContributorAuthor

@rustbot ready

@rustbotrustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jun 19, 2026

@DarksonnDarksonn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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


#[test]
#[cfg(windows)]
fn junction_point_overlong_path() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd like to see this regression test fail without the change. Do you mind opening a second temporary PR containing just the test so that we can run it through CI? We can close it again when we've confirmed the regression test catches the bug.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Confirmed failure in #158201.

Comment threadlibrary/std/src/sys/fs/windows.rs Outdated
Comment on lines +1694 to +1700
PathBuffer: [MaybeUninit::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize],
PathBuffer: [MaybeUninit::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize / 2],
};
// The path is followed by its null terminator and the (empty) print name's
// null terminator, so the buffer must hold two extra `u16`s. This single
// bounds check keeps the buffer, the copy, and `data_len` below in sync; if
// the path doesn't fit, fail rather than overflow the buffer.
let Some(ptr) = header.PathBuffer.get_mut(..abs_path.len() + 2) else {
return Err(io::const_error!(io::ErrorKind::InvalidInput, "`original` path is too long"));
};
ptr[..abs_path.len()].write_copy_of_slice(&abs_path);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This buffer is uninitialized. Don't you need to set path[abs_path.len()] and path[abs_path.len()+1] to zero?

@ChrisDentonChrisDentonJun 19, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The path has an explicit length so it doesn't need to be null terminated at all. I'm uncertain where that idea came from but it's probably just a misunderstanding? I mean, I guess there's no harm in writing a null but if so it shouldn't be part of the length.

@rustbotrustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 19, 2026
@ChrisDenton

Copy link
Copy Markdown
Member

To give some context here, this was originally a hacky function used only in tests. It's currently publicly exposed as a nightly-only API but it's not considered ready for stabilisation. E.g. 16kb is way too much for a stack buffer (though admittedly using a stack buffer for shorter paths would be useful).

PathBuffer: [MaybeUninit<u16>; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize],
// `MAXIMUM_REPARSE_DATA_BUFFER_SIZE` is a size in bytes; halve it for a
// count of `u16`s (the `readlink` path uses it as a byte buffer).
PathBuffer: [MaybeUninit<u16>; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize / 2],

@ChrisDentonChrisDentonJun 19, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This doesn't sound right at all. What makes you say MAXIMUM_REPARSE_DATA_BUFFER_SIZE is in bytes?

View changes since the review

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Huh, apparently it is.

The protocol docs make no mention of a maximum size, only that it's a 16 bit unsigned integer (hence my surprise at 16kb being a limit). But the public headers for the kernel API do have MAXIMUM_REPARSE_DATA_BUFFER_SIZE in bytes of 16kb.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should it be changed to an u8 array as well?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I would say no. It's the mount-point WCHAR path, and u16 keeps the copy a clean write_copy_of_slice(&abs_path).

@devnexen
devnexenforce-pushed the windows_fs_oflow_fix branch from d842451 to 28748e5CompareJune 21, 2026 06:05
rust-borsBot pushed a commit that referenced this pull request Jun 21, 2026
Temporary CI-verification test for #158147. Without the fix,
a >16 KiB junction target passes the old `> u16::MAX` length check yet
overflows the inline reparse stack buffer. This test must fail on master
and pass once the fix lands.
@DarksonnDarksonn added O-windows Operating system: Windows A-filesystem Area: `std::fs` labels Jun 21, 2026
@devnexen

Copy link
Copy Markdown
ContributorAuthor

@rustbot ready

@rustbotrustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jun 21, 2026

@DarksonnDarksonn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Comment threadlibrary/std/src/sys/fs/windows.rs Outdated
// Size of the reparse data after the 8-byte ReparseTag/ReparseDataLength/
// Reserved header: the four name offset/length `u16` fields (8 bytes) plus
// the path.
let data_len = 8 + abs_path.len() * 2;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Isn't it 16 bytes?

  • ReparseTag is 4 bytes
  • ReparseDataLength is 2 bytes
  • Reserved is 2 bytes
  • SubstituteNameOffset is 2 bytes
  • SubstituteNameLength is 2 bytes
  • PrintNameOffset is 2 bytes
  • PrintNameLength is 2 bytes

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Right, it's 16 bytes. Switched to offset_of! so both lengths derive from the struct.

@rustbotrustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 22, 2026
@devnexen
devnexenforce-pushed the windows_fs_oflow_fix branch from 28748e5 to b7af0d1CompareJune 22, 2026 23:24
@devnexen

Copy link
Copy Markdown
ContributorAuthor

@rustbot ready

@rust-borsrust-borsBot added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Jul 1, 2026
@rust-bors

rust-borsBot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

This pull request was unapproved.

View changes since this unapproval

@rust-borsrust-borsBot removed the S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. label Jul 1, 2026
@Darksonn

Copy link
Copy Markdown
Member

@devnexen Any update on this?

@devnexen
devnexenforce-pushed the windows_fs_oflow_fix branch from b7af0d1 to 74afb0aCompareJuly 25, 2026 15:16
@rustbot

This comment has been minimized.

The guard checked `data_len > u16::MAX`, allowing paths far larger than
`PathBuffer` (a fixed 16384-element array), which the subsequent single
`copy_from` then overflows. Bound against `MAXIMUM_REPARSE_DATA_BUFFER_SIZE`
plus header instead, matching the kernel's limit.
@devnexen
devnexenforce-pushed the windows_fs_oflow_fix branch from 74afb0a to 3313cd6CompareJuly 25, 2026 15:32
@rustbot

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@Darksonn

Copy link
Copy Markdown
Member

Please remember to use @rustbot ready when this is ready for review.

@bors try

@rust-bors

This comment has been minimized.

rust-borsBot pushed a commit that referenced this pull request Aug 5, 2026
std: fix stack buffer overflow in Windows junction_point
@rust-bors

rust-borsBot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

☀️ Try build successful (CI)
Build commit: 409d767 (409d767a80e64b1f76845dfd4cd80eaa8eb67050)
Base parent: 7218ebe (7218ebe93668f51a94a572b690c433dfdbdc2c3d)

@DarksonnDarksonn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@rust-bors

rust-borsBot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

📌 Commit 3313cd6 has been approved by Darksonn

It is now in the queue for this repository.

🌲 The tree is currently closed for pull requests below priority 10. This pull request will be tested once the tree is reopened.

Reason for tree closure: manually handling queue due to backlog

@rust-borsrust-borsBot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Aug 5, 2026
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Aug 5, 2026
…arksonn
std: fix stack buffer overflow in Windows junction_point
The guard checked `data_len > u16::MAX`, allowing paths far larger than `PathBuffer` (a fixed 16384-element array), which the subsequent single `copy_from` then overflows. Bound against `MAXIMUM_REPARSE_DATA_BUFFER_SIZE` plus header instead, matching the kernel's limit.
rust-borsBot pushed a commit that referenced this pull request Aug 5, 2026
…uwer
Rollup of 22 pull requests
Successful merges:
- #158147 (std: fix stack buffer overflow in Windows junction_point)
- #159784 (Hint that memchr returns an in-bounds index)
- #160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- #160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- #160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- #160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- #160422 (move mir-opt miri tests to CI logic)
- #160444 (Avoid resolving path keywords outside `TypeNS`)
- #160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe my unsafe speculative flag)
- #155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- #158726 (std: move futex implementations into sys::sync::futex)
- #159225 (Split IncrCompSession out of Session)
- #159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- #160198 (Rework `smallest_range_containing` to handle duplicates)
- #160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- #160390 (autodiff: Handle slice-tailed DSTs in type trees)
- #160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- #160520 (Add some tests for specialization)
- #160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- #160531 (docs: fix typo in AllowExprMetavar comment)
- #160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- #160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Aug 5, 2026
…arksonn
std: fix stack buffer overflow in Windows junction_point
The guard checked `data_len > u16::MAX`, allowing paths far larger than `PathBuffer` (a fixed 16384-element array), which the subsequent single `copy_from` then overflows. Bound against `MAXIMUM_REPARSE_DATA_BUFFER_SIZE` plus header instead, matching the kernel's limit.
rust-borsBot pushed a commit that referenced this pull request Aug 5, 2026
…uwer
Rollup of 25 pull requests
Successful merges:
- #154585 (treat no_mangle_generic_items as hard error instead of lint warning)
- #158147 (std: fix stack buffer overflow in Windows junction_point)
- #160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- #160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- #160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- #160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- #160422 (move mir-opt miri tests to CI logic)
- #160444 (Avoid resolving path keywords outside `TypeNS`)
- #160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe my unsafe speculative flag)
- #155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- #158726 (std: move futex implementations into sys::sync::futex)
- #158762 (Emit thumb code on VEX V5)
- #159225 (Split IncrCompSession out of Session)
- #159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- #160198 (Rework `smallest_range_containing` to handle duplicates)
- #160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- #160390 (autodiff: Handle slice-tailed DSTs in type trees)
- #160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- #160516 (Add regression test for HRTB projection in closure)
- #160520 (Add some tests for specialization)
- #160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- #160523 (Add regression test for opaque type)
- #160531 (docs: fix typo in AllowExprMetavar comment)
- #160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- #160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
rust-borsBot pushed a commit that referenced this pull request Aug 5, 2026
…uwer
Rollup of 25 pull requests
Successful merges:
- #158147 (std: fix stack buffer overflow in Windows junction_point)
- #160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- #160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- #160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- #160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- #160422 (move mir-opt miri tests to CI logic)
- #160444 (Avoid resolving path keywords outside `TypeNS`)
- #160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe by unsafe speculative flag)
- #155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- #158726 (std: move futex implementations into sys::sync::futex)
- #158762 (Emit thumb code on VEX V5)
- #159225 (Split IncrCompSession out of Session)
- #159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- #160198 (Rework `smallest_range_containing` to handle duplicates)
- #160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- #160390 (autodiff: Handle slice-tailed DSTs in type trees)
- #160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- #160501 (Add bootstrap CLI snapshot test for testing miri)
- #160516 (Add regression test for HRTB projection in closure)
- #160520 (Add some tests for specialization)
- #160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- #160523 (Add regression test for opaque type)
- #160531 (docs: fix typo in AllowExprMetavar comment)
- #160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- #160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
@rust-bors
rust-borsBot merged commit ebab4cf into rust-lang:mainAug 5, 2026
14 checks passed
rust-timer added a commit that referenced this pull request Aug 5, 2026
Rollup merge of #158147 - devnexen:windows_fs_oflow_fix, r=Darksonn
std: fix stack buffer overflow in Windows junction_point
The guard checked `data_len > u16::MAX`, allowing paths far larger than `PathBuffer` (a fixed 16384-element array), which the subsequent single `copy_from` then overflows. Bound against `MAXIMUM_REPARSE_DATA_BUFFER_SIZE` plus header instead, matching the kernel's limit.
@rustbotrustbot added this to the 1.99.0 milestone Aug 5, 2026
github-actionsBot pushed a commit to rust-lang/rustc-dev-guide that referenced this pull request Aug 10, 2026
…uwer
Rollup of 25 pull requests
Successful merges:
- rust-lang/rust#158147 (std: fix stack buffer overflow in Windows junction_point)
- rust-lang/rust#160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- rust-lang/rust#160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- rust-lang/rust#160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- rust-lang/rust#160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- rust-lang/rust#160422 (move mir-opt miri tests to CI logic)
- rust-lang/rust#160444 (Avoid resolving path keywords outside `TypeNS`)
- rust-lang/rust#160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe by unsafe speculative flag)
- rust-lang/rust#155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- rust-lang/rust#158726 (std: move futex implementations into sys::sync::futex)
- rust-lang/rust#158762 (Emit thumb code on VEX V5)
- rust-lang/rust#159225 (Split IncrCompSession out of Session)
- rust-lang/rust#159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- rust-lang/rust#160198 (Rework `smallest_range_containing` to handle duplicates)
- rust-lang/rust#160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- rust-lang/rust#160390 (autodiff: Handle slice-tailed DSTs in type trees)
- rust-lang/rust#160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- rust-lang/rust#160501 (Add bootstrap CLI snapshot test for testing miri)
- rust-lang/rust#160516 (Add regression test for HRTB projection in closure)
- rust-lang/rust#160520 (Add some tests for specialization)
- rust-lang/rust#160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- rust-lang/rust#160523 (Add regression test for opaque type)
- rust-lang/rust#160531 (docs: fix typo in AllowExprMetavar comment)
- rust-lang/rust#160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- rust-lang/rust#160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
flip1995 pushed a commit to flip1995/rust-clippy that referenced this pull request Aug 17, 2026
…uwer
Rollup of 25 pull requests
Successful merges:
- rust-lang/rust#158147 (std: fix stack buffer overflow in Windows junction_point)
- rust-lang/rust#160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- rust-lang/rust#160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- rust-lang/rust#160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- rust-lang/rust#160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- rust-lang/rust#160422 (move mir-opt miri tests to CI logic)
- rust-lang/rust#160444 (Avoid resolving path keywords outside `TypeNS`)
- rust-lang/rust#160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe by unsafe speculative flag)
- rust-lang/rust#155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- rust-lang/rust#158726 (std: move futex implementations into sys::sync::futex)
- rust-lang/rust#158762 (Emit thumb code on VEX V5)
- rust-lang/rust#159225 (Split IncrCompSession out of Session)
- rust-lang/rust#159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- rust-lang/rust#160198 (Rework `smallest_range_containing` to handle duplicates)
- rust-lang/rust#160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- rust-lang/rust#160390 (autodiff: Handle slice-tailed DSTs in type trees)
- rust-lang/rust#160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- rust-lang/rust#160501 (Add bootstrap CLI snapshot test for testing miri)
- rust-lang/rust#160516 (Add regression test for HRTB projection in closure)
- rust-lang/rust#160520 (Add some tests for specialization)
- rust-lang/rust#160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- rust-lang/rust#160523 (Add regression test for opaque type)
- rust-lang/rust#160531 (docs: fix typo in AllowExprMetavar comment)
- rust-lang/rust#160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- rust-lang/rust#160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-filesystemArea: `std::fs`O-windowsOperating system: WindowsS-waiting-on-borsStatus: Waiting on bors to run and complete tests. Bors will change the label on completion.T-libsRelevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@devnexen@rustbot@rust-log-analyzer@ChrisDenton@Darksonn@jhpratt
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

std: fix stack buffer overflow in Windows junction_point - #158147

Merged
rust-bors[bot] merged 1 commit into
rust-lang:mainfrom
devnexen:windows_fs_oflow_fix
Aug 5, 2026
Merged

std: fix stack buffer overflow in Windows junction_point#158147
rust-bors[bot] merged 1 commit into
rust-lang:mainfrom
devnexen:windows_fs_oflow_fix

Conversation

@devnexen

@devnexendevnexen commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

View all comments

The guard checked data_len > u16::MAX, allowing paths far larger than PathBuffer (a fixed 16384-element array), which the subsequent single copy_from then overflows. Bound against MAXIMUM_REPARSE_DATA_BUFFER_SIZE plus header instead, matching the kernel's limit.

@rustbotrustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Jun 19, 2026
@rustbot

Copy link
Copy Markdown
Collaborator

r? @Darksonn

rustbot has assigned @Darksonn.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: @ChrisDenton, libs
  • @ChrisDenton, libs expanded to 12 candidates
  • Random selection from Darksonn, Mark-Simulacrum, clarfonthey, jhpratt

@DarksonnDarksonn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Comment threadlibrary/std/src/sys/fs/windows.rs Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It sounds like this should be changed to ptr[..abs_path.len()].copy_from_slice(abs_path) or similar so that we actually perform a bounds check here.

Also, it would be really nice with a test that'd catch this (may be easier to check that the test is failing if we insert a bounds check first).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

In fact, maybe the bounds check should be entirely rewritten to

ptr.get(..abs_path.len())
.ok_or_else(|| io::const_error!(io::ErrorKind::InvalidInput, "`original` path is too long"))?
.copy_from_slice(abs_path)

This way there's no risk that the two bounds checks are not kept in sync. For instance, why is there a + 8 in the previous check? I don't understand that part.

Comment threadlibrary/std/src/sys/fs/windows.rs Outdated
Comment on lines 1679 to 1683
PathBuffer: [MaybeUninit<u16>; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize],
}
let data_len = 12 + (abs_path.len() * 2);
if data_len > u16::MAX as usize {
if data_len + 8 > c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize {
return Err(io::const_error!(io::ErrorKind::InvalidInput, "`original` path is too long"));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

data_len counts the number of bytes, but MAXIMUM_REPARSE_DATA_BUFFER_SIZE counts the number of u16s. This doesn't sound right.

@rustbotrustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 19, 2026
@rustbot

Copy link
Copy Markdown
Collaborator

Reminder, once the PR becomes ready for a review, use @rustbot ready.

@rust-log-analyzer

This comment has been minimized.

@devnexen

Copy link
Copy Markdown
ContributorAuthor

@rustbot ready

@rustbotrustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jun 19, 2026

@DarksonnDarksonn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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


#[test]
#[cfg(windows)]
fn junction_point_overlong_path() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd like to see this regression test fail without the change. Do you mind opening a second temporary PR containing just the test so that we can run it through CI? We can close it again when we've confirmed the regression test catches the bug.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Confirmed failure in #158201.

Comment threadlibrary/std/src/sys/fs/windows.rs Outdated
Comment on lines +1694 to +1700
PathBuffer: [MaybeUninit::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize],
PathBuffer: [MaybeUninit::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize / 2],
};
// The path is followed by its null terminator and the (empty) print name's
// null terminator, so the buffer must hold two extra `u16`s. This single
// bounds check keeps the buffer, the copy, and `data_len` below in sync; if
// the path doesn't fit, fail rather than overflow the buffer.
let Some(ptr) = header.PathBuffer.get_mut(..abs_path.len() + 2) else {
return Err(io::const_error!(io::ErrorKind::InvalidInput, "`original` path is too long"));
};
ptr[..abs_path.len()].write_copy_of_slice(&abs_path);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This buffer is uninitialized. Don't you need to set path[abs_path.len()] and path[abs_path.len()+1] to zero?

@ChrisDentonChrisDentonJun 19, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The path has an explicit length so it doesn't need to be null terminated at all. I'm uncertain where that idea came from but it's probably just a misunderstanding? I mean, I guess there's no harm in writing a null but if so it shouldn't be part of the length.

@rustbotrustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 19, 2026
@ChrisDenton

Copy link
Copy Markdown
Member

To give some context here, this was originally a hacky function used only in tests. It's currently publicly exposed as a nightly-only API but it's not considered ready for stabilisation. E.g. 16kb is way too much for a stack buffer (though admittedly using a stack buffer for shorter paths would be useful).

PathBuffer: [MaybeUninit<u16>; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize],
// `MAXIMUM_REPARSE_DATA_BUFFER_SIZE` is a size in bytes; halve it for a
// count of `u16`s (the `readlink` path uses it as a byte buffer).
PathBuffer: [MaybeUninit<u16>; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize / 2],

@ChrisDentonChrisDentonJun 19, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This doesn't sound right at all. What makes you say MAXIMUM_REPARSE_DATA_BUFFER_SIZE is in bytes?

View changes since the review

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Huh, apparently it is.

The protocol docs make no mention of a maximum size, only that it's a 16 bit unsigned integer (hence my surprise at 16kb being a limit). But the public headers for the kernel API do have MAXIMUM_REPARSE_DATA_BUFFER_SIZE in bytes of 16kb.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should it be changed to an u8 array as well?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I would say no. It's the mount-point WCHAR path, and u16 keeps the copy a clean write_copy_of_slice(&abs_path).

@devnexen
devnexenforce-pushed the windows_fs_oflow_fix branch from d842451 to 28748e5CompareJune 21, 2026 06:05
rust-borsBot pushed a commit that referenced this pull request Jun 21, 2026
Temporary CI-verification test for #158147. Without the fix,
a >16 KiB junction target passes the old `> u16::MAX` length check yet
overflows the inline reparse stack buffer. This test must fail on master
and pass once the fix lands.
@DarksonnDarksonn added O-windows Operating system: Windows A-filesystem Area: `std::fs` labels Jun 21, 2026
@devnexen

Copy link
Copy Markdown
ContributorAuthor

@rustbot ready

@rustbotrustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jun 21, 2026

@DarksonnDarksonn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Comment threadlibrary/std/src/sys/fs/windows.rs Outdated
// Size of the reparse data after the 8-byte ReparseTag/ReparseDataLength/
// Reserved header: the four name offset/length `u16` fields (8 bytes) plus
// the path.
let data_len = 8 + abs_path.len() * 2;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Isn't it 16 bytes?

  • ReparseTag is 4 bytes
  • ReparseDataLength is 2 bytes
  • Reserved is 2 bytes
  • SubstituteNameOffset is 2 bytes
  • SubstituteNameLength is 2 bytes
  • PrintNameOffset is 2 bytes
  • PrintNameLength is 2 bytes

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Right, it's 16 bytes. Switched to offset_of! so both lengths derive from the struct.

@rustbotrustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 22, 2026
@devnexen
devnexenforce-pushed the windows_fs_oflow_fix branch from 28748e5 to b7af0d1CompareJune 22, 2026 23:24
@devnexen

Copy link
Copy Markdown
ContributorAuthor

@rustbot ready

@rust-borsrust-borsBot added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Jul 1, 2026
@rust-bors

rust-borsBot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

This pull request was unapproved.

View changes since this unapproval

@rust-borsrust-borsBot removed the S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. label Jul 1, 2026
@Darksonn

Copy link
Copy Markdown
Member

@devnexen Any update on this?

@devnexen
devnexenforce-pushed the windows_fs_oflow_fix branch from b7af0d1 to 74afb0aCompareJuly 25, 2026 15:16
@rustbot

This comment has been minimized.

The guard checked `data_len > u16::MAX`, allowing paths far larger than
`PathBuffer` (a fixed 16384-element array), which the subsequent single
`copy_from` then overflows. Bound against `MAXIMUM_REPARSE_DATA_BUFFER_SIZE`
plus header instead, matching the kernel's limit.
@devnexen
devnexenforce-pushed the windows_fs_oflow_fix branch from 74afb0a to 3313cd6CompareJuly 25, 2026 15:32
@rustbot

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@Darksonn

Copy link
Copy Markdown
Member

Please remember to use @rustbot ready when this is ready for review.

@bors try

@rust-bors

This comment has been minimized.

rust-borsBot pushed a commit that referenced this pull request Aug 5, 2026
std: fix stack buffer overflow in Windows junction_point
@rust-bors

rust-borsBot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

☀️ Try build successful (CI)
Build commit: 409d767 (409d767a80e64b1f76845dfd4cd80eaa8eb67050)
Base parent: 7218ebe (7218ebe93668f51a94a572b690c433dfdbdc2c3d)

@DarksonnDarksonn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@rust-bors

rust-borsBot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

📌 Commit 3313cd6 has been approved by Darksonn

It is now in the queue for this repository.

🌲 The tree is currently closed for pull requests below priority 10. This pull request will be tested once the tree is reopened.

Reason for tree closure: manually handling queue due to backlog

@rust-borsrust-borsBot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Aug 5, 2026
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Aug 5, 2026
…arksonn
std: fix stack buffer overflow in Windows junction_point
The guard checked `data_len > u16::MAX`, allowing paths far larger than `PathBuffer` (a fixed 16384-element array), which the subsequent single `copy_from` then overflows. Bound against `MAXIMUM_REPARSE_DATA_BUFFER_SIZE` plus header instead, matching the kernel's limit.
rust-borsBot pushed a commit that referenced this pull request Aug 5, 2026
…uwer
Rollup of 22 pull requests
Successful merges:
- #158147 (std: fix stack buffer overflow in Windows junction_point)
- #159784 (Hint that memchr returns an in-bounds index)
- #160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- #160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- #160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- #160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- #160422 (move mir-opt miri tests to CI logic)
- #160444 (Avoid resolving path keywords outside `TypeNS`)
- #160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe my unsafe speculative flag)
- #155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- #158726 (std: move futex implementations into sys::sync::futex)
- #159225 (Split IncrCompSession out of Session)
- #159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- #160198 (Rework `smallest_range_containing` to handle duplicates)
- #160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- #160390 (autodiff: Handle slice-tailed DSTs in type trees)
- #160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- #160520 (Add some tests for specialization)
- #160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- #160531 (docs: fix typo in AllowExprMetavar comment)
- #160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- #160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Aug 5, 2026
…arksonn
std: fix stack buffer overflow in Windows junction_point
The guard checked `data_len > u16::MAX`, allowing paths far larger than `PathBuffer` (a fixed 16384-element array), which the subsequent single `copy_from` then overflows. Bound against `MAXIMUM_REPARSE_DATA_BUFFER_SIZE` plus header instead, matching the kernel's limit.
rust-borsBot pushed a commit that referenced this pull request Aug 5, 2026
…uwer
Rollup of 25 pull requests
Successful merges:
- #154585 (treat no_mangle_generic_items as hard error instead of lint warning)
- #158147 (std: fix stack buffer overflow in Windows junction_point)
- #160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- #160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- #160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- #160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- #160422 (move mir-opt miri tests to CI logic)
- #160444 (Avoid resolving path keywords outside `TypeNS`)
- #160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe my unsafe speculative flag)
- #155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- #158726 (std: move futex implementations into sys::sync::futex)
- #158762 (Emit thumb code on VEX V5)
- #159225 (Split IncrCompSession out of Session)
- #159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- #160198 (Rework `smallest_range_containing` to handle duplicates)
- #160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- #160390 (autodiff: Handle slice-tailed DSTs in type trees)
- #160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- #160516 (Add regression test for HRTB projection in closure)
- #160520 (Add some tests for specialization)
- #160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- #160523 (Add regression test for opaque type)
- #160531 (docs: fix typo in AllowExprMetavar comment)
- #160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- #160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
rust-borsBot pushed a commit that referenced this pull request Aug 5, 2026
…uwer
Rollup of 25 pull requests
Successful merges:
- #158147 (std: fix stack buffer overflow in Windows junction_point)
- #160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- #160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- #160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- #160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- #160422 (move mir-opt miri tests to CI logic)
- #160444 (Avoid resolving path keywords outside `TypeNS`)
- #160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe by unsafe speculative flag)
- #155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- #158726 (std: move futex implementations into sys::sync::futex)
- #158762 (Emit thumb code on VEX V5)
- #159225 (Split IncrCompSession out of Session)
- #159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- #160198 (Rework `smallest_range_containing` to handle duplicates)
- #160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- #160390 (autodiff: Handle slice-tailed DSTs in type trees)
- #160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- #160501 (Add bootstrap CLI snapshot test for testing miri)
- #160516 (Add regression test for HRTB projection in closure)
- #160520 (Add some tests for specialization)
- #160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- #160523 (Add regression test for opaque type)
- #160531 (docs: fix typo in AllowExprMetavar comment)
- #160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- #160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
@rust-bors
rust-borsBot merged commit ebab4cf into rust-lang:mainAug 5, 2026
14 checks passed
rust-timer added a commit that referenced this pull request Aug 5, 2026
Rollup merge of #158147 - devnexen:windows_fs_oflow_fix, r=Darksonn
std: fix stack buffer overflow in Windows junction_point
The guard checked `data_len > u16::MAX`, allowing paths far larger than `PathBuffer` (a fixed 16384-element array), which the subsequent single `copy_from` then overflows. Bound against `MAXIMUM_REPARSE_DATA_BUFFER_SIZE` plus header instead, matching the kernel's limit.
@rustbotrustbot added this to the 1.99.0 milestone Aug 5, 2026
github-actionsBot pushed a commit to rust-lang/rustc-dev-guide that referenced this pull request Aug 10, 2026
…uwer
Rollup of 25 pull requests
Successful merges:
- rust-lang/rust#158147 (std: fix stack buffer overflow in Windows junction_point)
- rust-lang/rust#160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- rust-lang/rust#160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- rust-lang/rust#160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- rust-lang/rust#160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- rust-lang/rust#160422 (move mir-opt miri tests to CI logic)
- rust-lang/rust#160444 (Avoid resolving path keywords outside `TypeNS`)
- rust-lang/rust#160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe by unsafe speculative flag)
- rust-lang/rust#155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- rust-lang/rust#158726 (std: move futex implementations into sys::sync::futex)
- rust-lang/rust#158762 (Emit thumb code on VEX V5)
- rust-lang/rust#159225 (Split IncrCompSession out of Session)
- rust-lang/rust#159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- rust-lang/rust#160198 (Rework `smallest_range_containing` to handle duplicates)
- rust-lang/rust#160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- rust-lang/rust#160390 (autodiff: Handle slice-tailed DSTs in type trees)
- rust-lang/rust#160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- rust-lang/rust#160501 (Add bootstrap CLI snapshot test for testing miri)
- rust-lang/rust#160516 (Add regression test for HRTB projection in closure)
- rust-lang/rust#160520 (Add some tests for specialization)
- rust-lang/rust#160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- rust-lang/rust#160523 (Add regression test for opaque type)
- rust-lang/rust#160531 (docs: fix typo in AllowExprMetavar comment)
- rust-lang/rust#160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- rust-lang/rust#160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
flip1995 pushed a commit to flip1995/rust-clippy that referenced this pull request Aug 17, 2026
…uwer
Rollup of 25 pull requests
Successful merges:
- rust-lang/rust#158147 (std: fix stack buffer overflow in Windows junction_point)
- rust-lang/rust#160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- rust-lang/rust#160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- rust-lang/rust#160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- rust-lang/rust#160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- rust-lang/rust#160422 (move mir-opt miri tests to CI logic)
- rust-lang/rust#160444 (Avoid resolving path keywords outside `TypeNS`)
- rust-lang/rust#160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe by unsafe speculative flag)
- rust-lang/rust#155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- rust-lang/rust#158726 (std: move futex implementations into sys::sync::futex)
- rust-lang/rust#158762 (Emit thumb code on VEX V5)
- rust-lang/rust#159225 (Split IncrCompSession out of Session)
- rust-lang/rust#159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- rust-lang/rust#160198 (Rework `smallest_range_containing` to handle duplicates)
- rust-lang/rust#160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- rust-lang/rust#160390 (autodiff: Handle slice-tailed DSTs in type trees)
- rust-lang/rust#160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- rust-lang/rust#160501 (Add bootstrap CLI snapshot test for testing miri)
- rust-lang/rust#160516 (Add regression test for HRTB projection in closure)
- rust-lang/rust#160520 (Add some tests for specialization)
- rust-lang/rust#160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- rust-lang/rust#160523 (Add regression test for opaque type)
- rust-lang/rust#160531 (docs: fix typo in AllowExprMetavar comment)
- rust-lang/rust#160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- rust-lang/rust#160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-filesystemArea: `std::fs`O-windowsOperating system: WindowsS-waiting-on-borsStatus: Waiting on bors to run and complete tests. Bors will change the label on completion.T-libsRelevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@devnexen@rustbot@rust-log-analyzer@ChrisDenton@Darksonn@jhpratt
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

std: fix stack buffer overflow in Windows junction_point - #158147

Merged
rust-bors[bot] merged 1 commit into
rust-lang:mainfrom
devnexen:windows_fs_oflow_fix
Aug 5, 2026
Merged

std: fix stack buffer overflow in Windows junction_point#158147
rust-bors[bot] merged 1 commit into
rust-lang:mainfrom
devnexen:windows_fs_oflow_fix

Conversation

@devnexen

@devnexendevnexen commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

View all comments

The guard checked data_len > u16::MAX, allowing paths far larger than PathBuffer (a fixed 16384-element array), which the subsequent single copy_from then overflows. Bound against MAXIMUM_REPARSE_DATA_BUFFER_SIZE plus header instead, matching the kernel's limit.

@rustbotrustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Jun 19, 2026
@rustbot

Copy link
Copy Markdown
Collaborator

r? @Darksonn

rustbot has assigned @Darksonn.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: @ChrisDenton, libs
  • @ChrisDenton, libs expanded to 12 candidates
  • Random selection from Darksonn, Mark-Simulacrum, clarfonthey, jhpratt

@DarksonnDarksonn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Comment threadlibrary/std/src/sys/fs/windows.rs Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It sounds like this should be changed to ptr[..abs_path.len()].copy_from_slice(abs_path) or similar so that we actually perform a bounds check here.

Also, it would be really nice with a test that'd catch this (may be easier to check that the test is failing if we insert a bounds check first).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

In fact, maybe the bounds check should be entirely rewritten to

ptr.get(..abs_path.len())
.ok_or_else(|| io::const_error!(io::ErrorKind::InvalidInput, "`original` path is too long"))?
.copy_from_slice(abs_path)

This way there's no risk that the two bounds checks are not kept in sync. For instance, why is there a + 8 in the previous check? I don't understand that part.

Comment threadlibrary/std/src/sys/fs/windows.rs Outdated
Comment on lines 1679 to 1683
PathBuffer: [MaybeUninit<u16>; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize],
}
let data_len = 12 + (abs_path.len() * 2);
if data_len > u16::MAX as usize {
if data_len + 8 > c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize {
return Err(io::const_error!(io::ErrorKind::InvalidInput, "`original` path is too long"));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

data_len counts the number of bytes, but MAXIMUM_REPARSE_DATA_BUFFER_SIZE counts the number of u16s. This doesn't sound right.

@rustbotrustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 19, 2026
@rustbot

Copy link
Copy Markdown
Collaborator

Reminder, once the PR becomes ready for a review, use @rustbot ready.

@rust-log-analyzer

This comment has been minimized.

@devnexen

Copy link
Copy Markdown
ContributorAuthor

@rustbot ready

@rustbotrustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jun 19, 2026

@DarksonnDarksonn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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


#[test]
#[cfg(windows)]
fn junction_point_overlong_path() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd like to see this regression test fail without the change. Do you mind opening a second temporary PR containing just the test so that we can run it through CI? We can close it again when we've confirmed the regression test catches the bug.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Confirmed failure in #158201.

Comment threadlibrary/std/src/sys/fs/windows.rs Outdated
Comment on lines +1694 to +1700
PathBuffer: [MaybeUninit::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize],
PathBuffer: [MaybeUninit::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize / 2],
};
// The path is followed by its null terminator and the (empty) print name's
// null terminator, so the buffer must hold two extra `u16`s. This single
// bounds check keeps the buffer, the copy, and `data_len` below in sync; if
// the path doesn't fit, fail rather than overflow the buffer.
let Some(ptr) = header.PathBuffer.get_mut(..abs_path.len() + 2) else {
return Err(io::const_error!(io::ErrorKind::InvalidInput, "`original` path is too long"));
};
ptr[..abs_path.len()].write_copy_of_slice(&abs_path);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This buffer is uninitialized. Don't you need to set path[abs_path.len()] and path[abs_path.len()+1] to zero?

@ChrisDentonChrisDentonJun 19, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The path has an explicit length so it doesn't need to be null terminated at all. I'm uncertain where that idea came from but it's probably just a misunderstanding? I mean, I guess there's no harm in writing a null but if so it shouldn't be part of the length.

@rustbotrustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 19, 2026
@ChrisDenton

Copy link
Copy Markdown
Member

To give some context here, this was originally a hacky function used only in tests. It's currently publicly exposed as a nightly-only API but it's not considered ready for stabilisation. E.g. 16kb is way too much for a stack buffer (though admittedly using a stack buffer for shorter paths would be useful).

PathBuffer: [MaybeUninit<u16>; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize],
// `MAXIMUM_REPARSE_DATA_BUFFER_SIZE` is a size in bytes; halve it for a
// count of `u16`s (the `readlink` path uses it as a byte buffer).
PathBuffer: [MaybeUninit<u16>; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize / 2],

@ChrisDentonChrisDentonJun 19, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This doesn't sound right at all. What makes you say MAXIMUM_REPARSE_DATA_BUFFER_SIZE is in bytes?

View changes since the review

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Huh, apparently it is.

The protocol docs make no mention of a maximum size, only that it's a 16 bit unsigned integer (hence my surprise at 16kb being a limit). But the public headers for the kernel API do have MAXIMUM_REPARSE_DATA_BUFFER_SIZE in bytes of 16kb.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should it be changed to an u8 array as well?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I would say no. It's the mount-point WCHAR path, and u16 keeps the copy a clean write_copy_of_slice(&abs_path).

@devnexen
devnexenforce-pushed the windows_fs_oflow_fix branch from d842451 to 28748e5CompareJune 21, 2026 06:05
rust-borsBot pushed a commit that referenced this pull request Jun 21, 2026
Temporary CI-verification test for #158147. Without the fix,
a >16 KiB junction target passes the old `> u16::MAX` length check yet
overflows the inline reparse stack buffer. This test must fail on master
and pass once the fix lands.
@DarksonnDarksonn added O-windows Operating system: Windows A-filesystem Area: `std::fs` labels Jun 21, 2026
@devnexen

Copy link
Copy Markdown
ContributorAuthor

@rustbot ready

@rustbotrustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jun 21, 2026

@DarksonnDarksonn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Comment threadlibrary/std/src/sys/fs/windows.rs Outdated
// Size of the reparse data after the 8-byte ReparseTag/ReparseDataLength/
// Reserved header: the four name offset/length `u16` fields (8 bytes) plus
// the path.
let data_len = 8 + abs_path.len() * 2;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Isn't it 16 bytes?

  • ReparseTag is 4 bytes
  • ReparseDataLength is 2 bytes
  • Reserved is 2 bytes
  • SubstituteNameOffset is 2 bytes
  • SubstituteNameLength is 2 bytes
  • PrintNameOffset is 2 bytes
  • PrintNameLength is 2 bytes

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Right, it's 16 bytes. Switched to offset_of! so both lengths derive from the struct.

@rustbotrustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 22, 2026
@devnexen
devnexenforce-pushed the windows_fs_oflow_fix branch from 28748e5 to b7af0d1CompareJune 22, 2026 23:24
@devnexen

Copy link
Copy Markdown
ContributorAuthor

@rustbot ready

@rust-borsrust-borsBot added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Jul 1, 2026
@rust-bors

rust-borsBot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

This pull request was unapproved.

View changes since this unapproval

@rust-borsrust-borsBot removed the S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. label Jul 1, 2026
@Darksonn

Copy link
Copy Markdown
Member

@devnexen Any update on this?

@devnexen
devnexenforce-pushed the windows_fs_oflow_fix branch from b7af0d1 to 74afb0aCompareJuly 25, 2026 15:16
@rustbot

This comment has been minimized.

The guard checked `data_len > u16::MAX`, allowing paths far larger than
`PathBuffer` (a fixed 16384-element array), which the subsequent single
`copy_from` then overflows. Bound against `MAXIMUM_REPARSE_DATA_BUFFER_SIZE`
plus header instead, matching the kernel's limit.
@devnexen
devnexenforce-pushed the windows_fs_oflow_fix branch from 74afb0a to 3313cd6CompareJuly 25, 2026 15:32
@rustbot

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@Darksonn

Copy link
Copy Markdown
Member

Please remember to use @rustbot ready when this is ready for review.

@bors try

@rust-bors

This comment has been minimized.

rust-borsBot pushed a commit that referenced this pull request Aug 5, 2026
std: fix stack buffer overflow in Windows junction_point
@rust-bors

rust-borsBot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

☀️ Try build successful (CI)
Build commit: 409d767 (409d767a80e64b1f76845dfd4cd80eaa8eb67050)
Base parent: 7218ebe (7218ebe93668f51a94a572b690c433dfdbdc2c3d)

@DarksonnDarksonn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@rust-bors

rust-borsBot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

📌 Commit 3313cd6 has been approved by Darksonn

It is now in the queue for this repository.

🌲 The tree is currently closed for pull requests below priority 10. This pull request will be tested once the tree is reopened.

Reason for tree closure: manually handling queue due to backlog

@rust-borsrust-borsBot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Aug 5, 2026
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Aug 5, 2026
…arksonn
std: fix stack buffer overflow in Windows junction_point
The guard checked `data_len > u16::MAX`, allowing paths far larger than `PathBuffer` (a fixed 16384-element array), which the subsequent single `copy_from` then overflows. Bound against `MAXIMUM_REPARSE_DATA_BUFFER_SIZE` plus header instead, matching the kernel's limit.
rust-borsBot pushed a commit that referenced this pull request Aug 5, 2026
…uwer
Rollup of 22 pull requests
Successful merges:
- #158147 (std: fix stack buffer overflow in Windows junction_point)
- #159784 (Hint that memchr returns an in-bounds index)
- #160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- #160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- #160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- #160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- #160422 (move mir-opt miri tests to CI logic)
- #160444 (Avoid resolving path keywords outside `TypeNS`)
- #160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe my unsafe speculative flag)
- #155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- #158726 (std: move futex implementations into sys::sync::futex)
- #159225 (Split IncrCompSession out of Session)
- #159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- #160198 (Rework `smallest_range_containing` to handle duplicates)
- #160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- #160390 (autodiff: Handle slice-tailed DSTs in type trees)
- #160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- #160520 (Add some tests for specialization)
- #160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- #160531 (docs: fix typo in AllowExprMetavar comment)
- #160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- #160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Aug 5, 2026
…arksonn
std: fix stack buffer overflow in Windows junction_point
The guard checked `data_len > u16::MAX`, allowing paths far larger than `PathBuffer` (a fixed 16384-element array), which the subsequent single `copy_from` then overflows. Bound against `MAXIMUM_REPARSE_DATA_BUFFER_SIZE` plus header instead, matching the kernel's limit.
rust-borsBot pushed a commit that referenced this pull request Aug 5, 2026
…uwer
Rollup of 25 pull requests
Successful merges:
- #154585 (treat no_mangle_generic_items as hard error instead of lint warning)
- #158147 (std: fix stack buffer overflow in Windows junction_point)
- #160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- #160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- #160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- #160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- #160422 (move mir-opt miri tests to CI logic)
- #160444 (Avoid resolving path keywords outside `TypeNS`)
- #160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe my unsafe speculative flag)
- #155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- #158726 (std: move futex implementations into sys::sync::futex)
- #158762 (Emit thumb code on VEX V5)
- #159225 (Split IncrCompSession out of Session)
- #159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- #160198 (Rework `smallest_range_containing` to handle duplicates)
- #160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- #160390 (autodiff: Handle slice-tailed DSTs in type trees)
- #160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- #160516 (Add regression test for HRTB projection in closure)
- #160520 (Add some tests for specialization)
- #160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- #160523 (Add regression test for opaque type)
- #160531 (docs: fix typo in AllowExprMetavar comment)
- #160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- #160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
rust-borsBot pushed a commit that referenced this pull request Aug 5, 2026
…uwer
Rollup of 25 pull requests
Successful merges:
- #158147 (std: fix stack buffer overflow in Windows junction_point)
- #160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- #160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- #160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- #160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- #160422 (move mir-opt miri tests to CI logic)
- #160444 (Avoid resolving path keywords outside `TypeNS`)
- #160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe by unsafe speculative flag)
- #155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- #158726 (std: move futex implementations into sys::sync::futex)
- #158762 (Emit thumb code on VEX V5)
- #159225 (Split IncrCompSession out of Session)
- #159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- #160198 (Rework `smallest_range_containing` to handle duplicates)
- #160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- #160390 (autodiff: Handle slice-tailed DSTs in type trees)
- #160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- #160501 (Add bootstrap CLI snapshot test for testing miri)
- #160516 (Add regression test for HRTB projection in closure)
- #160520 (Add some tests for specialization)
- #160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- #160523 (Add regression test for opaque type)
- #160531 (docs: fix typo in AllowExprMetavar comment)
- #160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- #160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
@rust-bors
rust-borsBot merged commit ebab4cf into rust-lang:mainAug 5, 2026
14 checks passed
rust-timer added a commit that referenced this pull request Aug 5, 2026
Rollup merge of #158147 - devnexen:windows_fs_oflow_fix, r=Darksonn
std: fix stack buffer overflow in Windows junction_point
The guard checked `data_len > u16::MAX`, allowing paths far larger than `PathBuffer` (a fixed 16384-element array), which the subsequent single `copy_from` then overflows. Bound against `MAXIMUM_REPARSE_DATA_BUFFER_SIZE` plus header instead, matching the kernel's limit.
@rustbotrustbot added this to the 1.99.0 milestone Aug 5, 2026
github-actionsBot pushed a commit to rust-lang/rustc-dev-guide that referenced this pull request Aug 10, 2026
…uwer
Rollup of 25 pull requests
Successful merges:
- rust-lang/rust#158147 (std: fix stack buffer overflow in Windows junction_point)
- rust-lang/rust#160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- rust-lang/rust#160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- rust-lang/rust#160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- rust-lang/rust#160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- rust-lang/rust#160422 (move mir-opt miri tests to CI logic)
- rust-lang/rust#160444 (Avoid resolving path keywords outside `TypeNS`)
- rust-lang/rust#160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe by unsafe speculative flag)
- rust-lang/rust#155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- rust-lang/rust#158726 (std: move futex implementations into sys::sync::futex)
- rust-lang/rust#158762 (Emit thumb code on VEX V5)
- rust-lang/rust#159225 (Split IncrCompSession out of Session)
- rust-lang/rust#159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- rust-lang/rust#160198 (Rework `smallest_range_containing` to handle duplicates)
- rust-lang/rust#160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- rust-lang/rust#160390 (autodiff: Handle slice-tailed DSTs in type trees)
- rust-lang/rust#160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- rust-lang/rust#160501 (Add bootstrap CLI snapshot test for testing miri)
- rust-lang/rust#160516 (Add regression test for HRTB projection in closure)
- rust-lang/rust#160520 (Add some tests for specialization)
- rust-lang/rust#160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- rust-lang/rust#160523 (Add regression test for opaque type)
- rust-lang/rust#160531 (docs: fix typo in AllowExprMetavar comment)
- rust-lang/rust#160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- rust-lang/rust#160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
flip1995 pushed a commit to flip1995/rust-clippy that referenced this pull request Aug 17, 2026
…uwer
Rollup of 25 pull requests
Successful merges:
- rust-lang/rust#158147 (std: fix stack buffer overflow in Windows junction_point)
- rust-lang/rust#160130 (Select cache values to verify by key fingerprint, not value fingerprint)
- rust-lang/rust#160343 (Rename `OutlivesPredicate` to `OutlivesClause`)
- rust-lang/rust#160360 (Remove rustc_middle dependency on rustc_hir_pretty)
- rust-lang/rust#160387 (rustc_codegen_ssa: Correctly apply the static `--jobs-backend` limit to backend parallelism)
- rust-lang/rust#160422 (move mir-opt miri tests to CI logic)
- rust-lang/rust#160444 (Avoid resolving path keywords outside `TypeNS`)
- rust-lang/rust#160510 (Resolver: (un)tracked borrows for `CmRefCell` made safe by unsafe speculative flag)
- rust-lang/rust#155424 ([blocked] Link to proposed LLM policy in CONTRIBUTING and pull request template)
- rust-lang/rust#158726 (std: move futex implementations into sys::sync::futex)
- rust-lang/rust#158762 (Emit thumb code on VEX V5)
- rust-lang/rust#159225 (Split IncrCompSession out of Session)
- rust-lang/rust#159820 (Make the `rustc_unsafe_specialization_marker` attribute actually `unsafe`)
- rust-lang/rust#160198 (Rework `smallest_range_containing` to handle duplicates)
- rust-lang/rust#160362 (Split `SpannedTypeVisitor` into its own crate, `rustc_ty_walk`)
- rust-lang/rust#160390 (autodiff: Handle slice-tailed DSTs in type trees)
- rust-lang/rust#160420 (Suggest `cast_signed()` for overflowing signed integer literals)
- rust-lang/rust#160501 (Add bootstrap CLI snapshot test for testing miri)
- rust-lang/rust#160516 (Add regression test for HRTB projection in closure)
- rust-lang/rust#160520 (Add some tests for specialization)
- rust-lang/rust#160522 (fix(bootstrap): Normalize the names of proc macro dependency crates)
- rust-lang/rust#160523 (Add regression test for opaque type)
- rust-lang/rust#160531 (docs: fix typo in AllowExprMetavar comment)
- rust-lang/rust#160538 (Update expect messages in tcp.rs doc examples to follow the style guide)
- rust-lang/rust#160548 (bootstrap: Register `coverage-map` and `coverage-run` aliases via a separate step)
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-filesystemArea: `std::fs`O-windowsOperating system: WindowsS-waiting-on-borsStatus: Waiting on bors to run and complete tests. Bors will change the label on completion.T-libsRelevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@devnexen@rustbot@rust-log-analyzer@ChrisDenton@Darksonn@jhpratt