Skip to content

Commit 6861750

Browse files
committed
Fix buffer overrun in (test-only) symlink_junction
1 parent 540a50d commit 6861750

File tree

1 file changed

+25
-9
lines changed
  • library/std/src/sys/windows

1 file changed

+25
-9
lines changed

library/std/src/sys/windows/fs.rs

+25-9
Original file line numberDiff line numberDiff line change
@@ -1403,24 +1403,40 @@ fn symlink_junction_inner(original: &Path, junction: &Path) -> io::Result<()> {
14031403
opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT | c::FILE_FLAG_BACKUP_SEMANTICS);
14041404
let f = File::open(junction, &opts)?;
14051405
let h = f.as_inner().as_raw_handle();
1406-
14071406
unsafe {
14081407
let mut data = Align8([MaybeUninit::<u8>::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]);
14091408
let data_ptr = data.0.as_mut_ptr();
1409+
let data_end = data_ptr.add(c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
14101410
let db = data_ptr.cast::<c::REPARSE_MOUNTPOINT_DATA_BUFFER>();
14111411
// Zero the header to ensure it's fully initialized, including reserved parameters.
14121412
*db = mem::zeroed();
1413-
let buf = ptr::addr_of_mut!((*db).ReparseTarget).cast::<c::WCHAR>();
1414-
let mut i = 0;
1413+
let reparse_target_slice = {
1414+
let buf_start = ptr::addr_of_mut!((*db).ReparseTarget).cast::<c::WCHAR>();
1415+
// Compute offset in bytes and then divide so that we round down
1416+
// rather than hit any UB (admittedly this arithmetic should work
1417+
// out so that this isn't necessary)
1418+
let buf_len_bytes = usize::try_from(data_end.byte_offset_from(buf_start)).unwrap();
1419+
let buf_len_wchars = buf_len_bytes / core::mem::size_of::<c::WCHAR>();
1420+
core::slice::from_raw_parts_mut(buf_start, buf_len_wchars)
1421+
};
1422+
14151423
// FIXME: this conversion is very hacky
1416-
let v = br"\??\";
1417-
let v = v.iter().map(|x| *x as u16);
1418-
for c in v.chain(original.as_os_str().encode_wide()) {
1419-
*buf.add(i) = c;
1424+
let iter = br"\??\"
1425+
.iter()
1426+
.map(|x| *x as u16)
1427+
.chain(original.as_os_str().encode_wide())
1428+
.chain(core::iter::once(0));
1429+
let mut i = 0;
1430+
for c in iter {
1431+
if i >= reparse_target_slice.len() {
1432+
return Err(crate::io::const_io_error!(
1433+
crate::io::ErrorKind::InvalidFilename,
1434+
"Input filename is too long"
1435+
));
1436+
}
1437+
reparse_target_slice[i] = c;
14201438
i += 1;
14211439
}
1422-
*buf.add(i) = 0;
1423-
i += 1;
14241440
(*db).ReparseTag = c::IO_REPARSE_TAG_MOUNT_POINT;
14251441
(*db).ReparseTargetMaximumLength = (i * 2) as c::WORD;
14261442
(*db).ReparseTargetLength = ((i - 1) * 2) as c::WORD;

0 commit comments

Comments
 (0)