[iso] attempt to fix the clusterfuck of GRUB 2.06 incompatible versions

* As was *ENTIRELY PREDICTIBLE*, the lack of timely releases from the GRUB
  project has resulted in distro maintainers (Ubuntu, Fedora, etc.) taking
  matters in their own hand and applying patches on top of their 2.06 version.
  However, these patches result in 2.06 bootloaders that are incompatible
  with 2.06 modules that don't have the same patches applied. Especially this
  now results in the infamous "452: out of range pointer" error message when
  using patched modules with unpatched bootloader or unpatched modules with
  patched bootloaders.
* Making this issue worse, we also have distro maintainers who won't add a
  suffix to their GRUB version, AS ONE SHOULD DO WHEN ONE APPLIES TONS OF
  PATCHES ON TOP OF A PROJECT'S SOURCE, and MISreport their non 2.06 GRUB as
  "2.06", and, because we can't detect what patches are needed from modules
  themselves (unlike what is the case for grub_debug_is_enabled), we have no
  way of telling incompatible GRUB 2.06 binaries from one another.
* As a result, we have no choice but to append a sanitized version of the ISO
  label to the GRUB version, as a means to differentiate between incompatible
  versions, and tweak our existing bootloader download mechanism to *ATTEMPT*
  to download a compatible 'core.img' from our server... where we will have
  to waste a lot of time adding new binaries and symlinks to try to make all
  these GRUB "2.06" based images work, and will probably miss quite few with
  the end results that users who are just trying to install Linux will be left
  stranded.
* Again, I have to point out how the end result of regular users wanting to
  try Linux and being unable to do so is the *DIRECT* result of the GRUB project
  maintainers having sat on a 2-year influx of CONTINUOUS patches, and thinking
  that "Release Early, Release Often" is only a gimmick, and not something that
  should apply to their project, even as they have been warned before, by yours
  truly, that *NOT* releasing on a timely basis is causing actual grievances...
  That's because, had the GRUB maintainers released on a timely basis (at least
  once a year) Fedora and Ubuntu would be using vanilla GRUB 2.07 with the memory
  patches, and we wouldn't be trying to mix that with old GRUB 2.06 binaries.
* For more on this, see #2233, noting that we will need to apply a compatibility
  breaking change during the 4.1 release, to revert the patches we applied to
  the default 2.06 'core.img' in pbatard/rufus-web@320b800592.
This commit is contained in:
Pete Batard 2023-05-16 14:03:03 +01:00
parent 23d89d9764
commit 3a0f7d3813
No known key found for this signature in database
GPG Key ID: 38E0CF5E69EDD671
5 changed files with 131 additions and 44 deletions

View File

@ -887,7 +887,6 @@ void GetGrubVersion(char* buf, size_t buf_size)
const char* grub_version_str[] = { "GRUB version %s", "GRUB version %s" };
const char* grub_debug_is_enabled_str = "grub_debug_is_enabled";
const size_t max_string_size = 32; // The strings above *MUST* be no longer than this value
char *p, unauthorized[] = {'<', '>', ':', '|', '*', '?', '\\', '/'};
size_t i, j;
BOOL has_grub_debug_is_enabled = FALSE;
@ -902,13 +901,9 @@ void GetGrubVersion(char* buf, size_t buf_size)
has_grub_debug_is_enabled = TRUE;
}
}
// Sanitize the string
for (p = &img_report.grub2_version[0]; *p; p++) {
for (i = 0; i < sizeof(unauthorized); i++) {
if (*p == unauthorized[i])
*p = '_';
}
}
uprintf(" Reported Grub version: %s", img_report.grub2_version);
// <Shakes fist angrily> "KASPERSKYYYYYY!!!..." (https://github.com/pbatard/rufus/issues/467)
// But seriously, these guys should know better than "security" through obscurity...
if (img_report.grub2_version[0] == '0')
@ -931,16 +926,33 @@ void GetGrubVersion(char* buf, size_t buf_size)
// if [ -e /boot/grub2/i386-pc/normal.mod ]; then set prefix = ...
// you still must embed 'configfile.mod' and 'normal.mod' in 'core.img' in order
// to do that, which ends up tripling the file size...
// Also, as mentioned above, Fedora have started applying *BREAKING* patches
// willy-nilly, without bothering to alter the GRUB version string.
// Soooo, since the universe is conspiring against us and since we already have
// a facility for it, we'll use it to dowload the relevant 'core.img' by
// appending a missing version suffix as needed...
// Also, as mentioned above, Fedora, Ubuntu and others have started applying
// *BREAKING* patches willy-nilly, without bothering to alter the GRUB version
// string. And it gets worse with 2.06 since there are patches we can't detect
// that will produce "452: out of range pointer" whether they are applied OR NOT
// (meaning that if you use a patched GRUB 2.06 with unpatched GRUB 2.06 modules
// you will get the error, and if you use unpatched with patched modules, you
// will also get the error).
// Soooo, since the universe, and project maintainers who do not REALISE that
// NOT RELEASING IN A TIMELY MANNER *DOES* HAVE VERY NEGATIVE CONSEQUENCES FOR
// END USERS, are conspiring against us, and since we already have a facility
// for it, we'll use it to dowload the relevant 'core.img' by appending a missing
// version suffix as needed. Especially, if GRUB only identifies itself as '2.06'
// we'll append a sanitized version of the ISO label to try to differentiate
// between GRUB 2.06 incompatible versions...
if (img_report.grub2_version[0] != 0) {
if (has_grub_debug_is_enabled)
strcat(img_report.grub2_version, "-fedora");
// Make sure we append '-nonstandard' and '-gdie' before the sanitized label.
BOOL append_label = (safe_strcmp(img_report.grub2_version, "2.06") == 0);
// Must be in the same order as we have on the server
if (img_report.has_grub2 > 1)
strcat(img_report.grub2_version, "-nonstandard");
safe_strcat(img_report.grub2_version, sizeof(img_report.grub2_version), "-nonstandard");
if (has_grub_debug_is_enabled)
safe_strcat(img_report.grub2_version, sizeof(img_report.grub2_version), "-gdie");
if (append_label) {
safe_strcat(img_report.grub2_version, sizeof(img_report.grub2_version), "-");
safe_strcat(img_report.grub2_version, sizeof(img_report.grub2_version), img_report.label);
}
sanitize_label(img_report.grub2_version);
}
}
@ -1188,9 +1200,7 @@ out:
free(buf);
DeleteFileU(path);
}
if (img_report.grub2_version[0] != 0) {
uprintf(" Detected Grub version: %s", img_report.grub2_version);
} else {
if (img_report.grub2_version[0] == 0) {
uprintf(" Could not detect Grub version");
img_report.has_grub2 = 0;
}

View File

@ -1480,3 +1480,67 @@ void* get_data_from_asn1(const uint8_t* buf, size_t buf_len, const char* oid_str
free(oid);
return data;
}
/*
* Sanitize an ISO volume label or GRUB version, so that we can use it for bootloader lookup.
* Note that this call modifies the string passed as parameter.
*/
int sanitize_label(char* label)
{
// Notice: Do not add "-beta" to this list as we have existing GRUB lookups for
// "grub-2.02-beta2" and stuff...
static const char* remove[] = { "-i386", "-i686", "-amd64", "-x86-64", ".x86-64",
"-x64", "-armhf", "-arm64", "-aarch64", "-32-bit", "-64-bit", "-32bit", "-64bit",
"-intel", "-cd", "-dvd", "-standard", "-live", "-install", "-server", "-net",
"-desktop", "-lts", "-studio", "-baseos", "-kde", "-xfce", "-lxde", "-gnome",
"-mate", "-unstable", "-debug", "-release", "-final", "-stream", "-cinnamon",
"-cinn", "-leap", "-tumbleweed", "-budgie", "-ws", "-iot", "-ostree", ".iso"
};
size_t i, len;
char *s;
len = strlen(label);
for (i = 0; i < len; i++) {
char c = label[i];
// Convert to lowercase
if (c >= 'A' && c <= 'Z')
c += 0x20;
// Convert non alphanum (except '.') to dash
if ((c < '0' && c != '.') || (c > '9' && c < 'a') || (c > 'z'))
c = '-';
label[i] = c;
}
// Remove all leading '-'
for (i = 0; i < len && label[i] == '-'; i++);
if (i != 0)
memcpy(label, &label[i], len - i);
len = strlen(label);
if (len <= 1)
return -1;
// Remove all trailing '-'
for (i = len - 1; i > 0 && label[i] == '-'; i--)
label[i] = 0;
len = strlen(label);
if (len <= 1)
return -1;
// Remove all duplicate '-' (non-optimized!)
for (i = 0; len >= 2 && i < len - 2; i++) {
if (label[i] == '-' && label[i + 1] == '-') {
memcpy(&label[i + 1], &label[i + 2], len - i - 1);
len--;
i--;
}
}
// Remove specific substrings
for (i = 0; i < ARRAYSIZE(remove); i++) {
s = strstr(label, remove[i]);
if (s != NULL)
strcpy(s, &s[strlen(remove[i])]);
}
return 0;
}

View File

@ -1118,7 +1118,7 @@ static void DisplayISOProps(void)
PRINT_ISO_PROP(HAS_KOLIBRIOS(img_report), " Uses: KolibriOS");
PRINT_ISO_PROP(HAS_REACTOS(img_report), " Uses: ReactOS");
PRINT_ISO_PROP(img_report.has_grub4dos, " Uses: Grub4DOS");
PRINT_ISO_PROP(img_report.has_grub2, " Uses: GRUB2");
PRINT_ISO_PROP(img_report.has_grub2, " Uses: GRUB2 (%s)", img_report.grub2_version);
if (img_report.has_efi == 0x80)
uprintf(" Uses: EFI (through '%s')", img_report.efi_img_path);
else
@ -1430,7 +1430,7 @@ static DWORD WINAPI BootCheckThread(LPVOID param)
const char* ldlinux = "ldlinux";
const char* syslinux = "syslinux";
const char* ldlinux_ext[3] = { "sys", "bss", "c32" };
char tmp[MAX_PATH], tmp2[MAX_PATH];
char tmp[MAX_PATH], tmp2[MAX_PATH], c;
syslinux_ldlinux_len[0] = 0; syslinux_ldlinux_len[1] = 0;
safe_free(grub2_buf);
@ -1658,23 +1658,17 @@ static DWORD WINAPI BootCheckThread(LPVOID param)
static_sprintf(tmp, "%s-%s", grub, img_report.grub2_version);
IGNORE_RETVAL(_mkdir(tmp));
IGNORE_RETVAL(_chdir(tmp));
static_sprintf(tmp, "%s/%s-%s/%s", FILES_URL, grub, img_report.grub2_version, core_img);
grub2_len = (long)DownloadSignedFile(tmp, core_img, hMainDialog, FALSE);
if ((grub2_len == 0) && (DownloadStatus == 404)) {
// Manjaro (always them!) are using "2.03.5" as identifier, so we must detect first dot...
BOOL first_dot = TRUE;
// Couldn't locate the file on the server => try to download without the version extra
uprintf("Extended version was not found, trying main version...");
static_strcpy(tmp2, img_report.grub2_version);
// Isolate the #.### part
for (i = 0; ((tmp2[i] >= '0') && (tmp2[i] <= '9')) || ((tmp2[i] == '.') && first_dot); i++) {
if (tmp2[i] == '.')
first_dot = FALSE;
}
tmp2[i] = 0;
static_sprintf(tmp, "%s/%s-%s/%s", FILES_URL, grub, tmp2, core_img);
grub2_len = (long)DownloadSignedFile(tmp, core_img, hMainDialog, FALSE);
// The following loops through the grub2 version (which may have the ISO label appended)
// and breaks it according to '.' or '-' until it finds a match on the server.
//
for (i = (int)strlen(img_report.grub2_version), grub2_len = 0; i > 0 && grub2_len <= 0; i--) {
c = img_report.grub2_version[i];
if (c != 0 && c != '.' && c != '-')
continue;
img_report.grub2_version[i] = 0;
static_sprintf(tmp, "%s/%s-%s/%s", FILES_URL, grub, img_report.grub2_version, core_img);
grub2_len = (long)DownloadSignedFile(tmp, core_img, hMainDialog, FALSE);
img_report.grub2_version[i] = c;
}
if (grub2_len <= 0) {
PrintInfo(0, MSG_195, "Grub2");
@ -3829,7 +3823,25 @@ extern int TestChecksum(void);
// Ctrl-T => Alternate Test mode that doesn't require a full rebuild
if ((ctrl_without_focus || ((GetKeyState(VK_CONTROL) & 0x8000) && (msg.message == WM_KEYDOWN)))
&& (msg.wParam == 'T')) {
TestChecksum();
char tmp[256], c;
char label[256] = "2.06-blah-bli-ubutnu.23.2.1-blo";
size_t i;
for (i = strlen(label); i > 0; i--) {
c = label[i];
if (c != 0 && c != '.' && c != '-')
continue;
label[i] = 0;
static_sprintf(tmp, "%s/%s-%s/core.img", FILES_URL, "grub", label);
uprintf(tmp);
label[i] = c;
}
// TestChecksum();
//FILE* fd = fopen("D:\\ISOs\\vol.txt", "r");
//while (fgets(label, 256, fd) != NULL) {
// sanitize_label(label);
// uprintf(label);
//}
//fclose(fd);
continue;
}
#endif

View File

@ -403,7 +403,7 @@ typedef struct {
uint16_t sl_version; // Syslinux/Isolinux version
char sl_version_str[12];
char sl_version_ext[32];
char grub2_version[64];
char grub2_version[192];
} RUFUS_IMG_REPORT;
/* Isolate the Syslinux version numbers */
@ -676,6 +676,7 @@ extern char* replace_in_token_data(const char* filename, const char* token, cons
extern char* replace_char(const char* src, const char c, const char* rep);
extern void parse_update(char* buf, size_t len);
extern void* get_data_from_asn1(const uint8_t* buf, size_t buf_len, const char* oid_str, uint8_t asn1_type, size_t* data_len);
extern int sanitize_label(char* label);
extern int IsHDD(DWORD DriveIndex, uint16_t vid, uint16_t pid, const char* strid);
extern char* GetSignatureName(const char* path, const char* country_code, BOOL bSilent);
extern uint64_t GetSignatureTimeStamp(const char* path);

View File

@ -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 4.0.2038"
CAPTION "Rufus 4.0.2039"
FONT 9, "Segoe UI Symbol", 400, 0, 0x0
BEGIN
LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP
@ -392,8 +392,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 4,0,2038,0
PRODUCTVERSION 4,0,2038,0
FILEVERSION 4,0,2039,0
PRODUCTVERSION 4,0,2039,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -411,13 +411,13 @@ BEGIN
VALUE "Comments", "https://rufus.ie"
VALUE "CompanyName", "Akeo Consulting"
VALUE "FileDescription", "Rufus"
VALUE "FileVersion", "4.0.2038"
VALUE "FileVersion", "4.0.2039"
VALUE "InternalName", "Rufus"
VALUE "LegalCopyright", "© 2011-2023 Pete Batard (GPL v3)"
VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html"
VALUE "OriginalFilename", "rufus-4.0.exe"
VALUE "ProductName", "Rufus"
VALUE "ProductVersion", "4.0.2038"
VALUE "ProductVersion", "4.0.2039"
END
END
BLOCK "VarFileInfo"