From 1e6e38b18075adc8527b08e7ab8a6c99946cf415 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Mon, 6 Apr 2020 16:27:05 +0100 Subject: [PATCH] [iso] update MD5SUMS/md5sums.txt text file for distros that have them * The upcoming Ubuntu 20.04 comes with MD5 validation turned on by default. * When creating persistent boot media, we may update some of the validated files to add persistence, update the search labels, etc. * Make sure that the files we modify get their MD5 updated where needed. * Also add 'loopback.cfg' to the list of config files we can add persistence to. * Part of #1499 --- src/iso.c | 118 +++++++++++++++++++++++++++++++++++++++++---------- src/rufus.h | 5 ++- src/rufus.rc | 10 ++--- src/stdio.c | 49 ++++++++++++++++++++- 4 files changed, 153 insertions(+), 29 deletions(-) diff --git a/src/iso.c b/src/iso.c index fc7eae2b..079b4100 100644 --- a/src/iso.c +++ b/src/iso.c @@ -1,7 +1,7 @@ /* * Rufus: The Reliable USB Formatting Utility * ISO file extraction - * Copyright © 2011-2019 Pete Batard + * Copyright © 2011-2020 Pete Batard * Based on libcdio's iso & udf samples: * Copyright © 2003-2014 Rocky Bernstein * @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -82,6 +83,7 @@ static const char* bootmgr_efi_name = "bootmgr.efi"; static const char* grldr_name = "grldr"; static const char* ldlinux_name = "ldlinux.sys"; static const char* ldlinux_c32 = "ldlinux.c32"; +static const char* md5sum_name[] = { "MD5SUMS", "md5sum.txt" }; static const char* casper_dirname = "/casper"; static const char* efi_dirname = "/efi/boot"; static const char* efi_bootname[] = { "bootia32.efi", "bootia64.efi", "bootx64.efi", "bootarm.efi", "bootaa64.efi", "bootebc.efi" }; @@ -90,7 +92,7 @@ static const char* wininst_name[] = { "install.wim", "install.esd", "install.swm // We only support GRUB/BIOS (x86) that uses a standard config dir (/boot/grub/i386-pc/) // If the disc was mastered properly, GRUB/EFI will take care of itself static const char* grub_dirname = "/boot/grub/i386-pc"; -static const char* grub_cfg = "grub.cfg"; +static const char* grub_cfg[] = { "grub.cfg", "loopback.cfg" }; static const char* menu_cfg = "menu.cfg"; // NB: Do not alter the order of the array below without validating hardcoded indexes in check_iso_props static const char* syslinux_cfg[] = { "isolinux.cfg", "syslinux.cfg", "extlinux.conf", "txt.cfg" }; @@ -110,7 +112,7 @@ static const int64_t old_c32_threshold[NB_OLD_C32] = OLD_C32_THRESHOLD; static uint8_t joliet_level = 0; static uint64_t total_blocks, nb_blocks; static BOOL scan_only = FALSE; -static StrArray config_path, isolinux_path; +static StrArray config_path, isolinux_path, modified_path; // Ensure filenames do not contain invalid FAT32 or NTFS characters static __inline char* sanitize_filename(char* filename, BOOL* is_identical) @@ -183,9 +185,11 @@ static BOOL check_iso_props(const char* psz_dirname, int64_t file_length, const len = safe_strlen(psz_basename); if ((len >= 4) && safe_stricmp(&psz_basename[len - 4], ".cfg") == 0) { props->is_cfg = TRUE; - if (safe_stricmp(psz_basename, grub_cfg) == 0) { - props->is_grub_cfg = TRUE; - } else if (safe_stricmp(psz_basename, menu_cfg) == 0) { + for (i = 0; i < ARRAYSIZE(grub_cfg); i++) { + if (safe_stricmp(psz_basename, grub_cfg[i]) == 0) + props->is_grub_cfg = TRUE; + } + if (safe_stricmp(psz_basename, menu_cfg) == 0) { props->is_menu_cfg = TRUE; } } @@ -218,6 +222,7 @@ static BOOL check_iso_props(const char* psz_dirname, int64_t file_length, const img_report.has_bootmgr = TRUE; } if (safe_stricmp(psz_basename, bootmgr_efi_name) == 0) { + img_report.has_efi |= 1; img_report.has_bootmgr_efi = TRUE; } if (safe_stricmp(psz_basename, grldr_name) == 0) { @@ -226,12 +231,13 @@ static BOOL check_iso_props(const char* psz_dirname, int64_t file_length, const if (safe_stricmp(psz_basename, kolibri_name) == 0) { img_report.has_kolibrios = TRUE; } - if (safe_stricmp(psz_basename, bootmgr_efi_name) == 0) { - img_report.has_efi |= 1; - } if (safe_stricmp(psz_basename, manjaro_marker) == 0) { img_report.disable_iso = TRUE; } + for (i = 0; i < ARRAYSIZE(md5sum_name); i++) { + if (safe_stricmp(psz_basename, md5sum_name[i]) == 0) + img_report.has_md5sum = (uint8_t)(i + 1); + } } // Check for ReactOS' setupldr.sys anywhere @@ -248,7 +254,7 @@ static BOOL check_iso_props(const char* psz_dirname, int64_t file_length, const if (safe_stricmp(psz_dirname, efi_dirname) == 0) { for (i=0; iis_grub_cfg) || (props->is_menu_cfg) || (props->is_syslinux_cfg)) { - // Ubuntu & derivatives are assumed to use 'file=/cdrom/preseed/...' - // somewhere in their kernel options and use 'persistent' as keyword. if (replace_in_token_data(src, props->is_grub_cfg ? "linux" : "append", - "file=/cdrom/preseed", "persistent file=/cdrom/preseed", TRUE) != NULL) + "file=/cdrom/preseed", "persistent file=/cdrom/preseed", TRUE) != NULL) { + // Ubuntu & derivatives are assumed to use 'file=/cdrom/preseed/...' + // somewhere in their kernel options and use 'persistent' as keyword. uprintf(" Added 'persistent' kernel option"); - // Debian & derivatives are assumed to use 'boot=live' in - // their kernel options and use 'persistence' as keyword. - else if (replace_in_token_data(src, props->is_grub_cfg ? "linux" : "append", - "boot=live", "boot=live persistence", TRUE) != NULL) + modified = TRUE; + } else if (replace_in_token_data(src, props->is_grub_cfg ? "linux" : "append", + "boot=live", "boot=live persistence", TRUE) != NULL) { + // Debian & derivatives are assumed to use 'boot=live' in + // their kernel options and use 'persistence' as keyword. uprintf(" Added 'persistence' kernel option"); + modified = TRUE; + } // Other distros can go to hell. Seriously, just check all partitions for // an ext volume with the right label and use persistence *THEN*. I mean, // why on earth do you need a bloody *NONSTANDARD* kernel option and/or a @@ -336,12 +346,15 @@ static void fix_config(const char* psz_fullpath, const char* psz_path, const cha if (props->is_grub_cfg) { // Older versions of GRUB EFI used "linuxefi", newer just use "linux" if ((replace_in_token_data(src, "linux", iso_label, usb_label, TRUE) != NULL) || - (replace_in_token_data(src, "linuxefi", iso_label, usb_label, TRUE) != NULL)) + (replace_in_token_data(src, "linuxefi", iso_label, usb_label, TRUE) != NULL)) { uprintf(" Patched %s: '%s' ➔ '%s'\n", src, iso_label, usb_label); - } - else if (replace_in_token_data(src, (props->is_conf) ? "options" : "append", - iso_label, usb_label, TRUE) != NULL) + modified = TRUE; + } + } else if (replace_in_token_data(src, (props->is_conf) ? "options" : "append", + iso_label, usb_label, TRUE) != NULL) { uprintf(" Patched %s: '%s' ➔ '%s'\n", src, iso_label, usb_label); + modified = TRUE; + } } safe_free(iso_label); safe_free(usb_label); @@ -364,13 +377,18 @@ static void fix_config(const char* psz_fullpath, const char* psz_path, const cha if ((iso_label != NULL) && (usb_label != NULL)) { safe_sprintf(iso_label, MAX_PATH, "cd9660:/dev/iso9660/%s", img_report.label); safe_sprintf(usb_label, MAX_PATH, "msdosfs:/dev/msdosfs/%s", img_report.usb_label); - if (replace_in_token_data(src, "set", iso_label, usb_label, TRUE) != NULL) + if (replace_in_token_data(src, "set", iso_label, usb_label, TRUE) != NULL) { uprintf(" Patched %s: '%s' ➔ '%s'\n", src, iso_label, usb_label); + modified = TRUE; + } } safe_free(iso_label); safe_free(usb_label); } + if (modified) + StrArrayAdd(&modified_path, psz_fullpath, TRUE); + free(src); } @@ -551,6 +569,59 @@ out: return 1; } +// This upates the MD5SUMS/md5sum.txt file that some distros (Ubuntu, Mint...) +// use to validate the media. Because we may alter some of the validated files +// to add persistence and whatnot, we need to alter the MD5 list as a result. +// The format of the file is expected to always be " " on +// individual lines. +static void update_md5sum(void) +{ + BOOL display_header = TRUE; + intptr_t pos; + uint32_t i, j, size, md5_size; + uint8_t *buf = NULL, sum[16]; + char md5_path[64], *md5_data = NULL, *str_pos; + + if (!img_report.has_md5sum) + return; + + assert(img_report.has_md5sum <= ARRAYSIZE(md5sum_name)); + if (img_report.has_md5sum > ARRAYSIZE(md5sum_name)) + return; + + static_sprintf(md5_path, "%s\\%s", psz_extract_dir, md5sum_name[img_report.has_md5sum - 1]); + md5_size = read_file(md5_path, (uint8_t**)&md5_data); + if (md5_size == 0) + return; + + for (i = 0; i < modified_path.Index; i++) { + str_pos = strstr(md5_data, &modified_path.String[i][2]); + if (str_pos == NULL) + // File is not listed in md5 sums + continue; + if (display_header) { + uprintf("Updating %s:", md5_path); + display_header = FALSE; + } + uprintf("● %s", &modified_path.String[i][2]); + pos = str_pos - md5_data; + size = read_file(modified_path.String[i], &buf); + if (size == 0) + continue; + HashBuffer(CHECKSUM_MD5, buf, size, sum); + free(buf); + while ((pos > 0) && (md5_data[pos - 1] != '\n')) + pos--; + for (j = 0; j < 16; j++) { + md5_data[pos + 2 * j] = ((sum[j] >> 4) < 10) ? ('0' + (sum[j] >> 4)) : ('a' - 0xa + (sum[j] >> 4)); + md5_data[pos + 2 * j + 1] = ((sum[j] & 15) < 10) ? ('0' + (sum[j] & 15)) : ('a' - 0xa + (sum[j] & 15)); + } + } + + write_file(md5_path, md5_data, md5_size); + free(md5_data); +} + // Returns 0 on success, nonzero on error static int iso_extract_files(iso9660_t* p_iso, const char *psz_path) { @@ -770,6 +841,7 @@ BOOL ExtractISO(const char* src_iso, const char* dest_dir, BOOL scan) } nb_blocks = 0; iso_blocking_status = 0; + StrArrayCreate(&modified_path, 8); } // First try to open as UDF - fallback to ISO if it failed @@ -1007,6 +1079,8 @@ out: } if (fd != NULL) fclose(fd); + update_md5sum(); + StrArrayDestroy(&modified_path); } else if (HAS_BOOTMGR(img_report) && enable_ntfs_compression) { // bootmgr might need to be uncompressed: https://github.com/pbatard/rufus/issues/1381 RunCommand("compact /u bootmgr* efi/boot/*.efi", dest_dir, TRUE); diff --git a/src/rufus.h b/src/rufus.h index 359baa1d..eba48a1a 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -1,6 +1,6 @@ /* * Rufus: The Reliable USB Formatting Utility - * Copyright © 2011-2019 Pete Batard + * Copyright © 2011-2020 Pete Batard * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -333,6 +333,7 @@ typedef struct { BOOLEAN disable_iso; uint16_t winpe; uint8_t has_efi; + uint8_t has_md5sum; uint8_t wininst_index; uint8_t has_symlinks; BOOLEAN has_4GB_file; @@ -533,6 +534,8 @@ extern void DownloadNewVersion(void); extern BOOL DownloadISO(void); extern BOOL IsDownloadable(const char* url); extern BOOL IsShown(HWND hDlg); +extern uint32_t read_file(const char* path, uint8_t** buf); +extern uint32_t write_file(const char* path, const uint8_t* buf, const uint32_t size); extern char* get_token_data_file_indexed(const char* token, const char* filename, int index); #define get_token_data_file(token, filename) get_token_data_file_indexed(token, filename, 1) extern char* set_token_data_file(const char* token, const char* data, const char* filename); diff --git a/src/rufus.rc b/src/rufus.rc index 01fb1b80..15bce928 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 232, 326 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 3.10.1633" +CAPTION "Rufus 3.10.1634" FONT 9, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP @@ -395,8 +395,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 3,10,1633,0 - PRODUCTVERSION 3,10,1633,0 + FILEVERSION 3,10,1634,0 + PRODUCTVERSION 3,10,1634,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -414,13 +414,13 @@ BEGIN VALUE "Comments", "https://rufus.ie" VALUE "CompanyName", "Akeo Consulting" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "3.10.1633" + VALUE "FileVersion", "3.10.1634" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", "© 2011-2020 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html" VALUE "OriginalFilename", "rufus-3.10.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "3.10.1633" + VALUE "ProductVersion", "3.10.1634" END END BLOCK "VarFileInfo" diff --git a/src/stdio.c b/src/stdio.c index 6aa10657..db935b0a 100644 --- a/src/stdio.c +++ b/src/stdio.c @@ -2,7 +2,7 @@ * Rufus: The Reliable USB Formatting Utility * Standard User I/O Routines (logging, status, error, etc.) * Copyright © 2020 Mattiwatti - * Copyright © 2011-2019 Pete Batard + * Copyright © 2011-2020 Pete Batard * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -93,6 +93,53 @@ void _uprintfs(const char* str) free(wstr); } +uint32_t read_file(const char* path, uint8_t** buf) +{ + FILE* fd = fopenU(path, "rb"); + if (fd == NULL) { + uprintf("Error: Can't open file '%s'", path); + return 0; + } + + fseek(fd, 0L, SEEK_END); + uint32_t size = (uint32_t)ftell(fd); + fseek(fd, 0L, SEEK_SET); + + *buf = malloc(size); + if (*buf == NULL) { + uprintf("Error: Can't allocate %d bytes buffer for file '%s'", size, path); + size = 0; + goto out; + } + if (fread(*buf, 1, size, fd) != size) { + uprintf("Error: Can't read '%s'", path); + size = 0; + } + +out: + fclose(fd); + if (size == 0) { + free(*buf); + *buf = NULL; + } + return size; +} + +uint32_t write_file(const char* path, const uint8_t* buf, const uint32_t size) +{ + uint32_t written; + FILE* fd = fopenU(path, "wb"); + if (fd == NULL) { + uprintf("Error: Can't create '%s'", path); + return 0; + } + written = (uint32_t)fwrite(buf, 1, size, fd); + if (written != size) + uprintf("Error: Can't write '%s'", path); + fclose(fd); + return written; +} + // Prints a bitstring of a number of any size, with or without leading zeroes. // See also the printbits() and printbitslz() helper macros in rufus.h char *_printbits(size_t const size, void const * const ptr, int leading_zeroes)