1
1
Fork 0
mirror of https://github.com/pbatard/rufus.git synced 2024-08-14 23:57:05 +00:00

[core] work around Windows' moronic behaviour for mounted VHDs

* If you attempt to read past the end of a mounted VHD, not only will Windows happily
  return data that doesn't exist (instead of returning End of Disk), but it will also
  corrupt the existing data!
* So, to appease the capricious Windows gods, we now make sure that we never attempt
  to read (or write) past the boundaries of the source or target when writing images.
* This should address the last issue from #2468.
* Also set version to rufus-next and make some small improvement in winio.h.
This commit is contained in:
Pete Batard 2024-06-03 12:58:37 +01:00
parent ae3c65e7f8
commit bdff2dc45c
No known key found for this signature in database
GPG key ID: 38E0CF5E69EDD671
5 changed files with 39 additions and 33 deletions

20
configure vendored
View file

@ -1,6 +1,6 @@
#! /bin/sh #! /bin/sh
# Guess values for system-dependent variables and create Makefiles. # Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.71 for rufus 4.5. # Generated by GNU Autoconf 2.71 for rufus 4.6.
# #
# Report bugs to <https://github.com/pbatard/rufus/issues>. # Report bugs to <https://github.com/pbatard/rufus/issues>.
# #
@ -611,8 +611,8 @@ MAKEFLAGS=
# Identity of this package. # Identity of this package.
PACKAGE_NAME='rufus' PACKAGE_NAME='rufus'
PACKAGE_TARNAME='rufus' PACKAGE_TARNAME='rufus'
PACKAGE_VERSION='4.5' PACKAGE_VERSION='4.6'
PACKAGE_STRING='rufus 4.5' PACKAGE_STRING='rufus 4.6'
PACKAGE_BUGREPORT='https://github.com/pbatard/rufus/issues' PACKAGE_BUGREPORT='https://github.com/pbatard/rufus/issues'
PACKAGE_URL='https://rufus.ie' PACKAGE_URL='https://rufus.ie'
@ -1269,7 +1269,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing. # Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh. # This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF cat <<_ACEOF
\`configure' configures rufus 4.5 to adapt to many kinds of systems. \`configure' configures rufus 4.6 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]... Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1336,7 +1336,7 @@ fi
if test -n "$ac_init_help"; then if test -n "$ac_init_help"; then
case $ac_init_help in case $ac_init_help in
short | recursive ) echo "Configuration of rufus 4.5:";; short | recursive ) echo "Configuration of rufus 4.6:";;
esac esac
cat <<\_ACEOF cat <<\_ACEOF
@ -1428,7 +1428,7 @@ fi
test -n "$ac_init_help" && exit $ac_status test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then if $ac_init_version; then
cat <<\_ACEOF cat <<\_ACEOF
rufus configure 4.5 rufus configure 4.6
generated by GNU Autoconf 2.71 generated by GNU Autoconf 2.71
Copyright (C) 2021 Free Software Foundation, Inc. Copyright (C) 2021 Free Software Foundation, Inc.
@ -1504,7 +1504,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake. running configure, to aid debugging if configure makes a mistake.
It was created by rufus $as_me 4.5, which was It was created by rufus $as_me 4.6, which was
generated by GNU Autoconf 2.71. Invocation command line was generated by GNU Autoconf 2.71. Invocation command line was
$ $0$ac_configure_args_raw $ $0$ac_configure_args_raw
@ -2767,7 +2767,7 @@ fi
# Define the identity of the package. # Define the identity of the package.
PACKAGE='rufus' PACKAGE='rufus'
VERSION='4.5' VERSION='4.6'
printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h
@ -5309,7 +5309,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their # report actual input values of CONFIG_FILES etc. instead of their
# values after options handling. # values after options handling.
ac_log=" ac_log="
This file was extended by rufus $as_me 4.5, which was This file was extended by rufus $as_me 4.6, which was
generated by GNU Autoconf 2.71. Invocation command line was generated by GNU Autoconf 2.71. Invocation command line was
CONFIG_FILES = $CONFIG_FILES CONFIG_FILES = $CONFIG_FILES
@ -5365,7 +5365,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config='$ac_cs_config_escaped' ac_cs_config='$ac_cs_config_escaped'
ac_cs_version="\\ ac_cs_version="\\
rufus config.status 4.5 rufus config.status 4.6
configured by $0, generated by GNU Autoconf 2.71, configured by $0, generated by GNU Autoconf 2.71,
with options \\"\$ac_cs_config\\" with options \\"\$ac_cs_config\\"

View file

@ -1,4 +1,4 @@
AC_INIT([rufus], [4.5], [https://github.com/pbatard/rufus/issues], [rufus], [https://rufus.ie]) AC_INIT([rufus], [4.6], [https://github.com/pbatard/rufus/issues], [rufus], [https://rufus.ie])
AM_INIT_AUTOMAKE([-Wno-portability foreign no-dist no-dependencies]) AM_INIT_AUTOMAKE([-Wno-portability foreign no-dist no-dependencies])
AC_CONFIG_SRCDIR([src/rufus.c]) AC_CONFIG_SRCDIR([src/rufus.c])
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])

View file

@ -1150,8 +1150,8 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, BOOL bZeroDrive)
BOOL s, ret = FALSE; BOOL s, ret = FALSE;
LARGE_INTEGER li; LARGE_INTEGER li;
HANDLE hSourceImage = INVALID_HANDLE_VALUE; HANDLE hSourceImage = INVALID_HANDLE_VALUE;
DWORD i, read_size[NUM_BUFFERS], write_size, comp_size, buf_size; DWORD i, read_size[NUM_BUFFERS] = { 0 }, write_size, comp_size, buf_size;
uint64_t wb, target_size = bZeroDrive ? SelectedDrive.DiskSize : img_report.image_size; uint64_t wb, target_size = bZeroDrive ? SelectedDrive.DiskSize : MIN((uint64_t)SelectedDrive.DiskSize, img_report.image_size);
uint64_t cur_value, last_value = 0; uint64_t cur_value, last_value = 0;
int64_t bled_ret; int64_t bled_ret;
uint8_t* buffer = NULL; uint8_t* buffer = NULL;
@ -1341,7 +1341,7 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, BOOL bZeroDrive)
assert((uintptr_t)buffer % SelectedDrive.SectorSize == 0); assert((uintptr_t)buffer % SelectedDrive.SectorSize == 0);
// Start the initial read // Start the initial read
ReadFileAsync(hSourceImage, &buffer[read_bufnum * buf_size], buf_size); ReadFileAsync(hSourceImage, &buffer[read_bufnum * buf_size], (DWORD)MIN(buf_size, target_size));
read_size[proc_bufnum] = 1; // To avoid early loop exit read_size[proc_bufnum] = 1; // To avoid early loop exit
for (wb = 0; read_size[proc_bufnum] != 0; wb += read_size[proc_bufnum]) { for (wb = 0; read_size[proc_bufnum] != 0; wb += read_size[proc_bufnum]) {
@ -1362,21 +1362,25 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, BOOL bZeroDrive)
goto out; goto out;
} }
// 2. Update the read size
// 2a) Don't overflow our projected size (mostly for VHDs) // 2. WriteFile fails unless the size is a multiple of sector size
if (wb + read_size[read_bufnum] > target_size) if (read_size[read_bufnum] % SelectedDrive.SectorSize != 0) {
read_size[read_bufnum] = (DWORD)(target_size - wb); assert(HI_ALIGN_X_TO_Y(read_size[read_bufnum], SelectedDrive.SectorSize) <= buf_size);
// 2b) WriteFile fails unless the size is a multiple of sector size read_size[read_bufnum] = HI_ALIGN_X_TO_Y(read_size[read_bufnum], SelectedDrive.SectorSize);
if (read_size[read_bufnum] % SelectedDrive.SectorSize != 0) }
read_size[read_bufnum] = ((read_size[read_bufnum] + SelectedDrive.SectorSize - 1) /
SelectedDrive.SectorSize) * SelectedDrive.SectorSize;
// 3. Switch to the next reading buffer // 3. Switch to the next reading buffer
proc_bufnum = read_bufnum; proc_bufnum = read_bufnum;
read_bufnum = (read_bufnum + 1) % NUM_BUFFERS; read_bufnum = (read_bufnum + 1) % NUM_BUFFERS;
// 3. Launch the next asynchronous read operation // 3. Launch the next asynchronous read operation
ReadFileAsync(hSourceImage, &buffer[read_bufnum * buf_size], buf_size); // It is VERY IMPORTANT here that we don't attempt to read past the source
// or target sizes, as mounted VHDs will SCREW YOU if you attempt to do so
// and will even start returning ERRONEOUS DATA for sectors before the end
// of the disk... So we make sure to adjust the size not to ever overflow.
// Also we need to make sure we add read_size[proc_bufnum] to wb since we
// have already read the data and are about to write it.
ReadFileAsync(hSourceImage, &buffer[read_bufnum * buf_size], (DWORD)MIN(buf_size, target_size - (wb + read_size[proc_bufnum])));
// 4. Synchronously write the current data buffer // 4. Synchronously write the current data buffer
for (i = 1; i <= WRITE_RETRIES; i++) { for (i = 1; i <= WRITE_RETRIES; i++) {

View file

@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDD_DIALOG DIALOGEX 12, 12, 232, 326 IDD_DIALOG DIALOGEX 12, 12, 232, 326
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_ACCEPTFILES EXSTYLE WS_EX_ACCEPTFILES
CAPTION "Rufus 4.5.2181" CAPTION "Rufus 4.6.2182"
FONT 9, "Segoe UI Symbol", 400, 0, 0x0 FONT 9, "Segoe UI Symbol", 400, 0, 0x0
BEGIN BEGIN
LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP
@ -397,8 +397,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 4,5,2181,0 FILEVERSION 4,6,2182,0
PRODUCTVERSION 4,5,2181,0 PRODUCTVERSION 4,6,2182,0
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -416,13 +416,13 @@ BEGIN
VALUE "Comments", "https://rufus.ie" VALUE "Comments", "https://rufus.ie"
VALUE "CompanyName", "Akeo Consulting" VALUE "CompanyName", "Akeo Consulting"
VALUE "FileDescription", "Rufus" VALUE "FileDescription", "Rufus"
VALUE "FileVersion", "4.5.2181" VALUE "FileVersion", "4.6.2182"
VALUE "InternalName", "Rufus" VALUE "InternalName", "Rufus"
VALUE "LegalCopyright", "<22> 2011-2024 Pete Batard (GPL v3)" VALUE "LegalCopyright", "<22> 2011-2024 Pete Batard (GPL v3)"
VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html" VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html"
VALUE "OriginalFilename", "rufus-4.5.exe" VALUE "OriginalFilename", "rufus-4.6.exe"
VALUE "ProductName", "Rufus" VALUE "ProductName", "Rufus"
VALUE "ProductVersion", "4.5.2181" VALUE "ProductVersion", "4.6.2182"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View file

@ -102,11 +102,13 @@ static __inline BOOL ReadFileAsync(HANDLE h, LPVOID lpBuffer, DWORD nNumberOfByt
ASYNC_FD* fd = (ASYNC_FD*)h; ASYNC_FD* fd = (ASYNC_FD*)h;
fd->Overlapped.bOffsetUpdated = FALSE; fd->Overlapped.bOffsetUpdated = FALSE;
if (!ReadFile(fd->hFile, lpBuffer, nNumberOfBytesToRead, NULL, if (!ReadFile(fd->hFile, lpBuffer, nNumberOfBytesToRead, NULL,
(OVERLAPPED*)&fd->Overlapped)) (OVERLAPPED*)&fd->Overlapped)) {
// TODO: Is it possible to get ERROR_HANDLE_EOF here? // Is it possible to get ERROR_HANDLE_EOF here?
assert(GetLastError() != ERROR_HANDLE_EOF);
fd->iStatus = (GetLastError() == ERROR_IO_PENDING) ? -1 : 0; fd->iStatus = (GetLastError() == ERROR_IO_PENDING) ? -1 : 0;
else } else {
fd->iStatus = 1; fd->iStatus = 1;
}
return (fd->iStatus != 0); return (fd->iStatus != 0);
} }
@ -165,11 +167,11 @@ static __inline BOOL GetSizeAsync(HANDLE h, LPDWORD lpNumberOfBytes)
SetLastError(ERROR_NO_MORE_ITEMS); SetLastError(ERROR_NO_MORE_ITEMS);
return FALSE; return FALSE;
} }
fd->Overlapped.bOffsetUpdated = TRUE;
if (!GetOverlappedResultEx(fd->hFile, (OVERLAPPED*)&fd->Overlapped, if (!GetOverlappedResultEx(fd->hFile, (OVERLAPPED*)&fd->Overlapped,
lpNumberOfBytes, WRITE_TIMEOUT, (fd->iStatus < 0))) lpNumberOfBytes, WRITE_TIMEOUT, (fd->iStatus < 0)))
// When reading from VHD/VHDX we get SECTOR_NOT_FOUND rather than EOF for the end of the drive // When reading from VHD/VHDX we get SECTOR_NOT_FOUND rather than EOF for the end of the drive
return (GetLastError() == ERROR_HANDLE_EOF || GetLastError() == ERROR_SECTOR_NOT_FOUND); return (GetLastError() == ERROR_HANDLE_EOF || GetLastError() == ERROR_SECTOR_NOT_FOUND);
fd->Overlapped.Offset += *lpNumberOfBytes; fd->Overlapped.Offset += *lpNumberOfBytes;
fd->Overlapped.bOffsetUpdated = TRUE;
return TRUE; return TRUE;
} }