diff options
Diffstat (limited to 'debian/patches')
116 files changed, 16557 insertions, 0 deletions
diff --git a/debian/patches/0063-loader-efi-chainloader-Simplify-the-loader-state.patch b/debian/patches/0063-loader-efi-chainloader-Simplify-the-loader-state.patch new file mode 100644 index 0000000..51a7b68 --- /dev/null +++ b/debian/patches/0063-loader-efi-chainloader-Simplify-the-loader-state.patch @@ -0,0 +1,119 @@ +From 9c8e1c85ec9971f2c6bb9a8a7530e94f7dbec14a Mon Sep 17 00:00:00 2001 +From: Chris Coulson <chris.coulson@canonical.com> +Date: Tue, 5 Apr 2022 10:02:04 +0100 +Subject: loader/efi/chainloader: Simplify the loader state + +The chainloader command retains the source buffer and device path passed +to LoadImage(), requiring the unload hook passed to grub_loader_set() to +free them. It isn't required to retain this state though - they aren't +required by StartImage() or anything else in the boot hook, so clean them +up before grub_cmd_chainloader() finishes. + +Signed-off-by: Chris Coulson <chris.coulson@canonical.com> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/loader/efi/chainloader.c | 38 +++++++++++++++++------------- + 1 file changed, 21 insertions(+), 17 deletions(-) + +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index 2bd80f4db..d1602c89b 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -44,25 +44,20 @@ GRUB_MOD_LICENSE ("GPLv3+"); + + static grub_dl_t my_mod; + +-static grub_efi_physical_address_t address; +-static grub_efi_uintn_t pages; +-static grub_efi_device_path_t *file_path; + static grub_efi_handle_t image_handle; +-static grub_efi_char16_t *cmdline; + + static grub_err_t + grub_chainloader_unload (void) + { ++ grub_efi_loaded_image_t *loaded_image; + grub_efi_boot_services_t *b; + ++ loaded_image = grub_efi_get_loaded_image (image_handle); ++ if (loaded_image != NULL) ++ grub_free (loaded_image->load_options); ++ + b = grub_efi_system_table->boot_services; + efi_call_1 (b->unload_image, image_handle); +- efi_call_2 (b->free_pages, address, pages); +- +- grub_free (file_path); +- grub_free (cmdline); +- cmdline = 0; +- file_path = 0; + + grub_dl_unref (my_mod); + return GRUB_ERR_NONE; +@@ -140,7 +135,7 @@ make_file_path (grub_efi_device_path_t *dp, const char *filename) + char *dir_start; + char *dir_end; + grub_size_t size; +- grub_efi_device_path_t *d; ++ grub_efi_device_path_t *d, *file_path; + + dir_start = grub_strchr (filename, ')'); + if (! dir_start) +@@ -222,11 +217,14 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + grub_efi_status_t status; + grub_efi_boot_services_t *b; + grub_device_t dev = 0; +- grub_efi_device_path_t *dp = 0; ++ grub_efi_device_path_t *dp = NULL, *file_path = NULL; + grub_efi_loaded_image_t *loaded_image; + char *filename; + void *boot_image = 0; + grub_efi_handle_t dev_handle = 0; ++ grub_efi_physical_address_t address = 0; ++ grub_efi_uintn_t pages = 0; ++ grub_efi_char16_t *cmdline = NULL; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); +@@ -234,11 +232,6 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + + grub_dl_ref (my_mod); + +- /* Initialize some global variables. */ +- address = 0; +- image_handle = 0; +- file_path = 0; +- + b = grub_efi_system_table->boot_services; + + file = grub_file_open (filename, GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE); +@@ -408,6 +401,10 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + grub_file_close (file); + grub_device_close (dev); + ++ /* We're finished with the source image buffer and file path now. */ ++ efi_call_2 (b->free_pages, address, pages); ++ grub_free (file_path); ++ + grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0); + return 0; + +@@ -419,11 +416,18 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + if (file) + grub_file_close (file); + ++ grub_free (cmdline); + grub_free (file_path); + + if (address) + efi_call_2 (b->free_pages, address, pages); + ++ if (image_handle != NULL) ++ { ++ efi_call_1 (b->unload_image, image_handle); ++ image_handle = NULL; ++ } ++ + grub_dl_unref (my_mod); + + return grub_errno; diff --git a/debian/patches/0064-commands-boot-Add-API-to-pass-context-to-loader.patch b/debian/patches/0064-commands-boot-Add-API-to-pass-context-to-loader.patch new file mode 100644 index 0000000..47caba2 --- /dev/null +++ b/debian/patches/0064-commands-boot-Add-API-to-pass-context-to-loader.patch @@ -0,0 +1,158 @@ +From bb35dbb9bf213bc9dde9a5a653e93b4c4d2bbf22 Mon Sep 17 00:00:00 2001 +From: Chris Coulson <chris.coulson@canonical.com> +Date: Fri, 29 Apr 2022 21:16:02 +0100 +Subject: commands/boot: Add API to pass context to loader + +Loaders rely on global variables for saving context which is consumed +in the boot hook and freed in the unload hook. In the case where a loader +command is executed twice, calling grub_loader_set a second time executes +the unload hook, but in some cases this runs when the loader's global +context has already been updated, resulting in the updated context being +freed and potential use-after-free bugs when the boot hook is subsequently +called. + +This adds a new API (grub_loader_set_ex) which allows a loader to specify +context that is passed to its boot and unload hooks. This is an alternative +to requiring that loaders call grub_loader_unset before mutating their +global context. + +Signed-off-by: Chris Coulson <chris.coulson@canonical.com> +(cherry picked from commit 4322a64dde7e8fedb58e50b79408667129d45dd3) +--- + grub-core/commands/boot.c | 66 ++++++++++++++++++++++++++++++++++----- + include/grub/loader.h | 5 +++ + 2 files changed, 63 insertions(+), 8 deletions(-) + +diff --git a/grub-core/commands/boot.c b/grub-core/commands/boot.c +index bbca81e94..53691a62d 100644 +--- a/grub-core/commands/boot.c ++++ b/grub-core/commands/boot.c +@@ -27,10 +27,20 @@ + + GRUB_MOD_LICENSE ("GPLv3+"); + +-static grub_err_t (*grub_loader_boot_func) (void); +-static grub_err_t (*grub_loader_unload_func) (void); ++static grub_err_t (*grub_loader_boot_func) (void *); ++static grub_err_t (*grub_loader_unload_func) (void *); ++static void *grub_loader_context; + static int grub_loader_flags; + ++struct grub_simple_loader_hooks ++{ ++ grub_err_t (*boot) (void); ++ grub_err_t (*unload) (void); ++}; ++ ++/* Don't heap allocate this to avoid making grub_loader_set fallible. */ ++static struct grub_simple_loader_hooks simple_loader_hooks; ++ + struct grub_preboot + { + grub_err_t (*preboot_func) (int); +@@ -44,6 +54,29 @@ static int grub_loader_loaded; + static struct grub_preboot *preboots_head = 0, + *preboots_tail = 0; + ++static grub_err_t ++grub_simple_boot_hook (void *context) ++{ ++ struct grub_simple_loader_hooks *hooks; ++ ++ hooks = (struct grub_simple_loader_hooks *) context; ++ return hooks->boot (); ++} ++ ++static grub_err_t ++grub_simple_unload_hook (void *context) ++{ ++ struct grub_simple_loader_hooks *hooks; ++ grub_err_t ret; ++ ++ hooks = (struct grub_simple_loader_hooks *) context; ++ ++ ret = hooks->unload (); ++ grub_memset (hooks, 0, sizeof (*hooks)); ++ ++ return ret; ++} ++ + int + grub_loader_is_loaded (void) + { +@@ -110,28 +143,45 @@ grub_loader_unregister_preboot_hook (struct grub_preboot *hnd) + } + + void +-grub_loader_set (grub_err_t (*boot) (void), +- grub_err_t (*unload) (void), +- int flags) ++grub_loader_set_ex (grub_err_t (*boot) (void *), ++ grub_err_t (*unload) (void *), ++ void *context, ++ int flags) + { + if (grub_loader_loaded && grub_loader_unload_func) +- grub_loader_unload_func (); ++ grub_loader_unload_func (grub_loader_context); + + grub_loader_boot_func = boot; + grub_loader_unload_func = unload; ++ grub_loader_context = context; + grub_loader_flags = flags; + + grub_loader_loaded = 1; + } + ++void ++grub_loader_set (grub_err_t (*boot) (void), ++ grub_err_t (*unload) (void), ++ int flags) ++{ ++ grub_loader_set_ex (grub_simple_boot_hook, ++ grub_simple_unload_hook, ++ &simple_loader_hooks, ++ flags); ++ ++ simple_loader_hooks.boot = boot; ++ simple_loader_hooks.unload = unload; ++} ++ + void + grub_loader_unset(void) + { + if (grub_loader_loaded && grub_loader_unload_func) +- grub_loader_unload_func (); ++ grub_loader_unload_func (grub_loader_context); + + grub_loader_boot_func = 0; + grub_loader_unload_func = 0; ++ grub_loader_context = 0; + + grub_loader_loaded = 0; + } +@@ -158,7 +208,7 @@ grub_loader_boot (void) + return err; + } + } +- err = (grub_loader_boot_func) (); ++ err = (grub_loader_boot_func) (grub_loader_context); + + for (cur = preboots_tail; cur; cur = cur->prev) + if (! err) +diff --git a/include/grub/loader.h b/include/grub/loader.h +index b20864282..1846fa6c5 100644 +--- a/include/grub/loader.h ++++ b/include/grub/loader.h +@@ -40,6 +40,11 @@ void EXPORT_FUNC (grub_loader_set) (grub_err_t (*boot) (void), + grub_err_t (*unload) (void), + int flags); + ++void EXPORT_FUNC (grub_loader_set_ex) (grub_err_t (*boot) (void *), ++ grub_err_t (*unload) (void *), ++ void *context, ++ int flags); ++ + /* Unset current loader, if any. */ + void EXPORT_FUNC (grub_loader_unset) (void); + diff --git a/debian/patches/0065-loader-efi-chainloader-Use-grub_loader_set_ex.patch b/debian/patches/0065-loader-efi-chainloader-Use-grub_loader_set_ex.patch new file mode 100644 index 0000000..4a4a0e7 --- /dev/null +++ b/debian/patches/0065-loader-efi-chainloader-Use-grub_loader_set_ex.patch @@ -0,0 +1,75 @@ +From 19b4f19cfea30655032c978e228d78e056f55f1a Mon Sep 17 00:00:00 2001 +From: Chris Coulson <chris.coulson@canonical.com> +Date: Tue, 5 Apr 2022 11:48:58 +0100 +Subject: loader/efi/chainloader: Use grub_loader_set_ex() + +This ports the EFI chainloader to use grub_loader_set_ex() in order to fix +a use-after-free bug that occurs when grub_cmd_chainloader() is executed +more than once before a boot attempt is performed. + +Fixes: CVE-2022-28736 + +Signed-off-by: Chris Coulson <chris.coulson@canonical.com> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/loader/efi/chainloader.c | 16 +++++++--------- + 1 file changed, 7 insertions(+), 9 deletions(-) + +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index d1602c89b..7557eb269 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -44,11 +44,10 @@ GRUB_MOD_LICENSE ("GPLv3+"); + + static grub_dl_t my_mod; + +-static grub_efi_handle_t image_handle; +- + static grub_err_t +-grub_chainloader_unload (void) ++grub_chainloader_unload (void *context) + { ++ grub_efi_handle_t image_handle = (grub_efi_handle_t) context; + grub_efi_loaded_image_t *loaded_image; + grub_efi_boot_services_t *b; + +@@ -64,8 +63,9 @@ grub_chainloader_unload (void) + } + + static grub_err_t +-grub_chainloader_boot (void) ++grub_chainloader_boot (void *context) + { ++ grub_efi_handle_t image_handle = (grub_efi_handle_t) context; + grub_efi_boot_services_t *b; + grub_efi_status_t status; + grub_efi_uintn_t exit_data_size; +@@ -225,6 +225,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + grub_efi_physical_address_t address = 0; + grub_efi_uintn_t pages = 0; + grub_efi_char16_t *cmdline = NULL; ++ grub_efi_handle_t image_handle = NULL; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); +@@ -405,7 +406,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + efi_call_2 (b->free_pages, address, pages); + grub_free (file_path); + +- grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0); ++ grub_loader_set_ex (grub_chainloader_boot, grub_chainloader_unload, image_handle, 0); + return 0; + + fail: +@@ -423,10 +424,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + efi_call_2 (b->free_pages, address, pages); + + if (image_handle != NULL) +- { +- efi_call_1 (b->unload_image, image_handle); +- image_handle = NULL; +- } ++ efi_call_1 (b->unload_image, image_handle); + + grub_dl_unref (my_mod); + diff --git a/debian/patches/0066-kern-efi-sb-Reject-non-kernel-files-in-the-shim_lock.patch b/debian/patches/0066-kern-efi-sb-Reject-non-kernel-files-in-the-shim_lock.patch new file mode 100644 index 0000000..18ecc25 --- /dev/null +++ b/debian/patches/0066-kern-efi-sb-Reject-non-kernel-files-in-the-shim_lock.patch @@ -0,0 +1,99 @@ +From 24e6d59ac676791507ff5267bf3bef6cbaff6aef Mon Sep 17 00:00:00 2001 +From: Julian Andres Klode <julian.klode@canonical.com> +Date: Thu, 2 Dec 2021 15:03:53 +0100 +Subject: kern/efi/sb: Reject non-kernel files in the shim_lock verifier + +We must not allow other verifiers to pass things like the GRUB modules. +Instead of maintaining a blocklist, maintain an allowlist of things +that we do not care about. + +This allowlist really should be made reusable, and shared by the +lockdown verifier, but this is the minimal patch addressing +security concerns where the TPM verifier was able to mark modules +as verified (or the OpenPGP verifier for that matter), when it +should not do so on shim-powered secure boot systems. + +Fixes: CVE-2022-28735 + +Signed-off-by: Julian Andres Klode <julian.klode@canonical.com> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/kern/efi/sb.c | 39 ++++++++++++++++++++++++++++++++++++--- + include/grub/verify.h | 1 + + 2 files changed, 37 insertions(+), 3 deletions(-) + +diff --git a/grub-core/kern/efi/sb.c b/grub-core/kern/efi/sb.c +index c52ec6226..89c4bb3fd 100644 +--- a/grub-core/kern/efi/sb.c ++++ b/grub-core/kern/efi/sb.c +@@ -119,10 +119,11 @@ shim_lock_verifier_init (grub_file_t io __attribute__ ((unused)), + void **context __attribute__ ((unused)), + enum grub_verify_flags *flags) + { +- *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION; ++ *flags = GRUB_VERIFY_FLAGS_NONE; + + switch (type & GRUB_FILE_TYPE_MASK) + { ++ /* Files we check. */ + case GRUB_FILE_TYPE_LINUX_KERNEL: + case GRUB_FILE_TYPE_MULTIBOOT_KERNEL: + case GRUB_FILE_TYPE_BSD_KERNEL: +@@ -130,11 +131,43 @@ shim_lock_verifier_init (grub_file_t io __attribute__ ((unused)), + case GRUB_FILE_TYPE_PLAN9_KERNEL: + case GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE: + *flags = GRUB_VERIFY_FLAGS_SINGLE_CHUNK; ++ return GRUB_ERR_NONE; + +- /* Fall through. */ ++ /* Files that do not affect secureboot state. */ ++ case GRUB_FILE_TYPE_NONE: ++ case GRUB_FILE_TYPE_LOOPBACK: ++ case GRUB_FILE_TYPE_LINUX_INITRD: ++ case GRUB_FILE_TYPE_OPENBSD_RAMDISK: ++ case GRUB_FILE_TYPE_XNU_RAMDISK: ++ case GRUB_FILE_TYPE_SIGNATURE: ++ case GRUB_FILE_TYPE_PUBLIC_KEY: ++ case GRUB_FILE_TYPE_PUBLIC_KEY_TRUST: ++ case GRUB_FILE_TYPE_PRINT_BLOCKLIST: ++ case GRUB_FILE_TYPE_TESTLOAD: ++ case GRUB_FILE_TYPE_GET_SIZE: ++ case GRUB_FILE_TYPE_FONT: ++ case GRUB_FILE_TYPE_ZFS_ENCRYPTION_KEY: ++ case GRUB_FILE_TYPE_CAT: ++ case GRUB_FILE_TYPE_HEXCAT: ++ case GRUB_FILE_TYPE_CMP: ++ case GRUB_FILE_TYPE_HASHLIST: ++ case GRUB_FILE_TYPE_TO_HASH: ++ case GRUB_FILE_TYPE_KEYBOARD_LAYOUT: ++ case GRUB_FILE_TYPE_PIXMAP: ++ case GRUB_FILE_TYPE_GRUB_MODULE_LIST: ++ case GRUB_FILE_TYPE_CONFIG: ++ case GRUB_FILE_TYPE_THEME: ++ case GRUB_FILE_TYPE_GETTEXT_CATALOG: ++ case GRUB_FILE_TYPE_FS_SEARCH: ++ case GRUB_FILE_TYPE_LOADENV: ++ case GRUB_FILE_TYPE_SAVEENV: ++ case GRUB_FILE_TYPE_VERIFY_SIGNATURE: ++ *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION; ++ return GRUB_ERR_NONE; + ++ /* Other files. */ + default: +- return GRUB_ERR_NONE; ++ return grub_error (GRUB_ERR_ACCESS_DENIED, N_("prohibited by secure boot policy")); + } + } + +diff --git a/include/grub/verify.h b/include/grub/verify.h +index 6fde244fc..67448165f 100644 +--- a/include/grub/verify.h ++++ b/include/grub/verify.h +@@ -24,6 +24,7 @@ + + enum grub_verify_flags + { ++ GRUB_VERIFY_FLAGS_NONE = 0, + GRUB_VERIFY_FLAGS_SKIP_VERIFICATION = 1, + GRUB_VERIFY_FLAGS_SINGLE_CHUNK = 2, + /* Defer verification to another authority. */ diff --git a/debian/patches/0067-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch b/debian/patches/0067-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch new file mode 100644 index 0000000..d319507 --- /dev/null +++ b/debian/patches/0067-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch @@ -0,0 +1,37 @@ +From c15fa5fb039cd5062dfa02a03efd924422c4a8ed Mon Sep 17 00:00:00 2001 +From: Daniel Axtens <dja@axtens.net> +Date: Fri, 25 Jun 2021 02:19:05 +1000 +Subject: kern/file: Do not leak device_name on error in grub_file_open() + +If we have an error in grub_file_open() before we free device_name, we +will leak it. + +Free device_name in the error path and null out the pointer in the good +path once we free it there. + +Signed-off-by: Daniel Axtens <dja@axtens.net> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/kern/file.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c +index 58454458c..ffdcaba05 100644 +--- a/grub-core/kern/file.c ++++ b/grub-core/kern/file.c +@@ -79,6 +79,7 @@ grub_file_open (const char *name, enum grub_file_type type) + + device = grub_device_open (device_name); + grub_free (device_name); ++ device_name = NULL; + if (! device) + goto fail; + +@@ -131,6 +132,7 @@ grub_file_open (const char *name, enum grub_file_type type) + return file; + + fail: ++ grub_free (device_name); + if (device) + grub_device_close (device); + diff --git a/debian/patches/0068-video-readers-png-Abort-sooner-if-a-read-operation-f.patch b/debian/patches/0068-video-readers-png-Abort-sooner-if-a-read-operation-f.patch new file mode 100644 index 0000000..58e6e50 --- /dev/null +++ b/debian/patches/0068-video-readers-png-Abort-sooner-if-a-read-operation-f.patch @@ -0,0 +1,197 @@ +From 907f100c841f39e37e4801f726f6b47c2aa9191f Mon Sep 17 00:00:00 2001 +From: Daniel Axtens <dja@axtens.net> +Date: Tue, 6 Jul 2021 14:02:55 +1000 +Subject: video/readers/png: Abort sooner if a read operation fails + +Fuzzing revealed some inputs that were taking a long time, potentially +forever, because they did not bail quickly upon encountering an I/O error. + +Try to catch I/O errors sooner and bail out. + +Signed-off-by: Daniel Axtens <dja@axtens.net> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/video/readers/png.c | 55 ++++++++++++++++++++++++++++++----- + 1 file changed, 47 insertions(+), 8 deletions(-) + +diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c +index 0157ff742..e2a6b1cf3 100644 +--- a/grub-core/video/readers/png.c ++++ b/grub-core/video/readers/png.c +@@ -142,6 +142,7 @@ static grub_uint8_t + grub_png_get_byte (struct grub_png_data *data) + { + grub_uint8_t r; ++ grub_ssize_t bytes_read = 0; + + if ((data->inside_idat) && (data->idat_remain == 0)) + { +@@ -175,7 +176,14 @@ grub_png_get_byte (struct grub_png_data *data) + } + + r = 0; +- grub_file_read (data->file, &r, 1); ++ bytes_read = grub_file_read (data->file, &r, 1); ++ ++ if (bytes_read != 1) ++ { ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "png: unexpected end of data"); ++ return 0; ++ } + + if (data->inside_idat) + data->idat_remain--; +@@ -231,15 +239,16 @@ grub_png_decode_image_palette (struct grub_png_data *data, + if (len == 0) + return GRUB_ERR_NONE; + +- for (i = 0; 3 * i < len && i < 256; i++) ++ grub_errno = GRUB_ERR_NONE; ++ for (i = 0; 3 * i < len && i < 256 && grub_errno == GRUB_ERR_NONE; i++) + for (j = 0; j < 3; j++) + data->palette[i][j] = grub_png_get_byte (data); +- for (i *= 3; i < len; i++) ++ for (i *= 3; i < len && grub_errno == GRUB_ERR_NONE; i++) + grub_png_get_byte (data); + + grub_png_get_dword (data); + +- return GRUB_ERR_NONE; ++ return grub_errno; + } + + static grub_err_t +@@ -256,9 +265,13 @@ grub_png_decode_image_header (struct grub_png_data *data) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "png: invalid image size"); + + color_bits = grub_png_get_byte (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + data->is_16bit = (color_bits == 16); + + color_type = grub_png_get_byte (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + /* According to PNG spec, no other types are valid. */ + if ((color_type & ~(PNG_COLOR_MASK_ALPHA | PNG_COLOR_MASK_COLOR)) +@@ -340,14 +353,20 @@ grub_png_decode_image_header (struct grub_png_data *data) + if (grub_png_get_byte (data) != PNG_COMPRESSION_BASE) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "png: compression method not supported"); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + if (grub_png_get_byte (data) != PNG_FILTER_TYPE_BASE) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "png: filter method not supported"); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + if (grub_png_get_byte (data) != PNG_INTERLACE_NONE) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "png: interlace method not supported"); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + /* Skip crc checksum. */ + grub_png_get_dword (data); +@@ -449,7 +468,7 @@ grub_png_get_huff_code (struct grub_png_data *data, struct huff_table *ht) + int code, i; + + code = 0; +- for (i = 0; i < ht->max_length; i++) ++ for (i = 0; i < ht->max_length && grub_errno == GRUB_ERR_NONE; i++) + { + code = (code << 1) + grub_png_get_bits (data, 1); + if (code < ht->maxval[i]) +@@ -504,8 +523,14 @@ grub_png_init_dynamic_block (struct grub_png_data *data) + grub_uint8_t lens[DEFLATE_HCLEN_MAX]; + + nl = DEFLATE_HLIT_BASE + grub_png_get_bits (data, 5); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + nd = DEFLATE_HDIST_BASE + grub_png_get_bits (data, 5); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + nb = DEFLATE_HCLEN_BASE + grub_png_get_bits (data, 4); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + if ((nl > DEFLATE_HLIT_MAX) || (nd > DEFLATE_HDIST_MAX) || + (nb > DEFLATE_HCLEN_MAX)) +@@ -533,7 +558,7 @@ grub_png_init_dynamic_block (struct grub_png_data *data) + data->dist_offset); + + prev = 0; +- for (i = 0; i < nl + nd; i++) ++ for (i = 0; i < nl + nd && grub_errno == GRUB_ERR_NONE; i++) + { + int n, code; + struct huff_table *ht; +@@ -721,17 +746,21 @@ grub_png_read_dynamic_block (struct grub_png_data *data) + len = cplens[n]; + if (cplext[n]) + len += grub_png_get_bits (data, cplext[n]); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + n = grub_png_get_huff_code (data, &data->dist_table); + dist = cpdist[n]; + if (cpdext[n]) + dist += grub_png_get_bits (data, cpdext[n]); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + pos = data->wp - dist; + if (pos < 0) + pos += WSIZE; + +- while (len > 0) ++ while (len > 0 && grub_errno == GRUB_ERR_NONE) + { + data->slide[data->wp] = data->slide[pos]; + grub_png_output_byte (data, data->slide[data->wp]); +@@ -759,7 +788,11 @@ grub_png_decode_image_data (struct grub_png_data *data) + int final; + + cmf = grub_png_get_byte (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + flg = grub_png_get_byte (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + if ((cmf & 0xF) != Z_DEFLATED) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, +@@ -774,7 +807,11 @@ grub_png_decode_image_data (struct grub_png_data *data) + int block_type; + + final = grub_png_get_bits (data, 1); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + block_type = grub_png_get_bits (data, 2); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + switch (block_type) + { +@@ -790,7 +827,7 @@ grub_png_decode_image_data (struct grub_png_data *data) + grub_png_get_byte (data); + grub_png_get_byte (data); + +- for (i = 0; i < len; i++) ++ for (i = 0; i < len && grub_errno == GRUB_ERR_NONE; i++) + grub_png_output_byte (data, grub_png_get_byte (data)); + + break; +@@ -1045,6 +1082,8 @@ grub_png_decode_png (struct grub_png_data *data) + + len = grub_png_get_dword (data); + type = grub_png_get_dword (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ break; + data->next_offset = data->file->offset + len + 4; + + switch (type) diff --git a/debian/patches/0069-video-readers-png-Refuse-to-handle-multiple-image-he.patch b/debian/patches/0069-video-readers-png-Refuse-to-handle-multiple-image-he.patch new file mode 100644 index 0000000..1c0aba1 --- /dev/null +++ b/debian/patches/0069-video-readers-png-Refuse-to-handle-multiple-image-he.patch @@ -0,0 +1,27 @@ +From 5e496e28b3c76666c98b737153f9b0c2bedf489d Mon Sep 17 00:00:00 2001 +From: Daniel Axtens <dja@axtens.net> +Date: Tue, 6 Jul 2021 14:13:40 +1000 +Subject: video/readers/png: Refuse to handle multiple image headers + +This causes the bitmap to be leaked. Do not permit multiple image headers. + +Signed-off-by: Daniel Axtens <dja@axtens.net> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/video/readers/png.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c +index e2a6b1cf3..8955b8ecf 100644 +--- a/grub-core/video/readers/png.c ++++ b/grub-core/video/readers/png.c +@@ -258,6 +258,9 @@ grub_png_decode_image_header (struct grub_png_data *data) + int color_bits; + enum grub_video_blit_format blt; + ++ if (data->image_width || data->image_height) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "png: two image headers found"); ++ + data->image_width = grub_png_get_dword (data); + data->image_height = grub_png_get_dword (data); + diff --git a/debian/patches/0070-video-readers-png-Drop-greyscale-support-to-fix-heap.patch b/debian/patches/0070-video-readers-png-Drop-greyscale-support-to-fix-heap.patch new file mode 100644 index 0000000..08c33f8 --- /dev/null +++ b/debian/patches/0070-video-readers-png-Drop-greyscale-support-to-fix-heap.patch @@ -0,0 +1,168 @@ +From 558c69b5d36d14d55bff21e6570205fe73a02ca2 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens <dja@axtens.net> +Date: Tue, 6 Jul 2021 18:51:35 +1000 +Subject: video/readers/png: Drop greyscale support to fix heap out-of-bounds + write + +A 16-bit greyscale PNG without alpha is processed in the following loop: + + for (i = 0; i < (data->image_width * data->image_height); + i++, d1 += 4, d2 += 2) + { + d1[R3] = d2[1]; + d1[G3] = d2[1]; + d1[B3] = d2[1]; + } + +The increment of d1 is wrong. d1 is incremented by 4 bytes per iteration, +but there are only 3 bytes allocated for storage. This means that image +data will overwrite somewhat-attacker-controlled parts of memory - 3 bytes +out of every 4 following the end of the image. + +This has existed since greyscale support was added in 2013 in commit +3ccf16dff98f (grub-core/video/readers/png.c: Support grayscale). + +Saving starfield.png as a 16-bit greyscale image without alpha in the gimp +and attempting to load it causes grub-emu to crash - I don't think this code +has ever worked. + +Delete all PNG greyscale support. + +Fixes: CVE-2021-3695 + +Signed-off-by: Daniel Axtens <dja@axtens.net> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/video/readers/png.c | 87 +++-------------------------------- + 1 file changed, 7 insertions(+), 80 deletions(-) + +diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c +index 8955b8ecf..a3161e25b 100644 +--- a/grub-core/video/readers/png.c ++++ b/grub-core/video/readers/png.c +@@ -100,7 +100,7 @@ struct grub_png_data + + unsigned image_width, image_height; + int bpp, is_16bit; +- int raw_bytes, is_gray, is_alpha, is_palette; ++ int raw_bytes, is_alpha, is_palette; + int row_bytes, color_bits; + grub_uint8_t *image_data; + +@@ -296,13 +296,13 @@ grub_png_decode_image_header (struct grub_png_data *data) + data->bpp = 3; + else + { +- data->is_gray = 1; +- data->bpp = 1; ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "png: color type not supported"); + } + + if ((color_bits != 8) && (color_bits != 16) + && (color_bits != 4 +- || !(data->is_gray || data->is_palette))) ++ || !data->is_palette)) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "png: bit depth must be 8 or 16"); + +@@ -331,7 +331,7 @@ grub_png_decode_image_header (struct grub_png_data *data) + } + + #ifndef GRUB_CPU_WORDS_BIGENDIAN +- if (data->is_16bit || data->is_gray || data->is_palette) ++ if (data->is_16bit || data->is_palette) + #endif + { + data->image_data = grub_calloc (data->image_height, data->row_bytes); +@@ -899,27 +899,8 @@ grub_png_convert_image (struct grub_png_data *data) + int shift; + int mask = (1 << data->color_bits) - 1; + unsigned j; +- if (data->is_gray) +- { +- /* Generic formula is +- (0xff * i) / ((1U << data->color_bits) - 1) +- but for allowed bit depth of 1, 2 and for it's +- equivalent to +- (0xff / ((1U << data->color_bits) - 1)) * i +- Precompute the multipliers to avoid division. +- */ +- +- const grub_uint8_t multipliers[5] = { 0xff, 0xff, 0x55, 0x24, 0x11 }; +- for (i = 0; i < (1U << data->color_bits); i++) +- { +- grub_uint8_t col = multipliers[data->color_bits] * i; +- palette[i][0] = col; +- palette[i][1] = col; +- palette[i][2] = col; +- } +- } +- else +- grub_memcpy (palette, data->palette, 3 << data->color_bits); ++ ++ grub_memcpy (palette, data->palette, 3 << data->color_bits); + d1c = d1; + d2c = d2; + for (j = 0; j < data->image_height; j++, d1c += data->image_width * 3, +@@ -956,60 +937,6 @@ grub_png_convert_image (struct grub_png_data *data) + } + return; + } +- +- if (data->is_gray) +- { +- switch (data->bpp) +- { +- case 4: +- /* 16-bit gray with alpha. */ +- for (i = 0; i < (data->image_width * data->image_height); +- i++, d1 += 4, d2 += 4) +- { +- d1[R4] = d2[3]; +- d1[G4] = d2[3]; +- d1[B4] = d2[3]; +- d1[A4] = d2[1]; +- } +- break; +- case 2: +- if (data->is_16bit) +- /* 16-bit gray without alpha. */ +- { +- for (i = 0; i < (data->image_width * data->image_height); +- i++, d1 += 4, d2 += 2) +- { +- d1[R3] = d2[1]; +- d1[G3] = d2[1]; +- d1[B3] = d2[1]; +- } +- } +- else +- /* 8-bit gray with alpha. */ +- { +- for (i = 0; i < (data->image_width * data->image_height); +- i++, d1 += 4, d2 += 2) +- { +- d1[R4] = d2[1]; +- d1[G4] = d2[1]; +- d1[B4] = d2[1]; +- d1[A4] = d2[0]; +- } +- } +- break; +- /* 8-bit gray without alpha. */ +- case 1: +- for (i = 0; i < (data->image_width * data->image_height); +- i++, d1 += 3, d2++) +- { +- d1[R3] = d2[0]; +- d1[G3] = d2[0]; +- d1[B3] = d2[0]; +- } +- break; +- } +- return; +- } + + { + /* Only copy the upper 8 bit. */ diff --git a/debian/patches/0071-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch b/debian/patches/0071-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch new file mode 100644 index 0000000..7f73935 --- /dev/null +++ b/debian/patches/0071-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch @@ -0,0 +1,38 @@ +From 21e3b255f91d9b7711f8346f1e4acf8cc19bf4fb Mon Sep 17 00:00:00 2001 +From: Daniel Axtens <dja@axtens.net> +Date: Tue, 6 Jul 2021 23:25:07 +1000 +Subject: video/readers/png: Avoid heap OOB R/W inserting huff table items + +In fuzzing we observed crashes where a code would attempt to be inserted +into a huffman table before the start, leading to a set of heap OOB reads +and writes as table entries with negative indices were shifted around and +the new code written in. + +Catch the case where we would underflow the array and bail. + +Fixes: CVE-2021-3696 + +Signed-off-by: Daniel Axtens <dja@axtens.net> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/video/readers/png.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c +index a3161e25b..d7ed5aa6c 100644 +--- a/grub-core/video/readers/png.c ++++ b/grub-core/video/readers/png.c +@@ -438,6 +438,13 @@ grub_png_insert_huff_item (struct huff_table *ht, int code, int len) + for (i = len; i < ht->max_length; i++) + n += ht->maxval[i]; + ++ if (n > ht->num_values) ++ { ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "png: out of range inserting huffman table item"); ++ return; ++ } ++ + for (i = 0; i < n; i++) + ht->values[ht->num_values - i] = ht->values[ht->num_values - i - 1]; + diff --git a/debian/patches/0072-video-readers-png-Sanity-check-some-huffman-codes.patch b/debian/patches/0072-video-readers-png-Sanity-check-some-huffman-codes.patch new file mode 100644 index 0000000..b355584 --- /dev/null +++ b/debian/patches/0072-video-readers-png-Sanity-check-some-huffman-codes.patch @@ -0,0 +1,39 @@ +From e1c0a986e39ab93954436bcf6e6a9a7ea465e4e7 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens <dja@axtens.net> +Date: Tue, 6 Jul 2021 19:19:11 +1000 +Subject: video/readers/png: Sanity check some huffman codes + +ASAN picked up two OOB global reads: we weren't checking if some code +values fit within the cplens or cpdext arrays. Check and throw an error +if not. + +Signed-off-by: Daniel Axtens <dja@axtens.net> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/video/readers/png.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c +index d7ed5aa6c..7f2ba7849 100644 +--- a/grub-core/video/readers/png.c ++++ b/grub-core/video/readers/png.c +@@ -753,6 +753,9 @@ grub_png_read_dynamic_block (struct grub_png_data *data) + int len, dist, pos; + + n -= 257; ++ if (((unsigned int) n) >= ARRAY_SIZE (cplens)) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "png: invalid huff code"); + len = cplens[n]; + if (cplext[n]) + len += grub_png_get_bits (data, cplext[n]); +@@ -760,6 +763,9 @@ grub_png_read_dynamic_block (struct grub_png_data *data) + return grub_errno; + + n = grub_png_get_huff_code (data, &data->dist_table); ++ if (((unsigned int) n) >= ARRAY_SIZE (cpdist)) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "png: invalid huff code"); + dist = cpdist[n]; + if (cpdext[n]) + dist += grub_png_get_bits (data, cpdext[n]); diff --git a/debian/patches/0073-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch b/debian/patches/0073-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch new file mode 100644 index 0000000..1f5b558 --- /dev/null +++ b/debian/patches/0073-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch @@ -0,0 +1,254 @@ +From 40be99c5f8162887d1922fb9428b39de4cdad3af Mon Sep 17 00:00:00 2001 +From: Daniel Axtens <dja@axtens.net> +Date: Mon, 28 Jun 2021 14:16:14 +1000 +Subject: video/readers/jpeg: Abort sooner if a read operation fails + +Fuzzing revealed some inputs that were taking a long time, potentially +forever, because they did not bail quickly upon encountering an I/O error. + +Try to catch I/O errors sooner and bail out. + +Signed-off-by: Daniel Axtens <dja@axtens.net> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/video/readers/jpeg.c | 86 +++++++++++++++++++++++++++------- + 1 file changed, 70 insertions(+), 16 deletions(-) + +diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c +index e31602f76..10225abd5 100644 +--- a/grub-core/video/readers/jpeg.c ++++ b/grub-core/video/readers/jpeg.c +@@ -109,9 +109,17 @@ static grub_uint8_t + grub_jpeg_get_byte (struct grub_jpeg_data *data) + { + grub_uint8_t r; ++ grub_ssize_t bytes_read; + + r = 0; +- grub_file_read (data->file, &r, 1); ++ bytes_read = grub_file_read (data->file, &r, 1); ++ ++ if (bytes_read != 1) ++ { ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: unexpected end of data"); ++ return 0; ++ } + + return r; + } +@@ -120,9 +128,17 @@ static grub_uint16_t + grub_jpeg_get_word (struct grub_jpeg_data *data) + { + grub_uint16_t r; ++ grub_ssize_t bytes_read; + + r = 0; +- grub_file_read (data->file, &r, sizeof (grub_uint16_t)); ++ bytes_read = grub_file_read (data->file, &r, sizeof (grub_uint16_t)); ++ ++ if (bytes_read != sizeof (grub_uint16_t)) ++ { ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: unexpected end of data"); ++ return 0; ++ } + + return grub_be_to_cpu16 (r); + } +@@ -135,6 +151,11 @@ grub_jpeg_get_bit (struct grub_jpeg_data *data) + if (data->bit_mask == 0) + { + data->bit_save = grub_jpeg_get_byte (data); ++ if (grub_errno != GRUB_ERR_NONE) { ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: file read error"); ++ return 0; ++ } + if (data->bit_save == JPEG_ESC_CHAR) + { + if (grub_jpeg_get_byte (data) != 0) +@@ -143,6 +164,11 @@ grub_jpeg_get_bit (struct grub_jpeg_data *data) + "jpeg: invalid 0xFF in data stream"); + return 0; + } ++ if (grub_errno != GRUB_ERR_NONE) ++ { ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: file read error"); ++ return 0; ++ } + } + data->bit_mask = 0x80; + } +@@ -161,7 +187,7 @@ grub_jpeg_get_number (struct grub_jpeg_data *data, int num) + return 0; + + msb = value = grub_jpeg_get_bit (data); +- for (i = 1; i < num; i++) ++ for (i = 1; i < num && grub_errno == GRUB_ERR_NONE; i++) + value = (value << 1) + (grub_jpeg_get_bit (data) != 0); + if (!msb) + value += 1 - (1 << num); +@@ -202,6 +228,8 @@ grub_jpeg_decode_huff_table (struct grub_jpeg_data *data) + while (data->file->offset + sizeof (count) + 1 <= next_marker) + { + id = grub_jpeg_get_byte (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + ac = (id >> 4) & 1; + id &= 0xF; + if (id > 1) +@@ -252,6 +280,8 @@ grub_jpeg_decode_quan_table (struct grub_jpeg_data *data) + + next_marker = data->file->offset; + next_marker += grub_jpeg_get_word (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + if (next_marker > data->file->size) + { +@@ -263,6 +293,8 @@ grub_jpeg_decode_quan_table (struct grub_jpeg_data *data) + <= next_marker) + { + id = grub_jpeg_get_byte (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + if (id >= 0x10) /* Upper 4-bit is precision. */ + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "jpeg: only 8-bit precision is supported"); +@@ -294,6 +326,9 @@ grub_jpeg_decode_sof (struct grub_jpeg_data *data) + next_marker = data->file->offset; + next_marker += grub_jpeg_get_word (data); + ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; ++ + if (grub_jpeg_get_byte (data) != 8) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "jpeg: only 8-bit precision is supported"); +@@ -319,6 +354,8 @@ grub_jpeg_decode_sof (struct grub_jpeg_data *data) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index"); + + ss = grub_jpeg_get_byte (data); /* Sampling factor. */ ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + if (!id) + { + grub_uint8_t vs, hs; +@@ -498,7 +535,7 @@ grub_jpeg_idct_transform (jpeg_data_unit_t du) + } + } + +-static void ++static grub_err_t + grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du) + { + int h1, h2, qt; +@@ -513,6 +550,9 @@ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du) + data->dc_value[id] += + grub_jpeg_get_number (data, grub_jpeg_get_huff_code (data, h1)); + ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; ++ + du[0] = data->dc_value[id] * (int) data->quan_table[qt][0]; + pos = 1; + while (pos < ARRAY_SIZE (data->quan_table[qt])) +@@ -527,11 +567,13 @@ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du) + num >>= 4; + pos += num; + ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; ++ + if (pos >= ARRAY_SIZE (jpeg_zigzag_order)) + { +- grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "jpeg: invalid position in zigzag order!?"); +- return; ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: invalid position in zigzag order!?"); + } + + du[jpeg_zigzag_order[pos]] = val * (int) data->quan_table[qt][pos]; +@@ -539,6 +581,7 @@ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du) + } + + grub_jpeg_idct_transform (du); ++ return GRUB_ERR_NONE; + } + + static void +@@ -597,7 +640,8 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data) + data_offset += grub_jpeg_get_word (data); + + cc = grub_jpeg_get_byte (data); +- ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + if (cc != 3 && cc != 1) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "jpeg: component count must be 1 or 3"); +@@ -610,7 +654,8 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data) + id = grub_jpeg_get_byte (data) - 1; + if ((id < 0) || (id >= 3)) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index"); +- ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + ht = grub_jpeg_get_byte (data); + data->comp_index[id][1] = (ht >> 4); + data->comp_index[id][2] = (ht & 0xF) + 2; +@@ -618,11 +663,14 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data) + if ((data->comp_index[id][1] < 0) || (data->comp_index[id][1] > 3) || + (data->comp_index[id][2] < 0) || (data->comp_index[id][2] > 3)) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid hufftable index"); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + } + + grub_jpeg_get_byte (data); /* Skip 3 unused bytes. */ + grub_jpeg_get_word (data); +- ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + if (data->file->offset != data_offset) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in sos"); + +@@ -640,6 +688,7 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data) + { + unsigned c1, vb, hb, nr1, nc1; + int rst = data->dri; ++ grub_err_t err = GRUB_ERR_NONE; + + vb = 8 << data->log_vs; + hb = 8 << data->log_hs; +@@ -660,17 +709,22 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data) + + for (r2 = 0; r2 < (1U << data->log_vs); r2++) + for (c2 = 0; c2 < (1U << data->log_hs); c2++) +- grub_jpeg_decode_du (data, 0, data->ydu[r2 * 2 + c2]); ++ { ++ err = grub_jpeg_decode_du (data, 0, data->ydu[r2 * 2 + c2]); ++ if (err != GRUB_ERR_NONE) ++ return err; ++ } + + if (data->color_components >= 3) + { +- grub_jpeg_decode_du (data, 1, data->cbdu); +- grub_jpeg_decode_du (data, 2, data->crdu); ++ err = grub_jpeg_decode_du (data, 1, data->cbdu); ++ if (err != GRUB_ERR_NONE) ++ return err; ++ err = grub_jpeg_decode_du (data, 2, data->crdu); ++ if (err != GRUB_ERR_NONE) ++ return err; + } + +- if (grub_errno) +- return grub_errno; +- + nr2 = (data->r1 == nr1 - 1) ? (data->image_height - data->r1 * vb) : vb; + nc2 = (c1 == nc1 - 1) ? (data->image_width - c1 * hb) : hb; + diff --git a/debian/patches/0074-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch b/debian/patches/0074-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch new file mode 100644 index 0000000..c4228f9 --- /dev/null +++ b/debian/patches/0074-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch @@ -0,0 +1,28 @@ +From 610c5986058312cfc0375fc04f88fcc116bdd043 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens <dja@axtens.net> +Date: Mon, 28 Jun 2021 14:16:58 +1000 +Subject: video/readers/jpeg: Do not reallocate a given huff table + +Fix a memory leak where an invalid file could cause us to reallocate +memory for a huffman table we had already allocated memory for. + +Signed-off-by: Daniel Axtens <dja@axtens.net> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/video/readers/jpeg.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c +index 10225abd5..caa211f06 100644 +--- a/grub-core/video/readers/jpeg.c ++++ b/grub-core/video/readers/jpeg.c +@@ -245,6 +245,9 @@ grub_jpeg_decode_huff_table (struct grub_jpeg_data *data) + n += count[i]; + + id += ac * 2; ++ if (data->huff_value[id] != NULL) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: attempt to reallocate huffman table"); + data->huff_value[id] = grub_malloc (n); + if (grub_errno) + return grub_errno; diff --git a/debian/patches/0075-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch b/debian/patches/0075-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch new file mode 100644 index 0000000..07fd802 --- /dev/null +++ b/debian/patches/0075-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch @@ -0,0 +1,42 @@ +From 9286f0009b922571c247012e699c3ed5f6e918bc Mon Sep 17 00:00:00 2001 +From: Daniel Axtens <dja@axtens.net> +Date: Mon, 28 Jun 2021 14:25:17 +1000 +Subject: video/readers/jpeg: Refuse to handle multiple start of streams + +An invalid file could contain multiple start of stream blocks, which +would cause us to reallocate and leak our bitmap. Refuse to handle +multiple start of streams. + +Additionally, fix a grub_error() call formatting. + +Signed-off-by: Daniel Axtens <dja@axtens.net> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/video/readers/jpeg.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c +index caa211f06..1df1171d7 100644 +--- a/grub-core/video/readers/jpeg.c ++++ b/grub-core/video/readers/jpeg.c +@@ -677,6 +677,9 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data) + if (data->file->offset != data_offset) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in sos"); + ++ if (*data->bitmap) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: too many start of scan blocks"); ++ + if (grub_video_bitmap_create (data->bitmap, data->image_width, + data->image_height, + GRUB_VIDEO_BLIT_FORMAT_RGB_888)) +@@ -699,8 +702,8 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data) + nc1 = (data->image_width + hb - 1) >> (3 + data->log_hs); + + if (data->bitmap_ptr == NULL) +- return grub_error(GRUB_ERR_BAD_FILE_TYPE, +- "jpeg: attempted to decode data before start of stream"); ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: attempted to decode data before start of stream"); + + for (; data->r1 < nr1 && (!data->dri || rst); + data->r1++, data->bitmap_ptr += (vb * data->image_width - hb * nc1) * 3) diff --git a/debian/patches/0076-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch b/debian/patches/0076-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch new file mode 100644 index 0000000..b292cbc --- /dev/null +++ b/debian/patches/0076-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch @@ -0,0 +1,73 @@ +From a10c2350a766f9b315735931a49499a7e2c77bf3 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens <dja@axtens.net> +Date: Wed, 7 Jul 2021 15:38:19 +1000 +Subject: video/readers/jpeg: Block int underflow -> wild pointer write + +Certain 1 px wide images caused a wild pointer write in +grub_jpeg_ycrcb_to_rgb(). This was caused because in grub_jpeg_decode_data(), +we have the following loop: + +for (; data->r1 < nr1 && (!data->dri || rst); + data->r1++, data->bitmap_ptr += (vb * data->image_width - hb * nc1) * 3) + +We did not check if vb * width >= hb * nc1. + +On a 64-bit platform, if that turns out to be negative, it will underflow, +be interpreted as unsigned 64-bit, then be added to the 64-bit pointer, so +we see data->bitmap_ptr jump, e.g.: + +0x6180_0000_0480 to +0x6181_0000_0498 + ^ + ~--- carry has occurred and this pointer is now far away from + any object. + +On a 32-bit platform, it will decrement the pointer, creating a pointer +that won't crash but will overwrite random data. + +Catch the underflow and error out. + +Fixes: CVE-2021-3697 + +Signed-off-by: Daniel Axtens <dja@axtens.net> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/video/readers/jpeg.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c +index 1df1171d7..97a533b24 100644 +--- a/grub-core/video/readers/jpeg.c ++++ b/grub-core/video/readers/jpeg.c +@@ -23,6 +23,7 @@ + #include <grub/mm.h> + #include <grub/misc.h> + #include <grub/bufio.h> ++#include <grub/safemath.h> + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -693,6 +694,7 @@ static grub_err_t + grub_jpeg_decode_data (struct grub_jpeg_data *data) + { + unsigned c1, vb, hb, nr1, nc1; ++ unsigned stride_a, stride_b, stride; + int rst = data->dri; + grub_err_t err = GRUB_ERR_NONE; + +@@ -705,8 +707,14 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "jpeg: attempted to decode data before start of stream"); + ++ if (grub_mul(vb, data->image_width, &stride_a) || ++ grub_mul(hb, nc1, &stride_b) || ++ grub_sub(stride_a, stride_b, &stride)) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: cannot decode image with these dimensions"); ++ + for (; data->r1 < nr1 && (!data->dri || rst); +- data->r1++, data->bitmap_ptr += (vb * data->image_width - hb * nc1) * 3) ++ data->r1++, data->bitmap_ptr += stride * 3) + for (c1 = 0; c1 < nc1 && (!data->dri || rst); + c1++, rst--, data->bitmap_ptr += hb * 3) + { diff --git a/debian/patches/0077-normal-charset-Fix-array-out-of-bounds-formatting-un.patch b/debian/patches/0077-normal-charset-Fix-array-out-of-bounds-formatting-un.patch new file mode 100644 index 0000000..066775a --- /dev/null +++ b/debian/patches/0077-normal-charset-Fix-array-out-of-bounds-formatting-un.patch @@ -0,0 +1,33 @@ +From 557370849b914110a9efbd7256dc3942a8af8b99 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens <dja@axtens.net> +Date: Tue, 13 Jul 2021 13:24:38 +1000 +Subject: normal/charset: Fix array out-of-bounds formatting unicode for + display + +In some cases attempting to display arbitrary binary strings leads +to ASAN splats reading the widthspec array out of bounds. + +Check the index. If it would be out of bounds, return a width of 1. +I don't know if that's strictly correct, but we're not really expecting +great display of arbitrary binary data, and it's certainly not worse than +an OOB read. + +Signed-off-by: Daniel Axtens <dja@axtens.net> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/normal/charset.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/grub-core/normal/charset.c b/grub-core/normal/charset.c +index 4dfcc3107..7a5a7c153 100644 +--- a/grub-core/normal/charset.c ++++ b/grub-core/normal/charset.c +@@ -395,6 +395,8 @@ grub_unicode_estimate_width (const struct grub_unicode_glyph *c) + { + if (grub_unicode_get_comb_type (c->base)) + return 0; ++ if (((unsigned long) (c->base >> 3)) >= ARRAY_SIZE (widthspec)) ++ return 1; + if (widthspec[c->base >> 3] & (1 << (c->base & 7))) + return 2; + else diff --git a/debian/patches/0078-net-netbuff-Block-overly-large-netbuff-allocs.patch b/debian/patches/0078-net-netbuff-Block-overly-large-netbuff-allocs.patch new file mode 100644 index 0000000..150f101 --- /dev/null +++ b/debian/patches/0078-net-netbuff-Block-overly-large-netbuff-allocs.patch @@ -0,0 +1,45 @@ +From 4ea64c827f8bc57180772fd5671ddd010cb7b2ed Mon Sep 17 00:00:00 2001 +From: Daniel Axtens <dja@axtens.net> +Date: Tue, 8 Mar 2022 23:47:46 +1100 +Subject: net/netbuff: Block overly large netbuff allocs + +A netbuff shouldn't be too huge. It's bounded by MTU and TCP segment +reassembly. + +This helps avoid some bugs (and provides a spot to instrument to catch +them at their source). + +Signed-off-by: Daniel Axtens <dja@axtens.net> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/net/netbuff.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/grub-core/net/netbuff.c b/grub-core/net/netbuff.c +index dbeeefe47..d5e9e9a0d 100644 +--- a/grub-core/net/netbuff.c ++++ b/grub-core/net/netbuff.c +@@ -79,10 +79,23 @@ grub_netbuff_alloc (grub_size_t len) + + COMPILE_TIME_ASSERT (NETBUFF_ALIGN % sizeof (grub_properly_aligned_t) == 0); + ++ /* ++ * The largest size of a TCP packet is 64 KiB, and everything else ++ * should be a lot smaller - most MTUs are 1500 or less. Cap data ++ * size at 64 KiB + a buffer. ++ */ ++ if (len > 0xffffUL + 0x1000UL) ++ { ++ grub_error (GRUB_ERR_BUG, ++ "attempted to allocate a packet that is too big"); ++ return NULL; ++ } ++ + if (len < NETBUFFMINLEN) + len = NETBUFFMINLEN; + + len = ALIGN_UP (len, NETBUFF_ALIGN); ++ + #ifdef GRUB_MACHINE_EMU + data = grub_malloc (len + sizeof (*nb)); + #else diff --git a/debian/patches/0079-net-ip-Do-IP-fragment-maths-safely.patch b/debian/patches/0079-net-ip-Do-IP-fragment-maths-safely.patch new file mode 100644 index 0000000..7c5d8dc --- /dev/null +++ b/debian/patches/0079-net-ip-Do-IP-fragment-maths-safely.patch @@ -0,0 +1,43 @@ +From 2a4f87df650fd2ef639b48b43fc834b97b6b2bfa Mon Sep 17 00:00:00 2001 +From: Daniel Axtens <dja@axtens.net> +Date: Mon, 20 Dec 2021 19:41:21 +1100 +Subject: net/ip: Do IP fragment maths safely + +This avoids an underflow and subsequent unpleasantness. + +Fixes: CVE-2022-28733 + +Signed-off-by: Daniel Axtens <dja@axtens.net> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/net/ip.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/grub-core/net/ip.c b/grub-core/net/ip.c +index 01410798b..937be8767 100644 +--- a/grub-core/net/ip.c ++++ b/grub-core/net/ip.c +@@ -25,6 +25,7 @@ + #include <grub/net/netbuff.h> + #include <grub/mm.h> + #include <grub/priority_queue.h> ++#include <grub/safemath.h> + #include <grub/time.h> + + struct iphdr { +@@ -551,7 +552,14 @@ grub_net_recv_ip4_packets (struct grub_net_buff *nb, + { + rsm->total_len = (8 * (grub_be_to_cpu16 (iph->frags) & OFFSET_MASK) + + (nb->tail - nb->data)); +- rsm->total_len -= ((iph->verhdrlen & 0xf) * sizeof (grub_uint32_t)); ++ ++ if (grub_sub (rsm->total_len, (iph->verhdrlen & 0xf) * sizeof (grub_uint32_t), ++ &rsm->total_len)) ++ { ++ grub_dprintf ("net", "IP reassembly size underflow\n"); ++ return GRUB_ERR_NONE; ++ } ++ + rsm->asm_netbuff = grub_netbuff_alloc (rsm->total_len); + if (!rsm->asm_netbuff) + { diff --git a/debian/patches/0080-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch b/debian/patches/0080-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch new file mode 100644 index 0000000..0f3cdc7 --- /dev/null +++ b/debian/patches/0080-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch @@ -0,0 +1,55 @@ +From 21158c5dfb5e0c5015277346128903397d498da4 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens <dja@axtens.net> +Date: Thu, 16 Sep 2021 01:29:54 +1000 +Subject: net/dns: Fix double-free addresses on corrupt DNS response + +grub_net_dns_lookup() takes as inputs a pointer to an array of addresses +("addresses") for the given name, and pointer to a number of addresses +("naddresses"). grub_net_dns_lookup() is responsible for allocating +"addresses", and the caller is responsible for freeing it if +"naddresses" > 0. + +The DNS recv_hook will sometimes set and free the addresses array, +for example if the packet is too short: + + if (ptr + 10 >= nb->tail) + { + if (!*data->naddresses) + grub_free (*data->addresses); + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + +Later on the nslookup command code unconditionally frees the "addresses" +array. Normally this is fine: the array is either populated with valid +data or is NULL. But in these sorts of error cases it is neither NULL +nor valid and we get a double-free. + +Only free "addresses" if "naddresses" > 0. + +It looks like the other use of grub_net_dns_lookup() is not affected. + +Signed-off-by: Daniel Axtens <dja@axtens.net> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/net/dns.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/grub-core/net/dns.c b/grub-core/net/dns.c +index 906ec7d67..135faac03 100644 +--- a/grub-core/net/dns.c ++++ b/grub-core/net/dns.c +@@ -667,9 +667,11 @@ grub_cmd_nslookup (struct grub_command *cmd __attribute__ ((unused)), + grub_net_addr_to_str (&addresses[i], buf); + grub_printf ("%s\n", buf); + } +- grub_free (addresses); + if (naddresses) +- return GRUB_ERR_NONE; ++ { ++ grub_free (addresses); ++ return GRUB_ERR_NONE; ++ } + return grub_error (GRUB_ERR_NET_NO_DOMAIN, N_("no DNS record found")); + } + diff --git a/debian/patches/0081-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch b/debian/patches/0081-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch new file mode 100644 index 0000000..0fc28a9 --- /dev/null +++ b/debian/patches/0081-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch @@ -0,0 +1,69 @@ +From 968febf3a4de5df0f91cc13bc6b6053fc22575e1 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens <dja@axtens.net> +Date: Mon, 20 Dec 2021 21:55:43 +1100 +Subject: net/dns: Don't read past the end of the string we're checking against + +I don't really understand what's going on here but fuzzing found +a bug where we read past the end of check_with. That's a C string, +so use grub_strlen() to make sure we don't overread it. + +Signed-off-by: Daniel Axtens <dja@axtens.net> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/net/dns.c | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +diff --git a/grub-core/net/dns.c b/grub-core/net/dns.c +index 135faac03..17961a9f1 100644 +--- a/grub-core/net/dns.c ++++ b/grub-core/net/dns.c +@@ -146,11 +146,18 @@ check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head, + int *length, char *set) + { + const char *readable_ptr = check_with; ++ int readable_len; + const grub_uint8_t *ptr; + char *optr = set; + int bytes_processed = 0; + if (length) + *length = 0; ++ ++ if (readable_ptr != NULL) ++ readable_len = grub_strlen (readable_ptr); ++ else ++ readable_len = 0; ++ + for (ptr = name_at; ptr < tail && bytes_processed < tail - head + 2; ) + { + /* End marker. */ +@@ -172,13 +179,16 @@ check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head, + ptr = head + (((ptr[0] & 0x3f) << 8) | ptr[1]); + continue; + } +- if (readable_ptr && grub_memcmp (ptr + 1, readable_ptr, *ptr) != 0) ++ if (readable_ptr != NULL && (*ptr > readable_len || grub_memcmp (ptr + 1, readable_ptr, *ptr) != 0)) + return 0; + if (grub_memchr (ptr + 1, 0, *ptr) + || grub_memchr (ptr + 1, '.', *ptr)) + return 0; + if (readable_ptr) +- readable_ptr += *ptr; ++ { ++ readable_ptr += *ptr; ++ readable_len -= *ptr; ++ } + if (readable_ptr && *readable_ptr != '.' && *readable_ptr != 0) + return 0; + bytes_processed += *ptr + 1; +@@ -192,7 +202,10 @@ check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head, + if (optr) + *optr++ = '.'; + if (readable_ptr && *readable_ptr) +- readable_ptr++; ++ { ++ readable_ptr++; ++ readable_len--; ++ } + ptr += *ptr + 1; + } + return 0; diff --git a/debian/patches/0082-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch b/debian/patches/0082-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch new file mode 100644 index 0000000..bb4cd8c --- /dev/null +++ b/debian/patches/0082-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch @@ -0,0 +1,111 @@ +From e7573be61b3cf005cdf0a068652153437daca4b3 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens <dja@axtens.net> +Date: Mon, 20 Sep 2021 01:12:24 +1000 +Subject: net/tftp: Prevent a UAF and double-free from a failed seek + +A malicious tftp server can cause UAFs and a double free. + +An attempt to read from a network file is handled by grub_net_fs_read(). If +the read is at an offset other than the current offset, grub_net_seek_real() +is invoked. + +In grub_net_seek_real(), if a backwards seek cannot be satisfied from the +currently received packets, and the underlying transport does not provide +a seek method, then grub_net_seek_real() will close and reopen the network +protocol layer. + +For tftp, the ->close() call goes to tftp_close() and frees the tftp_data_t +file->data. The file->data pointer is not nulled out after the free. + +If the ->open() call fails, the file->data will not be reallocated and will +continue point to a freed memory block. This could happen from a server +refusing to send the requisite ack to the new tftp request, for example. + +The seek and the read will then fail, but the grub_file continues to exist: +the failed seek does not necessarily cause the entire file to be thrown +away (e.g. where the file is checked to see if it is gzipped/lzio/xz/etc., +a read failure is interpreted as a decompressor passing on the file, not as +an invalidation of the entire grub_file_t structure). + +This means subsequent attempts to read or seek the file will use the old +file->data after free. Eventually, the file will be close()d again and +file->data will be freed again. + +Mark a net_fs file that doesn't reopen as broken. Do not permit read() or +close() on a broken file (seek is not exposed directly to the file API - +it is only called as part of read, so this blocks seeks as well). + +As an additional defence, null out the ->data pointer if tftp_open() fails. +That would have lead to a simple null pointer dereference rather than +a mess of UAFs. + +This may affect other protocols, I haven't checked. + +Signed-off-by: Daniel Axtens <dja@axtens.net> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/net/net.c | 11 +++++++++-- + grub-core/net/tftp.c | 1 + + include/grub/net.h | 1 + + 3 files changed, 11 insertions(+), 2 deletions(-) + +diff --git a/grub-core/net/net.c b/grub-core/net/net.c +index 15a2f29a9..af7440776 100644 +--- a/grub-core/net/net.c ++++ b/grub-core/net/net.c +@@ -1548,7 +1548,8 @@ grub_net_fs_close (grub_file_t file) + grub_netbuff_free (file->device->net->packs.first->nb); + grub_net_remove_packet (file->device->net->packs.first); + } +- file->device->net->protocol->close (file); ++ if (!file->device->net->broken) ++ file->device->net->protocol->close (file); + grub_free (file->device->net->name); + return GRUB_ERR_NONE; + } +@@ -1770,7 +1771,10 @@ grub_net_seek_real (struct grub_file *file, grub_off_t offset) + file->device->net->stall = 0; + err = file->device->net->protocol->open (file, file->device->net->name); + if (err) +- return err; ++ { ++ file->device->net->broken = 1; ++ return err; ++ } + grub_net_fs_read_real (file, NULL, offset); + return grub_errno; + } +@@ -1779,6 +1783,9 @@ grub_net_seek_real (struct grub_file *file, grub_off_t offset) + static grub_ssize_t + grub_net_fs_read (grub_file_t file, char *buf, grub_size_t len) + { ++ if (file->device->net->broken) ++ return -1; ++ + if (file->offset != file->device->net->offset) + { + grub_err_t err; +diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c +index f3e787938..d1afa2535 100644 +--- a/grub-core/net/tftp.c ++++ b/grub-core/net/tftp.c +@@ -404,6 +404,7 @@ tftp_open (struct grub_file *file, const char *filename) + { + grub_net_udp_close (data->sock); + grub_free (data); ++ file->data = NULL; + return grub_errno; + } + +diff --git a/include/grub/net.h b/include/grub/net.h +index cbcae79b1..8d71ca6cc 100644 +--- a/include/grub/net.h ++++ b/include/grub/net.h +@@ -277,6 +277,7 @@ typedef struct grub_net + grub_fs_t fs; + int eof; + int stall; ++ int broken; + } *grub_net_t; + + extern grub_net_t (*EXPORT_VAR (grub_net_open)) (const char *name); diff --git a/debian/patches/0083-net-tftp-Avoid-a-trivial-UAF.patch b/debian/patches/0083-net-tftp-Avoid-a-trivial-UAF.patch new file mode 100644 index 0000000..8e42215 --- /dev/null +++ b/debian/patches/0083-net-tftp-Avoid-a-trivial-UAF.patch @@ -0,0 +1,34 @@ +From fb66f40ba67b88408a43cb38492053985bfe4968 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens <dja@axtens.net> +Date: Tue, 18 Jan 2022 14:29:20 +1100 +Subject: net/tftp: Avoid a trivial UAF + +Under tftp errors, we print a tftp error message from the tftp header. +However, the tftph pointer is a pointer inside nb, the netbuff. Previously, +we were freeing the nb and then dereferencing it. Don't do that, use it +and then free it later. + +This isn't really _bad_ per se, especially as we're single-threaded, but +it trips up fuzzers. + +Signed-off-by: Daniel Axtens <dja@axtens.net> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/net/tftp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c +index d1afa2535..4222d93b6 100644 +--- a/grub-core/net/tftp.c ++++ b/grub-core/net/tftp.c +@@ -251,9 +251,9 @@ tftp_receive (grub_net_udp_socket_t sock __attribute__ ((unused)), + return GRUB_ERR_NONE; + case TFTP_ERROR: + data->have_oack = 1; +- grub_netbuff_free (nb); + grub_error (GRUB_ERR_IO, "%s", tftph->u.err.errmsg); + grub_error_save (&data->save_err); ++ grub_netbuff_free (nb); + return GRUB_ERR_NONE; + default: + grub_netbuff_free (nb); diff --git a/debian/patches/0084-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch b/debian/patches/0084-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch new file mode 100644 index 0000000..763e46a --- /dev/null +++ b/debian/patches/0084-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch @@ -0,0 +1,40 @@ +From 6df718714dea5043243e367750b5c6abebcf79fe Mon Sep 17 00:00:00 2001 +From: Daniel Axtens <dja@axtens.net> +Date: Tue, 1 Mar 2022 23:14:15 +1100 +Subject: net/http: Do not tear down socket if it's already been torn down + +It's possible for data->sock to get torn down in tcp error handling. +If we unconditionally tear it down again we will end up doing writes +to an offset of the NULL pointer when we go to tear it down again. + +Detect if it has been torn down and don't do it again. + +Signed-off-by: Daniel Axtens <dja@axtens.net> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/net/http.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/grub-core/net/http.c b/grub-core/net/http.c +index 3fe155f1b..ef6eaff0d 100644 +--- a/grub-core/net/http.c ++++ b/grub-core/net/http.c +@@ -422,7 +422,7 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial) + return err; + } + +- for (i = 0; !data->headers_recv && i < 100; i++) ++ for (i = 0; data->sock && !data->headers_recv && i < 100; i++) + { + grub_net_tcp_retransmit (); + grub_net_poll_cards (300, &data->headers_recv); +@@ -430,7 +430,8 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial) + + if (!data->headers_recv) + { +- grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT); ++ if (data->sock) ++ grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT); + if (data->err) + { + char *str = data->errmsg; diff --git a/debian/patches/0085-net-http-Fix-OOB-write-for-split-http-headers.patch b/debian/patches/0085-net-http-Fix-OOB-write-for-split-http-headers.patch new file mode 100644 index 0000000..3b6ff59 --- /dev/null +++ b/debian/patches/0085-net-http-Fix-OOB-write-for-split-http-headers.patch @@ -0,0 +1,45 @@ +From f407a45bd3483f6bbf58c5e9386a44caa14287e3 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens <dja@axtens.net> +Date: Tue, 8 Mar 2022 18:17:03 +1100 +Subject: net/http: Fix OOB write for split http headers + +GRUB has special code for handling an http header that is split +across two packets. + +The code tracks the end of line by looking for a "\n" byte. The +code for split headers has always advanced the pointer just past the +end of the line, whereas the code that handles unsplit headers does +not advance the pointer. This extra advance causes the length to be +one greater, which breaks an assumption in parse_line(), leading to +it writing a NUL byte one byte past the end of the buffer where we +reconstruct the line from the two packets. + +It's conceivable that an attacker controlled set of packets could +cause this to zero out the first byte of the "next" pointer of the +grub_mm_region structure following the current_line buffer. + +Do not advance the pointer in the split header case. + +Fixes: CVE-2022-28734 + +Signed-off-by: Daniel Axtens <dja@axtens.net> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/net/http.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/grub-core/net/http.c b/grub-core/net/http.c +index ef6eaff0d..9f45ad4e8 100644 +--- a/grub-core/net/http.c ++++ b/grub-core/net/http.c +@@ -190,9 +190,7 @@ http_receive (grub_net_tcp_socket_t sock __attribute__ ((unused)), + int have_line = 1; + char *t; + ptr = grub_memchr (nb->data, '\n', nb->tail - nb->data); +- if (ptr) +- ptr++; +- else ++ if (ptr == NULL) + { + have_line = 0; + ptr = (char *) nb->tail; diff --git a/debian/patches/0086-net-http-Error-out-on-headers-with-LF-without-CR.patch b/debian/patches/0086-net-http-Error-out-on-headers-with-LF-without-CR.patch new file mode 100644 index 0000000..5b7ede1 --- /dev/null +++ b/debian/patches/0086-net-http-Error-out-on-headers-with-LF-without-CR.patch @@ -0,0 +1,47 @@ +From 870b94755b6a341d21632293677b346ff033e5f0 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens <dja@axtens.net> +Date: Tue, 8 Mar 2022 19:04:40 +1100 +Subject: net/http: Error out on headers with LF without CR + +In a similar vein to the previous patch, parse_line() would write +a NUL byte past the end of the buffer if there was an HTTP header +with a LF rather than a CRLF. + +RFC-2616 says: + + Many HTTP/1.1 header field values consist of words separated by LWS + or special characters. These special characters MUST be in a quoted + string to be used within a parameter value (as defined in section 3.6). + +We don't support quoted sections or continuation lines, etc. + +If we see an LF that's not part of a CRLF, bail out. + +Fixes: CVE-2022-28734 + +Signed-off-by: Daniel Axtens <dja@axtens.net> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/net/http.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/grub-core/net/http.c b/grub-core/net/http.c +index 9f45ad4e8..6988d38fb 100644 +--- a/grub-core/net/http.c ++++ b/grub-core/net/http.c +@@ -68,7 +68,15 @@ parse_line (grub_file_t file, http_data_t data, char *ptr, grub_size_t len) + char *end = ptr + len; + while (end > ptr && *(end - 1) == '\r') + end--; ++ ++ /* LF without CR. */ ++ if (end == ptr + len) ++ { ++ data->errmsg = grub_strdup (_("invalid HTTP header - LF without CR")); ++ return GRUB_ERR_NONE; ++ } + *end = 0; ++ + /* Trailing CRLF. */ + if (data->in_chunk_len == 1) + { diff --git a/debian/patches/0087-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch b/debian/patches/0087-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch new file mode 100644 index 0000000..6561abd --- /dev/null +++ b/debian/patches/0087-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch @@ -0,0 +1,71 @@ +From 2d014248d540c7e087934a94b6e7a2aa7fc2c704 Mon Sep 17 00:00:00 2001 +From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com> +Date: Wed, 6 Apr 2022 18:03:37 +0530 +Subject: fs/f2fs: Do not read past the end of nat journal entries + +A corrupt f2fs file system could specify a nat journal entry count +that is beyond the maximum NAT_JOURNAL_ENTRIES. + +Check if the specified nat journal entry count before accessing the +array, and throw an error if it is too large. + +Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com> +Signed-off-by: Daniel Axtens <dja@axtens.net> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/fs/f2fs.c | 21 ++++++++++++++------- + 1 file changed, 14 insertions(+), 7 deletions(-) + +diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c +index 8a9992ca9..63702214b 100644 +--- a/grub-core/fs/f2fs.c ++++ b/grub-core/fs/f2fs.c +@@ -632,23 +632,27 @@ get_nat_journal (struct grub_f2fs_data *data) + return err; + } + +-static grub_uint32_t +-get_blkaddr_from_nat_journal (struct grub_f2fs_data *data, grub_uint32_t nid) ++static grub_err_t ++get_blkaddr_from_nat_journal (struct grub_f2fs_data *data, grub_uint32_t nid, ++ grub_uint32_t *blkaddr) + { + grub_uint16_t n = grub_le_to_cpu16 (data->nat_j.n_nats); +- grub_uint32_t blkaddr = 0; + grub_uint16_t i; + ++ if (n >= NAT_JOURNAL_ENTRIES) ++ return grub_error (GRUB_ERR_BAD_FS, ++ "invalid number of nat journal entries"); ++ + for (i = 0; i < n; i++) + { + if (grub_le_to_cpu32 (data->nat_j.entries[i].nid) == nid) + { +- blkaddr = grub_le_to_cpu32 (data->nat_j.entries[i].ne.block_addr); ++ *blkaddr = grub_le_to_cpu32 (data->nat_j.entries[i].ne.block_addr); + break; + } + } + +- return blkaddr; ++ return GRUB_ERR_NONE; + } + + static grub_uint32_t +@@ -656,10 +660,13 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid) + { + struct grub_f2fs_nat_block *nat_block; + grub_uint32_t seg_off, block_off, entry_off, block_addr; +- grub_uint32_t blkaddr; ++ grub_uint32_t blkaddr = 0; + grub_err_t err; + +- blkaddr = get_blkaddr_from_nat_journal (data, nid); ++ err = get_blkaddr_from_nat_journal (data, nid, &blkaddr); ++ if (err != GRUB_ERR_NONE) ++ return 0; ++ + if (blkaddr) + return blkaddr; + diff --git a/debian/patches/0088-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch b/debian/patches/0088-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch new file mode 100644 index 0000000..5f06bd4 --- /dev/null +++ b/debian/patches/0088-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch @@ -0,0 +1,131 @@ +From 9561d7ef621e5e68f12bcd916252ef1c11e60366 Mon Sep 17 00:00:00 2001 +From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com> +Date: Wed, 6 Apr 2022 18:49:09 +0530 +Subject: fs/f2fs: Do not read past the end of nat bitmap + +A corrupt f2fs filesystem could have a block offset or a bitmap +offset that would cause us to read beyond the bounds of the nat +bitmap. + +Introduce the nat_bitmap_size member in grub_f2fs_data which holds +the size of nat bitmap. + +Set the size when loading the nat bitmap in nat_bitmap_ptr(), and +catch when an invalid offset would create a pointer past the end of +the allocated space. + +Check against the bitmap size in grub_f2fs_test_bit() test bit to avoid +reading past the end of the nat bitmap. + +Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com> +Signed-off-by: Daniel Axtens <dja@axtens.net> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/fs/f2fs.c | 33 +++++++++++++++++++++++++++------ + 1 file changed, 27 insertions(+), 6 deletions(-) + +diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c +index 63702214b..8898b235e 100644 +--- a/grub-core/fs/f2fs.c ++++ b/grub-core/fs/f2fs.c +@@ -122,6 +122,7 @@ GRUB_MOD_LICENSE ("GPLv3+"); + #define F2FS_INLINE_DOTS 0x10 /* File having implicit dot dentries. */ + + #define MAX_VOLUME_NAME 512 ++#define MAX_NAT_BITMAP_SIZE 3900 + + enum FILE_TYPE + { +@@ -183,7 +184,7 @@ struct grub_f2fs_checkpoint + grub_uint32_t checksum_offset; + grub_uint64_t elapsed_time; + grub_uint8_t alloc_type[MAX_ACTIVE_LOGS]; +- grub_uint8_t sit_nat_version_bitmap[3900]; ++ grub_uint8_t sit_nat_version_bitmap[MAX_NAT_BITMAP_SIZE]; + grub_uint32_t checksum; + } GRUB_PACKED; + +@@ -302,6 +303,7 @@ struct grub_f2fs_data + + struct grub_f2fs_nat_journal nat_j; + char *nat_bitmap; ++ grub_uint32_t nat_bitmap_size; + + grub_disk_t disk; + struct grub_f2fs_node *inode; +@@ -377,15 +379,20 @@ sum_blk_addr (struct grub_f2fs_data *data, int base, int type) + } + + static void * +-nat_bitmap_ptr (struct grub_f2fs_data *data) ++nat_bitmap_ptr (struct grub_f2fs_data *data, grub_uint32_t *nat_bitmap_size) + { + struct grub_f2fs_checkpoint *ckpt = &data->ckpt; + grub_uint32_t offset; ++ *nat_bitmap_size = MAX_NAT_BITMAP_SIZE; + + if (grub_le_to_cpu32 (data->sblock.cp_payload) > 0) + return ckpt->sit_nat_version_bitmap; + + offset = grub_le_to_cpu32 (ckpt->sit_ver_bitmap_bytesize); ++ if (offset >= MAX_NAT_BITMAP_SIZE) ++ return NULL; ++ ++ *nat_bitmap_size = *nat_bitmap_size - offset; + + return ckpt->sit_nat_version_bitmap + offset; + } +@@ -438,11 +445,15 @@ grub_f2fs_crc_valid (grub_uint32_t blk_crc, void *buf, const grub_uint32_t len) + } + + static int +-grub_f2fs_test_bit (grub_uint32_t nr, const char *p) ++grub_f2fs_test_bit (grub_uint32_t nr, const char *p, grub_uint32_t len) + { + int mask; ++ grub_uint32_t shifted_nr = (nr >> 3); ++ ++ if (shifted_nr >= len) ++ return -1; + +- p += (nr >> 3); ++ p += shifted_nr; + mask = 1 << (7 - (nr & 0x07)); + + return mask & *p; +@@ -662,6 +673,7 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid) + grub_uint32_t seg_off, block_off, entry_off, block_addr; + grub_uint32_t blkaddr = 0; + grub_err_t err; ++ int result_bit; + + err = get_blkaddr_from_nat_journal (data, nid, &blkaddr); + if (err != GRUB_ERR_NONE) +@@ -682,8 +694,15 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid) + ((seg_off * data->blocks_per_seg) << 1) + + (block_off & (data->blocks_per_seg - 1)); + +- if (grub_f2fs_test_bit (block_off, data->nat_bitmap)) ++ result_bit = grub_f2fs_test_bit (block_off, data->nat_bitmap, ++ data->nat_bitmap_size); ++ if (result_bit > 0) + block_addr += data->blocks_per_seg; ++ else if (result_bit == -1) ++ { ++ grub_free (nat_block); ++ return 0; ++ } + + err = grub_f2fs_block_read (data, block_addr, nat_block); + if (err) +@@ -833,7 +852,9 @@ grub_f2fs_mount (grub_disk_t disk) + if (err) + goto fail; + +- data->nat_bitmap = nat_bitmap_ptr (data); ++ data->nat_bitmap = nat_bitmap_ptr (data, &data->nat_bitmap_size); ++ if (data->nat_bitmap == NULL) ++ goto fail; + + err = get_nat_journal (data); + if (err) diff --git a/debian/patches/0089-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch b/debian/patches/0089-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch new file mode 100644 index 0000000..cf71b38 --- /dev/null +++ b/debian/patches/0089-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch @@ -0,0 +1,37 @@ +From 998bd74c11c0e00f69fe2f37a8200381faf51061 Mon Sep 17 00:00:00 2001 +From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com> +Date: Wed, 6 Apr 2022 18:17:43 +0530 +Subject: fs/f2fs: Do not copy file names that are too long + +A corrupt f2fs file system might specify a name length which is greater +than the maximum name length supported by the GRUB f2fs driver. + +We will allocate enough memory to store the overly long name, but there +are only F2FS_NAME_LEN bytes in the source, so we would read past the end +of the source. + +While checking directory entries, do not copy a file name with an invalid +length. + +Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com> +Signed-off-by: Daniel Axtens <dja@axtens.net> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/fs/f2fs.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c +index 8898b235e..df6beb544 100644 +--- a/grub-core/fs/f2fs.c ++++ b/grub-core/fs/f2fs.c +@@ -1003,6 +1003,10 @@ grub_f2fs_check_dentries (struct grub_f2fs_dir_iter_ctx *ctx) + + ftype = ctx->dentry[i].file_type; + name_len = grub_le_to_cpu16 (ctx->dentry[i].name_len); ++ ++ if (name_len >= F2FS_NAME_LEN) ++ return 0; ++ + filename = grub_malloc (name_len + 1); + if (!filename) + return 0; diff --git a/debian/patches/0090-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch b/debian/patches/0090-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch new file mode 100644 index 0000000..d02cbe2 --- /dev/null +++ b/debian/patches/0090-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch @@ -0,0 +1,75 @@ +From 23c785c3e965731ac440f9c150fdfeec6dd433e7 Mon Sep 17 00:00:00 2001 +From: Darren Kenny <darren.kenny@oracle.com> +Date: Tue, 29 Mar 2022 10:49:56 +0000 +Subject: fs/btrfs: Fix several fuzz issues with invalid dir item sizing + +According to the btrfs code in Linux, the structure of a directory item +leaf should be of the form: + + |struct btrfs_dir_item|name|data| + +in GRUB the name len and data len are in the grub_btrfs_dir_item +structure's n and m fields respectively. + +The combined size of the structure, name and data should be less than +the allocated memory, a difference to the Linux kernel's struct +btrfs_dir_item is that the grub_btrfs_dir_item has an extra field for +where the name is stored, so we adjust for that too. + +Signed-off-by: Darren Kenny <darren.kenny@oracle.com> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/fs/btrfs.c | 26 ++++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c +index 63203034d..eb9857d74 100644 +--- a/grub-core/fs/btrfs.c ++++ b/grub-core/fs/btrfs.c +@@ -1961,6 +1961,7 @@ grub_btrfs_dir (grub_device_t device, const char *path, + int r = 0; + grub_uint64_t tree; + grub_uint8_t type; ++ grub_size_t est_size = 0; + + if (!data) + return grub_errno; +@@ -2019,6 +2020,18 @@ grub_btrfs_dir (grub_device_t device, const char *path, + break; + } + ++ if (direl == NULL || ++ grub_add (grub_le_to_cpu16 (direl->n), ++ grub_le_to_cpu16 (direl->m), &est_size) || ++ grub_add (est_size, sizeof (*direl), &est_size) || ++ grub_sub (est_size, sizeof (direl->name), &est_size) || ++ est_size > allocated) ++ { ++ grub_errno = GRUB_ERR_OUT_OF_RANGE; ++ r = -grub_errno; ++ goto out; ++ } ++ + for (cdirel = direl; + (grub_uint8_t *) cdirel - (grub_uint8_t *) direl + < (grub_ssize_t) elemsize; +@@ -2029,6 +2042,19 @@ grub_btrfs_dir (grub_device_t device, const char *path, + char c; + struct grub_btrfs_inode inode; + struct grub_dirhook_info info; ++ ++ if (cdirel == NULL || ++ grub_add (grub_le_to_cpu16 (cdirel->n), ++ grub_le_to_cpu16 (cdirel->m), &est_size) || ++ grub_add (est_size, sizeof (*cdirel), &est_size) || ++ grub_sub (est_size, sizeof (cdirel->name), &est_size) || ++ est_size > allocated) ++ { ++ grub_errno = GRUB_ERR_OUT_OF_RANGE; ++ r = -grub_errno; ++ goto out; ++ } ++ + err = grub_btrfs_read_inode (data, &inode, cdirel->key.object_id, + tree); + grub_memset (&info, 0, sizeof (info)); diff --git a/debian/patches/0091-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch b/debian/patches/0091-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch new file mode 100644 index 0000000..4ae22c9 --- /dev/null +++ b/debian/patches/0091-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch @@ -0,0 +1,133 @@ +From 22976cf1b9864455173e1bfc617bc63f13fbecf7 Mon Sep 17 00:00:00 2001 +From: Darren Kenny <darren.kenny@oracle.com> +Date: Tue, 29 Mar 2022 15:52:46 +0000 +Subject: fs/btrfs: Fix more ASAN and SEGV issues found with fuzzing + +The fuzzer is generating btrfs file systems that have chunks with +invalid combinations of stripes and substripes for the given RAID +configurations. + +After examining the Linux kernel fs/btrfs/tree-checker.c code, it +appears that sub-stripes should only be applied to RAID10, and in that +case there should only ever be 2 of them. + +Similarly, RAID single should only have 1 stripe, and RAID1/1C3/1C4 +should have 2. 3 or 4 stripes respectively, which is what redundancy +corresponds. + +Some of the chunks ended up with a size of 0, which grub_malloc() still +returned memory for and in turn generated ASAN errors later when +accessed. + +While it would be possible to specifically limit the number of stripes, +a more correct test was on the combination of the chunk item, and the +number of stripes by the size of the chunk stripe structure in +comparison to the size of the chunk itself. + +Signed-off-by: Darren Kenny <darren.kenny@oracle.com> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/fs/btrfs.c | 55 ++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 55 insertions(+) + +diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c +index eb9857d74..b3d71cd9e 100644 +--- a/grub-core/fs/btrfs.c ++++ b/grub-core/fs/btrfs.c +@@ -912,6 +912,12 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + return grub_error (GRUB_ERR_BAD_FS, + "couldn't find the chunk descriptor"); + ++ if (!chsize) ++ { ++ grub_dprintf ("btrfs", "zero-size chunk\n"); ++ return grub_error (GRUB_ERR_BAD_FS, ++ "got an invalid zero-size chunk"); ++ } + chunk = grub_malloc (chsize); + if (!chunk) + return grub_errno; +@@ -970,6 +976,16 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + stripe_length = grub_divmod64 (grub_le_to_cpu64 (chunk->size), + nstripes, + NULL); ++ ++ /* For single, there should be exactly 1 stripe. */ ++ if (grub_le_to_cpu16 (chunk->nstripes) != 1) ++ { ++ grub_dprintf ("btrfs", "invalid RAID_SINGLE: nstripes != 1 (%u)\n", ++ grub_le_to_cpu16 (chunk->nstripes)); ++ return grub_error (GRUB_ERR_BAD_FS, ++ "invalid RAID_SINGLE: nstripes != 1 (%u)", ++ grub_le_to_cpu16 (chunk->nstripes)); ++ } + if (stripe_length == 0) + stripe_length = 512; + stripen = grub_divmod64 (off, stripe_length, &stripe_offset); +@@ -989,6 +1005,19 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + stripen = 0; + stripe_offset = off; + csize = grub_le_to_cpu64 (chunk->size) - off; ++ ++ /* ++ * Redundancy, and substripes only apply to RAID10, and there ++ * should be exactly 2 sub-stripes. ++ */ ++ if (grub_le_to_cpu16 (chunk->nstripes) != redundancy) ++ { ++ grub_dprintf ("btrfs", "invalid RAID1: nstripes != %u (%u)\n", ++ redundancy, grub_le_to_cpu16 (chunk->nstripes)); ++ return grub_error (GRUB_ERR_BAD_FS, ++ "invalid RAID1: nstripes != %u (%u)", ++ redundancy, grub_le_to_cpu16 (chunk->nstripes)); ++ } + break; + } + case GRUB_BTRFS_CHUNK_TYPE_RAID0: +@@ -1025,6 +1054,20 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + stripe_offset = low + chunk_stripe_length + * high; + csize = chunk_stripe_length - low; ++ ++ /* ++ * Substripes only apply to RAID10, and there ++ * should be exactly 2 sub-stripes. ++ */ ++ if (grub_le_to_cpu16 (chunk->nsubstripes) != 2) ++ { ++ grub_dprintf ("btrfs", "invalid RAID10: nsubstripes != 2 (%u)", ++ grub_le_to_cpu16 (chunk->nsubstripes)); ++ return grub_error (GRUB_ERR_BAD_FS, ++ "invalid RAID10: nsubstripes != 2 (%u)", ++ grub_le_to_cpu16 (chunk->nsubstripes)); ++ } ++ + break; + } + case GRUB_BTRFS_CHUNK_TYPE_RAID5: +@@ -1124,6 +1167,8 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + + for (j = 0; j < 2; j++) + { ++ grub_size_t est_chunk_alloc = 0; ++ + grub_dprintf ("btrfs", "chunk 0x%" PRIxGRUB_UINT64_T + "+0x%" PRIxGRUB_UINT64_T + " (%d stripes (%d substripes) of %" +@@ -1136,6 +1181,16 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + grub_dprintf ("btrfs", "reading laddr 0x%" PRIxGRUB_UINT64_T "\n", + addr); + ++ if (grub_mul (sizeof (struct grub_btrfs_chunk_stripe), ++ grub_le_to_cpu16 (chunk->nstripes), &est_chunk_alloc) || ++ grub_add (est_chunk_alloc, ++ sizeof (struct grub_btrfs_chunk_item), &est_chunk_alloc) || ++ est_chunk_alloc > chunk->size) ++ { ++ err = GRUB_ERR_BAD_FS; ++ break; ++ } ++ + if (is_raid56) + { + err = btrfs_read_from_chunk (data, chunk, stripen, diff --git a/debian/patches/0092-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch b/debian/patches/0092-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch new file mode 100644 index 0000000..30c2dad --- /dev/null +++ b/debian/patches/0092-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch @@ -0,0 +1,75 @@ +From 589500ad3777d1335c8e5cb139f7c0c6089112a8 Mon Sep 17 00:00:00 2001 +From: Darren Kenny <darren.kenny@oracle.com> +Date: Thu, 7 Apr 2022 15:18:12 +0000 +Subject: fs/btrfs: Fix more fuzz issues related to chunks + +The corpus was generating issues in grub_btrfs_read_logical() when +attempting to iterate over stripe entries in the superblock's +bootmapping. + +In most cases the reason for the failure was that the number of stripes +in chunk->nstripes exceeded the possible space statically allocated in +superblock bootmapping space. Each stripe entry in the bootmapping block +consists of a grub_btrfs_key followed by a grub_btrfs_chunk_stripe. + +Another issue that came up was that while calculating the chunk size, +in an earlier piece of code in that function, depending on the data +provided in the btrfs file system, it would end up calculating a size +that was too small to contain even 1 grub_btrfs_chunk_item, which is +obviously invalid too. + +Signed-off-by: Darren Kenny <darren.kenny@oracle.com> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/fs/btrfs.c | 24 ++++++++++++++++++++++++ + 1 file changed, 24 insertions(+) + +diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c +index b3d71cd9e..54a46b8f8 100644 +--- a/grub-core/fs/btrfs.c ++++ b/grub-core/fs/btrfs.c +@@ -918,6 +918,17 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + return grub_error (GRUB_ERR_BAD_FS, + "got an invalid zero-size chunk"); + } ++ ++ /* ++ * The space being allocated for a chunk should at least be able to ++ * contain one chunk item. ++ */ ++ if (chsize < sizeof (struct grub_btrfs_chunk_item)) ++ { ++ grub_dprintf ("btrfs", "chunk-size too small\n"); ++ return grub_error (GRUB_ERR_BAD_FS, ++ "got an invalid chunk size"); ++ } + chunk = grub_malloc (chsize); + if (!chunk) + return grub_errno; +@@ -1165,6 +1176,13 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + if (csize > (grub_uint64_t) size) + csize = size; + ++ /* ++ * The space for a chunk stripe is limited to the space provide in the super-block's ++ * bootstrap mapping with an initial btrfs key at the start of each chunk. ++ */ ++ grub_size_t avail_stripes = sizeof (data->sblock.bootstrap_mapping) / ++ (sizeof (struct grub_btrfs_key) + sizeof (struct grub_btrfs_chunk_stripe)); ++ + for (j = 0; j < 2; j++) + { + grub_size_t est_chunk_alloc = 0; +@@ -1191,6 +1209,12 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + break; + } + ++ if (grub_le_to_cpu16 (chunk->nstripes) > avail_stripes) ++ { ++ err = GRUB_ERR_BAD_FS; ++ break; ++ } ++ + if (is_raid56) + { + err = btrfs_read_from_chunk (data, chunk, stripen, diff --git a/debian/patches/at_keyboard-module-init.patch b/debian/patches/at_keyboard-module-init.patch new file mode 100644 index 0000000..deb713d --- /dev/null +++ b/debian/patches/at_keyboard-module-init.patch @@ -0,0 +1,44 @@ +From e619f11201a4d93ce36d384221c899f88f7618c9 Mon Sep 17 00:00:00 2001 +From: Jeroen Dekkers <jeroen@dekkers.ch> +Date: Sat, 12 Jan 2019 21:02:18 +0100 +Subject: at_keyboard: initialize keyboard in module init if keyboard is ready + +The change in 0c62a5b2 caused at_keyboard to fail on some +machines. Immediately initializing the keyboard in the module init if +the keyboard is ready makes the problem go away. + +Bug-Debian: https://bugs.debian.org/741464 +Last-Update: 2019-02-09 + +Patch-Name: at_keyboard-module-init.patch +--- + grub-core/term/at_keyboard.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/grub-core/term/at_keyboard.c b/grub-core/term/at_keyboard.c +index 597111077..beb007002 100644 +--- a/grub-core/term/at_keyboard.c ++++ b/grub-core/term/at_keyboard.c +@@ -244,6 +244,14 @@ grub_at_keyboard_getkey (struct grub_term_input *term __attribute__ ((unused))) + return ret; + } + ++static grub_err_t ++grub_keyboard_controller_mod_init (struct grub_term_input *term __attribute__ ((unused))) { ++ if (KEYBOARD_COMMAND_ISREADY (grub_inb (KEYBOARD_REG_STATUS))) ++ grub_keyboard_controller_init (); ++ ++ return GRUB_ERR_NONE; ++} ++ + static void + grub_keyboard_controller_init (void) + { +@@ -314,6 +322,7 @@ grub_at_restore_hw (void) + static struct grub_term_input grub_at_keyboard_term = + { + .name = "at_keyboard", ++ .init = grub_keyboard_controller_mod_init, + .fini = grub_keyboard_controller_fini, + .getkey = grub_at_keyboard_getkey + }; diff --git a/debian/patches/bash-completion-drop-have-checks.patch b/debian/patches/bash-completion-drop-have-checks.patch new file mode 100644 index 0000000..c425471 --- /dev/null +++ b/debian/patches/bash-completion-drop-have-checks.patch @@ -0,0 +1,143 @@ +From c543561137513e37ae17879366ebf4e10348daa2 Mon Sep 17 00:00:00 2001 +From: Colin Watson <cjwatson@debian.org> +Date: Fri, 16 Nov 2018 16:37:02 +0000 +Subject: bash-completion: Drop "have" checks + +These don't work with and aren't needed by dynamically-loaded +completions. + +Bug-Debian: https://bugs.debian.org/912852 +Forwarded: no +Last-Update: 2018-11-16 + +Patch-Name: bash-completion-drop-have-checks.patch +--- + .../bash-completion.d/grub-completion.bash.in | 39 +++++++------------ + 1 file changed, 13 insertions(+), 26 deletions(-) + +diff --git a/util/bash-completion.d/grub-completion.bash.in b/util/bash-completion.d/grub-completion.bash.in +index 44bf135b9..d4235e7ef 100644 +--- a/util/bash-completion.d/grub-completion.bash.in ++++ b/util/bash-completion.d/grub-completion.bash.in +@@ -166,13 +166,11 @@ _grub_set_entry () { + } + + __grub_set_default_program="@grub_set_default@" +-have ${__grub_set_default_program} && \ +- complete -F _grub_set_entry -o filenames ${__grub_set_default_program} ++complete -F _grub_set_entry -o filenames ${__grub_set_default_program} + unset __grub_set_default_program + + __grub_reboot_program="@grub_reboot@" +-have ${__grub_reboot_program} && \ +- complete -F _grub_set_entry -o filenames ${__grub_reboot_program} ++complete -F _grub_set_entry -o filenames ${__grub_reboot_program} + unset __grub_reboot_program + + +@@ -198,8 +196,7 @@ _grub_editenv () { + } + + __grub_editenv_program="@grub_editenv@" +-have ${__grub_editenv_program} && \ +- complete -F _grub_editenv -o filenames ${__grub_editenv_program} ++complete -F _grub_editenv -o filenames ${__grub_editenv_program} + unset __grub_editenv_program + + +@@ -219,8 +216,7 @@ _grub_mkconfig () { + fi + } + __grub_mkconfig_program="@grub_mkconfig@" +-have ${__grub_mkconfig_program} && \ +- complete -F _grub_mkconfig -o filenames ${__grub_mkconfig_program} ++complete -F _grub_mkconfig -o filenames ${__grub_mkconfig_program} + unset __grub_mkconfig_program + + +@@ -254,13 +250,11 @@ _grub_setup () { + } + + __grub_bios_setup_program="@grub_bios_setup@" +-have ${__grub_bios_setup_program} && \ +- complete -F _grub_setup -o filenames ${__grub_bios_setup_program} ++complete -F _grub_setup -o filenames ${__grub_bios_setup_program} + unset __grub_bios_setup_program + + __grub_sparc64_setup_program="@grub_sparc64_setup@" +-have ${__grub_sparc64_setup_program} && \ +- complete -F _grub_setup -o filenames ${__grub_sparc64_setup_program} ++complete -F _grub_setup -o filenames ${__grub_sparc64_setup_program} + unset __grub_sparc64_setup_program + + +@@ -305,8 +299,7 @@ _grub_install () { + fi + } + __grub_install_program="@grub_install@" +-have ${__grub_install_program} && \ +- complete -F _grub_install -o filenames ${__grub_install_program} ++complete -F _grub_install -o filenames ${__grub_install_program} + unset __grub_install_program + + +@@ -327,8 +320,7 @@ _grub_mkfont () { + fi + } + __grub_mkfont_program="@grub_mkfont@" +-have ${__grub_mkfont_program} && \ +- complete -F _grub_mkfont -o filenames ${__grub_mkfont_program} ++complete -F _grub_mkfont -o filenames ${__grub_mkfont_program} + unset __grub_mkfont_program + + +@@ -358,8 +350,7 @@ _grub_mkrescue () { + fi + } + __grub_mkrescue_program="@grub_mkrescue@" +-have ${__grub_mkrescue_program} && \ +- complete -F _grub_mkrescue -o filenames ${__grub_mkrescue_program} ++complete -F _grub_mkrescue -o filenames ${__grub_mkrescue_program} + unset __grub_mkrescue_program + + +@@ -400,8 +391,7 @@ _grub_mkimage () { + fi + } + __grub_mkimage_program="@grub_mkimage@" +-have ${__grub_mkimage_program} && \ +- complete -F _grub_mkimage -o filenames ${__grub_mkimage_program} ++complete -F _grub_mkimage -o filenames ${__grub_mkimage_program} + unset __grub_mkimage_program + + +@@ -422,8 +412,7 @@ _grub_mkpasswd_pbkdf2 () { + fi + } + __grub_mkpasswd_pbkdf2_program="@grub_mkpasswd_pbkdf2@" +-have ${__grub_mkpasswd_pbkdf2_program} && \ +- complete -F _grub_mkpasswd_pbkdf2 -o filenames ${__grub_mkpasswd_pbkdf2_program} ++complete -F _grub_mkpasswd_pbkdf2 -o filenames ${__grub_mkpasswd_pbkdf2_program} + unset __grub_mkpasswd_pbkdf2_program + + +@@ -460,8 +449,7 @@ _grub_probe () { + fi + } + __grub_probe_program="@grub_probe@" +-have ${__grub_probe_program} && \ +- complete -F _grub_probe -o filenames ${__grub_probe_program} ++complete -F _grub_probe -o filenames ${__grub_probe_program} + unset __grub_probe_program + + +@@ -482,8 +470,7 @@ _grub_script_check () { + fi + } + __grub_script_check_program="@grub_script_check@" +-have ${__grub_script_check_program} && \ +- complete -F _grub_script_check -o filenames ${__grub_script_check_program} ++complete -F _grub_script_check -o filenames ${__grub_script_check_program} + + + # Local variables: diff --git a/debian/patches/blacklist-1440x900x32.patch b/debian/patches/blacklist-1440x900x32.patch new file mode 100644 index 0000000..e19fc08 --- /dev/null +++ b/debian/patches/blacklist-1440x900x32.patch @@ -0,0 +1,34 @@ +From ee6cee995e403b3fa81798cddb5247be6de3205b Mon Sep 17 00:00:00 2001 +From: Colin Watson <cjwatson@ubuntu.com> +Date: Mon, 13 Jan 2014 12:13:11 +0000 +Subject: Blacklist 1440x900x32 from VBE preferred mode handling + +Bug-Ubuntu: https://bugs.launchpad.net/bugs/701111 +Forwarded: no +Last-Update: 2013-11-14 + +Patch-Name: blacklist-1440x900x32.patch +--- + grub-core/video/i386/pc/vbe.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/grub-core/video/i386/pc/vbe.c b/grub-core/video/i386/pc/vbe.c +index b7f911926..4b1bd7d5e 100644 +--- a/grub-core/video/i386/pc/vbe.c ++++ b/grub-core/video/i386/pc/vbe.c +@@ -1054,6 +1054,15 @@ grub_video_vbe_setup (unsigned int width, unsigned int height, + || vbe_mode_info.y_resolution > height) + /* Resolution exceeds that of preferred mode. */ + continue; ++ ++ /* Blacklist 1440x900x32 from preferred mode handling until a ++ better solution is available. This mode causes problems on ++ many Thinkpads. See: ++ https://bugs.launchpad.net/ubuntu/+source/grub2/+bug/701111 */ ++ if (vbe_mode_info.x_resolution == 1440 && ++ vbe_mode_info.y_resolution == 900 && ++ vbe_mode_info.bits_per_pixel == 32) ++ continue; + } + else + { diff --git a/debian/patches/bootp-new-net_bootp6-command.patch b/debian/patches/bootp-new-net_bootp6-command.patch new file mode 100644 index 0000000..775213a --- /dev/null +++ b/debian/patches/bootp-new-net_bootp6-command.patch @@ -0,0 +1,1119 @@ +From 2ce72d9b58e2166f47603851fb9b66acb314cca1 Mon Sep 17 00:00:00 2001 +From: Michael Chang <mchang@suse.com> +Date: Thu, 27 Oct 2016 17:41:04 -0400 +Subject: bootp: New net_bootp6 command + +Implement new net_bootp6 command for IPv6 network auto configuration via the +DHCPv6 protocol (RFC3315). + +Signed-off-by: Michael Chang <mchang@suse.com> +Signed-off-by: Ken Lin <ken.lin@hpe.com> + +Last-Update: 2021-09-24 + +Patch-Name: bootp-new-net_bootp6-command.patch +--- + grub-core/net/bootp.c | 908 +++++++++++++++++++++++++++++++++++++++++- + grub-core/net/ip.c | 39 ++ + include/grub/net.h | 72 ++++ + 3 files changed, 1018 insertions(+), 1 deletion(-) + +diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c +index 6fb562702..00c11af39 100644 +--- a/grub-core/net/bootp.c ++++ b/grub-core/net/bootp.c +@@ -24,6 +24,98 @@ + #include <grub/net/netbuff.h> + #include <grub/net/udp.h> + #include <grub/datetime.h> ++#include <grub/time.h> ++#include <grub/list.h> ++ ++static int ++dissect_url (const char *url, char **proto, char **host, char **path) ++{ ++ const char *p, *ps; ++ grub_size_t l; ++ ++ *proto = *host = *path = NULL; ++ ps = p = url; ++ ++ while ((p = grub_strchr (p, ':'))) ++ { ++ if (grub_strlen (p) < sizeof ("://") - 1) ++ break; ++ if (grub_memcmp (p, "://", sizeof ("://") - 1) == 0) ++ { ++ l = p - ps; ++ *proto = grub_malloc (l + 1); ++ if (!*proto) ++ { ++ grub_print_error (); ++ return 0; ++ } ++ ++ grub_memcpy (*proto, ps, l); ++ (*proto)[l] = '\0'; ++ p += sizeof ("://") - 1; ++ break; ++ } ++ ++p; ++ } ++ ++ if (!*proto) ++ { ++ grub_dprintf ("bootp", "url: %s is not valid, protocol not found\n", url); ++ return 0; ++ } ++ ++ ps = p; ++ p = grub_strchr (p, '/'); ++ ++ if (!p) ++ { ++ grub_dprintf ("bootp", "url: %s is not valid, host/path not found\n", url); ++ grub_free (*proto); ++ *proto = NULL; ++ return 0; ++ } ++ ++ l = p - ps; ++ ++ if (l > 2 && ps[0] == '[' && ps[l - 1] == ']') ++ { ++ *host = grub_malloc (l - 1); ++ if (!*host) ++ { ++ grub_print_error (); ++ grub_free (*proto); ++ *proto = NULL; ++ return 0; ++ } ++ grub_memcpy (*host, ps + 1, l - 2); ++ (*host)[l - 2] = 0; ++ } ++ else ++ { ++ *host = grub_malloc (l + 1); ++ if (!*host) ++ { ++ grub_print_error (); ++ grub_free (*proto); ++ *proto = NULL; ++ return 0; ++ } ++ grub_memcpy (*host, ps, l); ++ (*host)[l] = 0; ++ } ++ ++ *path = grub_strdup (p); ++ if (!*path) ++ { ++ grub_print_error (); ++ grub_free (*host); ++ grub_free (*proto); ++ *host = NULL; ++ *proto = NULL; ++ return 0; ++ } ++ return 1; ++} + + struct grub_dhcp_discover_options + { +@@ -607,6 +699,578 @@ out: + return err; + } + ++/* The default netbuff size for sending DHCPv6 packets which should be ++ large enough to hold the information */ ++#define GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE 512 ++ ++struct grub_dhcp6_options ++{ ++ grub_uint8_t *client_duid; ++ grub_uint16_t client_duid_len; ++ grub_uint8_t *server_duid; ++ grub_uint16_t server_duid_len; ++ grub_uint32_t iaid; ++ grub_uint32_t t1; ++ grub_uint32_t t2; ++ grub_net_network_level_address_t *ia_addr; ++ grub_uint32_t preferred_lifetime; ++ grub_uint32_t valid_lifetime; ++ grub_net_network_level_address_t *dns_server_addrs; ++ grub_uint16_t num_dns_server; ++ char *boot_file_proto; ++ char *boot_file_server_ip; ++ char *boot_file_path; ++}; ++ ++typedef struct grub_dhcp6_options *grub_dhcp6_options_t; ++ ++struct grub_dhcp6_session ++{ ++ struct grub_dhcp6_session *next; ++ struct grub_dhcp6_session **prev; ++ grub_uint32_t iaid; ++ grub_uint32_t transaction_id:24; ++ grub_uint64_t start_time; ++ struct grub_net_dhcp6_option_duid_ll duid; ++ struct grub_net_network_level_interface *iface; ++ ++ /* The associated dhcpv6 options */ ++ grub_dhcp6_options_t adv; ++ grub_dhcp6_options_t reply; ++}; ++ ++typedef struct grub_dhcp6_session *grub_dhcp6_session_t; ++ ++typedef void (*dhcp6_option_hook_fn) (const struct grub_net_dhcp6_option *opt, void *data); ++ ++static void ++foreach_dhcp6_option (const struct grub_net_dhcp6_option *opt, grub_size_t size, ++ dhcp6_option_hook_fn hook, void *hook_data); ++ ++static void ++parse_dhcp6_iaaddr (const struct grub_net_dhcp6_option *opt, void *data) ++{ ++ grub_dhcp6_options_t dhcp6 = (grub_dhcp6_options_t )data; ++ ++ grub_uint16_t code = grub_be_to_cpu16 (opt->code); ++ grub_uint16_t len = grub_be_to_cpu16 (opt->len); ++ ++ if (code == GRUB_NET_DHCP6_OPTION_IAADDR) ++ { ++ const struct grub_net_dhcp6_option_iaaddr *iaaddr; ++ iaaddr = (const struct grub_net_dhcp6_option_iaaddr *)opt->data; ++ ++ if (len < sizeof (*iaaddr)) ++ { ++ grub_dprintf ("bootp", "DHCPv6: code %u with insufficient length %u\n", code, len); ++ return; ++ } ++ if (!dhcp6->ia_addr) ++ { ++ dhcp6->ia_addr = grub_malloc (sizeof(*dhcp6->ia_addr)); ++ dhcp6->ia_addr->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; ++ dhcp6->ia_addr->ipv6[0] = grub_get_unaligned64 (iaaddr->addr); ++ dhcp6->ia_addr->ipv6[1] = grub_get_unaligned64 (iaaddr->addr + 8); ++ dhcp6->preferred_lifetime = grub_be_to_cpu32 (iaaddr->preferred_lifetime); ++ dhcp6->valid_lifetime = grub_be_to_cpu32 (iaaddr->valid_lifetime); ++ } ++ } ++} ++ ++static void ++parse_dhcp6_option (const struct grub_net_dhcp6_option *opt, void *data) ++{ ++ grub_dhcp6_options_t dhcp6 = (grub_dhcp6_options_t)data; ++ grub_uint16_t code = grub_be_to_cpu16 (opt->code); ++ grub_uint16_t len = grub_be_to_cpu16 (opt->len); ++ ++ switch (code) ++ { ++ case GRUB_NET_DHCP6_OPTION_CLIENTID: ++ ++ if (dhcp6->client_duid || !len) ++ { ++ grub_dprintf ("bootp", "Skipped DHCPv6 CLIENTID with length %u\n", len); ++ break; ++ } ++ dhcp6->client_duid = grub_malloc (len); ++ grub_memcpy (dhcp6->client_duid, opt->data, len); ++ dhcp6->client_duid_len = len; ++ break; ++ ++ case GRUB_NET_DHCP6_OPTION_SERVERID: ++ ++ if (dhcp6->server_duid || !len) ++ { ++ grub_dprintf ("bootp", "Skipped DHCPv6 SERVERID with length %u\n", len); ++ break; ++ } ++ dhcp6->server_duid = grub_malloc (len); ++ grub_memcpy (dhcp6->server_duid, opt->data, len); ++ dhcp6->server_duid_len = len; ++ break; ++ ++ case GRUB_NET_DHCP6_OPTION_IA_NA: ++ { ++ const struct grub_net_dhcp6_option_iana *ia_na; ++ grub_uint16_t data_len; ++ ++ if (dhcp6->iaid || len < sizeof (*ia_na)) ++ { ++ grub_dprintf ("bootp", "Skipped DHCPv6 IA_NA with length %u\n", len); ++ break; ++ } ++ ia_na = (const struct grub_net_dhcp6_option_iana *)opt->data; ++ dhcp6->iaid = grub_be_to_cpu32 (ia_na->iaid); ++ dhcp6->t1 = grub_be_to_cpu32 (ia_na->t1); ++ dhcp6->t2 = grub_be_to_cpu32 (ia_na->t2); ++ ++ data_len = len - sizeof (*ia_na); ++ if (data_len) ++ foreach_dhcp6_option ((const struct grub_net_dhcp6_option *)ia_na->data, data_len, parse_dhcp6_iaaddr, dhcp6); ++ } ++ break; ++ ++ case GRUB_NET_DHCP6_OPTION_DNS_SERVERS: ++ { ++ const grub_uint8_t *po; ++ grub_uint16_t ln; ++ grub_net_network_level_address_t *la; ++ ++ if (!len || len & 0xf) ++ { ++ grub_dprintf ("bootp", "Skip invalid length DHCPv6 DNS_SERVERS \n"); ++ break; ++ } ++ dhcp6->num_dns_server = ln = len >> 4; ++ dhcp6->dns_server_addrs = la = grub_calloc (ln, sizeof (*la)); ++ ++ for (po = opt->data; ln > 0; po += 0x10, la++, ln--) ++ { ++ la->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; ++ la->ipv6[0] = grub_get_unaligned64 (po); ++ la->ipv6[1] = grub_get_unaligned64 (po + 8); ++ la->option = DNS_OPTION_PREFER_IPV6; ++ } ++ } ++ break; ++ ++ case GRUB_NET_DHCP6_OPTION_BOOTFILE_URL: ++ dissect_url ((const char *)opt->data, ++ &dhcp6->boot_file_proto, ++ &dhcp6->boot_file_server_ip, ++ &dhcp6->boot_file_path); ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++static void ++foreach_dhcp6_option (const struct grub_net_dhcp6_option *opt, grub_size_t size, dhcp6_option_hook_fn hook, void *hook_data) ++{ ++ while (size) ++ { ++ grub_uint16_t code, len; ++ ++ if (size < sizeof (*opt)) ++ { ++ grub_dprintf ("bootp", "DHCPv6: Options stopped with remaining size %" PRIxGRUB_SIZE "\n", size); ++ break; ++ } ++ size -= sizeof (*opt); ++ len = grub_be_to_cpu16 (opt->len); ++ code = grub_be_to_cpu16 (opt->code); ++ if (size < len) ++ { ++ grub_dprintf ("bootp", "DHCPv6: Options stopped at out of bound length %u for option %u\n", len, code); ++ break; ++ } ++ if (!len) ++ { ++ grub_dprintf ("bootp", "DHCPv6: Options stopped at zero length option %u\n", code); ++ break; ++ } ++ else ++ { ++ if (hook) ++ hook (opt, hook_data); ++ size -= len; ++ opt = (const struct grub_net_dhcp6_option *)((grub_uint8_t *)opt + len + sizeof (*opt)); ++ } ++ } ++} ++ ++static grub_dhcp6_options_t ++grub_dhcp6_options_get (const struct grub_net_dhcp6_packet *v6h, ++ grub_size_t size) ++{ ++ grub_dhcp6_options_t options; ++ ++ if (size < sizeof (*v6h)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("DHCPv6 packet size too small")); ++ return NULL; ++ } ++ ++ options = grub_zalloc (sizeof(*options)); ++ if (!options) ++ return NULL; ++ ++ foreach_dhcp6_option ((const struct grub_net_dhcp6_option *)v6h->dhcp_options, ++ size - sizeof (*v6h), parse_dhcp6_option, options); ++ ++ return options; ++} ++ ++static void ++grub_dhcp6_options_free (grub_dhcp6_options_t options) ++{ ++ if (options->client_duid) ++ grub_free (options->client_duid); ++ if (options->server_duid) ++ grub_free (options->server_duid); ++ if (options->ia_addr) ++ grub_free (options->ia_addr); ++ if (options->dns_server_addrs) ++ grub_free (options->dns_server_addrs); ++ if (options->boot_file_proto) ++ grub_free (options->boot_file_proto); ++ if (options->boot_file_server_ip) ++ grub_free (options->boot_file_server_ip); ++ if (options->boot_file_path) ++ grub_free (options->boot_file_path); ++ ++ grub_free (options); ++} ++ ++static grub_dhcp6_session_t grub_dhcp6_sessions; ++#define FOR_DHCP6_SESSIONS(var) FOR_LIST_ELEMENTS (var, grub_dhcp6_sessions) ++ ++static void ++grub_net_configure_by_dhcp6_info (const char *name, ++ struct grub_net_card *card, ++ grub_dhcp6_options_t dhcp6, ++ int is_def, ++ int flags, ++ struct grub_net_network_level_interface **ret_inf) ++{ ++ grub_net_network_level_netaddress_t netaddr; ++ struct grub_net_network_level_interface *inf; ++ ++ if (dhcp6->ia_addr) ++ { ++ inf = grub_net_add_addr (name, card, dhcp6->ia_addr, &card->default_address, flags); ++ ++ netaddr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; ++ netaddr.ipv6.base[0] = dhcp6->ia_addr->ipv6[0]; ++ netaddr.ipv6.base[1] = 0; ++ netaddr.ipv6.masksize = 64; ++ grub_net_add_route (name, netaddr, inf); ++ ++ if (ret_inf) ++ *ret_inf = inf; ++ } ++ ++ if (dhcp6->dns_server_addrs) ++ { ++ grub_uint16_t i; ++ ++ for (i = 0; i < dhcp6->num_dns_server; ++i) ++ grub_net_add_dns_server (dhcp6->dns_server_addrs + i); ++ } ++ ++ if (dhcp6->boot_file_path) ++ grub_env_set_net_property (name, "boot_file", dhcp6->boot_file_path, ++ grub_strlen (dhcp6->boot_file_path)); ++ ++ if (is_def && dhcp6->boot_file_server_ip) ++ { ++ grub_net_default_server = grub_strdup (dhcp6->boot_file_server_ip); ++ grub_env_set ("net_default_interface", name); ++ grub_env_export ("net_default_interface"); ++ } ++} ++ ++static void ++grub_dhcp6_session_add (struct grub_net_network_level_interface *iface, ++ grub_uint32_t iaid) ++{ ++ grub_dhcp6_session_t se; ++ struct grub_datetime date; ++ grub_err_t err; ++ grub_int64_t t = 0; ++ ++ se = grub_malloc (sizeof (*se)); ++ ++ err = grub_get_datetime (&date); ++ if (err || !grub_datetime2unixtime (&date, &t)) ++ { ++ grub_errno = GRUB_ERR_NONE; ++ t = 0; ++ } ++ ++ se->iface = iface; ++ se->iaid = iaid; ++ se->transaction_id = t; ++ se->start_time = grub_get_time_ms (); ++ se->duid.type = grub_cpu_to_be16_compile_time (3) ; ++ se->duid.hw_type = grub_cpu_to_be16_compile_time (1); ++ grub_memcpy (&se->duid.hwaddr, &iface->hwaddress.mac, sizeof (se->duid.hwaddr)); ++ se->adv = NULL; ++ se->reply = NULL; ++ grub_list_push (GRUB_AS_LIST_P (&grub_dhcp6_sessions), GRUB_AS_LIST (se)); ++} ++ ++static void ++grub_dhcp6_session_remove (grub_dhcp6_session_t se) ++{ ++ grub_list_remove (GRUB_AS_LIST (se)); ++ if (se->adv) ++ grub_dhcp6_options_free (se->adv); ++ if (se->reply) ++ grub_dhcp6_options_free (se->reply); ++ grub_free (se); ++} ++ ++static void ++grub_dhcp6_session_remove_all (void) ++{ ++ grub_dhcp6_session_t se; ++ ++ FOR_DHCP6_SESSIONS (se) ++ { ++ grub_dhcp6_session_remove (se); ++ se = grub_dhcp6_sessions; ++ } ++} ++ ++static grub_err_t ++grub_dhcp6_session_configure_network (grub_dhcp6_session_t se) ++{ ++ char *name; ++ ++ name = grub_xasprintf ("%s:dhcp6", se->iface->card->name); ++ if (!name) ++ return grub_errno; ++ ++ grub_net_configure_by_dhcp6_info (name, se->iface->card, se->reply, 1, 0, 0); ++ grub_free (name); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_dhcp6_session_send_request (grub_dhcp6_session_t se) ++{ ++ struct grub_net_buff *nb; ++ struct grub_net_dhcp6_option *opt; ++ struct grub_net_dhcp6_packet *v6h; ++ struct grub_net_dhcp6_option_iana *ia_na; ++ struct grub_net_dhcp6_option_iaaddr *iaaddr; ++ struct udphdr *udph; ++ grub_net_network_level_address_t multicast; ++ grub_net_link_level_address_t ll_multicast; ++ grub_uint64_t elapsed; ++ struct grub_net_network_level_interface *inf = se->iface; ++ grub_dhcp6_options_t dhcp6 = se->adv; ++ grub_err_t err = GRUB_ERR_NONE; ++ ++ multicast.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; ++ multicast.ipv6[0] = grub_cpu_to_be64_compile_time (0xff02ULL << 48); ++ multicast.ipv6[1] = grub_cpu_to_be64_compile_time (0x10002ULL); ++ ++ err = grub_net_link_layer_resolve (inf, &multicast, &ll_multicast); ++ if (err) ++ return err; ++ ++ nb = grub_netbuff_alloc (GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE); ++ ++ if (!nb) ++ return grub_errno; ++ ++ err = grub_netbuff_reserve (nb, GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ err = grub_netbuff_push (nb, dhcp6->client_duid_len + sizeof (*opt)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ opt = (struct grub_net_dhcp6_option *)nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_CLIENTID); ++ opt->len = grub_cpu_to_be16 (dhcp6->client_duid_len); ++ grub_memcpy (opt->data, dhcp6->client_duid , dhcp6->client_duid_len); ++ ++ err = grub_netbuff_push (nb, dhcp6->server_duid_len + sizeof (*opt)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ opt = (struct grub_net_dhcp6_option *)nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_SERVERID); ++ opt->len = grub_cpu_to_be16 (dhcp6->server_duid_len); ++ grub_memcpy (opt->data, dhcp6->server_duid , dhcp6->server_duid_len); ++ ++ err = grub_netbuff_push (nb, sizeof (*ia_na) + sizeof (*opt)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ if (dhcp6->ia_addr) ++ { ++ err = grub_netbuff_push (nb, sizeof(*iaaddr) + sizeof (*opt)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ } ++ opt = (struct grub_net_dhcp6_option *)nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IA_NA); ++ opt->len = grub_cpu_to_be16 (sizeof (*ia_na)); ++ if (dhcp6->ia_addr) ++ opt->len += grub_cpu_to_be16 (sizeof(*iaaddr) + sizeof (*opt)); ++ ++ ia_na = (struct grub_net_dhcp6_option_iana *)opt->data; ++ ia_na->iaid = grub_cpu_to_be32 (dhcp6->iaid); ++ ++ ia_na->t1 = grub_cpu_to_be32 (dhcp6->t1); ++ ia_na->t2 = grub_cpu_to_be32 (dhcp6->t2); ++ ++ if (dhcp6->ia_addr) ++ { ++ opt = (struct grub_net_dhcp6_option *)ia_na->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IAADDR); ++ opt->len = grub_cpu_to_be16 (sizeof (*iaaddr)); ++ iaaddr = (struct grub_net_dhcp6_option_iaaddr *)opt->data; ++ grub_set_unaligned64 (iaaddr->addr, dhcp6->ia_addr->ipv6[0]); ++ grub_set_unaligned64 (iaaddr->addr + 8, dhcp6->ia_addr->ipv6[1]); ++ ++ iaaddr->preferred_lifetime = grub_cpu_to_be32 (dhcp6->preferred_lifetime); ++ iaaddr->valid_lifetime = grub_cpu_to_be32 (dhcp6->valid_lifetime); ++ } ++ ++ err = grub_netbuff_push (nb, sizeof (*opt) + 2 * sizeof (grub_uint16_t)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ opt = (struct grub_net_dhcp6_option*) nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_ORO); ++ opt->len = grub_cpu_to_be16_compile_time (2 * sizeof (grub_uint16_t)); ++ grub_set_unaligned16 (opt->data, grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_BOOTFILE_URL)); ++ grub_set_unaligned16 (opt->data + 2, grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_DNS_SERVERS)); ++ ++ err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (grub_uint16_t)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ opt = (struct grub_net_dhcp6_option*) nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_ELAPSED_TIME); ++ opt->len = grub_cpu_to_be16_compile_time (sizeof (grub_uint16_t)); ++ ++ /* the time is expressed in hundredths of a second */ ++ elapsed = grub_divmod64 (grub_get_time_ms () - se->start_time, 10, 0); ++ ++ if (elapsed > 0xffff) ++ elapsed = 0xffff; ++ ++ grub_set_unaligned16 (opt->data, grub_cpu_to_be16 ((grub_uint16_t)elapsed)); ++ ++ err = grub_netbuff_push (nb, sizeof (*v6h)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ v6h = (struct grub_net_dhcp6_packet *) nb->data; ++ v6h->message_type = GRUB_NET_DHCP6_REQUEST; ++ v6h->transaction_id = se->transaction_id; ++ ++ err = grub_netbuff_push (nb, sizeof (*udph)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ udph = (struct udphdr *) nb->data; ++ udph->src = grub_cpu_to_be16_compile_time (DHCP6_CLIENT_PORT); ++ udph->dst = grub_cpu_to_be16_compile_time (DHCP6_SERVER_PORT); ++ udph->chksum = 0; ++ udph->len = grub_cpu_to_be16 (nb->tail - nb->data); ++ ++ udph->chksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_UDP, ++ &inf->address, ++ &multicast); ++ err = grub_net_send_ip_packet (inf, &multicast, &ll_multicast, nb, ++ GRUB_NET_IP_UDP); ++ ++ grub_netbuff_free (nb); ++ ++ return err; ++} ++ ++struct grub_net_network_level_interface * ++grub_net_configure_by_dhcpv6_reply (const char *name, ++ struct grub_net_card *card, ++ grub_net_interface_flags_t flags, ++ const struct grub_net_dhcp6_packet *v6h, ++ grub_size_t size, ++ int is_def, ++ char **device, char **path) ++{ ++ struct grub_net_network_level_interface *inf; ++ grub_dhcp6_options_t dhcp6; ++ ++ dhcp6 = grub_dhcp6_options_get (v6h, size); ++ if (!dhcp6) ++ { ++ grub_print_error (); ++ return NULL; ++ } ++ ++ grub_net_configure_by_dhcp6_info (name, card, dhcp6, is_def, flags, &inf); ++ ++ if (device && dhcp6->boot_file_proto && dhcp6->boot_file_server_ip) ++ { ++ *device = grub_xasprintf ("%s,%s", dhcp6->boot_file_proto, dhcp6->boot_file_server_ip); ++ grub_print_error (); ++ } ++ if (path && dhcp6->boot_file_path) ++ { ++ *path = grub_strdup (dhcp6->boot_file_path); ++ grub_print_error (); ++ if (*path) ++ { ++ char *slash; ++ slash = grub_strrchr (*path, '/'); ++ if (slash) ++ *slash = 0; ++ else ++ **path = 0; ++ } ++ } ++ ++ grub_dhcp6_options_free (dhcp6); ++ return inf; ++} ++ + /* + * This is called directly from net/ip.c:handle_dgram(), because those + * BOOTP/DHCP packets are a bit special due to their improper +@@ -675,6 +1339,77 @@ grub_net_process_dhcp (struct grub_net_buff *nb, + } + } + ++grub_err_t ++grub_net_process_dhcp6 (struct grub_net_buff *nb, ++ struct grub_net_card *card __attribute__ ((unused))) ++{ ++ const struct grub_net_dhcp6_packet *v6h; ++ grub_dhcp6_session_t se; ++ grub_size_t size; ++ grub_dhcp6_options_t options; ++ ++ v6h = (const struct grub_net_dhcp6_packet *) nb->data; ++ size = nb->tail - nb->data; ++ ++ options = grub_dhcp6_options_get (v6h, size); ++ if (!options) ++ return grub_errno; ++ ++ if (!options->client_duid || !options->server_duid || !options->ia_addr) ++ { ++ grub_dhcp6_options_free (options); ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Bad DHCPv6 Packet"); ++ } ++ ++ FOR_DHCP6_SESSIONS (se) ++ { ++ if (se->transaction_id == v6h->transaction_id && ++ grub_memcmp (options->client_duid, &se->duid, sizeof (se->duid)) == 0 && ++ se->iaid == options->iaid) ++ break; ++ } ++ ++ if (!se) ++ { ++ grub_dprintf ("bootp", "DHCPv6 session not found\n"); ++ grub_dhcp6_options_free (options); ++ return GRUB_ERR_NONE; ++ } ++ ++ if (v6h->message_type == GRUB_NET_DHCP6_ADVERTISE) ++ { ++ if (se->adv) ++ { ++ grub_dprintf ("bootp", "Skipped DHCPv6 Advertised .. \n"); ++ grub_dhcp6_options_free (options); ++ return GRUB_ERR_NONE; ++ } ++ ++ se->adv = options; ++ return grub_dhcp6_session_send_request (se); ++ } ++ else if (v6h->message_type == GRUB_NET_DHCP6_REPLY) ++ { ++ if (!se->adv) ++ { ++ grub_dprintf ("bootp", "Skipped DHCPv6 Reply .. \n"); ++ grub_dhcp6_options_free (options); ++ return GRUB_ERR_NONE; ++ } ++ ++ se->reply = options; ++ grub_dhcp6_session_configure_network (se); ++ grub_dhcp6_session_remove (se); ++ return GRUB_ERR_NONE; ++ } ++ else ++ { ++ grub_dhcp6_options_free (options); ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ + static grub_err_t + grub_cmd_dhcpopt (struct grub_command *cmd __attribute__ ((unused)), + int argc, char **args) +@@ -900,7 +1635,174 @@ grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)), + return err; + } + +-static grub_command_t cmd_getdhcp, cmd_bootp, cmd_dhcp; ++static grub_err_t ++grub_cmd_bootp6 (struct grub_command *cmd __attribute__ ((unused)), ++ int argc, char **args) ++{ ++ struct grub_net_card *card; ++ grub_uint32_t iaid = 0; ++ int interval; ++ grub_err_t err; ++ grub_dhcp6_session_t se; ++ ++ err = GRUB_ERR_NONE; ++ ++ FOR_NET_CARDS (card) ++ { ++ struct grub_net_network_level_interface *iface; ++ ++ if (argc > 0 && grub_strcmp (card->name, args[0]) != 0) ++ continue; ++ ++ iface = grub_net_ipv6_get_link_local (card, &card->default_address); ++ if (!iface) ++ { ++ grub_dhcp6_session_remove_all (); ++ return grub_errno; ++ } ++ ++ grub_dhcp6_session_add (iface, iaid++); ++ } ++ ++ for (interval = 200; interval < 10000; interval *= 2) ++ { ++ int done = 1; ++ ++ FOR_DHCP6_SESSIONS (se) ++ { ++ struct grub_net_buff *nb; ++ struct grub_net_dhcp6_option *opt; ++ struct grub_net_dhcp6_packet *v6h; ++ struct grub_net_dhcp6_option_duid_ll *duid; ++ struct grub_net_dhcp6_option_iana *ia_na; ++ grub_net_network_level_address_t multicast; ++ grub_net_link_level_address_t ll_multicast; ++ struct udphdr *udph; ++ ++ multicast.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; ++ multicast.ipv6[0] = grub_cpu_to_be64_compile_time (0xff02ULL << 48); ++ multicast.ipv6[1] = grub_cpu_to_be64_compile_time (0x10002ULL); ++ ++ err = grub_net_link_layer_resolve (se->iface, ++ &multicast, &ll_multicast); ++ if (err) ++ { ++ grub_dhcp6_session_remove_all (); ++ return err; ++ } ++ ++ nb = grub_netbuff_alloc (GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE); ++ ++ if (!nb) ++ { ++ grub_dhcp6_session_remove_all (); ++ return grub_errno; ++ } ++ ++ err = grub_netbuff_reserve (nb, GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE); ++ if (err) ++ { ++ grub_dhcp6_session_remove_all (); ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (grub_uint16_t)); ++ if (err) ++ { ++ grub_dhcp6_session_remove_all (); ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ opt = (struct grub_net_dhcp6_option *)nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_ELAPSED_TIME); ++ opt->len = grub_cpu_to_be16_compile_time (sizeof (grub_uint16_t)); ++ grub_set_unaligned16 (opt->data, 0); ++ ++ err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (*duid)); ++ if (err) ++ { ++ grub_dhcp6_session_remove_all (); ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ opt = (struct grub_net_dhcp6_option *)nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_CLIENTID); ++ opt->len = grub_cpu_to_be16 (sizeof (*duid)); ++ ++ duid = (struct grub_net_dhcp6_option_duid_ll *) opt->data; ++ grub_memcpy (duid, &se->duid, sizeof (*duid)); ++ ++ err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (*ia_na)); ++ if (err) ++ { ++ grub_dhcp6_session_remove_all (); ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ opt = (struct grub_net_dhcp6_option *)nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IA_NA); ++ opt->len = grub_cpu_to_be16 (sizeof (*ia_na)); ++ ia_na = (struct grub_net_dhcp6_option_iana *)opt->data; ++ ia_na->iaid = grub_cpu_to_be32 (se->iaid); ++ ia_na->t1 = 0; ++ ia_na->t2 = 0; ++ ++ err = grub_netbuff_push (nb, sizeof (*v6h)); ++ if (err) ++ { ++ grub_dhcp6_session_remove_all (); ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ v6h = (struct grub_net_dhcp6_packet *)nb->data; ++ v6h->message_type = GRUB_NET_DHCP6_SOLICIT; ++ v6h->transaction_id = se->transaction_id; ++ ++ grub_netbuff_push (nb, sizeof (*udph)); ++ ++ udph = (struct udphdr *) nb->data; ++ udph->src = grub_cpu_to_be16_compile_time (DHCP6_CLIENT_PORT); ++ udph->dst = grub_cpu_to_be16_compile_time (DHCP6_SERVER_PORT); ++ udph->chksum = 0; ++ udph->len = grub_cpu_to_be16 (nb->tail - nb->data); ++ ++ udph->chksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_UDP, ++ &se->iface->address, &multicast); ++ ++ err = grub_net_send_ip_packet (se->iface, &multicast, ++ &ll_multicast, nb, GRUB_NET_IP_UDP); ++ done = 0; ++ grub_netbuff_free (nb); ++ ++ if (err) ++ { ++ grub_dhcp6_session_remove_all (); ++ return err; ++ } ++ } ++ if (!done) ++ grub_net_poll_cards (interval, 0); ++ } ++ ++ FOR_DHCP6_SESSIONS (se) ++ { ++ grub_error_push (); ++ err = grub_error (GRUB_ERR_FILE_NOT_FOUND, ++ N_("couldn't autoconfigure %s"), ++ se->iface->card->name); ++ } ++ ++ grub_dhcp6_session_remove_all (); ++ ++ return err; ++} ++ ++static grub_command_t cmd_getdhcp, cmd_bootp, cmd_dhcp, cmd_bootp6; + + void + grub_bootp_init (void) +@@ -914,6 +1816,9 @@ grub_bootp_init (void) + cmd_getdhcp = grub_register_command ("net_get_dhcp_option", grub_cmd_dhcpopt, + N_("VAR INTERFACE NUMBER DESCRIPTION"), + N_("retrieve DHCP option and save it into VAR. If VAR is - then print the value.")); ++ cmd_bootp6 = grub_register_command ("net_bootp6", grub_cmd_bootp6, ++ N_("[CARD]"), ++ N_("perform a DHCPv6 autoconfiguration")); + } + + void +@@ -922,4 +1827,5 @@ grub_bootp_fini (void) + grub_unregister_command (cmd_getdhcp); + grub_unregister_command (cmd_bootp); + grub_unregister_command (cmd_dhcp); ++ grub_unregister_command (cmd_bootp6); + } +diff --git a/grub-core/net/ip.c b/grub-core/net/ip.c +index ea5edf8f1..01410798b 100644 +--- a/grub-core/net/ip.c ++++ b/grub-core/net/ip.c +@@ -239,6 +239,45 @@ handle_dgram (struct grub_net_buff *nb, + { + struct udphdr *udph; + udph = (struct udphdr *) nb->data; ++ ++ if (proto == GRUB_NET_IP_UDP && udph->dst == grub_cpu_to_be16_compile_time (DHCP6_CLIENT_PORT)) ++ { ++ if (udph->chksum) ++ { ++ grub_uint16_t chk, expected; ++ chk = udph->chksum; ++ udph->chksum = 0; ++ expected = grub_net_ip_transport_checksum (nb, ++ GRUB_NET_IP_UDP, ++ source, ++ dest); ++ if (expected != chk) ++ { ++ grub_dprintf ("net", "Invalid UDP checksum. " ++ "Expected %x, got %x\n", ++ grub_be_to_cpu16 (expected), ++ grub_be_to_cpu16 (chk)); ++ grub_netbuff_free (nb); ++ return GRUB_ERR_NONE; ++ } ++ udph->chksum = chk; ++ } ++ ++ err = grub_netbuff_pull (nb, sizeof (*udph)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ err = grub_net_process_dhcp6 (nb, card); ++ if (err) ++ grub_print_error (); ++ ++ grub_netbuff_free (nb); ++ return GRUB_ERR_NONE; ++ } ++ + if (proto == GRUB_NET_IP_UDP && grub_be_to_cpu16 (udph->dst) == 68) + { + const struct grub_net_bootp_packet *bootp; +diff --git a/include/grub/net.h b/include/grub/net.h +index 69bfe0947..1cb05627e 100644 +--- a/include/grub/net.h ++++ b/include/grub/net.h +@@ -448,6 +448,66 @@ struct grub_net_bootp_packet + grub_uint8_t vendor[0]; + } GRUB_PACKED; + ++struct grub_net_dhcp6_packet ++{ ++ grub_uint32_t message_type:8; ++ grub_uint32_t transaction_id:24; ++ grub_uint8_t dhcp_options[0]; ++} GRUB_PACKED; ++ ++struct grub_net_dhcp6_option { ++ grub_uint16_t code; ++ grub_uint16_t len; ++ grub_uint8_t data[0]; ++} GRUB_PACKED; ++ ++struct grub_net_dhcp6_option_iana { ++ grub_uint32_t iaid; ++ grub_uint32_t t1; ++ grub_uint32_t t2; ++ grub_uint8_t data[0]; ++} GRUB_PACKED; ++ ++struct grub_net_dhcp6_option_iaaddr { ++ grub_uint8_t addr[16]; ++ grub_uint32_t preferred_lifetime; ++ grub_uint32_t valid_lifetime; ++ grub_uint8_t data[0]; ++} GRUB_PACKED; ++ ++struct grub_net_dhcp6_option_duid_ll ++{ ++ grub_uint16_t type; ++ grub_uint16_t hw_type; ++ grub_uint8_t hwaddr[6]; ++} GRUB_PACKED; ++ ++enum ++ { ++ GRUB_NET_DHCP6_SOLICIT = 1, ++ GRUB_NET_DHCP6_ADVERTISE = 2, ++ GRUB_NET_DHCP6_REQUEST = 3, ++ GRUB_NET_DHCP6_REPLY = 7 ++ }; ++ ++enum ++ { ++ DHCP6_CLIENT_PORT = 546, ++ DHCP6_SERVER_PORT = 547 ++ }; ++ ++enum ++ { ++ GRUB_NET_DHCP6_OPTION_CLIENTID = 1, ++ GRUB_NET_DHCP6_OPTION_SERVERID = 2, ++ GRUB_NET_DHCP6_OPTION_IA_NA = 3, ++ GRUB_NET_DHCP6_OPTION_IAADDR = 5, ++ GRUB_NET_DHCP6_OPTION_ORO = 6, ++ GRUB_NET_DHCP6_OPTION_ELAPSED_TIME = 8, ++ GRUB_NET_DHCP6_OPTION_DNS_SERVERS = 23, ++ GRUB_NET_DHCP6_OPTION_BOOTFILE_URL = 59 ++ }; ++ + #define GRUB_NET_BOOTP_RFC1048_MAGIC_0 0x63 + #define GRUB_NET_BOOTP_RFC1048_MAGIC_1 0x82 + #define GRUB_NET_BOOTP_RFC1048_MAGIC_2 0x53 +@@ -483,6 +543,14 @@ grub_net_configure_by_dhcp_ack (const char *name, + grub_size_t size, + int is_def, char **device, char **path); + ++struct grub_net_network_level_interface * ++grub_net_configure_by_dhcpv6_reply (const char *name, ++ struct grub_net_card *card, ++ grub_net_interface_flags_t flags, ++ const struct grub_net_dhcp6_packet *v6, ++ grub_size_t size, ++ int is_def, char **device, char **path); ++ + grub_err_t + grub_net_add_ipv4_local (struct grub_net_network_level_interface *inf, + int mask); +@@ -491,6 +559,10 @@ void + grub_net_process_dhcp (struct grub_net_buff *nb, + struct grub_net_network_level_interface *iface); + ++grub_err_t ++grub_net_process_dhcp6 (struct grub_net_buff *nb, ++ struct grub_net_card *card); ++ + int + grub_net_hwaddr_cmp (const grub_net_link_level_address_t *a, + const grub_net_link_level_address_t *b); diff --git a/debian/patches/bootp-process-dhcpack-http-boot.patch b/debian/patches/bootp-process-dhcpack-http-boot.patch new file mode 100644 index 0000000..64b19f6 --- /dev/null +++ b/debian/patches/bootp-process-dhcpack-http-boot.patch @@ -0,0 +1,124 @@ +From cd78a54e5fa8d4a6f9223b7ddbb7db86ca0dd993 Mon Sep 17 00:00:00 2001 +From: Michael Chang <mchang@suse.com> +Date: Thu, 27 Oct 2016 17:42:19 -0400 +Subject: bootp: Add processing DHCPACK packet from HTTP Boot + +The vendor class identifier with the string "HTTPClient" is used to denote the +packet as responding to HTTP boot request. In DHCP4 config, the filename for +HTTP boot is the URL of the boot file while for PXE boot it is the path to the +boot file. As a consequence, the next-server becomes obseleted because the HTTP +URL already contains the server address for the boot file. For DHCP6 config, +there's no difference definition in existing config as dhcp6.bootfile-url can +be used to specify URL for both HTTP and PXE boot file. + +This patch adds processing for "HTTPClient" vendor class identifier in DHCPACK +packet by treating it as HTTP format, not as the PXE format. + +Signed-off-by: Michael Chang <mchang@suse.com> +Signed-off-by: Ken Lin <ken.lin@hpe.com> + +Last-Update: 2021-09-24 + +Patch-Name: bootp-process-dhcpack-http-boot.patch +--- + grub-core/net/bootp.c | 60 ++++++++++++++++++++++++++++++++++++++++++- + include/grub/net.h | 1 + + 2 files changed, 60 insertions(+), 1 deletion(-) + +diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c +index 00c11af39..f35d582b8 100644 +--- a/grub-core/net/bootp.c ++++ b/grub-core/net/bootp.c +@@ -154,7 +154,7 @@ struct grub_dhcp_request_options + { + grub_uint8_t type; + grub_uint8_t len; +- grub_uint8_t data[7]; ++ grub_uint8_t data[8]; + } GRUB_PACKED parameter_request; + grub_uint8_t end; + } GRUB_PACKED; +@@ -542,6 +542,63 @@ grub_net_configure_by_dhcp_ack (const char *name, + grub_free (val); + } + ++ opt = find_dhcp_option (bp, size, GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER, ++ &opt_len); ++ if (opt && opt_len) ++ { ++ grub_env_set_net_property (name, "vendor_class_identifier", ++ (const char *) opt, opt_len); ++ if (opt_len == sizeof ("HTTPClient") - 1 && ++ grub_memcmp (opt, "HTTPClient", sizeof ("HTTPClient") - 1) == 0) ++ { ++ char *proto, *ip, *pa; ++ ++ if (!dissect_url (bp->boot_file, &proto, &ip, &pa)) ++ return inter; ++ ++ grub_env_set_net_property (name, "boot_file", pa, grub_strlen (pa)); ++ if (is_def) ++ { ++ grub_net_default_server = grub_strdup (ip); ++ grub_env_set ("net_default_interface", name); ++ grub_env_export ("net_default_interface"); ++ } ++ if (device && !*device) ++ { ++ *device = grub_xasprintf ("%s,%s", proto, ip); ++ grub_print_error (); ++ } ++ if (path) ++ { ++ *path = grub_strdup (pa); ++ grub_print_error (); ++ if (*path) ++ { ++ char *slash; ++ slash = grub_strrchr (*path, '/'); ++ if (slash) ++ *slash = 0; ++ else ++ **path = 0; ++ } ++ } ++ grub_net_add_ipv4_local (inter, mask); ++ inter->dhcp_ack = grub_malloc (size); ++ if (inter->dhcp_ack) ++ { ++ grub_memcpy (inter->dhcp_ack, bp, size); ++ inter->dhcp_acklen = size; ++ } ++ else ++ grub_errno = GRUB_ERR_NONE; ++ ++ grub_free (proto); ++ grub_free (ip); ++ grub_free (pa); ++ return inter; ++ } ++ } ++ + inter->dhcp_ack = grub_malloc (size); + if (inter->dhcp_ack) + { +@@ -616,6 +673,7 @@ send_dhcp_packet (struct grub_net_network_level_interface *iface) + GRUB_NET_BOOTP_HOSTNAME, + GRUB_NET_BOOTP_ROOT_PATH, + GRUB_NET_BOOTP_EXTENSIONS_PATH, ++ GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER, + }, + }, + GRUB_NET_BOOTP_END, +diff --git a/include/grub/net.h b/include/grub/net.h +index 1cb05627e..cbcae79b1 100644 +--- a/include/grub/net.h ++++ b/include/grub/net.h +@@ -528,6 +528,7 @@ enum + GRUB_NET_DHCP_MESSAGE_TYPE = 53, + GRUB_NET_DHCP_SERVER_IDENTIFIER = 54, + GRUB_NET_DHCP_PARAMETER_REQUEST_LIST = 55, ++ GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER = 60, + GRUB_NET_BOOTP_CLIENT_ID = 61, + GRUB_NET_DHCP_TFTP_SERVER_NAME = 66, + GRUB_NET_DHCP_BOOTFILE_NAME = 67, diff --git a/debian/patches/core-in-fs.patch b/debian/patches/core-in-fs.patch new file mode 100644 index 0000000..1f18554 --- /dev/null +++ b/debian/patches/core-in-fs.patch @@ -0,0 +1,45 @@ +From bd289b232f3e9ddaa378d02f0f0040c2171078a4 Mon Sep 17 00:00:00 2001 +From: Colin Watson <cjwatson@debian.org> +Date: Mon, 13 Jan 2014 12:12:51 +0000 +Subject: Write marker if core.img was written to filesystem + +The Debian bug reporting script includes a warning in this case. + +Patch-Name: core-in-fs.patch +--- + util/setup.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/util/setup.c b/util/setup.c +index da5f2c07f..d1902656e 100644 +--- a/util/setup.c ++++ b/util/setup.c +@@ -58,6 +58,8 @@ + + #include <errno.h> + ++#define CORE_IMG_IN_FS "setup_left_core_image_in_filesystem" ++ + /* On SPARC this program fills in various fields inside of the 'boot' and 'core' + * image files. + * +@@ -670,6 +672,8 @@ SETUP (const char *dir, + #endif + grub_free (sectors); + ++ unlink (DEFAULT_DIRECTORY "/" CORE_IMG_IN_FS); ++ + goto finish; + } + +@@ -711,6 +715,10 @@ unable_to_embed: + /* The core image must be put on a filesystem unfortunately. */ + grub_util_info ("will leave the core image on the filesystem"); + ++ fp = grub_util_fd_open (DEFAULT_DIRECTORY "/" CORE_IMG_IN_FS, ++ GRUB_UTIL_FD_O_WRONLY); ++ grub_util_fd_close (fp); ++ + grub_util_biosdisk_flush (root_dev->disk); + + /* Clean out the blocklists. */ diff --git a/debian/patches/cve_2022_2601/0001-video-readers-Add-artificial-limit-to-image-dimensio.patch b/debian/patches/cve_2022_2601/0001-video-readers-Add-artificial-limit-to-image-dimensio.patch new file mode 100644 index 0000000..99c2f5a --- /dev/null +++ b/debian/patches/cve_2022_2601/0001-video-readers-Add-artificial-limit-to-image-dimensio.patch @@ -0,0 +1,109 @@ +From a85714545fe57a86d14ee231a4cd312158101d43 Mon Sep 17 00:00:00 2001 +From: Alec Brown <alec.r.brown@oracle.com> +Date: Wed, 26 Oct 2022 20:16:44 -0400 +Subject: [PATCH 01/14] video/readers: Add artificial limit to image dimensions + +In grub-core/video/readers/jpeg.c, the height and width of a JPEG image don't +have an upper limit for how big the JPEG image can be. In Coverity, this is +getting flagged as an untrusted loop bound. This issue can also seen in PNG and +TGA format images as well but Coverity isn't flagging it. To prevent this, the +constant IMAGE_HW_MAX_PX is being added to include/grub/bitmap.h, which has +a value of 16384, to act as an artificial limit and restrict the height and +width of images. This value was picked as it is double the current max +resolution size, which is 8K. + +Fixes: CID 292450 + +Signed-off-by: Alec Brown <alec.r.brown@oracle.com> +Reviewed-by: Darren Kenny <darren.kenny@oracle.com> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + docs/grub.texi | 3 ++- + grub-core/video/readers/jpeg.c | 6 +++++- + grub-core/video/readers/png.c | 6 +++++- + grub-core/video/readers/tga.c | 7 +++++++ + include/grub/bitmap.h | 2 ++ + 5 files changed, 21 insertions(+), 3 deletions(-) + +diff --git a/docs/grub.texi b/docs/grub.texi +index 0dbbdc374..2d6cd8358 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -1515,7 +1515,8 @@ resolution. @xref{gfxmode}. + Set a background image for use with the @samp{gfxterm} graphical terminal. + The value of this option must be a file readable by GRUB at boot time, and + it must end with @file{.png}, @file{.tga}, @file{.jpg}, or @file{.jpeg}. +-The image will be scaled if necessary to fit the screen. ++The image will be scaled if necessary to fit the screen. Image height and ++width will be restricted by an artificial limit of 16384. + + @item GRUB_THEME + Set a theme for use with the @samp{gfxterm} graphical terminal. +diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c +index 09596fbf5..ae634fd41 100644 +--- a/grub-core/video/readers/jpeg.c ++++ b/grub-core/video/readers/jpeg.c +@@ -346,7 +346,11 @@ grub_jpeg_decode_sof (struct grub_jpeg_data *data) + data->image_height = grub_jpeg_get_word (data); + data->image_width = grub_jpeg_get_word (data); + +- if ((!data->image_height) || (!data->image_width)) ++ grub_dprintf ("jpeg", "image height: %d\n", data->image_height); ++ grub_dprintf ("jpeg", "image width: %d\n", data->image_width); ++ ++ if ((!data->image_height) || (!data->image_width) || ++ (data->image_height > IMAGE_HW_MAX_PX) || (data->image_width > IMAGE_HW_MAX_PX)) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid image size"); + + cc = grub_jpeg_get_byte (data); +diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c +index 7f2ba7849..3163e97bf 100644 +--- a/grub-core/video/readers/png.c ++++ b/grub-core/video/readers/png.c +@@ -264,7 +264,11 @@ grub_png_decode_image_header (struct grub_png_data *data) + data->image_width = grub_png_get_dword (data); + data->image_height = grub_png_get_dword (data); + +- if ((!data->image_height) || (!data->image_width)) ++ grub_dprintf ("png", "image height: %d\n", data->image_height); ++ grub_dprintf ("png", "image width: %d\n", data->image_width); ++ ++ if ((!data->image_height) || (!data->image_width) || ++ (data->image_height > IMAGE_HW_MAX_PX) || (data->image_width > IMAGE_HW_MAX_PX)) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "png: invalid image size"); + + color_bits = grub_png_get_byte (data); +diff --git a/grub-core/video/readers/tga.c b/grub-core/video/readers/tga.c +index a9ec3a1b6..9c35bf29d 100644 +--- a/grub-core/video/readers/tga.c ++++ b/grub-core/video/readers/tga.c +@@ -340,6 +340,13 @@ grub_video_reader_tga (struct grub_video_bitmap **bitmap, + data.image_width = grub_le_to_cpu16 (data.hdr.image_width); + data.image_height = grub_le_to_cpu16 (data.hdr.image_height); + ++ grub_dprintf ("tga", "image height: %d\n", data.image_height); ++ grub_dprintf ("tga", "image width: %d\n", data.image_width); ++ ++ /* Check image height and width are within restrictions. */ ++ if ((data.image_height > IMAGE_HW_MAX_PX) || (data.image_width > IMAGE_HW_MAX_PX)) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "tga: invalid image size"); ++ + /* Check that bitmap encoding is supported. */ + switch (data.hdr.image_type) + { +diff --git a/include/grub/bitmap.h b/include/grub/bitmap.h +index 5728f8ca3..149d37bfe 100644 +--- a/include/grub/bitmap.h ++++ b/include/grub/bitmap.h +@@ -24,6 +24,8 @@ + #include <grub/types.h> + #include <grub/video.h> + ++#define IMAGE_HW_MAX_PX 16384 ++ + struct grub_video_bitmap + { + /* Bitmap format description. */ +-- +2.30.2 + diff --git a/debian/patches/cve_2022_2601/0002-font-Reject-glyphs-exceeds-font-max_glyph_width-or-f.patch b/debian/patches/cve_2022_2601/0002-font-Reject-glyphs-exceeds-font-max_glyph_width-or-f.patch new file mode 100644 index 0000000..7330e5a --- /dev/null +++ b/debian/patches/cve_2022_2601/0002-font-Reject-glyphs-exceeds-font-max_glyph_width-or-f.patch @@ -0,0 +1,33 @@ +From 5760fcfd466cc757540ea0d591bad6a08caeaa16 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang <zhangboyang.id@gmail.com> +Date: Wed, 3 Aug 2022 19:45:33 +0800 +Subject: [PATCH 02/14] font: Reject glyphs exceeds font->max_glyph_width or + font->max_glyph_height + +Check glyph's width and height against limits specified in font's +metadata. Reject the glyph (and font) if such limits are exceeded. + +Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/font/font.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/grub-core/font/font.c b/grub-core/font/font.c +index 42189c325..756ca0abf 100644 +--- a/grub-core/font/font.c ++++ b/grub-core/font/font.c +@@ -760,7 +760,9 @@ grub_font_get_glyph_internal (grub_font_t font, grub_uint32_t code) + || read_be_uint16 (font->file, &height) != 0 + || read_be_int16 (font->file, &xoff) != 0 + || read_be_int16 (font->file, &yoff) != 0 +- || read_be_int16 (font->file, &dwidth) != 0) ++ || read_be_int16 (font->file, &dwidth) != 0 ++ || width > font->max_char_width ++ || height > font->max_char_height) + { + remove_font (font); + return 0; +-- +2.30.2 + diff --git a/debian/patches/cve_2022_2601/0003-font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch b/debian/patches/cve_2022_2601/0003-font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch new file mode 100644 index 0000000..46ccb00 --- /dev/null +++ b/debian/patches/cve_2022_2601/0003-font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch @@ -0,0 +1,110 @@ +From 941d10ad6f1dcbd12fb613002249e29ba035f985 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang <zhangboyang.id@gmail.com> +Date: Fri, 5 Aug 2022 00:51:20 +0800 +Subject: [PATCH 03/14] font: Fix size overflow in + grub_font_get_glyph_internal() + +The length of memory allocation and file read may overflow. This patch +fixes the problem by using safemath macros. + +There is a lot of code repetition like "(x * y + 7) / 8". It is unsafe +if overflow happens. This patch introduces grub_video_bitmap_calc_1bpp_bufsz(). +It is safe replacement for such code. It has safemath-like prototype. + +This patch also introduces grub_cast(value, pointer), it casts value to +typeof(*pointer) then store the value to *pointer. It returns true when +overflow occurs or false if there is no overflow. The semantics of arguments +and return value are designed to be consistent with other safemath macros. + +Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/font/font.c | 17 +++++++++++++---- + include/grub/bitmap.h | 18 ++++++++++++++++++ + include/grub/safemath.h | 2 ++ + 3 files changed, 33 insertions(+), 4 deletions(-) + +diff --git a/grub-core/font/font.c b/grub-core/font/font.c +index 2f09a4a55..6a3fbebbd 100644 +--- a/grub-core/font/font.c ++++ b/grub-core/font/font.c +@@ -739,7 +739,8 @@ grub_font_get_glyph_internal (grub_font_t font, grub_uint32_t code) + grub_int16_t xoff; + grub_int16_t yoff; + grub_int16_t dwidth; +- int len; ++ grub_ssize_t len; ++ grub_size_t sz; + + if (index_entry->glyph) + /* Return cached glyph. */ +@@ -768,9 +769,17 @@ grub_font_get_glyph_internal (grub_font_t font, grub_uint32_t code) + return 0; + } + +- len = (width * height + 7) / 8; +- glyph = grub_malloc (sizeof (struct grub_font_glyph) + len); +- if (!glyph) ++ /* Calculate real struct size of current glyph. */ ++ if (grub_video_bitmap_calc_1bpp_bufsz (width, height, &len) || ++ grub_add (sizeof (struct grub_font_glyph), len, &sz)) ++ { ++ remove_font (font); ++ return 0; ++ } ++ ++ /* Allocate and initialize the glyph struct. */ ++ glyph = grub_malloc (sz); ++ if (glyph == NULL) + { + remove_font (font); + return 0; +diff --git a/include/grub/bitmap.h b/include/grub/bitmap.h +index 149d37bfe..431048936 100644 +--- a/include/grub/bitmap.h ++++ b/include/grub/bitmap.h +@@ -23,6 +23,7 @@ + #include <grub/symbol.h> + #include <grub/types.h> + #include <grub/video.h> ++#include <grub/safemath.h> + + #define IMAGE_HW_MAX_PX 16384 + +@@ -81,6 +82,23 @@ grub_video_bitmap_get_height (struct grub_video_bitmap *bitmap) + return bitmap->mode_info.height; + } + ++/* ++ * Calculate and store the size of data buffer of 1bit bitmap in result. ++ * Equivalent to "*result = (width * height + 7) / 8" if no overflow occurs. ++ * Return true when overflow occurs or false if there is no overflow. ++ * This function is intentionally implemented as a macro instead of ++ * an inline function. Although a bit awkward, it preserves data types for ++ * safemath macros and reduces macro side effects as much as possible. ++ * ++ * XXX: Will report false overflow if width * height > UINT64_MAX. ++ */ ++#define grub_video_bitmap_calc_1bpp_bufsz(width, height, result) \ ++({ \ ++ grub_uint64_t _bitmap_pixels; \ ++ grub_mul ((width), (height), &_bitmap_pixels) ? 1 : \ ++ grub_cast (_bitmap_pixels / GRUB_CHAR_BIT + !!(_bitmap_pixels % GRUB_CHAR_BIT), (result)); \ ++}) ++ + void EXPORT_FUNC (grub_video_bitmap_get_mode_info) (struct grub_video_bitmap *bitmap, + struct grub_video_mode_info *mode_info); + +diff --git a/include/grub/safemath.h b/include/grub/safemath.h +index c17b89bba..bb0f826de 100644 +--- a/include/grub/safemath.h ++++ b/include/grub/safemath.h +@@ -30,6 +30,8 @@ + #define grub_sub(a, b, res) __builtin_sub_overflow(a, b, res) + #define grub_mul(a, b, res) __builtin_mul_overflow(a, b, res) + ++#define grub_cast(a, res) grub_add ((a), 0, (res)) ++ + #else + #error gcc 5.1 or newer or clang 3.8 or newer is required + #endif diff --git a/debian/patches/cve_2022_2601/0004-font-Fix-several-integer-overflows-in-grub_font_cons.patch b/debian/patches/cve_2022_2601/0004-font-Fix-several-integer-overflows-in-grub_font_cons.patch new file mode 100644 index 0000000..9d3c9b2 --- /dev/null +++ b/debian/patches/cve_2022_2601/0004-font-Fix-several-integer-overflows-in-grub_font_cons.patch @@ -0,0 +1,81 @@ +From b1805f251b31a9d3cfae5c3572ddfa630145dbbf Mon Sep 17 00:00:00 2001 +From: Zhang Boyang <zhangboyang.id@gmail.com> +Date: Fri, 5 Aug 2022 01:58:27 +0800 +Subject: [PATCH 04/14] font: Fix several integer overflows in + grub_font_construct_glyph() + +This patch fixes several integer overflows in grub_font_construct_glyph(). +Glyphs of invalid size, zero or leading to an overflow, are rejected. +The inconsistency between "glyph" and "max_glyph_size" when grub_malloc() +returns NULL is fixed too. + +Fixes: CVE-2022-2601 + +Reported-by: Zhang Boyang <zhangboyang.id@gmail.com> +Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/font/font.c | 29 +++++++++++++++++------------ + 1 file changed, 17 insertions(+), 12 deletions(-) + +diff --git a/grub-core/font/font.c b/grub-core/font/font.c +index e781521a7..e6548892f 100644 +--- a/grub-core/font/font.c ++++ b/grub-core/font/font.c +@@ -1517,6 +1517,7 @@ grub_font_construct_glyph (grub_font_t hinted_font, + struct grub_video_signed_rect bounds; + static struct grub_font_glyph *glyph = 0; + static grub_size_t max_glyph_size = 0; ++ grub_size_t cur_glyph_size; + + ensure_comb_space (glyph_id); + +@@ -1533,29 +1534,33 @@ grub_font_construct_glyph (grub_font_t hinted_font, + if (!glyph_id->ncomb && !glyph_id->attributes) + return main_glyph; + +- if (max_glyph_size < sizeof (*glyph) + (bounds.width * bounds.height + GRUB_CHAR_BIT - 1) / GRUB_CHAR_BIT) ++ if (grub_video_bitmap_calc_1bpp_bufsz (bounds.width, bounds.height, &cur_glyph_size) || ++ grub_add (sizeof (*glyph), cur_glyph_size, &cur_glyph_size)) ++ return main_glyph; ++ ++ if (max_glyph_size < cur_glyph_size) + { + grub_free (glyph); +- max_glyph_size = (sizeof (*glyph) + (bounds.width * bounds.height + GRUB_CHAR_BIT - 1) / GRUB_CHAR_BIT) * 2; +- if (max_glyph_size < 8) +- max_glyph_size = 8; +- glyph = grub_malloc (max_glyph_size); ++ if (grub_mul (cur_glyph_size, 2, &max_glyph_size)) ++ max_glyph_size = 0; ++ glyph = max_glyph_size > 0 ? grub_malloc (max_glyph_size) : NULL; + } + if (!glyph) + { ++ max_glyph_size = 0; + grub_errno = GRUB_ERR_NONE; + return main_glyph; + } + +- grub_memset (glyph, 0, sizeof (*glyph) +- + (bounds.width * bounds.height +- + GRUB_CHAR_BIT - 1) / GRUB_CHAR_BIT); ++ grub_memset (glyph, 0, cur_glyph_size); + + glyph->font = main_glyph->font; +- glyph->width = bounds.width; +- glyph->height = bounds.height; +- glyph->offset_x = bounds.x; +- glyph->offset_y = bounds.y; ++ if (bounds.width == 0 || bounds.height == 0 || ++ grub_cast (bounds.width, &glyph->width) || ++ grub_cast (bounds.height, &glyph->height) || ++ grub_cast (bounds.x, &glyph->offset_x) || ++ grub_cast (bounds.y, &glyph->offset_y)) ++ return main_glyph; + + if (glyph_id->attributes & GRUB_UNICODE_GLYPH_ATTRIBUTE_MIRROR) + grub_font_blit_glyph_mirror (glyph, main_glyph, +-- +2.30.2 + diff --git a/debian/patches/cve_2022_2601/0005-font-Remove-grub_font_dup_glyph.patch b/debian/patches/cve_2022_2601/0005-font-Remove-grub_font_dup_glyph.patch new file mode 100644 index 0000000..7c957a6 --- /dev/null +++ b/debian/patches/cve_2022_2601/0005-font-Remove-grub_font_dup_glyph.patch @@ -0,0 +1,42 @@ +From 25ad31c19c331aaa2dbd9bd2b2e2655de5766a9d Mon Sep 17 00:00:00 2001 +From: Zhang Boyang <zhangboyang.id@gmail.com> +Date: Fri, 5 Aug 2022 02:13:29 +0800 +Subject: [PATCH 05/14] font: Remove grub_font_dup_glyph() + +Remove grub_font_dup_glyph() since nobody is using it since 2013, and +I'm too lazy to fix the integer overflow problem in it. + +Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/font/font.c | 14 -------------- + 1 file changed, 14 deletions(-) + +diff --git a/grub-core/font/font.c b/grub-core/font/font.c +index e6548892f..a8576ffec 100644 +--- a/grub-core/font/font.c ++++ b/grub-core/font/font.c +@@ -1055,20 +1055,6 @@ grub_font_get_glyph_with_fallback (grub_font_t font, grub_uint32_t code) + return best_glyph; + } + +-#if 0 +-static struct grub_font_glyph * +-grub_font_dup_glyph (struct grub_font_glyph *glyph) +-{ +- static struct grub_font_glyph *ret; +- ret = grub_malloc (sizeof (*ret) + (glyph->width * glyph->height + 7) / 8); +- if (!ret) +- return NULL; +- grub_memcpy (ret, glyph, sizeof (*ret) +- + (glyph->width * glyph->height + 7) / 8); +- return ret; +-} +-#endif +- + /* FIXME: suboptimal. */ + static void + grub_font_blit_glyph (struct grub_font_glyph *target, +-- +2.30.2 + diff --git a/debian/patches/cve_2022_2601/0006-font-Fix-integer-overflow-in-ensure_comb_space.patch b/debian/patches/cve_2022_2601/0006-font-Fix-integer-overflow-in-ensure_comb_space.patch new file mode 100644 index 0000000..f35c646 --- /dev/null +++ b/debian/patches/cve_2022_2601/0006-font-Fix-integer-overflow-in-ensure_comb_space.patch @@ -0,0 +1,48 @@ +From b2740b7e4a03bb8331d48b54b119afea76bb9d5f Mon Sep 17 00:00:00 2001 +From: Zhang Boyang <zhangboyang.id@gmail.com> +Date: Fri, 5 Aug 2022 02:27:05 +0800 +Subject: [PATCH 06/14] font: Fix integer overflow in ensure_comb_space() + +In fact it can't overflow at all because glyph_id->ncomb is only 8-bit +wide. But let's keep safe if somebody changes the width of glyph_id->ncomb +in the future. This patch also fixes the inconsistency between +render_max_comb_glyphs and render_combining_glyphs when grub_malloc() +returns NULL. + +Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/font/font.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/grub-core/font/font.c b/grub-core/font/font.c +index a8576ffec..9e3e0a94e 100644 +--- a/grub-core/font/font.c ++++ b/grub-core/font/font.c +@@ -1468,14 +1468,18 @@ ensure_comb_space (const struct grub_unicode_glyph *glyph_id) + if (glyph_id->ncomb <= render_max_comb_glyphs) + return; + +- render_max_comb_glyphs = 2 * glyph_id->ncomb; +- if (render_max_comb_glyphs < 8) ++ if (grub_mul (glyph_id->ncomb, 2, &render_max_comb_glyphs)) ++ render_max_comb_glyphs = 0; ++ if (render_max_comb_glyphs > 0 && render_max_comb_glyphs < 8) + render_max_comb_glyphs = 8; + grub_free (render_combining_glyphs); +- render_combining_glyphs = grub_malloc (render_max_comb_glyphs +- * sizeof (render_combining_glyphs[0])); ++ render_combining_glyphs = (render_max_comb_glyphs > 0) ? ++ grub_calloc (render_max_comb_glyphs, sizeof (render_combining_glyphs[0])) : NULL; + if (!render_combining_glyphs) +- grub_errno = 0; ++ { ++ render_max_comb_glyphs = 0; ++ grub_errno = GRUB_ERR_NONE; ++ } + } + + int +-- +2.30.2 + diff --git a/debian/patches/cve_2022_2601/0007-font-Fix-integer-overflow-in-BMP-index.patch b/debian/patches/cve_2022_2601/0007-font-Fix-integer-overflow-in-BMP-index.patch new file mode 100644 index 0000000..7d426f0 --- /dev/null +++ b/debian/patches/cve_2022_2601/0007-font-Fix-integer-overflow-in-BMP-index.patch @@ -0,0 +1,65 @@ +From afda8b60ba0712abe01ae1e64c5f7a067a0e6492 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang <zhangboyang.id@gmail.com> +Date: Mon, 15 Aug 2022 02:04:58 +0800 +Subject: [PATCH 07/14] font: Fix integer overflow in BMP index + +The BMP index (font->bmp_idx) is designed as a reverse lookup table of +char entries (font->char_index), in order to speed up lookups for BMP +chars (i.e. code < 0x10000). The values in BMP index are the subscripts +of the corresponding char entries, stored in grub_uint16_t, while 0xffff +means not found. + +This patch fixes the problem of large subscript truncated to grub_uint16_t, +leading BMP index to return wrong char entry or report false miss. The +code now checks for bounds and uses BMP index as a hint, and fallbacks +to binary-search if necessary. + +On the occasion add a comment about BMP index is initialized to 0xffff. + +Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/font/font.c | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +diff --git a/grub-core/font/font.c b/grub-core/font/font.c +index 9e3e0a94e..e4cb0d867 100644 +--- a/grub-core/font/font.c ++++ b/grub-core/font/font.c +@@ -300,6 +300,8 @@ load_font_index (grub_file_t file, grub_uint32_t sect_length, struct + font->bmp_idx = grub_malloc (0x10000 * sizeof (grub_uint16_t)); + if (!font->bmp_idx) + return 1; ++ ++ /* Init the BMP index array to 0xffff. */ + grub_memset (font->bmp_idx, 0xff, 0x10000 * sizeof (grub_uint16_t)); + + +@@ -328,7 +330,7 @@ load_font_index (grub_file_t file, grub_uint32_t sect_length, struct + return 1; + } + +- if (entry->code < 0x10000) ++ if (entry->code < 0x10000 && i < 0xffff) + font->bmp_idx[entry->code] = i; + + last_code = entry->code; +@@ -696,9 +698,12 @@ find_glyph (const grub_font_t font, grub_uint32_t code) + /* Use BMP index if possible. */ + if (code < 0x10000 && font->bmp_idx) + { +- if (font->bmp_idx[code] == 0xffff) +- return 0; +- return &table[font->bmp_idx[code]]; ++ if (font->bmp_idx[code] < 0xffff) ++ return &table[font->bmp_idx[code]]; ++ /* ++ * When we are here then lookup in BMP index result in miss, ++ * fallthough to binary-search. ++ */ + } + + /* Do a binary search in `char_index', which is ordered by code point. */ +-- +2.30.2 + diff --git a/debian/patches/cve_2022_2601/0008-font-Fix-integer-underflow-in-binary-search-of-char-.patch b/debian/patches/cve_2022_2601/0008-font-Fix-integer-underflow-in-binary-search-of-char-.patch new file mode 100644 index 0000000..0db8d15 --- /dev/null +++ b/debian/patches/cve_2022_2601/0008-font-Fix-integer-underflow-in-binary-search-of-char-.patch @@ -0,0 +1,86 @@ +From c140a086838e7c9af87842036f891b8393a8c4bc Mon Sep 17 00:00:00 2001 +From: Zhang Boyang <zhangboyang.id@gmail.com> +Date: Sun, 14 Aug 2022 18:09:38 +0800 +Subject: [PATCH 08/14] font: Fix integer underflow in binary search of char + index + +If search target is less than all entries in font->index then "hi" +variable is set to -1, which translates to SIZE_MAX and leads to errors. + +This patch fixes the problem by replacing the entire binary search code +with the libstdc++'s std::lower_bound() implementation. + +Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/font/font.c | 40 ++++++++++++++++++++++------------------ + 1 file changed, 22 insertions(+), 18 deletions(-) + +diff --git a/grub-core/font/font.c b/grub-core/font/font.c +index e4cb0d867..abd412a5e 100644 +--- a/grub-core/font/font.c ++++ b/grub-core/font/font.c +@@ -688,12 +688,12 @@ read_be_int16 (grub_file_t file, grub_int16_t * value) + static inline struct char_index_entry * + find_glyph (const grub_font_t font, grub_uint32_t code) + { +- struct char_index_entry *table; +- grub_size_t lo; +- grub_size_t hi; +- grub_size_t mid; ++ struct char_index_entry *table, *first, *end; ++ grub_size_t len; + + table = font->char_index; ++ if (table == NULL) ++ return NULL; + + /* Use BMP index if possible. */ + if (code < 0x10000 && font->bmp_idx) +@@ -706,25 +706,29 @@ find_glyph (const grub_font_t font, grub_uint32_t code) + */ + } + +- /* Do a binary search in `char_index', which is ordered by code point. */ +- lo = 0; +- hi = font->num_chars - 1; +- +- if (!table) +- return 0; ++ /* ++ * Do a binary search in char_index which is ordered by code point. ++ * The code below is the same as libstdc++'s std::lower_bound(). ++ */ ++ first = table; ++ len = font->num_chars; ++ end = first + len; + +- while (lo <= hi) ++ while (len > 0) + { +- mid = lo + (hi - lo) / 2; +- if (code < table[mid].code) +- hi = mid - 1; +- else if (code > table[mid].code) +- lo = mid + 1; ++ grub_size_t half = len >> 1; ++ struct char_index_entry *middle = first + half; ++ ++ if (middle->code < code) ++ { ++ first = middle + 1; ++ len = len - half - 1; ++ } + else +- return &table[mid]; ++ len = half; + } + +- return 0; ++ return (first < end && first->code == code) ? first : NULL; + } + + /* Get a glyph for the Unicode character CODE in FONT. The glyph is loaded +-- +2.30.2 + diff --git a/debian/patches/cve_2022_2601/0009-kern-efi-sb-Enforce-verification-of-font-files.patch b/debian/patches/cve_2022_2601/0009-kern-efi-sb-Enforce-verification-of-font-files.patch new file mode 100644 index 0000000..705835a --- /dev/null +++ b/debian/patches/cve_2022_2601/0009-kern-efi-sb-Enforce-verification-of-font-files.patch @@ -0,0 +1,54 @@ +From 630deb8c0d8b02b670ced4b7030414bcf17aa080 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang <zhangboyang.id@gmail.com> +Date: Sun, 14 Aug 2022 15:51:54 +0800 +Subject: [PATCH 09/14] kern/efi/sb: Enforce verification of font files + +As a mitigation and hardening measure enforce verification of font +files. Then only trusted font files can be load. This will reduce the +attack surface at cost of losing the ability of end-users to customize +fonts if e.g. UEFI Secure Boot is enabled. Vendors can always customize +fonts because they have ability to pack fonts into their GRUB bundles. + +This goal is achieved by: + + * Removing GRUB_FILE_TYPE_FONT from shim lock verifier's + skip-verification list. + + * Adding GRUB_FILE_TYPE_FONT to lockdown verifier's defer-auth list, + so font files must be verified by a verifier before they can be loaded. + +Suggested-by: Daniel Kiper <daniel.kiper@oracle.com> +Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/kern/efi/sb.c | 1 - + grub-core/kern/lockdown.c | 1 + + 2 files changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/kern/efi/sb.c b/grub-core/kern/efi/sb.c +index 89c4bb3fd..db42c2539 100644 +--- a/grub-core/kern/efi/sb.c ++++ b/grub-core/kern/efi/sb.c +@@ -145,7 +145,6 @@ shim_lock_verifier_init (grub_file_t io __attribute__ ((unused)), + case GRUB_FILE_TYPE_PRINT_BLOCKLIST: + case GRUB_FILE_TYPE_TESTLOAD: + case GRUB_FILE_TYPE_GET_SIZE: +- case GRUB_FILE_TYPE_FONT: + case GRUB_FILE_TYPE_ZFS_ENCRYPTION_KEY: + case GRUB_FILE_TYPE_CAT: + case GRUB_FILE_TYPE_HEXCAT: +diff --git a/grub-core/kern/lockdown.c b/grub-core/kern/lockdown.c +index 0bc70fd42..af6d493cd 100644 +--- a/grub-core/kern/lockdown.c ++++ b/grub-core/kern/lockdown.c +@@ -51,6 +51,7 @@ lockdown_verifier_init (grub_file_t io __attribute__ ((unused)), + case GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE: + case GRUB_FILE_TYPE_ACPI_TABLE: + case GRUB_FILE_TYPE_DEVICE_TREE_IMAGE: ++ case GRUB_FILE_TYPE_FONT: + *flags = GRUB_VERIFY_FLAGS_DEFER_AUTH; + + /* Fall through. */ +-- +2.30.2 + diff --git a/debian/patches/cve_2022_2601/0010-fbutil-Fix-integer-overflow.patch b/debian/patches/cve_2022_2601/0010-fbutil-Fix-integer-overflow.patch new file mode 100644 index 0000000..8dcac96 --- /dev/null +++ b/debian/patches/cve_2022_2601/0010-fbutil-Fix-integer-overflow.patch @@ -0,0 +1,85 @@ +From 50a11a81bc842c58962244a2dc86bbd31a426e12 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang <zhangboyang.id@gmail.com> +Date: Tue, 6 Sep 2022 03:03:21 +0800 +Subject: [PATCH 10/14] fbutil: Fix integer overflow + +Expressions like u64 = u32 * u32 are unsafe because their products are +truncated to u32 even if left hand side is u64. This patch fixes all +problems like that one in fbutil. + +To get right result not only left hand side have to be u64 but it's also +necessary to cast at least one of the operands of all leaf operators of +right hand side to u64, e.g. u64 = u32 * u32 + u32 * u32 should be +u64 = (u64)u32 * u32 + (u64)u32 * u32. + +For 1-bit bitmaps grub_uint64_t have to be used. It's safe because any +combination of values in (grub_uint64_t)u32 * u32 + u32 expression will +not overflow grub_uint64_t. + +Other expressions like ptr + u32 * u32 + u32 * u32 are also vulnerable. +They should be ptr + (grub_addr_t)u32 * u32 + (grub_addr_t)u32 * u32. + +This patch also adds a comment to grub_video_fb_get_video_ptr() which +says it's arguments must be valid and no sanity check is performed +(like its siblings in grub-core/video/fb/fbutil.c). + +Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/video/fb/fbutil.c | 4 ++-- + include/grub/fbutil.h | 13 +++++++++---- + 2 files changed, 11 insertions(+), 6 deletions(-) + +diff --git a/grub-core/video/fb/fbutil.c b/grub-core/video/fb/fbutil.c +index b98bb51fe..25ef39f47 100644 +--- a/grub-core/video/fb/fbutil.c ++++ b/grub-core/video/fb/fbutil.c +@@ -67,7 +67,7 @@ get_pixel (struct grub_video_fbblit_info *source, + case 1: + if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED) + { +- int bit_index = y * source->mode_info->width + x; ++ grub_uint64_t bit_index = (grub_uint64_t) y * source->mode_info->width + x; + grub_uint8_t *ptr = source->data + bit_index / 8; + int bit_pos = 7 - bit_index % 8; + color = (*ptr >> bit_pos) & 0x01; +@@ -138,7 +138,7 @@ set_pixel (struct grub_video_fbblit_info *source, + case 1: + if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED) + { +- int bit_index = y * source->mode_info->width + x; ++ grub_uint64_t bit_index = (grub_uint64_t) y * source->mode_info->width + x; + grub_uint8_t *ptr = source->data + bit_index / 8; + int bit_pos = 7 - bit_index % 8; + *ptr = (*ptr & ~(1 << bit_pos)) | ((color & 0x01) << bit_pos); +diff --git a/include/grub/fbutil.h b/include/grub/fbutil.h +index 4205eb917..78a1ab3b4 100644 +--- a/include/grub/fbutil.h ++++ b/include/grub/fbutil.h +@@ -31,14 +31,19 @@ struct grub_video_fbblit_info + grub_uint8_t *data; + }; + +-/* Don't use for 1-bit bitmaps, addressing needs to be done at the bit level +- and it doesn't make sense, in general, to ask for a pointer +- to a particular pixel's data. */ ++/* ++ * Don't use for 1-bit bitmaps, addressing needs to be done at the bit level ++ * and it doesn't make sense, in general, to ask for a pointer ++ * to a particular pixel's data. ++ * ++ * This function assumes that bounds checking has been done in previous phase ++ * and they are opted out in here. ++ */ + static inline void * + grub_video_fb_get_video_ptr (struct grub_video_fbblit_info *source, + unsigned int x, unsigned int y) + { +- return source->data + y * source->mode_info->pitch + x * source->mode_info->bytes_per_pixel; ++ return source->data + (grub_addr_t) y * source->mode_info->pitch + (grub_addr_t) x * source->mode_info->bytes_per_pixel; + } + + /* Advance pointer by VAL bytes. If there is no unaligned access available, +-- +2.30.2 + diff --git a/debian/patches/cve_2022_2601/0011-font-Fix-an-integer-underflow-in-blit_comb.patch b/debian/patches/cve_2022_2601/0011-font-Fix-an-integer-underflow-in-blit_comb.patch new file mode 100644 index 0000000..3a2b02c --- /dev/null +++ b/debian/patches/cve_2022_2601/0011-font-Fix-an-integer-underflow-in-blit_comb.patch @@ -0,0 +1,91 @@ +From 6d2668dea3774ed74c4cd1eadd146f1b846bc3d4 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang <zhangboyang.id@gmail.com> +Date: Mon, 24 Oct 2022 08:05:35 +0800 +Subject: [PATCH 11/14] font: Fix an integer underflow in blit_comb() + +The expression (ctx.bounds.height - combining_glyphs[i]->height) / 2 may +evaluate to a very big invalid value even if both ctx.bounds.height and +combining_glyphs[i]->height are small integers. For example, if +ctx.bounds.height is 10 and combining_glyphs[i]->height is 12, this +expression evaluates to 2147483647 (expected -1). This is because +coordinates are allowed to be negative but ctx.bounds.height is an +unsigned int. So, the subtraction operates on unsigned ints and +underflows to a very big value. The division makes things even worse. +The quotient is still an invalid value even if converted back to int. + +This patch fixes the problem by casting ctx.bounds.height to int. As +a result the subtraction will operate on int and grub_uint16_t which +will be promoted to an int. So, the underflow will no longer happen. Other +uses of ctx.bounds.height (and ctx.bounds.width) are also casted to int, +to ensure coordinates are always calculated on signed integers. + +Fixes: CVE-2022-3775 + +Reported-by: Daniel Axtens <dja@axtens.net> +Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/font/font.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/grub-core/font/font.c b/grub-core/font/font.c +index abd412a5e..3d3d803e8 100644 +--- a/grub-core/font/font.c ++++ b/grub-core/font/font.c +@@ -1203,12 +1203,12 @@ blit_comb (const struct grub_unicode_glyph *glyph_id, + ctx.bounds.height = main_glyph->height; + + above_rightx = main_glyph->offset_x + main_glyph->width; +- above_righty = ctx.bounds.y + ctx.bounds.height; ++ above_righty = ctx.bounds.y + (int) ctx.bounds.height; + + above_leftx = main_glyph->offset_x; +- above_lefty = ctx.bounds.y + ctx.bounds.height; ++ above_lefty = ctx.bounds.y + (int) ctx.bounds.height; + +- below_rightx = ctx.bounds.x + ctx.bounds.width; ++ below_rightx = ctx.bounds.x + (int) ctx.bounds.width; + below_righty = ctx.bounds.y; + + comb = grub_unicode_get_comb (glyph_id); +@@ -1221,7 +1221,7 @@ blit_comb (const struct grub_unicode_glyph *glyph_id, + + if (!combining_glyphs[i]) + continue; +- targetx = (ctx.bounds.width - combining_glyphs[i]->width) / 2 + ctx.bounds.x; ++ targetx = ((int) ctx.bounds.width - combining_glyphs[i]->width) / 2 + ctx.bounds.x; + /* CGJ is to avoid diacritics reordering. */ + if (comb[i].code + == GRUB_UNICODE_COMBINING_GRAPHEME_JOINER) +@@ -1231,8 +1231,8 @@ blit_comb (const struct grub_unicode_glyph *glyph_id, + case GRUB_UNICODE_COMB_OVERLAY: + do_blit (combining_glyphs[i], + targetx, +- (ctx.bounds.height - combining_glyphs[i]->height) / 2 +- - (ctx.bounds.height + ctx.bounds.y), &ctx); ++ ((int) ctx.bounds.height - combining_glyphs[i]->height) / 2 ++ - ((int) ctx.bounds.height + ctx.bounds.y), &ctx); + if (min_devwidth < combining_glyphs[i]->width) + min_devwidth = combining_glyphs[i]->width; + break; +@@ -1305,7 +1305,7 @@ blit_comb (const struct grub_unicode_glyph *glyph_id, + /* Fallthrough. */ + case GRUB_UNICODE_STACK_ATTACHED_ABOVE: + do_blit (combining_glyphs[i], targetx, +- -(ctx.bounds.height + ctx.bounds.y + space ++ -((int) ctx.bounds.height + ctx.bounds.y + space + + combining_glyphs[i]->height), &ctx); + if (min_devwidth < combining_glyphs[i]->width) + min_devwidth = combining_glyphs[i]->width; +@@ -1313,7 +1313,7 @@ blit_comb (const struct grub_unicode_glyph *glyph_id, + + case GRUB_UNICODE_COMB_HEBREW_DAGESH: + do_blit (combining_glyphs[i], targetx, +- -(ctx.bounds.height / 2 + ctx.bounds.y ++ -((int) ctx.bounds.height / 2 + ctx.bounds.y + + combining_glyphs[i]->height / 2), &ctx); + if (min_devwidth < combining_glyphs[i]->width) + min_devwidth = combining_glyphs[i]->width; +-- +2.30.2 + diff --git a/debian/patches/cve_2022_2601/0012-font-Harden-grub_font_blit_glyph-and-grub_font_blit_.patch b/debian/patches/cve_2022_2601/0012-font-Harden-grub_font_blit_glyph-and-grub_font_blit_.patch new file mode 100644 index 0000000..6296bf5 --- /dev/null +++ b/debian/patches/cve_2022_2601/0012-font-Harden-grub_font_blit_glyph-and-grub_font_blit_.patch @@ -0,0 +1,75 @@ +From fcd7aa0c278f7cf3fb9f93f1a3966e1792339eb6 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang <zhangboyang.id@gmail.com> +Date: Mon, 24 Oct 2022 07:15:41 +0800 +Subject: [PATCH 12/14] font: Harden grub_font_blit_glyph() and + grub_font_blit_glyph_mirror() + +As a mitigation and hardening measure add sanity checks to +grub_font_blit_glyph() and grub_font_blit_glyph_mirror(). This patch +makes these two functions do nothing if target blitting area isn't fully +contained in target bitmap. Therefore, if complex calculations in caller +overflows and malicious coordinates are given, we are still safe because +any coordinates which result in out-of-bound-write are rejected. However, +this patch only checks for invalid coordinates, and doesn't provide any +protection against invalid source glyph or destination glyph, e.g. +mismatch between glyph size and buffer size. + +This hardening measure is designed to mitigate possible overflows in +blit_comb(). If overflow occurs, it may return invalid bounding box +during dry run and call grub_font_blit_glyph() with malicious +coordinates during actual blitting. However, we are still safe because +the scratch glyph itself is valid, although its size makes no sense, and +any invalid coordinates are rejected. + +It would be better to call grub_fatal() if illegal parameter is detected. +However, doing this may end up in a dangerous recursion because grub_fatal() +would print messages to the screen and we are in the progress of drawing +characters on the screen. + +Reported-by: Daniel Axtens <dja@axtens.net> +Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/font/font.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/grub-core/font/font.c b/grub-core/font/font.c +index 3d3d803e8..cf15dc2f9 100644 +--- a/grub-core/font/font.c ++++ b/grub-core/font/font.c +@@ -1069,8 +1069,15 @@ static void + grub_font_blit_glyph (struct grub_font_glyph *target, + struct grub_font_glyph *src, unsigned dx, unsigned dy) + { ++ grub_uint16_t max_x, max_y; + unsigned src_bit, tgt_bit, src_byte, tgt_byte; + unsigned i, j; ++ ++ /* Harden against out-of-bound writes. */ ++ if ((grub_add (dx, src->width, &max_x) || max_x > target->width) || ++ (grub_add (dy, src->height, &max_y) || max_y > target->height)) ++ return; ++ + for (i = 0; i < src->height; i++) + { + src_bit = (src->width * i) % 8; +@@ -1102,9 +1109,16 @@ grub_font_blit_glyph_mirror (struct grub_font_glyph *target, + struct grub_font_glyph *src, + unsigned dx, unsigned dy) + { ++ grub_uint16_t max_x, max_y; + unsigned tgt_bit, src_byte, tgt_byte; + signed src_bit; + unsigned i, j; ++ ++ /* Harden against out-of-bound writes. */ ++ if ((grub_add (dx, src->width, &max_x) || max_x > target->width) || ++ (grub_add (dy, src->height, &max_y) || max_y > target->height)) ++ return; ++ + for (i = 0; i < src->height; i++) + { + src_bit = (src->width * i + src->width - 1) % 8; +-- +2.30.2 + diff --git a/debian/patches/cve_2022_2601/0013-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch b/debian/patches/cve_2022_2601/0013-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch new file mode 100644 index 0000000..2db665f --- /dev/null +++ b/debian/patches/cve_2022_2601/0013-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch @@ -0,0 +1,36 @@ +From dd539d695482069d28b40f2d3821f710cdcf6ee6 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang <zhangboyang.id@gmail.com> +Date: Fri, 28 Oct 2022 17:29:16 +0800 +Subject: [PATCH 13/14] font: Assign null_font to glyphs in ascii_font_glyph[] + +The calculations in blit_comb() need information from glyph's font, e.g. +grub_font_get_xheight(main_glyph->font). However, main_glyph->font is +NULL if main_glyph comes from ascii_font_glyph[]. Therefore +grub_font_get_*() crashes because of NULL pointer. + +There is already a solution, the null_font. So, assign it to those glyphs +in ascii_font_glyph[]. + +Reported-by: Daniel Axtens <dja@axtens.net> +Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/font/font.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/font/font.c b/grub-core/font/font.c +index cf15dc2f9..3821937e6 100644 +--- a/grub-core/font/font.c ++++ b/grub-core/font/font.c +@@ -137,7 +137,7 @@ ascii_glyph_lookup (grub_uint32_t code) + ascii_font_glyph[current]->offset_x = 0; + ascii_font_glyph[current]->offset_y = -2; + ascii_font_glyph[current]->device_width = 8; +- ascii_font_glyph[current]->font = NULL; ++ ascii_font_glyph[current]->font = &null_font; + + grub_memcpy (ascii_font_glyph[current]->bitmap, + &ascii_bitmaps[current * ASCII_BITMAP_SIZE], +-- +2.30.2 + diff --git a/debian/patches/cve_2022_2601/0014-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch b/debian/patches/cve_2022_2601/0014-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch new file mode 100644 index 0000000..a94450a --- /dev/null +++ b/debian/patches/cve_2022_2601/0014-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch @@ -0,0 +1,55 @@ +From da90d62316a3b105d2fbd7334d6521936bd6dcf6 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang <zhangboyang.id@gmail.com> +Date: Fri, 28 Oct 2022 21:31:39 +0800 +Subject: [PATCH 14/14] normal/charset: Fix an integer overflow in + grub_unicode_aglomerate_comb() + +The out->ncomb is a bit-field of 8 bits. So, the max possible value is 255. +However, code in grub_unicode_aglomerate_comb() doesn't check for an +overflow when incrementing out->ncomb. If out->ncomb is already 255, +after incrementing it will get 0 instead of 256, and cause illegal +memory access in subsequent processing. + +This patch introduces GRUB_UNICODE_NCOMB_MAX to represent the max +acceptable value of ncomb. The code now checks for this limit and +ignores additional combining characters when limit is reached. + +Reported-by: Daniel Axtens <dja@axtens.net> +Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/normal/charset.c | 3 +++ + include/grub/unicode.h | 2 ++ + 2 files changed, 5 insertions(+) + +diff --git a/grub-core/normal/charset.c b/grub-core/normal/charset.c +index 000e687bd..4f6647116 100644 +--- a/grub-core/normal/charset.c ++++ b/grub-core/normal/charset.c +@@ -472,6 +472,9 @@ grub_unicode_aglomerate_comb (const grub_uint32_t *in, grub_size_t inlen, + if (!haveout) + continue; + ++ if (out->ncomb == GRUB_UNICODE_NCOMB_MAX) ++ continue; ++ + if (comb_type == GRUB_UNICODE_COMB_MC + || comb_type == GRUB_UNICODE_COMB_ME + || comb_type == GRUB_UNICODE_COMB_MN) +diff --git a/include/grub/unicode.h b/include/grub/unicode.h +index 71a4d1a54..9360b0b97 100644 +--- a/include/grub/unicode.h ++++ b/include/grub/unicode.h +@@ -147,7 +147,9 @@ struct grub_unicode_glyph + grub_uint8_t bidi_level:6; /* minimum: 6 */ + enum grub_bidi_type bidi_type:5; /* minimum: :5 */ + ++#define GRUB_UNICODE_NCOMB_MAX ((1 << 8) - 1) + unsigned ncomb:8; ++ + /* Hint by unicode subsystem how wide this character usually is. + Real width is determined by font. Set only in UTF-8 stream. */ + int estimated_width:8; +-- +2.30.2 + diff --git a/debian/patches/debug_verifiers.patch b/debian/patches/debug_verifiers.patch new file mode 100644 index 0000000..2d2daca --- /dev/null +++ b/debian/patches/debug_verifiers.patch @@ -0,0 +1,28 @@ +From 55796e3e90a55d54aff94f2dfeb6e02055e08e30 Mon Sep 17 00:00:00 2001 +From: Steve McIntyre <93sam@debian.org> +Date: Sat, 17 Apr 2021 22:05:47 +0100 +Subject: Add debug to display what's going on with verifiers + +Patch-Name: debug_verifiers.patch +--- + grub-core/kern/verifiers.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/grub-core/kern/verifiers.c b/grub-core/kern/verifiers.c +index 1245d0d9e..5242a723f 100644 +--- a/grub-core/kern/verifiers.c ++++ b/grub-core/kern/verifiers.c +@@ -100,11 +100,13 @@ grub_verifiers_open (grub_file_t io, enum grub_file_type type) + FOR_LIST_ELEMENTS(ver, grub_file_verifiers) + { + enum grub_verify_flags flags = 0; ++ grub_dprintf ("verify", "trying verifier %s\n", ver->name); + err = ver->init (io, type, &context, &flags); + if (err) + goto fail_noclose; + if (flags & GRUB_VERIFY_FLAGS_DEFER_AUTH) + { ++ grub_dprintf ("verify", "verifier %s said GRUB_VERIFY_FLAGS_DEFER_AUTH\n", ver->name); + defer = 1; + continue; + } diff --git a/debian/patches/default-grub-d.patch b/debian/patches/default-grub-d.patch new file mode 100644 index 0000000..f7ca596 --- /dev/null +++ b/debian/patches/default-grub-d.patch @@ -0,0 +1,209 @@ +From 4dff7f7df2853c519c4b0f59ff224c0b31f8223e Mon Sep 17 00:00:00 2001 +From: Colin Watson <cjwatson@ubuntu.com> +Date: Mon, 13 Jan 2014 12:13:10 +0000 +Subject: Read /etc/default/grub.d/*.cfg after /etc/default/grub + +Bug-Ubuntu: https://bugs.launchpad.net/bugs/901600 +Forwarded: no +Last-Update: 2021-09-24 + +Patch-Name: default-grub-d.patch +--- + grub-core/osdep/unix/config.c | 128 ++++++++++++++++++++++++++++------ + util/grub-mkconfig.in | 5 ++ + 2 files changed, 112 insertions(+), 21 deletions(-) + +diff --git a/grub-core/osdep/unix/config.c b/grub-core/osdep/unix/config.c +index 7d6325138..545d64b4c 100644 +--- a/grub-core/osdep/unix/config.c ++++ b/grub-core/osdep/unix/config.c +@@ -24,6 +24,9 @@ + #include <grub/emu/config.h> + #include <grub/util/install.h> + #include <grub/util/misc.h> ++#include <grub/list.h> ++#include <grub/safemath.h> ++#include <assert.h> + #include <string.h> + #include <sys/types.h> + #include <sys/wait.h> +@@ -61,13 +64,27 @@ grub_util_get_localedir (void) + return LOCALEDIR; + } + ++struct cfglist ++{ ++ struct cfglist *next; ++ struct cfglist *prev; ++ char *path; ++}; ++ + void + grub_util_load_config (struct grub_util_config *cfg) + { + pid_t pid; + const char *argv[4]; +- char *script, *ptr; ++ char *script = NULL, *ptr; + const char *cfgfile, *iptr; ++ char *cfgdir; ++ grub_util_fd_dir_t d; ++ struct cfglist *cfgpaths = NULL, *cfgpath, *next_cfgpath; ++ int num_cfgpaths = 0; ++ size_t len_cfgpaths = 0; ++ char **sorted_cfgpaths = NULL; ++ int i; + FILE *f = NULL; + int fd; + const char *v; +@@ -83,29 +100,88 @@ grub_util_load_config (struct grub_util_config *cfg) + cfg->grub_distributor = xstrdup (v); + + cfgfile = grub_util_get_config_filename (); +- if (!grub_util_is_regular (cfgfile)) +- return; ++ if (grub_util_is_regular (cfgfile)) ++ { ++ size_t sz; ++ ++ ++num_cfgpaths; ++ sz = strlen (cfgfile); ++ if (grub_mul (sz, 4, &sz) || ++ grub_add (sz, sizeof (". ''; ") - 1, &sz) || ++ grub_add (len_cfgpaths, sz, &len_cfgpaths)) ++ grub_util_error ("%s", _("overflow is detected")); ++ } ++ ++ cfgdir = xasprintf ("%s.d", cfgfile); ++ d = grub_util_fd_opendir (cfgdir); ++ if (d) ++ { ++ grub_util_fd_dirent_t de; ++ ++ while ((de = grub_util_fd_readdir (d))) ++ { ++ const char *ext = strrchr (de->d_name, '.'); ++ size_t sz; ++ ++ if (!ext || strcmp (ext, ".cfg") != 0) ++ continue; ++ ++ cfgpath = xmalloc (sizeof (*cfgpath)); ++ cfgpath->path = grub_util_path_concat (2, cfgdir, de->d_name); ++ grub_list_push (GRUB_AS_LIST_P (&cfgpaths), GRUB_AS_LIST (cfgpath)); ++ ++num_cfgpaths; ++ sz = strlen (cfgpath->path); ++ if (grub_mul (sz, 4, &sz) || ++ grub_add (sz, sizeof (". ''; ") - 1, &sz) || ++ grub_add (len_cfgpaths, sz, &len_cfgpaths)) ++ grub_util_error ("%s", _("overflow is detected")); ++ } ++ grub_util_fd_closedir (d); ++ } ++ ++ if (num_cfgpaths == 0) ++ goto out; ++ ++ sorted_cfgpaths = xcalloc (num_cfgpaths, sizeof (*sorted_cfgpaths)); ++ i = 0; ++ if (grub_util_is_regular (cfgfile)) ++ sorted_cfgpaths[i++] = xstrdup (cfgfile); ++ FOR_LIST_ELEMENTS_SAFE (cfgpath, next_cfgpath, cfgpaths) ++ { ++ sorted_cfgpaths[i++] = cfgpath->path; ++ free (cfgpath); ++ } ++ assert (i == num_cfgpaths); ++ qsort (sorted_cfgpaths + 1, num_cfgpaths - 1, sizeof (*sorted_cfgpaths), ++ (int (*) (const void *, const void *)) strcmp); + + argv[0] = "sh"; + argv[1] = "-c"; + +- script = xcalloc (4, strlen (cfgfile) + 300); ++ if (grub_add (len_cfgpaths, 300, &len_cfgpaths)) ++ grub_util_error ("%s", _("overflow is detected")); ++ script = xmalloc (len_cfgpaths); + + ptr = script; +- memcpy (ptr, ". '", 3); +- ptr += 3; +- for (iptr = cfgfile; *iptr; iptr++) ++ for (i = 0; i < num_cfgpaths; i++) + { +- if (*iptr == '\\') ++ memcpy (ptr, ". '", 3); ++ ptr += 3; ++ for (iptr = sorted_cfgpaths[i]; *iptr; iptr++) + { +- memcpy (ptr, "'\\''", 4); +- ptr += 4; +- continue; ++ if (*iptr == '\\') ++ { ++ memcpy (ptr, "'\\''", 4); ++ ptr += 4; ++ continue; ++ } ++ *ptr++ = *iptr; + } +- *ptr++ = *iptr; ++ memcpy (ptr, "'; ", 3); ++ ptr += 3; + } + +- strcpy (ptr, "'; printf \"GRUB_ENABLE_CRYPTODISK=%s\\nGRUB_DISTRIBUTOR=%s\\n\" " ++ strcpy (ptr, "printf \"GRUB_ENABLE_CRYPTODISK=%s\\nGRUB_DISTRIBUTOR=%s\\n\" " + "\"$GRUB_ENABLE_CRYPTODISK\" \"$GRUB_DISTRIBUTOR\""); + + argv[2] = script; +@@ -125,15 +201,25 @@ grub_util_load_config (struct grub_util_config *cfg) + waitpid (pid, NULL, 0); + } + if (f) +- return; ++ goto out; + +- f = grub_util_fopen (cfgfile, "r"); +- if (f) ++ for (i = 0; i < num_cfgpaths; i++) + { +- grub_util_parse_config (f, cfg, 0); +- fclose (f); ++ f = grub_util_fopen (sorted_cfgpaths[i], "r"); ++ if (f) ++ { ++ grub_util_parse_config (f, cfg, 0); ++ fclose (f); ++ } ++ else ++ grub_util_warn (_("cannot open configuration file `%s': %s"), ++ cfgfile, strerror (errno)); + } +- else +- grub_util_warn (_("cannot open configuration file `%s': %s"), +- cfgfile, strerror (errno)); ++ ++out: ++ free (script); ++ for (i = 0; i < num_cfgpaths; i++) ++ free (sorted_cfgpaths[i]); ++ free (sorted_cfgpaths); ++ free (cfgdir); + } +diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in +index 0fd618e35..0265a5a66 100644 +--- a/util/grub-mkconfig.in ++++ b/util/grub-mkconfig.in +@@ -160,6 +160,11 @@ fi + if test -f ${sysconfdir}/default/grub ; then + . ${sysconfdir}/default/grub + fi ++for x in ${sysconfdir}/default/grub.d/*.cfg ; do ++ if [ -e "${x}" ]; then ++ . "${x}" ++ fi ++done + + if [ "x${GRUB_DISABLE_UUID}" = "xtrue" ]; then + if [ -z "${GRUB_DISABLE_LINUX_UUID}" ]; then diff --git a/debian/patches/dejavu-font-path.patch b/debian/patches/dejavu-font-path.patch new file mode 100644 index 0000000..cda9800 --- /dev/null +++ b/debian/patches/dejavu-font-path.patch @@ -0,0 +1,23 @@ +From 973e040bdeddcf366a7a45bb5d9f77e06f4784c7 Mon Sep 17 00:00:00 2001 +From: Fabian Greffrath <fabian@greffrath.com> +Date: Tue, 19 May 2020 12:19:26 +0200 +Subject: add /u/s/fonts/truetype/dejavu to the DejaVu fonts search paths + +Patch-Name: dejavu-font-path.patch +--- + configure.ac | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/configure.ac b/configure.ac +index b3fb7437e..22c6cf7ac 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1719,7 +1719,7 @@ fi + + if test x"$starfield_excuse" = x; then + for ext in pcf pcf.gz bdf bdf.gz ttf ttf.gz; do +- for dir in . /usr/src /usr/share/fonts/X11/misc /usr/share/fonts/truetype/ttf-dejavu /usr/share/fonts/dejavu /usr/share/fonts/truetype; do ++ for dir in . /usr/src /usr/share/fonts/X11/misc /usr/share/fonts/truetype/dejavu /usr/share/fonts/truetype/ttf-dejavu /usr/share/fonts/dejavu /usr/share/fonts/truetype; do + if test -f "$dir/DejaVuSans.$ext"; then + DJVU_FONT_SOURCE="$dir/DejaVuSans.$ext" + break 2 diff --git a/debian/patches/disable-floppies.patch b/debian/patches/disable-floppies.patch new file mode 100644 index 0000000..ee4ae5a --- /dev/null +++ b/debian/patches/disable-floppies.patch @@ -0,0 +1,37 @@ +From 6a1ff6845e571d2a9885763a3e52a16a9eec54bb Mon Sep 17 00:00:00 2001 +From: Colin Watson <cjwatson@debian.org> +Date: Mon, 13 Jan 2014 12:12:54 +0000 +Subject: Disable use of floppy devices + +An ugly kludge. Should this be merged upstream? + +Author: Robert Millan + +Patch-Name: disable-floppies.patch +--- + grub-core/kern/emu/hostdisk.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/grub-core/kern/emu/hostdisk.c b/grub-core/kern/emu/hostdisk.c +index d975265b2..f90b6c9ce 100644 +--- a/grub-core/kern/emu/hostdisk.c ++++ b/grub-core/kern/emu/hostdisk.c +@@ -532,6 +532,18 @@ read_device_map (const char *dev_map) + continue; + } + ++ if (! strncmp (p, "/dev/fd", sizeof ("/dev/fd") - 1)) ++ { ++ char *q = p + sizeof ("/dev/fd") - 1; ++ if (*q >= '0' && *q <= '9') ++ { ++ free (map[drive].drive); ++ map[drive].drive = NULL; ++ grub_util_info ("`%s' looks like a floppy drive, skipping", p); ++ continue; ++ } ++ } ++ + /* On Linux, the devfs uses symbolic links horribly, and that + confuses the interface very much, so use realpath to expand + symbolic links. */ diff --git a/debian/patches/dpkg-version-comparison.patch b/debian/patches/dpkg-version-comparison.patch new file mode 100644 index 0000000..d20e986 --- /dev/null +++ b/debian/patches/dpkg-version-comparison.patch @@ -0,0 +1,38 @@ +From 562d50025e18052cabc40c8eb63ed4d0bb5de236 Mon Sep 17 00:00:00 2001 +From: Robert Millan <rmh@aybabtu.com> +Date: Mon, 13 Jan 2014 12:12:52 +0000 +Subject: Improve handling of Debian kernel version numbers + +Forwarded: not-needed +Last-Update: 2013-12-20 + +Patch-Name: dpkg-version-comparison.patch +--- + util/grub-mkconfig_lib.in | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in +index 301d1ac22..17f9b3e58 100644 +--- a/util/grub-mkconfig_lib.in ++++ b/util/grub-mkconfig_lib.in +@@ -243,8 +243,9 @@ version_test_numeric () + + version_test_gt () + { +- version_test_gt_a="`echo "$1" | sed -e "s/[^-]*-//"`" +- version_test_gt_b="`echo "$2" | sed -e "s/[^-]*-//"`" ++ version_test_gt_sedexp="s/[^-]*-//;s/[._-]\(pre\|rc\|test\|git\|old\|trunk\)/~\1/g" ++ version_test_gt_a="`echo "$1" | sed -e "$version_test_gt_sedexp"`" ++ version_test_gt_b="`echo "$2" | sed -e "$version_test_gt_sedexp"`" + version_test_gt_cmp=gt + if [ "x$version_test_gt_b" = "x" ] ; then + return 0 +@@ -254,7 +255,7 @@ version_test_gt () + *.old:*) version_test_gt_a="`echo "$version_test_gt_a" | sed -e 's/\.old$//'`" ; version_test_gt_cmp=gt ;; + *:*.old) version_test_gt_b="`echo "$version_test_gt_b" | sed -e 's/\.old$//'`" ; version_test_gt_cmp=ge ;; + esac +- version_test_numeric "$version_test_gt_a" "$version_test_gt_cmp" "$version_test_gt_b" ++ dpkg --compare-versions "$version_test_gt_a" "$version_test_gt_cmp" "$version_test_gt_b" + return "$?" + } + diff --git a/debian/patches/efi-variable-storage-minimise-writes.patch b/debian/patches/efi-variable-storage-minimise-writes.patch new file mode 100644 index 0000000..c06dbe8 --- /dev/null +++ b/debian/patches/efi-variable-storage-minimise-writes.patch @@ -0,0 +1,895 @@ +From 6e3841fc4abf50d16d819c39ac5de74ccc4de225 Mon Sep 17 00:00:00 2001 +From: Colin Watson <cjwatson@ubuntu.com> +Date: Mon, 11 Mar 2019 11:17:43 +0000 +Subject: Minimise writes to EFI variable storage + +Some UEFI firmware is easily provoked into running out of space in its +variable storage. This is usually due to certain kernel drivers (e.g. +pstore), but regardless of the cause it can cause grub-install to fail +because it currently asks efibootmgr to delete and re-add entries, and +the deletion often doesn't result in an immediate garbage collection. +Writing variables frequently also increases wear on the NVRAM which may +have limited write cycles. For these reasons, it's desirable to find a +way to minimise writes while still allowing grub-install to ensure that +a suitable boot entry exists. + +Unfortunately, efibootmgr doesn't offer an interface that would let +grub-install do this. It doesn't in general make very much effort to +minimise writes; it doesn't allow modifying an existing Boot* variable +entry, except in certain limited ways; and current versions don't have a +way to export the expected variable data so that grub-install can +compare it to the current data. While it would be possible (and perhaps +desirable?) to add at least some of this to efibootmgr, that would still +leave the problem that there isn't a good upstreamable way for +grub-install to guarantee that it has a new enough version of +efibootmgr. In any case, it's cumbersome and slow for grub-install to +have to fork efibootmgr to get things done. + +Fortunately, a few years ago Peter Jones helpfully factored out a +substantial part of efibootmgr to the efivar and efiboot libraries, and +so it's now possible to have grub-install use those directly. We still +have to use some code from efibootmgr, but much less than would +previously have been necessary. + +grub-install now reuses existing boot entries where possible, and avoids +writing to variables when the new contents are the same as the old +contents. In the common upgrade case where nothing needs to change, it +no longer writes to NVRAM at all. It's also now slightly faster, since +using libefivar is faster than forking efibootmgr. + +Fixes Debian bug #891434. + +Signed-off-by: Colin Watson <cjwatson@ubuntu.com> + +Bug-Debian: https://bugs.debian.org/891434 +Forwarded: https://lists.gnu.org/archive/html/grub-devel/2019-03/msg00119.html +Last-Update: 2019-03-23 + +Patch-Name: efi-variable-storage-minimise-writes.patch +--- + INSTALL | 5 + + Makefile.util.def | 20 ++ + configure.ac | 12 + + grub-core/osdep/efivar.c | 3 + + grub-core/osdep/unix/efivar.c | 508 ++++++++++++++++++++++++++++++++ + grub-core/osdep/unix/platform.c | 100 +------ + include/grub/util/install.h | 5 + + util/grub-install.c | 4 +- + 8 files changed, 562 insertions(+), 95 deletions(-) + create mode 100644 grub-core/osdep/efivar.c + create mode 100644 grub-core/osdep/unix/efivar.c + +diff --git a/INSTALL b/INSTALL +index 79a0af7d9..590b52482 100644 +--- a/INSTALL ++++ b/INSTALL +@@ -23,6 +23,11 @@ configuring the GRUB. + * Other standard GNU/Unix tools + * a libc with large file support (e.g. glibc 2.1 or later) + ++On Unix-based systems, you also need: ++ ++* libefivar (recommended) ++* libefiboot (recommended; your OS may ship this together with libefivar) ++ + On GNU/Linux, you also need: + + * libdevmapper 1.02.34 or later (recommended) +diff --git a/Makefile.util.def b/Makefile.util.def +index 27f948291..a3d134b03 100644 +--- a/Makefile.util.def ++++ b/Makefile.util.def +@@ -570,6 +570,8 @@ program = { + common = grub-core/osdep/compress.c; + extra_dist = grub-core/osdep/unix/compress.c; + extra_dist = grub-core/osdep/basic/compress.c; ++ common = grub-core/osdep/efivar.c; ++ extra_dist = grub-core/osdep/unix/efivar.c; + common = util/editenv.c; + common = grub-core/osdep/blocklist.c; + common = grub-core/osdep/config.c; +@@ -583,12 +585,15 @@ program = { + common = grub-core/kern/emu/argp_common.c; + common = grub-core/osdep/init.c; + ++ cflags = '$(EFIVAR_CFLAGS)'; ++ + ldadd = '$(LIBLZMA)'; + ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; + ldadd = libgrubkern.a; + ldadd = grub-core/lib/gnulib/libgnu.a; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; ++ ldadd = '$(EFIVAR_LIBS)'; + + condition = COND_HAVE_EXEC; + }; +@@ -617,6 +622,8 @@ program = { + extra_dist = grub-core/osdep/basic/no_platform.c; + extra_dist = grub-core/osdep/unix/platform.c; + common = grub-core/osdep/compress.c; ++ common = grub-core/osdep/efivar.c; ++ extra_dist = grub-core/osdep/unix/efivar.c; + common = util/editenv.c; + common = grub-core/osdep/blocklist.c; + common = grub-core/osdep/config.c; +@@ -630,12 +637,15 @@ program = { + common = grub-core/kern/emu/argp_common.c; + common = grub-core/osdep/init.c; + ++ cflags = '$(EFIVAR_CFLAGS)'; ++ + ldadd = '$(LIBLZMA)'; + ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; + ldadd = libgrubkern.a; + ldadd = grub-core/lib/gnulib/libgnu.a; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; ++ ldadd = '$(EFIVAR_LIBS)'; + }; + + program = { +@@ -657,6 +667,8 @@ program = { + common = grub-core/osdep/platform.c; + common = grub-core/osdep/platform_unix.c; + common = grub-core/osdep/compress.c; ++ common = grub-core/osdep/efivar.c; ++ extra_dist = grub-core/osdep/unix/efivar.c; + common = util/editenv.c; + common = grub-core/osdep/blocklist.c; + common = grub-core/osdep/config.c; +@@ -669,12 +681,15 @@ program = { + common = grub-core/kern/emu/argp_common.c; + common = grub-core/osdep/init.c; + ++ cflags = '$(EFIVAR_CFLAGS)'; ++ + ldadd = '$(LIBLZMA)'; + ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; + ldadd = libgrubkern.a; + ldadd = grub-core/lib/gnulib/libgnu.a; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; ++ ldadd = '$(EFIVAR_LIBS)'; + }; + + program = { +@@ -696,6 +711,8 @@ program = { + common = grub-core/osdep/platform.c; + common = grub-core/osdep/platform_unix.c; + common = grub-core/osdep/compress.c; ++ common = grub-core/osdep/efivar.c; ++ extra_dist = grub-core/osdep/unix/efivar.c; + common = util/editenv.c; + common = grub-core/osdep/blocklist.c; + common = grub-core/osdep/config.c; +@@ -705,12 +722,15 @@ program = { + common = grub-core/kern/emu/argp_common.c; + common = grub-core/osdep/init.c; + ++ cflags = '$(EFIVAR_CFLAGS)'; ++ + ldadd = '$(LIBLZMA)'; + ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; + ldadd = libgrubkern.a; + ldadd = grub-core/lib/gnulib/libgnu.a; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; ++ ldadd = '$(EFIVAR_LIBS)'; + }; + + script = { +diff --git a/configure.ac b/configure.ac +index e11df6bc5..b3fb7437e 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -452,6 +452,18 @@ AC_CHECK_HEADER([util.h], [ + ]) + AC_SUBST([LIBUTIL]) + ++case "$host_os" in ++ cygwin | windows* | mingw32* | aros*) ++ ;; ++ *) ++ # For setting EFI variables in grub-install. ++ PKG_CHECK_MODULES([EFIVAR], [efivar efiboot], [ ++ AC_DEFINE([HAVE_EFIVAR], [1], ++ [Define to 1 if you have the efivar and efiboot libraries.]) ++ ], [:]) ++ ;; ++esac ++ + AC_CACHE_CHECK([whether -Wtrampolines work], [grub_cv_host_cc_wtrampolines], [ + SAVED_CFLAGS="$CFLAGS" + CFLAGS="$HOST_CFLAGS -Wtrampolines -Werror" +diff --git a/grub-core/osdep/efivar.c b/grub-core/osdep/efivar.c +new file mode 100644 +index 000000000..d2750e252 +--- /dev/null ++++ b/grub-core/osdep/efivar.c +@@ -0,0 +1,3 @@ ++#if !defined (__MINGW32__) && !defined (__CYGWIN__) && !defined (__AROS__) ++#include "unix/efivar.c" ++#endif +diff --git a/grub-core/osdep/unix/efivar.c b/grub-core/osdep/unix/efivar.c +new file mode 100644 +index 000000000..4a58328b4 +--- /dev/null ++++ b/grub-core/osdep/unix/efivar.c +@@ -0,0 +1,508 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2013,2019 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++/* Contains portions derived from efibootmgr, licensed as follows: ++ * ++ * Copyright (C) 2001-2004 Dell, Inc. <Matt_Domsch@dell.com> ++ * Copyright 2015-2016 Red Hat, Inc. <pjones@redhat.com> ++ * ++ * 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 ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include <config.h> ++ ++#ifdef HAVE_EFIVAR ++ ++#include <grub/util/install.h> ++#include <grub/emu/hostdisk.h> ++#include <grub/util/misc.h> ++#include <grub/list.h> ++#include <grub/misc.h> ++#include <grub/emu/exec.h> ++#include <sys/types.h> ++#include <ctype.h> ++#include <errno.h> ++#include <stdlib.h> ++#include <string.h> ++ ++#include <efiboot.h> ++#include <efivar.h> ++ ++struct efi_variable { ++ struct efi_variable *next; ++ struct efi_variable **prev; ++ char *name; ++ efi_guid_t guid; ++ uint8_t *data; ++ size_t data_size; ++ uint32_t attributes; ++ int num; ++}; ++ ++/* Boot option attributes. */ ++#define LOAD_OPTION_ACTIVE 0x00000001 ++ ++/* GUIDs. */ ++#define BLKX_UNKNOWN_GUID \ ++ EFI_GUID (0x47c7b225, 0xc42a, 0x11d2, 0x8e57, 0x00, 0xa0, 0xc9, 0x69, \ ++ 0x72, 0x3b) ++ ++/* Log all errors recorded by libefivar/libefiboot. */ ++static void ++show_efi_errors (void) ++{ ++ int i; ++ int saved_errno = errno; ++ ++ for (i = 0; ; ++i) ++ { ++ char *filename, *function, *message = NULL; ++ int line, error = 0, rc; ++ ++ rc = efi_error_get (i, &filename, &function, &line, &message, &error); ++ if (rc < 0) ++ /* Give up. The caller is going to log an error anyway. */ ++ break; ++ if (rc == 0) ++ /* No more errors. */ ++ break; ++ grub_util_warn ("%s: %s: %s", function, message, strerror (error)); ++ } ++ ++ efi_error_clear (); ++ errno = saved_errno; ++} ++ ++static struct efi_variable * ++new_efi_variable (void) ++{ ++ struct efi_variable *new = xmalloc (sizeof (*new)); ++ memset (new, 0, sizeof (*new)); ++ return new; ++} ++ ++static struct efi_variable * ++new_boot_variable (void) ++{ ++ struct efi_variable *new = new_efi_variable (); ++ new->guid = EFI_GLOBAL_GUID; ++ new->attributes = EFI_VARIABLE_NON_VOLATILE | ++ EFI_VARIABLE_BOOTSERVICE_ACCESS | ++ EFI_VARIABLE_RUNTIME_ACCESS; ++ return new; ++} ++ ++static void ++free_efi_variable (struct efi_variable *entry) ++{ ++ if (entry) ++ { ++ free (entry->name); ++ free (entry->data); ++ free (entry); ++ } ++} ++ ++static int ++read_efi_variable (const char *name, struct efi_variable **entry) ++{ ++ struct efi_variable *new = new_efi_variable (); ++ int rc; ++ ++ rc = efi_get_variable (EFI_GLOBAL_GUID, name, ++ &new->data, &new->data_size, &new->attributes); ++ if (rc < 0) ++ { ++ free_efi_variable (new); ++ new = NULL; ++ } ++ ++ if (new) ++ { ++ /* Latest Apple firmware sets the high bit which appears invalid ++ to the Linux kernel if we write it back, so let's zero it out if it ++ is set since it would be invalid to set it anyway. */ ++ new->attributes = new->attributes & ~(1 << 31); ++ ++ new->name = xstrdup (name); ++ new->guid = EFI_GLOBAL_GUID; ++ } ++ ++ *entry = new; ++ return rc; ++} ++ ++/* Set an EFI variable, but only if it differs from the current value. ++ Some firmware implementations are liable to fill up flash space if we set ++ variables unnecessarily, so try to keep write activity to a minimum. */ ++static int ++set_efi_variable (const char *name, struct efi_variable *entry) ++{ ++ struct efi_variable *old = NULL; ++ int rc = 0; ++ ++ read_efi_variable (name, &old); ++ efi_error_clear (); ++ if (old && old->attributes == entry->attributes && ++ old->data_size == entry->data_size && ++ memcmp (old->data, entry->data, entry->data_size) == 0) ++ grub_util_info ("skipping unnecessary update of EFI variable %s", name); ++ else ++ { ++ rc = efi_set_variable (EFI_GLOBAL_GUID, name, ++ entry->data, entry->data_size, entry->attributes, ++ 0644); ++ if (rc < 0) ++ grub_util_warn (_("Cannot set EFI variable %s"), name); ++ } ++ free_efi_variable (old); ++ return rc; ++} ++ ++static int ++cmpvarbyname (const void *p1, const void *p2) ++{ ++ const struct efi_variable *var1 = *(const struct efi_variable **)p1; ++ const struct efi_variable *var2 = *(const struct efi_variable **)p2; ++ return strcmp (var1->name, var2->name); ++} ++ ++static int ++read_boot_variables (struct efi_variable **varlist) ++{ ++ int rc; ++ efi_guid_t *guid = NULL; ++ char *name = NULL; ++ struct efi_variable **newlist = NULL; ++ int nentries = 0; ++ int i; ++ ++ while ((rc = efi_get_next_variable_name (&guid, &name)) > 0) ++ { ++ const char *snum = name + sizeof ("Boot") - 1; ++ struct efi_variable *var = NULL; ++ unsigned int num; ++ ++ if (memcmp (guid, &efi_guid_global, sizeof (efi_guid_global)) != 0 || ++ strncmp (name, "Boot", sizeof ("Boot") - 1) != 0 || ++ !grub_isxdigit (snum[0]) || !grub_isxdigit (snum[1]) || ++ !grub_isxdigit (snum[2]) || !grub_isxdigit (snum[3])) ++ continue; ++ ++ rc = read_efi_variable (name, &var); ++ if (rc < 0) ++ break; ++ ++ if (sscanf (var->name, "Boot%04X-%*s", &num) == 1 && num < 65536) ++ var->num = num; ++ ++ newlist = xrealloc (newlist, (++nentries) * sizeof (*newlist)); ++ newlist[nentries - 1] = var; ++ } ++ if (rc == 0 && newlist) ++ { ++ qsort (newlist, nentries, sizeof (*newlist), cmpvarbyname); ++ for (i = nentries - 1; i >= 0; --i) ++ grub_list_push (GRUB_AS_LIST_P (varlist), GRUB_AS_LIST (newlist[i])); ++ } ++ else if (newlist) ++ { ++ for (i = 0; i < nentries; ++i) ++ free_efi_variable (newlist[i]); ++ free (newlist); ++ } ++ return rc; ++} ++ ++#define GET_ORDER(data, i) \ ++ ((uint16_t) ((data)[(i) * 2]) + ((data)[(i) * 2 + 1] << 8)) ++#define SET_ORDER(data, i, num) \ ++ do { \ ++ (data)[(i) * 2] = (num) & 0xFF; \ ++ (data)[(i) * 2 + 1] = ((num) >> 8) & 0xFF; \ ++ } while (0) ++ ++static void ++remove_from_boot_order (struct efi_variable *order, uint16_t num) ++{ ++ unsigned int old_i, new_i; ++ ++ /* We've got an array (in order->data) of the order. Squeeze out any ++ instance of the entry we're deleting by shifting the remainder down. */ ++ for (old_i = 0, new_i = 0; ++ old_i < order->data_size / sizeof (uint16_t); ++ ++old_i) ++ { ++ uint16_t old_num = GET_ORDER (order->data, old_i); ++ if (old_num != num) ++ { ++ if (new_i != old_i) ++ SET_ORDER (order->data, new_i, old_num); ++ ++new_i; ++ } ++ } ++ ++ order->data_size = new_i * sizeof (uint16_t); ++} ++ ++static void ++add_to_boot_order (struct efi_variable *order, uint16_t num) ++{ ++ int i; ++ size_t new_data_size; ++ uint8_t *new_data; ++ ++ /* Check whether this entry is already in the boot order. If it is, leave ++ it alone. */ ++ for (i = 0; i < order->data_size / sizeof (uint16_t); ++i) ++ if (GET_ORDER (order->data, i) == num) ++ return; ++ ++ new_data_size = order->data_size + sizeof (uint16_t); ++ new_data = xmalloc (new_data_size); ++ SET_ORDER (new_data, 0, num); ++ memcpy (new_data + sizeof (uint16_t), order->data, order->data_size); ++ free (order->data); ++ order->data = new_data; ++ order->data_size = new_data_size; ++} ++ ++static int ++find_free_boot_num (struct efi_variable *entries) ++{ ++ int num_vars = 0, i; ++ struct efi_variable *entry; ++ ++ FOR_LIST_ELEMENTS (entry, entries) ++ ++num_vars; ++ ++ if (num_vars == 0) ++ return 0; ++ ++ /* O(n^2), but n is small and this is easy. */ ++ for (i = 0; i < num_vars; ++i) ++ { ++ int found = 0; ++ FOR_LIST_ELEMENTS (entry, entries) ++ { ++ if (entry->num == i) ++ { ++ found = 1; ++ break; ++ } ++ } ++ if (!found) ++ return i; ++ } ++ ++ return i; ++} ++ ++static int ++get_edd_version (void) ++{ ++ efi_guid_t blkx_guid = BLKX_UNKNOWN_GUID; ++ uint8_t *data = NULL; ++ size_t data_size = 0; ++ uint32_t attributes; ++ efidp_header *path; ++ int rc; ++ ++ rc = efi_get_variable (blkx_guid, "blk0", &data, &data_size, &attributes); ++ if (rc < 0) ++ return rc; ++ ++ path = (efidp_header *) data; ++ if (path->type == 2 && path->subtype == 1) ++ return 3; ++ return 1; ++} ++ ++static struct efi_variable * ++make_boot_variable (int num, const char *disk, int part, const char *loader, ++ const char *label) ++{ ++ struct efi_variable *entry = new_boot_variable (); ++ uint32_t options; ++ uint32_t edd10_devicenum; ++ ssize_t dp_needed, loadopt_needed; ++ efidp dp = NULL; ++ ++ options = EFIBOOT_ABBREV_HD; ++ switch (get_edd_version ()) { ++ case 1: ++ options = EFIBOOT_ABBREV_EDD10; ++ break; ++ case 3: ++ options = EFIBOOT_ABBREV_NONE; ++ break; ++ } ++ ++ /* This may not be the right disk; but it's probably only an issue on very ++ old hardware anyway. */ ++ edd10_devicenum = 0x80; ++ ++ dp_needed = efi_generate_file_device_path_from_esp (NULL, 0, disk, part, ++ loader, options, ++ edd10_devicenum); ++ if (dp_needed < 0) ++ goto err; ++ ++ dp = xmalloc (dp_needed); ++ dp_needed = efi_generate_file_device_path_from_esp ((uint8_t *) dp, ++ dp_needed, disk, part, ++ loader, options, ++ edd10_devicenum); ++ if (dp_needed < 0) ++ goto err; ++ ++ loadopt_needed = efi_loadopt_create (NULL, 0, LOAD_OPTION_ACTIVE, ++ dp, dp_needed, (unsigned char *) label, ++ NULL, 0); ++ if (loadopt_needed < 0) ++ goto err; ++ entry->data_size = loadopt_needed; ++ entry->data = xmalloc (entry->data_size); ++ loadopt_needed = efi_loadopt_create (entry->data, entry->data_size, ++ LOAD_OPTION_ACTIVE, dp, dp_needed, ++ (unsigned char *) label, NULL, 0); ++ if (loadopt_needed < 0) ++ goto err; ++ ++ entry->name = xasprintf ("Boot%04X", num); ++ entry->num = num; ++ ++ return entry; ++ ++err: ++ free_efi_variable (entry); ++ free (dp); ++ return NULL; ++} ++ ++int ++grub_install_efivar_register_efi (grub_device_t efidir_grub_dev, ++ const char *efifile_path, ++ const char *efi_distributor) ++{ ++ const char *efidir_disk; ++ int efidir_part; ++ struct efi_variable *entries = NULL, *entry; ++ struct efi_variable *order; ++ int entry_num = -1; ++ int rc; ++ ++ efidir_disk = grub_util_biosdisk_get_osdev (efidir_grub_dev->disk); ++ efidir_part = efidir_grub_dev->disk->partition ? efidir_grub_dev->disk->partition->number + 1 : 1; ++ ++#ifdef __linux__ ++ /* ++ * Linux uses efivarfs (mounted on /sys/firmware/efi/efivars) to access the ++ * EFI variable store. Some legacy systems may still use the deprecated ++ * efivars interface (accessed through /sys/firmware/efi/vars). Where both ++ * are present, libefivar will use the former in preference, so attempting ++ * to load efivars will not interfere with later operations. ++ */ ++ grub_util_exec_redirect_all ((const char * []){ "modprobe", "efivars", NULL }, ++ NULL, NULL, "/dev/null"); ++#endif ++ ++ if (!efi_variables_supported ()) ++ { ++ grub_util_warn ("%s", ++ _("EFI variables are not supported on this system.")); ++ /* Let the user continue. Perhaps they can still arrange to boot GRUB ++ manually. */ ++ return 0; ++ } ++ ++ rc = read_boot_variables (&entries); ++ if (rc < 0) ++ { ++ grub_util_warn ("%s", _("Cannot read EFI Boot* variables")); ++ goto err; ++ } ++ rc = read_efi_variable ("BootOrder", &order); ++ if (rc < 0) ++ { ++ order = new_boot_variable (); ++ order->name = xstrdup ("BootOrder"); ++ efi_error_clear (); ++ } ++ ++ /* Delete old entries from the same distributor. */ ++ FOR_LIST_ELEMENTS (entry, entries) ++ { ++ efi_load_option *load_option = (efi_load_option *) entry->data; ++ const char *label; ++ ++ if (entry->num < 0) ++ continue; ++ label = (const char *) efi_loadopt_desc (load_option, entry->data_size); ++ if (strcasecmp (label, efi_distributor) != 0) ++ continue; ++ ++ /* To avoid problems with some firmware implementations, reuse the first ++ matching variable we find rather than deleting and recreating it. */ ++ if (entry_num == -1) ++ entry_num = entry->num; ++ else ++ { ++ grub_util_info ("deleting superfluous EFI variable %s (%s)", ++ entry->name, label); ++ rc = efi_del_variable (EFI_GLOBAL_GUID, entry->name); ++ if (rc < 0) ++ { ++ grub_util_warn (_("Cannot delete EFI variable %s"), entry->name); ++ goto err; ++ } ++ } ++ ++ remove_from_boot_order (order, (uint16_t) entry->num); ++ } ++ ++ if (entry_num == -1) ++ entry_num = find_free_boot_num (entries); ++ entry = make_boot_variable (entry_num, efidir_disk, efidir_part, ++ efifile_path, efi_distributor); ++ if (!entry) ++ goto err; ++ ++ grub_util_info ("setting EFI variable %s", entry->name); ++ rc = set_efi_variable (entry->name, entry); ++ if (rc < 0) ++ goto err; ++ ++ add_to_boot_order (order, (uint16_t) entry_num); ++ ++ grub_util_info ("setting EFI variable BootOrder"); ++ rc = set_efi_variable ("BootOrder", order); ++ if (rc < 0) ++ goto err; ++ ++ return 0; ++ ++err: ++ show_efi_errors (); ++ return errno; ++} ++ ++#endif /* HAVE_EFIVAR */ +diff --git a/grub-core/osdep/unix/platform.c b/grub-core/osdep/unix/platform.c +index 9c439326a..b561174ea 100644 +--- a/grub-core/osdep/unix/platform.c ++++ b/grub-core/osdep/unix/platform.c +@@ -19,15 +19,12 @@ + #include <config.h> + + #include <grub/util/install.h> +-#include <grub/emu/hostdisk.h> + #include <grub/util/misc.h> + #include <grub/misc.h> + #include <grub/i18n.h> + #include <grub/emu/exec.h> + #include <sys/types.h> +-#include <dirent.h> + #include <string.h> +-#include <errno.h> + + static char * + get_ofpathname (const char *dev) +@@ -78,102 +75,19 @@ get_ofpathname (const char *dev) + dev); + } + +-static int +-grub_install_remove_efi_entries_by_distributor (const char *efi_distributor) +-{ +- int fd; +- pid_t pid = grub_util_exec_pipe ((const char * []){ "efibootmgr", NULL }, &fd); +- char *line = NULL; +- size_t len = 0; +- int rc = 0; +- +- if (!pid) +- { +- grub_util_warn (_("Unable to open stream from %s: %s"), +- "efibootmgr", strerror (errno)); +- return errno; +- } +- +- FILE *fp = fdopen (fd, "r"); +- if (!fp) +- { +- grub_util_warn (_("Unable to open stream from %s: %s"), +- "efibootmgr", strerror (errno)); +- return errno; +- } +- +- line = xmalloc (80); +- len = 80; +- while (1) +- { +- int ret; +- char *bootnum; +- ret = getline (&line, &len, fp); +- if (ret == -1) +- break; +- if (grub_memcmp (line, "Boot", sizeof ("Boot") - 1) != 0 +- || line[sizeof ("Boot") - 1] < '0' +- || line[sizeof ("Boot") - 1] > '9') +- continue; +- if (!strcasestr (line, efi_distributor)) +- continue; +- bootnum = line + sizeof ("Boot") - 1; +- bootnum[4] = '\0'; +- if (!verbosity) +- rc = grub_util_exec ((const char * []){ "efibootmgr", "-q", +- "-b", bootnum, "-B", NULL }); +- else +- rc = grub_util_exec ((const char * []){ "efibootmgr", +- "-b", bootnum, "-B", NULL }); +- } +- +- free (line); +- return rc; +-} +- + int + grub_install_register_efi (grub_device_t efidir_grub_dev, + const char *efifile_path, + const char *efi_distributor) + { +- const char * efidir_disk; +- int efidir_part; +- int ret; +- efidir_disk = grub_util_biosdisk_get_osdev (efidir_grub_dev->disk); +- efidir_part = efidir_grub_dev->disk->partition ? efidir_grub_dev->disk->partition->number + 1 : 1; +- +- if (grub_util_exec_redirect_null ((const char * []){ "efibootmgr", "--version", NULL })) +- { +- /* TRANSLATORS: This message is shown when required executable `%s' +- isn't found. */ +- grub_util_error (_("%s: not found"), "efibootmgr"); +- } +- +- /* On Linux, we need the efivars kernel modules. */ +-#ifdef __linux__ +- grub_util_exec ((const char * []){ "modprobe", "-q", "efivars", NULL }); ++#ifdef HAVE_EFIVAR ++ return grub_install_efivar_register_efi (efidir_grub_dev, efifile_path, ++ efi_distributor); ++#else ++ grub_util_error ("%s", ++ _("GRUB was not built with efivar support; " ++ "cannot register EFI boot entry")); + #endif +- /* Delete old entries from the same distributor. */ +- ret = grub_install_remove_efi_entries_by_distributor (efi_distributor); +- if (ret) +- return ret; +- +- char *efidir_part_str = xasprintf ("%d", efidir_part); +- +- if (!verbosity) +- ret = grub_util_exec ((const char * []){ "efibootmgr", "-q", +- "-c", "-d", efidir_disk, +- "-p", efidir_part_str, "-w", +- "-L", efi_distributor, "-l", +- efifile_path, NULL }); +- else +- ret = grub_util_exec ((const char * []){ "efibootmgr", +- "-c", "-d", efidir_disk, +- "-p", efidir_part_str, "-w", +- "-L", efi_distributor, "-l", +- efifile_path, NULL }); +- free (efidir_part_str); +- return ret; + } + + void +diff --git a/include/grub/util/install.h b/include/grub/util/install.h +index 135ba48d2..134b862ec 100644 +--- a/include/grub/util/install.h ++++ b/include/grub/util/install.h +@@ -226,6 +226,11 @@ grub_install_get_default_x86_platform (void); + const char * + grub_install_get_default_powerpc_machtype (void); + ++int ++grub_install_efivar_register_efi (grub_device_t efidir_grub_dev, ++ const char *efifile_path, ++ const char *efi_distributor); ++ + int + grub_install_register_efi (grub_device_t efidir_grub_dev, + const char *efifile_path, +diff --git a/util/grub-install.c b/util/grub-install.c +index 58f1453ba..05b695226 100644 +--- a/util/grub-install.c ++++ b/util/grub-install.c +@@ -2086,7 +2086,7 @@ main (int argc, char *argv[]) + "\\System\\Library\\CoreServices", + efi_distributor); + if (ret) +- grub_util_error (_("efibootmgr failed to register the boot entry: %s"), ++ grub_util_error (_("failed to register the EFI boot entry: %s"), + strerror (ret)); + } + +@@ -2203,7 +2203,7 @@ main (int argc, char *argv[]) + ret = grub_install_register_efi (efidir_grub_dev, + efifile_path, efi_distributor); + if (ret) +- grub_util_error (_("efibootmgr failed to register the boot entry: %s"), ++ grub_util_error (_("failed to register the EFI boot entry: %s"), + strerror (ret)); + } + break; diff --git a/debian/patches/efinet-set-dns-from-uefi-proto.patch b/debian/patches/efinet-set-dns-from-uefi-proto.patch new file mode 100644 index 0000000..9b5861b --- /dev/null +++ b/debian/patches/efinet-set-dns-from-uefi-proto.patch @@ -0,0 +1,341 @@ +From 5a2c53dd059351cf385575fa99d5763bc07e0de2 Mon Sep 17 00:00:00 2001 +From: Michael Chang <mchang@suse.com> +Date: Thu, 27 Oct 2016 17:43:21 -0400 +Subject: efinet: Setting DNS server from UEFI protocol + +In the URI device path node, any name rahter than address can be used for +looking up the resources so that DNS service become needed to get answer of the +name's address. Unfortunately the DNS is not defined in any of the device path +nodes so that we use the EFI_IP4_CONFIG2_PROTOCOL and EFI_IP6_CONFIG_PROTOCOL +to obtain it. + +These two protcols are defined the sections of UEFI specification. + + 27.5 EFI IPv4 Configuration II Protocol + 27.7 EFI IPv6 Configuration Protocol + +include/grub/efi/api.h: +Add new structure and protocol UUID of EFI_IP4_CONFIG2_PROTOCOL and +EFI_IP6_CONFIG_PROTOCOL. + +grub-core/net/drivers/efi/efinet.c: +Use the EFI_IP4_CONFIG2_PROTOCOL and EFI_IP6_CONFIG_PROTOCOL to obtain the list +of DNS server address for IPv4 and IPv6 respectively. The address of DNS +servers is structured into DHCPACK packet and feed into the same DHCP packet +processing functions to ensure the network interface is setting up the same way +it used to be. + +Signed-off-by: Michael Chang <mchang@suse.com> +Signed-off-by: Ken Lin <ken.lin@hpe.com> + +Last-Update: 2021-09-24 + +Patch-Name: efinet-set-dns-from-uefi-proto.patch +--- + grub-core/net/drivers/efi/efinet.c | 163 +++++++++++++++++++++++++++++ + include/grub/efi/api.h | 76 ++++++++++++++ + 2 files changed, 239 insertions(+) + +diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c +index 2d3b00f0e..82a28fb6e 100644 +--- a/grub-core/net/drivers/efi/efinet.c ++++ b/grub-core/net/drivers/efi/efinet.c +@@ -30,6 +30,8 @@ GRUB_MOD_LICENSE ("GPLv3+"); + /* GUID. */ + static grub_efi_guid_t net_io_guid = GRUB_EFI_SIMPLE_NETWORK_GUID; + static grub_efi_guid_t pxe_io_guid = GRUB_EFI_PXE_GUID; ++static grub_efi_guid_t ip4_config_guid = GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID; ++static grub_efi_guid_t ip6_config_guid = GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID; + + static grub_err_t + send_card_buffer (struct grub_net_card *dev, +@@ -325,6 +327,125 @@ grub_efinet_findcards (void) + grub_free (handles); + } + ++static grub_efi_handle_t ++grub_efi_locate_device_path (grub_efi_guid_t *protocol, grub_efi_device_path_t *device_path, ++ grub_efi_device_path_t **r_device_path) ++{ ++ grub_efi_handle_t handle; ++ grub_efi_status_t status; ++ ++ status = efi_call_3 (grub_efi_system_table->boot_services->locate_device_path, ++ protocol, &device_path, &handle); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ ++ if (r_device_path) ++ *r_device_path = device_path; ++ ++ return handle; ++} ++ ++static grub_efi_ipv4_address_t * ++grub_dns_server_ip4_address (grub_efi_device_path_t *dp, grub_efi_uintn_t *num_dns) ++{ ++ grub_efi_handle_t hnd; ++ grub_efi_status_t status; ++ grub_efi_ip4_config2_protocol_t *conf; ++ grub_efi_ipv4_address_t *addrs; ++ grub_efi_uintn_t data_size = 1 * sizeof (grub_efi_ipv4_address_t); ++ ++ hnd = grub_efi_locate_device_path (&ip4_config_guid, dp, NULL); ++ ++ if (!hnd) ++ return 0; ++ ++ conf = grub_efi_open_protocol (hnd, &ip4_config_guid, ++ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); ++ ++ if (!conf) ++ return 0; ++ ++ addrs = grub_malloc (data_size); ++ if (!addrs) ++ return 0; ++ ++ status = efi_call_4 (conf->get_data, conf, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER, ++ &data_size, addrs); ++ ++ if (status == GRUB_EFI_BUFFER_TOO_SMALL) ++ { ++ grub_free (addrs); ++ addrs = grub_malloc (data_size); ++ if (!addrs) ++ return 0; ++ ++ status = efi_call_4 (conf->get_data, conf, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER, ++ &data_size, addrs); ++ } ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (addrs); ++ return 0; ++ } ++ ++ *num_dns = data_size / sizeof (grub_efi_ipv4_address_t); ++ return addrs; ++} ++ ++static grub_efi_ipv6_address_t * ++grub_dns_server_ip6_address (grub_efi_device_path_t *dp, grub_efi_uintn_t *num_dns) ++{ ++ grub_efi_handle_t hnd; ++ grub_efi_status_t status; ++ grub_efi_ip6_config_protocol_t *conf; ++ grub_efi_ipv6_address_t *addrs; ++ grub_efi_uintn_t data_size = 1 * sizeof (grub_efi_ipv6_address_t); ++ ++ hnd = grub_efi_locate_device_path (&ip6_config_guid, dp, NULL); ++ ++ if (!hnd) ++ return 0; ++ ++ conf = grub_efi_open_protocol (hnd, &ip6_config_guid, ++ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); ++ ++ if (!conf) ++ return 0; ++ ++ addrs = grub_malloc (data_size); ++ if (!addrs) ++ return 0; ++ ++ status = efi_call_4 (conf->get_data, conf, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER, ++ &data_size, addrs); ++ ++ if (status == GRUB_EFI_BUFFER_TOO_SMALL) ++ { ++ grub_free (addrs); ++ addrs = grub_malloc (data_size); ++ if (!addrs) ++ return 0; ++ ++ status = efi_call_4 (conf->get_data, conf, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER, ++ &data_size, addrs); ++ } ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (addrs); ++ return 0; ++ } ++ ++ *num_dns = data_size / sizeof (grub_efi_ipv6_address_t); ++ return addrs; ++} ++ + static struct grub_net_buff * + grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *use_ipv6) + { +@@ -377,6 +498,8 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u + grub_efi_ipv4_device_path_t *ipv4 = (grub_efi_ipv4_device_path_t *) ldp; + struct grub_net_bootp_packet *bp; + grub_uint8_t *ptr; ++ grub_efi_ipv4_address_t *dns; ++ grub_efi_uintn_t num_dns; + + bp = (struct grub_net_bootp_packet *) nb->tail; + err = grub_netbuff_put (nb, sizeof (*bp) + 4); +@@ -438,6 +561,25 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u + *ptr++ = sizeof ("HTTPClient") - 1; + grub_memcpy (ptr, "HTTPClient", sizeof ("HTTPClient") - 1); + ++ dns = grub_dns_server_ip4_address (dp, &num_dns); ++ if (dns) ++ { ++ grub_efi_uintn_t size_dns = sizeof (*dns) * num_dns; ++ ++ ptr = nb->tail; ++ err = grub_netbuff_put (nb, size_dns + 2); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ *ptr++ = GRUB_NET_BOOTP_DNS; ++ *ptr++ = size_dns; ++ grub_memcpy (ptr, dns, size_dns); ++ grub_free (dns); ++ } ++ + ptr = nb->tail; + err = grub_netbuff_put (nb, 1); + if (err) +@@ -470,6 +612,8 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u + struct grub_net_dhcp6_option *opt; + struct grub_net_dhcp6_option_iana *iana; + struct grub_net_dhcp6_option_iaaddr *iaaddr; ++ grub_efi_ipv6_address_t *dns; ++ grub_efi_uintn_t num_dns; + + d6p = (struct grub_net_dhcp6_packet *)nb->tail; + err = grub_netbuff_put (nb, sizeof(*d6p)); +@@ -533,6 +677,25 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u + opt->len = grub_cpu_to_be16 (uri_len); + grub_memcpy (opt->data, uri_dp->uri, uri_len); + ++ dns = grub_dns_server_ip6_address (dp, &num_dns); ++ if (dns) ++ { ++ grub_efi_uintn_t size_dns = sizeof (*dns) * num_dns; ++ ++ opt = (struct grub_net_dhcp6_option *)nb->tail; ++ err = grub_netbuff_put (nb, sizeof(*opt) + size_dns); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_DNS_SERVERS); ++ opt->len = grub_cpu_to_be16 (size_dns); ++ grub_memcpy (opt->data, dns, size_dns); ++ grub_free (dns); ++ } ++ + *use_ipv6 = 1; + } + +diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h +index 4b4652ca5..9cab1a51d 100644 +--- a/include/grub/efi/api.h ++++ b/include/grub/efi/api.h +@@ -354,6 +354,16 @@ + { 0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44 } \ + } + ++#define GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID \ ++ { 0x5b446ed1, 0xe30b, 0x4faa, \ ++ { 0x87, 0x1a, 0x36, 0x54, 0xec, 0xa3, 0x60, 0x80 } \ ++ } ++ ++#define GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID \ ++ { 0x937fe521, 0x95ae, 0x4d1a, \ ++ { 0x89, 0x29, 0x48, 0xbc, 0xd9, 0x0a, 0xd3, 0x1a } \ ++ } ++ + struct grub_efi_sal_system_table + { + grub_uint32_t signature; +@@ -1793,6 +1803,72 @@ struct grub_efi_rng_protocol + }; + typedef struct grub_efi_rng_protocol grub_efi_rng_protocol_t; + ++enum grub_efi_ip4_config2_data_type { ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_POLICY, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_GATEWAY, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MAXIMUM ++}; ++typedef enum grub_efi_ip4_config2_data_type grub_efi_ip4_config2_data_type_t; ++ ++struct grub_efi_ip4_config2_protocol ++{ ++ grub_efi_status_t (*set_data) (struct grub_efi_ip4_config2_protocol *this, ++ grub_efi_ip4_config2_data_type_t data_type, ++ grub_efi_uintn_t data_size, ++ void *data); ++ ++ grub_efi_status_t (*get_data) (struct grub_efi_ip4_config2_protocol *this, ++ grub_efi_ip4_config2_data_type_t data_type, ++ grub_efi_uintn_t *data_size, ++ void *data); ++ ++ grub_efi_status_t (*register_data_notify) (struct grub_efi_ip4_config2_protocol *this, ++ grub_efi_ip4_config2_data_type_t data_type, ++ grub_efi_event_t event); ++ ++ grub_efi_status_t (*unregister_datanotify) (struct grub_efi_ip4_config2_protocol *this, ++ grub_efi_ip4_config2_data_type_t data_type, ++ grub_efi_event_t event); ++}; ++typedef struct grub_efi_ip4_config2_protocol grub_efi_ip4_config2_protocol_t; ++ ++enum grub_efi_ip6_config_data_type { ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_ALT_INTERFACEID, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_POLICY, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DUP_ADDR_DETECT_TRANSMITS, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_GATEWAY, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MAXIMUM ++}; ++typedef enum grub_efi_ip6_config_data_type grub_efi_ip6_config_data_type_t; ++ ++struct grub_efi_ip6_config_protocol ++{ ++ grub_efi_status_t (*set_data) (struct grub_efi_ip6_config_protocol *this, ++ grub_efi_ip6_config_data_type_t data_type, ++ grub_efi_uintn_t data_size, ++ void *data); ++ ++ grub_efi_status_t (*get_data) (struct grub_efi_ip6_config_protocol *this, ++ grub_efi_ip6_config_data_type_t data_type, ++ grub_efi_uintn_t *data_size, ++ void *data); ++ ++ grub_efi_status_t (*register_data_notify) (struct grub_efi_ip6_config_protocol *this, ++ grub_efi_ip6_config_data_type_t data_type, ++ grub_efi_event_t event); ++ ++ grub_efi_status_t (*unregister_datanotify) (struct grub_efi_ip6_config_protocol *this, ++ grub_efi_ip6_config_data_type_t data_type, ++ grub_efi_event_t event); ++}; ++typedef struct grub_efi_ip6_config_protocol grub_efi_ip6_config_protocol_t; ++ + #if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \ + || defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__) \ + || defined(__riscv) diff --git a/debian/patches/efinet-set-network-from-uefi-devpath.patch b/debian/patches/efinet-set-network-from-uefi-devpath.patch new file mode 100644 index 0000000..bf97ddf --- /dev/null +++ b/debian/patches/efinet-set-network-from-uefi-devpath.patch @@ -0,0 +1,388 @@ +From 3f85b646c8f6188f6e2122fc90351fb900e1b337 Mon Sep 17 00:00:00 2001 +From: Michael Chang <mchang@suse.com> +Date: Thu, 27 Oct 2016 17:43:05 -0400 +Subject: efinet: Setting network from UEFI device path + +The PXE Base Code protocol used to obtain cached PXE DHCPACK packet is no +longer provided for HTTP Boot. Instead, we have to get the HTTP boot +information from the device path nodes defined in following UEFI Specification +sections. + + 9.3.5.12 IPv4 Device Path + 9.3.5.13 IPv6 Device Path + 9.3.5.23 Uniform Resource Identifiers (URI) Device Path + +This patch basically does: + +include/grub/efi/api.h: +Add new structure of Uniform Resource Identifiers (URI) Device Path + +grub-core/net/drivers/efi/efinet.c: +Check if PXE Base Code is available, if not it will try to obtain the netboot +information from the device path where the image booted from. The DHCPACK +packet is recoverd from the information in device patch and feed into the same +DHCP packet processing functions to ensure the network interface is setting up +the same way it used to be. + +Signed-off-by: Michael Chang <mchang@suse.com> +Signed-off-by: Ken Lin <ken.lin@hpe.com> + +Patch-Name: efinet-set-network-from-uefi-devpath.patch +--- + grub-core/net/drivers/efi/efinet.c | 268 ++++++++++++++++++++++++++++- + include/grub/efi/api.h | 11 ++ + 2 files changed, 270 insertions(+), 9 deletions(-) + +diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c +index fc90415f2..2d3b00f0e 100644 +--- a/grub-core/net/drivers/efi/efinet.c ++++ b/grub-core/net/drivers/efi/efinet.c +@@ -23,6 +23,7 @@ + #include <grub/efi/api.h> + #include <grub/efi/efi.h> + #include <grub/i18n.h> ++#include <grub/net/netbuff.h> + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -324,6 +325,221 @@ grub_efinet_findcards (void) + grub_free (handles); + } + ++static struct grub_net_buff * ++grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *use_ipv6) ++{ ++ grub_efi_uint16_t uri_len; ++ grub_efi_device_path_t *ldp, *ddp; ++ grub_efi_uri_device_path_t *uri_dp; ++ struct grub_net_buff *nb; ++ grub_err_t err; ++ ++ ddp = grub_efi_duplicate_device_path (dp); ++ ldp = grub_efi_find_last_device_path (ddp); ++ ++ if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE ++ || GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_URI_DEVICE_PATH_SUBTYPE) ++ { ++ grub_free (ddp); ++ return NULL; ++ } ++ ++ uri_len = GRUB_EFI_DEVICE_PATH_LENGTH (ldp) > 4 ? GRUB_EFI_DEVICE_PATH_LENGTH (ldp) - 4 : 0; ++ ++ if (!uri_len) ++ { ++ grub_free (ddp); ++ return NULL; ++ } ++ ++ uri_dp = (grub_efi_uri_device_path_t *) ldp; ++ ++ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; ++ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; ++ ldp->length = sizeof (*ldp); ++ ++ ldp = grub_efi_find_last_device_path (ddp); ++ ++ if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE ++ || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE ++ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE)) ++ { ++ grub_free (ddp); ++ return NULL; ++ } ++ ++ nb = grub_netbuff_alloc (512); ++ if (!nb) ++ return NULL; ++ ++ if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE) ++ { ++ grub_efi_ipv4_device_path_t *ipv4 = (grub_efi_ipv4_device_path_t *) ldp; ++ struct grub_net_bootp_packet *bp; ++ grub_uint8_t *ptr; ++ ++ bp = (struct grub_net_bootp_packet *) nb->tail; ++ err = grub_netbuff_put (nb, sizeof (*bp) + 4); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ ++ if (sizeof(bp->boot_file) < uri_len) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ grub_memcpy (bp->boot_file, uri_dp->uri, uri_len); ++ grub_memcpy (&bp->your_ip, ipv4->local_ip_address, sizeof (bp->your_ip)); ++ grub_memcpy (&bp->server_ip, ipv4->remote_ip_address, sizeof (bp->server_ip)); ++ ++ bp->vendor[0] = GRUB_NET_BOOTP_RFC1048_MAGIC_0; ++ bp->vendor[1] = GRUB_NET_BOOTP_RFC1048_MAGIC_1; ++ bp->vendor[2] = GRUB_NET_BOOTP_RFC1048_MAGIC_2; ++ bp->vendor[3] = GRUB_NET_BOOTP_RFC1048_MAGIC_3; ++ ++ ptr = nb->tail; ++ err = grub_netbuff_put (nb, sizeof (ipv4->subnet_mask) + 2); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ *ptr++ = GRUB_NET_BOOTP_NETMASK; ++ *ptr++ = sizeof (ipv4->subnet_mask); ++ grub_memcpy (ptr, ipv4->subnet_mask, sizeof (ipv4->subnet_mask)); ++ ++ ptr = nb->tail; ++ err = grub_netbuff_put (nb, sizeof (ipv4->gateway_ip_address) + 2); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ *ptr++ = GRUB_NET_BOOTP_ROUTER; ++ *ptr++ = sizeof (ipv4->gateway_ip_address); ++ grub_memcpy (ptr, ipv4->gateway_ip_address, sizeof (ipv4->gateway_ip_address)); ++ ++ ptr = nb->tail; ++ err = grub_netbuff_put (nb, sizeof ("HTTPClient") + 1); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ *ptr++ = GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER; ++ *ptr++ = sizeof ("HTTPClient") - 1; ++ grub_memcpy (ptr, "HTTPClient", sizeof ("HTTPClient") - 1); ++ ++ ptr = nb->tail; ++ err = grub_netbuff_put (nb, 1); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ *ptr = GRUB_NET_BOOTP_END; ++ *use_ipv6 = 0; ++ ++ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; ++ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; ++ ldp->length = sizeof (*ldp); ++ ldp = grub_efi_find_last_device_path (ddp); ++ ++ if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE) ++ { ++ grub_efi_mac_address_device_path_t *mac = (grub_efi_mac_address_device_path_t *) ldp; ++ bp->hw_type = mac->if_type; ++ bp->hw_len = sizeof (bp->mac_addr); ++ grub_memcpy (bp->mac_addr, mac->mac_address, bp->hw_len); ++ } ++ } ++ else ++ { ++ grub_efi_ipv6_device_path_t *ipv6 = (grub_efi_ipv6_device_path_t *) ldp; ++ ++ struct grub_net_dhcp6_packet *d6p; ++ struct grub_net_dhcp6_option *opt; ++ struct grub_net_dhcp6_option_iana *iana; ++ struct grub_net_dhcp6_option_iaaddr *iaaddr; ++ ++ d6p = (struct grub_net_dhcp6_packet *)nb->tail; ++ err = grub_netbuff_put (nb, sizeof(*d6p)); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ d6p->message_type = GRUB_NET_DHCP6_REPLY; ++ ++ opt = (struct grub_net_dhcp6_option *)nb->tail; ++ err = grub_netbuff_put (nb, sizeof(*opt)); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IA_NA); ++ opt->len = grub_cpu_to_be16_compile_time (sizeof(*iana) + sizeof(*opt) + sizeof(*iaaddr)); ++ ++ err = grub_netbuff_put (nb, sizeof(*iana)); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ ++ opt = (struct grub_net_dhcp6_option *)nb->tail; ++ err = grub_netbuff_put (nb, sizeof(*opt)); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IAADDR); ++ opt->len = grub_cpu_to_be16_compile_time (sizeof (*iaaddr)); ++ ++ iaaddr = (struct grub_net_dhcp6_option_iaaddr *)nb->tail; ++ err = grub_netbuff_put (nb, sizeof(*iaaddr)); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ grub_memcpy (iaaddr->addr, ipv6->local_ip_address, sizeof(ipv6->local_ip_address)); ++ ++ opt = (struct grub_net_dhcp6_option *)nb->tail; ++ err = grub_netbuff_put (nb, sizeof(*opt) + uri_len); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_BOOTFILE_URL); ++ opt->len = grub_cpu_to_be16 (uri_len); ++ grub_memcpy (opt->data, uri_dp->uri, uri_len); ++ ++ *use_ipv6 = 1; ++ } ++ ++ grub_free (ddp); ++ return nb; ++} ++ + static void + grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + char **path) +@@ -340,6 +556,11 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + grub_efi_device_path_t *cdp; + struct grub_efi_pxe *pxe; + struct grub_efi_pxe_mode *pxe_mode; ++ grub_uint8_t *packet_buf; ++ grub_size_t packet_bufsz ; ++ int ipv6; ++ struct grub_net_buff *nb = NULL; ++ + if (card->driver != &efidriver) + continue; + cdp = grub_efi_get_device_path (card->efi_handle); +@@ -359,11 +580,21 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + ldp = grub_efi_find_last_device_path (dp); + if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE + || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE +- && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE)) ++ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE ++ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)) + continue; + dup_dp = grub_efi_duplicate_device_path (dp); + if (!dup_dp) + continue; ++ ++ if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE) ++ { ++ dup_ldp = grub_efi_find_last_device_path (dup_dp); ++ dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; ++ dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; ++ dup_ldp->length = sizeof (*dup_ldp); ++ } ++ + dup_ldp = grub_efi_find_last_device_path (dup_dp); + dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; + dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; +@@ -375,16 +606,31 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + } + pxe = grub_efi_open_protocol (hnd, &pxe_io_guid, + GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); +- if (! pxe) +- continue; +- pxe_mode = pxe->mode; ++ if (!pxe) ++ { ++ nb = grub_efinet_create_dhcp_ack_from_device_path (dp, &ipv6); ++ if (!nb) ++ { ++ grub_print_error (); ++ continue; ++ } ++ packet_buf = nb->head; ++ packet_bufsz = nb->tail - nb->head; ++ } ++ else ++ { ++ pxe_mode = pxe->mode; ++ packet_buf = (grub_uint8_t *) &pxe_mode->dhcp_ack; ++ packet_bufsz = sizeof (pxe_mode->dhcp_ack); ++ ipv6 = pxe_mode->using_ipv6; ++ } + +- if (pxe_mode->using_ipv6) ++ if (ipv6) + { + grub_net_configure_by_dhcpv6_reply (card->name, card, 0, + (struct grub_net_dhcp6_packet *) +- &pxe_mode->dhcp_ack, +- sizeof (pxe_mode->dhcp_ack), ++ packet_buf, ++ packet_bufsz, + 1, device, path); + if (grub_errno) + grub_print_error (); +@@ -393,10 +639,14 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + { + grub_net_configure_by_dhcp_ack (card->name, card, 0, + (struct grub_net_bootp_packet *) +- &pxe_mode->dhcp_ack, +- sizeof (pxe_mode->dhcp_ack), ++ packet_buf, ++ packet_bufsz, + 1, device, path); + } ++ ++ if (nb) ++ grub_netbuff_free (nb); ++ + return; + } + } +diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h +index 50ab8e844..4b4652ca5 100644 +--- a/include/grub/efi/api.h ++++ b/include/grub/efi/api.h +@@ -849,6 +849,8 @@ struct grub_efi_ipv4_device_path + grub_efi_uint16_t remote_port; + grub_efi_uint16_t protocol; + grub_efi_uint8_t static_ip_address; ++ grub_efi_ipv4_address_t gateway_ip_address; ++ grub_efi_ipv4_address_t subnet_mask; + } GRUB_PACKED; + typedef struct grub_efi_ipv4_device_path grub_efi_ipv4_device_path_t; + +@@ -903,6 +905,15 @@ struct grub_efi_sata_device_path + } GRUB_PACKED; + typedef struct grub_efi_sata_device_path grub_efi_sata_device_path_t; + ++#define GRUB_EFI_URI_DEVICE_PATH_SUBTYPE 24 ++ ++struct grub_efi_uri_device_path ++{ ++ grub_efi_device_path_t header; ++ grub_efi_uint8_t uri[0]; ++} GRUB_PACKED; ++typedef struct grub_efi_uri_device_path grub_efi_uri_device_path_t; ++ + #define GRUB_EFI_VENDOR_MESSAGING_DEVICE_PATH_SUBTYPE 10 + + /* Media Device Path. */ diff --git a/debian/patches/efinet-uefi-ipv6-pxe-support.patch b/debian/patches/efinet-uefi-ipv6-pxe-support.patch new file mode 100644 index 0000000..3a75beb --- /dev/null +++ b/debian/patches/efinet-uefi-ipv6-pxe-support.patch @@ -0,0 +1,126 @@ +From a124f295433d6d3f371730b93d6468e6d5ad58e1 Mon Sep 17 00:00:00 2001 +From: Michael Chang <mchang@suse.com> +Date: Thu, 27 Oct 2016 17:41:21 -0400 +Subject: efinet: UEFI IPv6 PXE support + +When grub2 image is booted from UEFI IPv6 PXE, the DHCPv6 Reply packet is +cached in firmware buffer which can be obtained by PXE Base Code protocol. The +network interface can be setup through the parameters in that obtained packet. + +Signed-off-by: Michael Chang <mchang@suse.com> +Signed-off-by: Ken Lin <ken.lin@hpe.com> + +Patch-Name: efinet-uefi-ipv6-pxe-support.patch +--- + grub-core/net/drivers/efi/efinet.c | 24 ++++++++++--- + include/grub/efi/api.h | 55 +++++++++++++++++++++++++++++- + 2 files changed, 73 insertions(+), 6 deletions(-) + +diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c +index 5388f952b..fc90415f2 100644 +--- a/grub-core/net/drivers/efi/efinet.c ++++ b/grub-core/net/drivers/efi/efinet.c +@@ -378,11 +378,25 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + if (! pxe) + continue; + pxe_mode = pxe->mode; +- grub_net_configure_by_dhcp_ack (card->name, card, 0, +- (struct grub_net_bootp_packet *) +- &pxe_mode->dhcp_ack, +- sizeof (pxe_mode->dhcp_ack), +- 1, device, path); ++ ++ if (pxe_mode->using_ipv6) ++ { ++ grub_net_configure_by_dhcpv6_reply (card->name, card, 0, ++ (struct grub_net_dhcp6_packet *) ++ &pxe_mode->dhcp_ack, ++ sizeof (pxe_mode->dhcp_ack), ++ 1, device, path); ++ if (grub_errno) ++ grub_print_error (); ++ } ++ else ++ { ++ grub_net_configure_by_dhcp_ack (card->name, card, 0, ++ (struct grub_net_bootp_packet *) ++ &pxe_mode->dhcp_ack, ++ sizeof (pxe_mode->dhcp_ack), ++ 1, device, path); ++ } + return; + } + } +diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h +index f1a52210c..50ab8e844 100644 +--- a/include/grub/efi/api.h ++++ b/include/grub/efi/api.h +@@ -1476,14 +1476,67 @@ typedef struct grub_efi_simple_text_output_interface grub_efi_simple_text_output + + typedef grub_uint8_t grub_efi_pxe_packet_t[1472]; + ++typedef struct { ++ grub_uint8_t addr[4]; ++} grub_efi_pxe_ipv4_address_t; ++ ++typedef struct { ++ grub_uint8_t addr[16]; ++} grub_efi_pxe_ipv6_address_t; ++ ++typedef struct { ++ grub_uint8_t addr[32]; ++} grub_efi_pxe_mac_address_t; ++ ++typedef union { ++ grub_uint32_t addr[4]; ++ grub_efi_pxe_ipv4_address_t v4; ++ grub_efi_pxe_ipv6_address_t v6; ++} grub_efi_pxe_ip_address_t; ++ ++#define GRUB_EFI_PXE_BASE_CODE_MAX_IPCNT 8 ++typedef struct { ++ grub_uint8_t filters; ++ grub_uint8_t ip_cnt; ++ grub_uint16_t reserved; ++ grub_efi_pxe_ip_address_t ip_list[GRUB_EFI_PXE_BASE_CODE_MAX_IPCNT]; ++} grub_efi_pxe_ip_filter_t; ++ ++typedef struct { ++ grub_efi_pxe_ip_address_t ip_addr; ++ grub_efi_pxe_mac_address_t mac_addr; ++} grub_efi_pxe_arp_entry_t; ++ ++typedef struct { ++ grub_efi_pxe_ip_address_t ip_addr; ++ grub_efi_pxe_ip_address_t subnet_mask; ++ grub_efi_pxe_ip_address_t gw_addr; ++} grub_efi_pxe_route_entry_t; ++ ++ ++#define GRUB_EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES 8 ++#define GRUB_EFI_PXE_BASE_CODE_MAX_ROUTE_ENTRIES 8 ++ + typedef struct grub_efi_pxe_mode + { +- grub_uint8_t unused[52]; ++ grub_uint8_t started; ++ grub_uint8_t ipv6_available; ++ grub_uint8_t ipv6_supported; ++ grub_uint8_t using_ipv6; ++ grub_uint8_t unused[16]; ++ grub_efi_pxe_ip_address_t station_ip; ++ grub_efi_pxe_ip_address_t subnet_mask; + grub_efi_pxe_packet_t dhcp_discover; + grub_efi_pxe_packet_t dhcp_ack; + grub_efi_pxe_packet_t proxy_offer; + grub_efi_pxe_packet_t pxe_discover; + grub_efi_pxe_packet_t pxe_reply; ++ grub_efi_pxe_packet_t pxe_bis_reply; ++ grub_efi_pxe_ip_filter_t ip_filter; ++ grub_uint32_t arp_cache_entries; ++ grub_efi_pxe_arp_entry_t arp_cache[GRUB_EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES]; ++ grub_uint32_t route_table_entries; ++ grub_efi_pxe_route_entry_t route_table[GRUB_EFI_PXE_BASE_CODE_MAX_ROUTE_ENTRIES]; + } grub_efi_pxe_mode_t; + + typedef struct grub_efi_pxe diff --git a/debian/patches/fix-lockdown.patch b/debian/patches/fix-lockdown.patch new file mode 100644 index 0000000..54a7928 --- /dev/null +++ b/debian/patches/fix-lockdown.patch @@ -0,0 +1,45 @@ +From b2c4515a832f82a4fe4ee8d32faa16b48de63d12 Mon Sep 17 00:00:00 2001 +From: Luca Boccassi <bluca@debian.org> +Date: Tue, 15 May 2018 11:36:46 +0100 +Subject: Do not overwrite sentinel byte in boot_params, breaks lockdown + +grub currently copies the entire boot_params, which includes setting +sentinel byte to 0xff, which triggers sanitize_boot_params in the kernel +which in turn clears various boot_params variables, including the +indication that the bootloader chain is verified and thus the kernel +disables lockdown mode. According to the information on the Fedora bug +tracker, only the information from byte 0x1f1 is necessary, so start +copying from there instead. + +Author: Luca Boccassi <bluca@debian.org> +Bug-Fedora: https://bugzilla.redhat.com/show_bug.cgi?id=1418360 +Forwarded: no + +Patch-Name: fix-lockdown.patch +--- + grub-core/loader/i386/efi/linux.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 45b68c05a..532e4e512 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -29,6 +29,7 @@ + #include <grub/linux.h> + #include <grub/efi/efi.h> + #include <grub/efi/sb.h> ++#include <stddef.h> + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -336,7 +337,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + lh.code32_start = (grub_uint32_t)(grub_addr_t) kernel_mem; + } + +- grub_memcpy (params, &lh, 2 * 512); ++ /* do not overwrite below boot_params->hdr to avoid setting the sentinel byte */ ++ start = offsetof (struct linux_kernel_params, setup_sects); ++ grub_memcpy ((grub_uint8_t *)params + start, (grub_uint8_t *)&lh + start, 2 * 512 - start); + + params->type_of_loader = 0x21; + diff --git a/debian/patches/font-Try-opening-fonts-from-the-bundled-memdisk.patch b/debian/patches/font-Try-opening-fonts-from-the-bundled-memdisk.patch new file mode 100644 index 0000000..7c9209a --- /dev/null +++ b/debian/patches/font-Try-opening-fonts-from-the-bundled-memdisk.patch @@ -0,0 +1,76 @@ +From: Chris Coulson <chris.coulson@canonical.com> +Date: Wed, 16 Nov 2022 14:40:04 +0000 +Subject: font: Try opening fonts from the bundled memdisk + +--- + grub-core/font/font.c | 48 +++++++++++++++++++++++++++++++----------------- + 1 file changed, 31 insertions(+), 17 deletions(-) + +diff --git a/grub-core/font/font.c b/grub-core/font/font.c +index e6616e6..e421d1a 100644 +--- a/grub-core/font/font.c ++++ b/grub-core/font/font.c +@@ -409,6 +409,27 @@ read_section_as_short (struct font_file_section *section, + return 0; + } + ++static grub_file_t ++try_open_from_prefix (const char *prefix, const char *filename) ++{ ++ grub_file_t file; ++ char *fullname, *ptr; ++ ++ fullname = grub_malloc (grub_strlen (prefix) + grub_strlen (filename) + 1 ++ + sizeof ("/fonts/") + sizeof (".pf2")); ++ if (!fullname) ++ return 0; ++ ptr = grub_stpcpy (fullname, prefix); ++ ptr = grub_stpcpy (ptr, "/fonts/"); ++ ptr = grub_stpcpy (ptr, filename); ++ ptr = grub_stpcpy (ptr, ".pf2"); ++ *ptr = 0; ++ ++ file = grub_buffile_open (fullname, GRUB_FILE_TYPE_FONT, 1024); ++ grub_free (fullname); ++ return file; ++} ++ + /* Load a font and add it to the beginning of the global font list. + Returns 0 upon success, nonzero upon failure. */ + grub_font_t +@@ -427,25 +448,18 @@ grub_font_load (const char *filename) + file = grub_buffile_open (filename, GRUB_FILE_TYPE_FONT, 1024); + else + { +- const char *prefix = grub_env_get ("prefix"); +- char *fullname, *ptr; +- if (!prefix) ++ file = try_open_from_prefix ("(memdisk)", filename); ++ if (!file) + { +- grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable `%s' isn't set"), +- "prefix"); +- goto fail; ++ const char *prefix = grub_env_get ("prefix"); ++ if (!prefix) ++ { ++ grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable `%s' isn't set"), ++ "prefix"); ++ goto fail; ++ } ++ file = try_open_from_prefix (prefix, filename); + } +- fullname = grub_malloc (grub_strlen (prefix) + grub_strlen (filename) + 1 +- + sizeof ("/fonts/") + sizeof (".pf2")); +- if (!fullname) +- goto fail; +- ptr = grub_stpcpy (fullname, prefix); +- ptr = grub_stpcpy (ptr, "/fonts/"); +- ptr = grub_stpcpy (ptr, filename); +- ptr = grub_stpcpy (ptr, ".pf2"); +- *ptr = 0; +- file = grub_buffile_open (fullname, GRUB_FILE_TYPE_FONT, 1024); +- grub_free (fullname); + } + if (!file) + goto fail; diff --git a/debian/patches/gettext-quiet.patch b/debian/patches/gettext-quiet.patch new file mode 100644 index 0000000..eddcce7 --- /dev/null +++ b/debian/patches/gettext-quiet.patch @@ -0,0 +1,30 @@ +From ddc3423d5c2bf1fb83a6f378726ff87b12794d19 Mon Sep 17 00:00:00 2001 +From: Colin Watson <cjwatson@ubuntu.com> +Date: Mon, 13 Jan 2014 12:13:02 +0000 +Subject: Silence error messages when translations are unavailable + +Bug: https://savannah.gnu.org/bugs/?35880 +Forwarded: https://savannah.gnu.org/bugs/?35880 +Last-Update: 2013-11-14 + +Patch-Name: gettext-quiet.patch +--- + grub-core/gettext/gettext.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/grub-core/gettext/gettext.c b/grub-core/gettext/gettext.c +index 4d02e62c1..2a19389f2 100644 +--- a/grub-core/gettext/gettext.c ++++ b/grub-core/gettext/gettext.c +@@ -427,6 +427,11 @@ grub_gettext_init_ext (struct grub_gettext_context *ctx, + if (locale[0] == 'e' && locale[1] == 'n' + && (locale[2] == '\0' || locale[2] == '_')) + grub_errno = err = GRUB_ERR_NONE; ++ ++ /* If no translations are available, fall back to untranslated text. */ ++ if (err == GRUB_ERR_FILE_NOT_FOUND) ++ grub_errno = err = GRUB_ERR_NONE; ++ + return err; + } + diff --git a/debian/patches/gfxpayload-dynamic.patch b/debian/patches/gfxpayload-dynamic.patch new file mode 100644 index 0000000..b0a19b3 --- /dev/null +++ b/debian/patches/gfxpayload-dynamic.patch @@ -0,0 +1,290 @@ +From bc7f762a1d253537eb524946884b0f3e50a419f0 Mon Sep 17 00:00:00 2001 +From: Evan Broder <evan@ebroder.net> +Date: Mon, 13 Jan 2014 12:13:29 +0000 +Subject: Add configure option to enable gfxpayload=keep dynamically + +Set GRUB_GFXPAYLOAD_LINUX=keep unless it's known to be unsupported on +the current hardware. See +https://blueprints.launchpad.net/ubuntu/+spec/packageselection-foundations-n-grub2-boot-framebuffer. + +Author: Colin Watson <cjwatson@ubuntu.com> +Forwarded: no +Last-Update: 2019-05-25 + +Patch-Name: gfxpayload-dynamic.patch +--- + configure.ac | 11 ++ + grub-core/Makefile.core.def | 8 ++ + grub-core/commands/i386/pc/hwmatch.c | 146 +++++++++++++++++++++++++++ + include/grub/file.h | 1 + + util/grub.d/10_linux.in | 37 ++++++- + 5 files changed, 200 insertions(+), 3 deletions(-) + create mode 100644 grub-core/commands/i386/pc/hwmatch.c + +diff --git a/configure.ac b/configure.ac +index c42e4c784..947fd529f 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1937,6 +1937,17 @@ else + fi + AC_SUBST([QUICK_BOOT]) + ++AC_ARG_ENABLE([gfxpayload-dynamic], ++ [AS_HELP_STRING([--enable-gfxpayload-dynamic], ++ [use GRUB_GFXPAYLOAD_LINUX=keep unless explicitly unsupported on current hardware (default=no)])], ++ [], [enable_gfxpayload_dynamic=no]) ++if test x"$enable_gfxpayload_dynamic" = xyes ; then ++ GFXPAYLOAD_DYNAMIC=1 ++else ++ GFXPAYLOAD_DYNAMIC=0 ++fi ++AC_SUBST([GFXPAYLOAD_DYNAMIC]) ++ + LIBS="" + + AC_SUBST([FONT_SOURCE]) +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index e5b3d27f5..2ff266806 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -964,6 +964,14 @@ module = { + common = lib/hexdump.c; + }; + ++module = { ++ name = hwmatch; ++ i386_pc = commands/i386/pc/hwmatch.c; ++ enable = i386_pc; ++ cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)'; ++ cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB)'; ++}; ++ + module = { + name = keystatus; + common = commands/keystatus.c; +diff --git a/grub-core/commands/i386/pc/hwmatch.c b/grub-core/commands/i386/pc/hwmatch.c +new file mode 100644 +index 000000000..6de07cecc +--- /dev/null ++++ b/grub-core/commands/i386/pc/hwmatch.c +@@ -0,0 +1,146 @@ ++/* hwmatch.c - Match hardware against a whitelist/blacklist. */ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2011 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++#include <grub/dl.h> ++#include <grub/misc.h> ++#include <grub/command.h> ++#include <grub/pci.h> ++#include <grub/normal.h> ++#include <grub/file.h> ++#include <grub/env.h> ++#include <grub/i18n.h> ++#include <regex.h> ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++/* Context for grub_cmd_hwmatch. */ ++struct hwmatch_ctx ++{ ++ grub_file_t matches_file; ++ int class_match; ++ int match; ++}; ++ ++/* Helper for grub_cmd_hwmatch. */ ++static int ++hwmatch_iter (grub_pci_device_t dev, grub_pci_id_t pciid, void *data) ++{ ++ struct hwmatch_ctx *ctx = data; ++ grub_pci_address_t addr; ++ grub_uint32_t class, baseclass, vendor, device; ++ grub_pci_id_t subpciid; ++ grub_uint32_t subvendor, subdevice, subclass; ++ char *id, *line; ++ ++ addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS); ++ class = grub_pci_read (addr); ++ baseclass = class >> 24; ++ ++ if (ctx->class_match != baseclass) ++ return 0; ++ ++ vendor = pciid & 0xffff; ++ device = pciid >> 16; ++ ++ addr = grub_pci_make_address (dev, GRUB_PCI_REG_SUBVENDOR); ++ subpciid = grub_pci_read (addr); ++ ++ subclass = (class >> 16) & 0xff; ++ subvendor = subpciid & 0xffff; ++ subdevice = subpciid >> 16; ++ ++ id = grub_xasprintf ("v%04xd%04xsv%04xsd%04xbc%02xsc%02x", ++ vendor, device, subvendor, subdevice, ++ baseclass, subclass); ++ ++ grub_file_seek (ctx->matches_file, 0); ++ while ((line = grub_file_getline (ctx->matches_file)) != NULL) ++ { ++ char *anchored_line; ++ regex_t regex; ++ int ret; ++ ++ if (! *line || *line == '#') ++ { ++ grub_free (line); ++ continue; ++ } ++ ++ anchored_line = grub_xasprintf ("^%s$", line); ++ ret = regcomp (®ex, anchored_line, REG_EXTENDED | REG_NOSUB); ++ grub_free (anchored_line); ++ if (ret) ++ { ++ grub_free (line); ++ continue; ++ } ++ ++ ret = regexec (®ex, id, 0, NULL, 0); ++ regfree (®ex); ++ grub_free (line); ++ if (! ret) ++ { ++ ctx->match = 1; ++ return 1; ++ } ++ } ++ ++ return 0; ++} ++ ++static grub_err_t ++grub_cmd_hwmatch (grub_command_t cmd __attribute__ ((unused)), ++ int argc, char **args) ++{ ++ struct hwmatch_ctx ctx = { .match = 0 }; ++ char *match_str; ++ ++ if (argc < 2) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "list file and class required"); ++ ++ ctx.matches_file = grub_file_open (args[0], GRUB_FILE_TYPE_HWMATCH); ++ if (! ctx.matches_file) ++ return grub_errno; ++ ++ ctx.class_match = grub_strtol (args[1], 0, 10); ++ ++ grub_pci_iterate (hwmatch_iter, &ctx); ++ ++ match_str = grub_xasprintf ("%d", ctx.match); ++ grub_env_set ("match", match_str); ++ grub_free (match_str); ++ ++ grub_file_close (ctx.matches_file); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_command_t cmd; ++ ++GRUB_MOD_INIT(hwmatch) ++{ ++ cmd = grub_register_command ("hwmatch", grub_cmd_hwmatch, ++ N_("MATCHES-FILE CLASS"), ++ N_("Match PCI devices.")); ++} ++ ++GRUB_MOD_FINI(hwmatch) ++{ ++ grub_unregister_command (cmd); ++} +diff --git a/include/grub/file.h b/include/grub/file.h +index 31567483c..e3c4cae2b 100644 +--- a/include/grub/file.h ++++ b/include/grub/file.h +@@ -122,6 +122,7 @@ enum grub_file_type + GRUB_FILE_TYPE_FS_SEARCH, + GRUB_FILE_TYPE_AUDIO, + GRUB_FILE_TYPE_VBE_DUMP, ++ GRUB_FILE_TYPE_HWMATCH, + + GRUB_FILE_TYPE_LOADENV, + GRUB_FILE_TYPE_SAVEENV, +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index 80315a31b..d46d7852b 100644 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -23,6 +23,7 @@ datarootdir="@datarootdir@" + ubuntu_recovery="@UBUNTU_RECOVERY@" + quiet_boot="@QUIET_BOOT@" + quick_boot="@QUICK_BOOT@" ++gfxpayload_dynamic="@GFXPAYLOAD_DYNAMIC@" + + . "$pkgdatadir/grub-mkconfig_lib" + +@@ -145,9 +146,10 @@ linux_entry () + if [ "x$GRUB_GFXPAYLOAD_LINUX" != xtext ]; then + echo " load_video" | sed "s/^/$submenu_indentation/" + fi +- if [ "$ubuntu_recovery" = 0 ] || [ x$type != xrecovery ]; then +- echo " set gfxpayload=$GRUB_GFXPAYLOAD_LINUX" | sed "s/^/$submenu_indentation/" +- fi ++ fi ++ if ([ "$ubuntu_recovery" = 0 ] || [ x$type != xrecovery ]) && \ ++ ([ "x$GRUB_GFXPAYLOAD_LINUX" != x ] || [ "$gfxpayload_dynamic" = 1 ]); then ++ echo " set gfxpayload=\$linux_gfx_mode" | sed "s/^/$submenu_indentation/" + fi + + echo " insmod gzio" | sed "s/^/$submenu_indentation/" +@@ -226,6 +228,35 @@ prepare_root_cache= + boot_device_id= + title_correction_code= + ++# Use ELILO's generic "efifb" when it's known to be available. ++# FIXME: We need an interface to select vesafb in case efifb can't be used. ++if [ "x$GRUB_GFXPAYLOAD_LINUX" != x ] || [ "$gfxpayload_dynamic" = 0 ]; then ++ echo "set linux_gfx_mode=$GRUB_GFXPAYLOAD_LINUX" ++else ++ cat << EOF ++if [ "\${recordfail}" != 1 ]; then ++ if [ -e \${prefix}/gfxblacklist.txt ]; then ++ if hwmatch \${prefix}/gfxblacklist.txt 3; then ++ if [ \${match} = 0 ]; then ++ set linux_gfx_mode=keep ++ else ++ set linux_gfx_mode=text ++ fi ++ else ++ set linux_gfx_mode=text ++ fi ++ else ++ set linux_gfx_mode=keep ++ fi ++else ++ set linux_gfx_mode=text ++fi ++EOF ++fi ++cat << EOF ++export linux_gfx_mode ++EOF ++ + # Extra indentation to add to menu entries in a submenu. We're not in a submenu + # yet, so it's empty. In a submenu it will be equal to '\t' (one tab). + submenu_indentation="" diff --git a/debian/patches/gfxpayload-keep-default.patch b/debian/patches/gfxpayload-keep-default.patch new file mode 100644 index 0000000..1308966 --- /dev/null +++ b/debian/patches/gfxpayload-keep-default.patch @@ -0,0 +1,39 @@ +From 70a2b23aadd93955a3869aa1c29a7f09c0696b95 Mon Sep 17 00:00:00 2001 +From: Colin Watson <cjwatson@debian.org> +Date: Mon, 13 Jan 2014 12:12:57 +0000 +Subject: Disable gfxpayload=keep by default + +Setting gfxpayload=keep has been known to cause efifb to be +inappropriately enabled. In any case, with the current Linux kernel the +result of this option is that early kernelspace will be unable to print +anything to the console, so (for example) if boot fails and you end up +dumped to an initramfs prompt, you won't be able to see anything on the +screen. As such it shouldn't be enabled by default in Debian, no matter +what kernel options are enabled. + +gfxpayload=keep is a good idea but rather ahead of its time ... + +Bug-Debian: http://bugs.debian.org/567245 +Forwarded: no +Last-Update: 2013-12-25 + +Patch-Name: gfxpayload-keep-default.patch +--- + util/grub.d/10_linux.in | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index e8b01c0d0..9446d6833 100644 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -114,10 +114,6 @@ linux_entry () + # FIXME: We need an interface to select vesafb in case efifb can't be used. + if [ "x$GRUB_GFXPAYLOAD_LINUX" = x ]; then + echo " load_video" | sed "s/^/$submenu_indentation/" +- if grep -qx "CONFIG_FB_EFI=y" "${config}" 2> /dev/null \ +- && grep -qx "CONFIG_VT_HW_CONSOLE_BINDING=y" "${config}" 2> /dev/null; then +- echo " set gfxpayload=keep" | sed "s/^/$submenu_indentation/" +- fi + else + if [ "x$GRUB_GFXPAYLOAD_LINUX" != xtext ]; then + echo " load_video" | sed "s/^/$submenu_indentation/" diff --git a/debian/patches/grub-install-extra-removable.patch b/debian/patches/grub-install-extra-removable.patch new file mode 100644 index 0000000..1e7d2b4 --- /dev/null +++ b/debian/patches/grub-install-extra-removable.patch @@ -0,0 +1,202 @@ +From a0bfbdf9139bc127d28c4102b941ee504f7f0041 Mon Sep 17 00:00:00 2001 +From: Steve McIntyre <93sam@debian.org> +Date: Wed, 3 Dec 2014 01:25:12 +0000 +Subject: Add support for forcing EFI installation to the removable media path + +Add an extra option to grub-install "--force-extra-removable". On EFI +platforms, this will cause an extra copy of the grub-efi image to be +written to the appropriate removable media patch +/boot/efi/EFI/BOOT/BOOT$ARCH.EFI as well. This will help with broken +UEFI implementations where the firmware does not work when configured +with new boot paths. + +Signed-off-by: Steve McIntyre <93sam@debian.org> + +Bug-Debian: https://bugs.debian.org/767037 https://bugs.debian.org/773092 +Forwarded: Not yet +Last-Update: 2021-09-24 + +Patch-Name: grub-install-extra-removable.patch +--- + util/grub-install.c | 110 +++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 108 insertions(+), 2 deletions(-) + +diff --git a/util/grub-install.c b/util/grub-install.c +index 2304cc5c4..b51fe4710 100644 +--- a/util/grub-install.c ++++ b/util/grub-install.c +@@ -56,6 +56,7 @@ + + static char *target; + static int removable = 0; ++static int force_extra_removable = 0; + static int recheck = 0; + static int update_nvram = 1; + static char *install_device = NULL; +@@ -113,7 +114,8 @@ enum + OPTION_LABEL_BGCOLOR, + OPTION_PRODUCT_VERSION, + OPTION_UEFI_SECURE_BOOT, +- OPTION_NO_UEFI_SECURE_BOOT ++ OPTION_NO_UEFI_SECURE_BOOT, ++ OPTION_FORCE_EXTRA_REMOVABLE + }; + + static int fs_probe = 1; +@@ -216,6 +218,10 @@ argp_parser (int key, char *arg, struct argp_state *state) + removable = 1; + return 0; + ++ case OPTION_FORCE_EXTRA_REMOVABLE: ++ force_extra_removable = 1; ++ return 0; ++ + case OPTION_ALLOW_FLOPPY: + allow_floppy = 1; + return 0; +@@ -322,6 +328,9 @@ static struct argp_option options[] = { + N_("do not install an image usable with UEFI Secure Boot, even if the " + "system was currently started using it. " + "This option is only available on EFI."), 2}, ++ {"force-extra-removable", OPTION_FORCE_EXTRA_REMOVABLE, 0, 0, ++ N_("force installation to the removable media path also. " ++ "This option is only available on EFI."), 2}, + {0, 0, 0, 0, 0, 0} + }; + +@@ -847,6 +856,91 @@ fill_core_services (const char *core_services) + free (sysv_plist); + } + ++/* Helper routine for also_install_removable() below. Walk through the ++ specified dir, looking to see if there is a file/dir that matches ++ the search string exactly, but in a case-insensitive manner. If so, ++ return a copy of the exact file/dir that *does* exist. If not, ++ return NULL */ ++static char * ++check_component_exists(const char *dir, ++ const char *search) ++{ ++ grub_util_fd_dir_t d; ++ grub_util_fd_dirent_t de; ++ char *found = NULL; ++ ++ d = grub_util_fd_opendir (dir); ++ if (!d) ++ grub_util_error (_("cannot open directory `%s': %s"), ++ dir, grub_util_fd_strerror ()); ++ ++ while ((de = grub_util_fd_readdir (d))) ++ { ++ if (strcasecmp (de->d_name, search) == 0) ++ { ++ found = xstrdup (de->d_name); ++ break; ++ } ++ } ++ grub_util_fd_closedir (d); ++ return found; ++} ++ ++/* Some complex directory-handling stuff in here, to cope with ++ * case-insensitive FAT/VFAT filesystem semantics. Ugh. */ ++static void ++also_install_removable(const char *src, ++ const char *base_efidir, ++ const char *efi_suffix_upper) ++{ ++ char *efi_file = NULL; ++ char *dst = NULL; ++ char *cur = NULL; ++ char *found = NULL; ++ ++ if (!efi_suffix_upper) ++ grub_util_error ("%s", _("efi_suffix_upper not set")); ++ efi_file = xasprintf ("BOOT%s.EFI", efi_suffix_upper); ++ ++ /* We need to install in $base_efidir/EFI/BOOT/$efi_file, but we ++ * need to cope with case-insensitive stuff here. Build the path one ++ * component at a time, checking for existing matches each time. */ ++ ++ /* Look for "EFI" in base_efidir. Make it if it does not exist in ++ * some form. */ ++ found = check_component_exists(base_efidir, "EFI"); ++ if (found == NULL) ++ found = xstrdup("EFI"); ++ dst = grub_util_path_concat (2, base_efidir, found); ++ cur = xstrdup (dst); ++ free (dst); ++ free (found); ++ grub_install_mkdir_p (cur); ++ ++ /* Now BOOT */ ++ found = check_component_exists(cur, "BOOT"); ++ if (found == NULL) ++ found = xstrdup("BOOT"); ++ dst = grub_util_path_concat (2, cur, found); ++ cur = xstrdup (dst); ++ free (dst); ++ free (found); ++ grub_install_mkdir_p (cur); ++ ++ /* Now $efi_file */ ++ found = check_component_exists(cur, efi_file); ++ if (found == NULL) ++ found = xstrdup(efi_file); ++ dst = grub_util_path_concat (2, cur, found); ++ cur = xstrdup (dst); ++ free (dst); ++ free (found); ++ grub_install_copy_file (src, cur, 1); ++ ++ free (cur); ++ free (efi_file); ++} ++ + int + main (int argc, char *argv[]) + { +@@ -864,6 +958,7 @@ main (int argc, char *argv[]) + char *relative_grubdir; + char **efidir_device_names = NULL; + grub_device_t efidir_grub_dev = NULL; ++ char *base_efidir = NULL; + char *efidir_grub_devname; + int efidir_is_mac = 0; + int is_prep = 0; +@@ -896,6 +991,9 @@ main (int argc, char *argv[]) + bootloader_id = xstrdup ("grub"); + } + ++ if (removable && force_extra_removable) ++ grub_util_error (_("Invalid to use both --removable and --force_extra_removable")); ++ + if (!grub_install_source_directory) + { + if (!target) +@@ -1115,6 +1213,8 @@ main (int argc, char *argv[]) + if (!efidir_is_mac && grub_strcmp (fs->name, "fat") != 0) + grub_util_error (_("%s doesn't look like an EFI partition"), efidir); + ++ base_efidir = xstrdup(efidir); ++ + /* The EFI specification requires that an EFI System Partition must + contain an "EFI" subdirectory, and that OS loaders are stored in + subdirectories below EFI. Vendors are expected to pick names that do +@@ -2048,9 +2148,15 @@ main (int argc, char *argv[]) + fprintf (config_dst_f, "configfile $prefix/grub.cfg\n"); + fclose (config_dst_f); + free (config_dst); ++ if (force_extra_removable) ++ also_install_removable(efi_signed, base_efidir, efi_suffix_upper); + } + else +- grub_install_copy_file (imgfile, dst, 1); ++ { ++ grub_install_copy_file (imgfile, dst, 1); ++ if (force_extra_removable) ++ also_install_removable(imgfile, base_efidir, efi_suffix_upper); ++ } + + grub_set_install_backup_ponr (); + diff --git a/debian/patches/grub-install-pvxen-paths.patch b/debian/patches/grub-install-pvxen-paths.patch new file mode 100644 index 0000000..88987a2 --- /dev/null +++ b/debian/patches/grub-install-pvxen-paths.patch @@ -0,0 +1,71 @@ +From 4e93755cd1c371ba856b375f453664fd07a67205 Mon Sep 17 00:00:00 2001 +From: Ian Campbell <ijc@hellion.org.uk> +Date: Sat, 6 Sep 2014 12:20:12 +0100 +Subject: grub-install: Install PV Xen binaries into the upstream specified + path + +Upstream have defined a specification for where guests ought to place their +xenpv grub binaries in order to facilitate chainloading from a stage 1 grub +loaded from dom0. + +http://xenbits.xen.org/docs/unstable-staging/misc/x86-xenpv-bootloader.html + +The spec calls for installation into /boot/xen/pvboot-i386.elf or +/boot/xen/pvboot-x86_64.elf. + +Signed-off-by: Ian Campbell <ijc@hellion.org.uk> + +Bug-Debian: https://bugs.debian.org/762307 +Forwarded: http://lists.gnu.org/archive/html/grub-devel/2014-10/msg00041.html +Last-Update: 2014-10-24 + +Patch-Name: grub-install-pvxen-paths.patch + +--- +v2: Respect bootdir, create /boot/xen as needed. +--- + util/grub-install.c | 24 ++++++++++++++++++++++-- + 1 file changed, 22 insertions(+), 2 deletions(-) + +diff --git a/util/grub-install.c b/util/grub-install.c +index d02bd488a..2304cc5c4 100644 +--- a/util/grub-install.c ++++ b/util/grub-install.c +@@ -2085,6 +2085,28 @@ main (int argc, char *argv[]) + } + break; + ++ case GRUB_INSTALL_PLATFORM_I386_XEN: ++ { ++ char *path = grub_util_path_concat (2, bootdir, "xen"); ++ char *dst = grub_util_path_concat (2, path, "pvboot-i386.elf"); ++ grub_install_mkdir_p (path); ++ grub_install_copy_file (imgfile, dst, 1); ++ free (dst); ++ free (path); ++ } ++ break; ++ ++ case GRUB_INSTALL_PLATFORM_X86_64_XEN: ++ { ++ char *path = grub_util_path_concat (2, bootdir, "xen"); ++ char *dst = grub_util_path_concat (2, path, "pvboot-x86_64.elf"); ++ grub_install_mkdir_p (path); ++ grub_install_copy_file (imgfile, dst, 1); ++ free (dst); ++ free (path); ++ } ++ break; ++ + case GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON: + case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS: + case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS: +@@ -2094,8 +2116,6 @@ main (int argc, char *argv[]) + case GRUB_INSTALL_PLATFORM_MIPSEL_ARC: + case GRUB_INSTALL_PLATFORM_ARM_UBOOT: + case GRUB_INSTALL_PLATFORM_I386_QEMU: +- case GRUB_INSTALL_PLATFORM_I386_XEN: +- case GRUB_INSTALL_PLATFORM_X86_64_XEN: + case GRUB_INSTALL_PLATFORM_I386_XEN_PVH: + grub_util_warn ("%s", + _("WARNING: no platform-specific install was performed")); diff --git a/debian/patches/grub-install-removable-shim.patch b/debian/patches/grub-install-removable-shim.patch new file mode 100644 index 0000000..a384387 --- /dev/null +++ b/debian/patches/grub-install-removable-shim.patch @@ -0,0 +1,195 @@ +From c8351a8a7a7664dfac4de63fb6df185b2a52a346 Mon Sep 17 00:00:00 2001 +From: Steve McIntyre <93sam@debian.org> +Date: Fri, 14 Jun 2019 16:37:11 +0100 +Subject: Deal with --force-extra-removable with signed shim too + +In this case, we need both the signed shim as /EFI/BOOT/BOOTXXX.EFI +and signed Grub as /EFI/BOOT/grubXXX.efi. + +Also install the BOOTXXX.CSV into /EFI/debian, and FBXXX.EFI into +/EFI/BOOT/ so that it can work when needed (*iff* we're updating the +NVRAM). + +[cjwatson: Refactored also_install_removable somewhat for brevity and so +that we're using consistent case-insensitive logic.] + +Bug-Debian: https://bugs.debian.org/930531 +Last-Update: 2021-09-24 + +Patch-Name: grub-install-removable-shim.patch +--- + util/grub-install.c | 83 +++++++++++++++++++++++++++++++++++---------- + 1 file changed, 66 insertions(+), 17 deletions(-) + +diff --git a/util/grub-install.c b/util/grub-install.c +index 05b695226..43fc27c55 100644 +--- a/util/grub-install.c ++++ b/util/grub-install.c +@@ -891,17 +891,13 @@ check_component_exists(const char *dir, + static void + also_install_removable(const char *src, + const char *base_efidir, +- const char *efi_suffix_upper) ++ const char *efi_file, ++ int is_needed) + { +- char *efi_file = NULL; + char *dst = NULL; + char *cur = NULL; + char *found = NULL; + +- if (!efi_suffix_upper) +- grub_util_error ("%s", _("efi_suffix_upper not set")); +- efi_file = xasprintf ("BOOT%s.EFI", efi_suffix_upper); +- + /* We need to install in $base_efidir/EFI/BOOT/$efi_file, but we + * need to cope with case-insensitive stuff here. Build the path one + * component at a time, checking for existing matches each time. */ +@@ -935,10 +931,9 @@ also_install_removable(const char *src, + cur = xstrdup (dst); + free (dst); + free (found); +- grub_install_copy_file (src, cur, 1); ++ grub_install_copy_file (src, cur, is_needed); + + free (cur); +- free (efi_file); + } + + int +@@ -2103,11 +2098,14 @@ main (int argc, char *argv[]) + case GRUB_INSTALL_PLATFORM_IA64_EFI: + { + char *dst = grub_util_path_concat (2, efidir, efi_file); ++ char *removable_file = xasprintf ("BOOT%s.EFI", efi_suffix_upper); ++ + if (uefi_secure_boot) + { + char *shim_signed = NULL; + char *mok_signed = NULL, *mok_file = NULL; + char *fb_signed = NULL, *fb_file = NULL; ++ char *csv_file = NULL; + char *config_dst; + FILE *config_dst_f; + +@@ -2116,11 +2114,15 @@ main (int argc, char *argv[]) + mok_file = xasprintf ("mm%s.efi", efi_suffix); + fb_signed = xasprintf ("fb%s.efi.signed", efi_suffix); + fb_file = xasprintf ("fb%s.efi", efi_suffix); ++ csv_file = xasprintf ("BOOT%s.CSV", efi_suffix_upper); ++ ++ /* If we have a signed shim binary, install that and all ++ its helpers in the normal vendor path */ + + if (grub_util_is_regular (shim_signed)) + { + char *chained_base, *chained_dst; +- char *mok_src, *mok_dst, *fb_src, *fb_dst; ++ char *mok_src, *mok_dst, *fb_src, *fb_dst, *csv_src, *csv_dst; + if (!removable) + { + free (efi_file); +@@ -2132,8 +2134,6 @@ main (int argc, char *argv[]) + chained_base = xasprintf ("grub%s.efi", efi_suffix); + chained_dst = grub_util_path_concat (2, efidir, chained_base); + grub_install_copy_file (efi_signed, chained_dst, 1); +- free (chained_dst); +- free (chained_base); + + /* Not critical, so not an error if they are not present (as it + won't be for older releases); but if we have them, make +@@ -2144,8 +2144,6 @@ main (int argc, char *argv[]) + mok_file); + grub_install_copy_file (mok_src, + mok_dst, 0); +- free (mok_src); +- free (mok_dst); + + fb_src = grub_util_path_concat (2, "/usr/lib/shim/", + fb_signed); +@@ -2153,30 +2151,81 @@ main (int argc, char *argv[]) + fb_file); + grub_install_copy_file (fb_src, + fb_dst, 0); ++ ++ csv_src = grub_util_path_concat (2, "/usr/lib/shim/", ++ csv_file); ++ csv_dst = grub_util_path_concat (2, efidir, ++ csv_file); ++ grub_install_copy_file (csv_src, ++ csv_dst, 0); ++ ++ /* Install binaries into .../EFI/BOOT too: ++ the shim binary ++ the grub binary ++ the shim fallback binary (not fatal on failure) */ ++ if (force_extra_removable) ++ { ++ grub_util_info ("Secure boot: installing shim and image into rm path"); ++ also_install_removable (shim_signed, base_efidir, removable_file, 1); ++ ++ also_install_removable (efi_signed, base_efidir, chained_base, 1); ++ ++ /* If we're updating the NVRAM, add fallback too - it ++ will re-update the NVRAM later if things break */ ++ if (update_nvram) ++ also_install_removable (fb_src, base_efidir, fb_file, 0); ++ } ++ ++ free (chained_dst); ++ free (chained_base); ++ free (mok_src); ++ free (mok_dst); + free (fb_src); + free (fb_dst); ++ free (csv_src); ++ free (csv_dst); + } + else +- grub_install_copy_file (efi_signed, dst, 1); ++ { ++ /* Tried to install for secure boot, but no signed ++ shim found. Fall back to just installing the signed ++ grub binary */ ++ grub_util_info ("Secure boot (no shim): installing signed grub binary"); ++ grub_install_copy_file (efi_signed, dst, 1); ++ if (force_extra_removable) ++ { ++ grub_util_info ("Secure boot (no shim): installing signed grub binary into rm path"); ++ also_install_removable (efi_signed, base_efidir, removable_file, 1); ++ } ++ } + ++ /* In either case, install our grub.cfg */ + config_dst = grub_util_path_concat (2, efidir, "grub.cfg"); + grub_install_copy_file (load_cfg, config_dst, 1); + config_dst_f = grub_util_fopen (config_dst, "ab"); + fprintf (config_dst_f, "configfile $prefix/grub.cfg\n"); + fclose (config_dst_f); + free (config_dst); +- if (force_extra_removable) +- also_install_removable(efi_signed, base_efidir, efi_suffix_upper); ++ ++ free (csv_file); ++ free (fb_file); ++ free (fb_signed); ++ free (mok_file); ++ free (mok_signed); ++ free (shim_signed); + } + else + { ++ /* No secure boot - just install our newly-generated image */ ++ grub_util_info ("No Secure Boot: installing core image"); + grub_install_copy_file (imgfile, dst, 1); + if (force_extra_removable) +- also_install_removable(imgfile, base_efidir, efi_suffix_upper); ++ also_install_removable (imgfile, base_efidir, removable_file, 1); + } + + grub_set_install_backup_ponr (); + ++ free (removable_file); + free (dst); + } + if (!removable && update_nvram) diff --git a/debian/patches/grub-legacy-0-based-partitions.patch b/debian/patches/grub-legacy-0-based-partitions.patch new file mode 100644 index 0000000..31dc3c1 --- /dev/null +++ b/debian/patches/grub-legacy-0-based-partitions.patch @@ -0,0 +1,39 @@ +From ae648ba6160a334707f8a8fc0768ec1bc60c4442 Mon Sep 17 00:00:00 2001 +From: Robert Millan <rmh@aybabtu.com> +Date: Mon, 13 Jan 2014 12:12:53 +0000 +Subject: Support running grub-probe in grub-legacy's update-grub + +Author: Colin Watson <cjwatson@debian.org> +Forwarded: not-needed +Last-Update: 2013-12-25 + +Patch-Name: grub-legacy-0-based-partitions.patch +--- + util/getroot.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/util/getroot.c b/util/getroot.c +index a5eaa64fd..6ae35ecaa 100644 +--- a/util/getroot.c ++++ b/util/getroot.c +@@ -245,6 +245,20 @@ find_partition (grub_disk_t dsk __attribute__ ((unused)), + + if (ctx->start == part_start) + { ++ /* This is dreadfully hardcoded, but there's a limit to what GRUB ++ Legacy was able to deal with anyway. */ ++ if (getenv ("GRUB_LEGACY_0_BASED_PARTITIONS")) ++ { ++ if (partition->parent) ++ /* Probably a BSD slice. */ ++ ctx->partname = xasprintf ("%d,%d", partition->parent->number, ++ partition->number + 1); ++ else ++ ctx->partname = xasprintf ("%d", partition->number); ++ ++ return 1; ++ } ++ + ctx->partname = grub_partition_get_name (partition); + return 1; + } diff --git a/debian/patches/grub.cfg-400.patch b/debian/patches/grub.cfg-400.patch new file mode 100644 index 0000000..2f1c304 --- /dev/null +++ b/debian/patches/grub.cfg-400.patch @@ -0,0 +1,25 @@ +From 2f1be2e80ba5dd1278401f21cfe07526312838e9 Mon Sep 17 00:00:00 2001 +From: Colin Watson <cjwatson@debian.org> +Date: Mon, 13 Jan 2014 12:12:55 +0000 +Subject: Make grub.cfg world-readable if it contains no passwords + +Patch-Name: grub.cfg-400.patch +--- + util/grub-mkconfig.in | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in +index f8cbb8d7a..0fd618e35 100644 +--- a/util/grub-mkconfig.in ++++ b/util/grub-mkconfig.in +@@ -289,6 +289,10 @@ for i in "${grub_mkconfig_dir}"/* ; do + esac + done + ++if [ "x${grub_cfg}" != "x" ] && ! grep "^password" ${grub_cfg}.new >/dev/null; then ++ chmod 444 ${grub_cfg}.new || true ++fi ++ + if test "x${grub_cfg}" != "x" ; then + if ! ${grub_script_check} ${grub_cfg}.new; then + # TRANSLATORS: %s is replaced by filename diff --git a/debian/patches/ieee1275-clear-reset.patch b/debian/patches/ieee1275-clear-reset.patch new file mode 100644 index 0000000..c528944 --- /dev/null +++ b/debian/patches/ieee1275-clear-reset.patch @@ -0,0 +1,32 @@ +From 791c1034910b5e87ec7ff4166300f0f26b647625 Mon Sep 17 00:00:00 2001 +From: Paulo Flabiano Smorigo <pfsmorigo@linux.vnet.ibm.com> +Date: Thu, 25 Sep 2014 18:41:29 -0300 +Subject: Include a text attribute reset in the clear command for ppc + +Always clear text attribute for clear command in order to avoid problems +after it boots. + +* grub-core/term/terminfo.c: Add escape for text attribute reset + +Bug-Ubuntu: https://bugs.launchpad.net/bugs/1295255 +Origin: other, https://lists.gnu.org/archive/html/grub-devel/2014-09/msg00076.html +Last-Update: 2014-09-26 + +Patch-Name: ieee1275-clear-reset.patch +--- + grub-core/term/terminfo.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/term/terminfo.c b/grub-core/term/terminfo.c +index 85ecf06b4..e5ec77107 100644 +--- a/grub-core/term/terminfo.c ++++ b/grub-core/term/terminfo.c +@@ -151,7 +151,7 @@ grub_terminfo_set_current (struct grub_term_output *term, + /* Clear the screen. Using serial console, screen(1) only recognizes the + * ANSI escape sequence. Using video console, Apple Open Firmware + * (version 3.1.1) only recognizes the literal ^L. So use both. */ +- data->cls = grub_strdup ("\e[2J"); ++ data->cls = grub_strdup ("\e[2J\e[m"); + data->reverse_video_on = grub_strdup ("\e[7m"); + data->reverse_video_off = grub_strdup ("\e[m"); + if (grub_strcmp ("ieee1275", str) == 0) diff --git a/debian/patches/ignore-grub_func_test-failures.patch b/debian/patches/ignore-grub_func_test-failures.patch new file mode 100644 index 0000000..6275b26 --- /dev/null +++ b/debian/patches/ignore-grub_func_test-failures.patch @@ -0,0 +1,29 @@ +From f8d8c2e9dfd49bd0e59e27c09fc535a547d13c01 Mon Sep 17 00:00:00 2001 +From: Colin Watson <cjwatson@debian.org> +Date: Mon, 13 Jan 2014 12:13:32 +0000 +Subject: Ignore functional test failures for now as they are broken + +See: https://lists.gnu.org/archive/html/grub-devel/2013-11/msg00242.html + +Forwarded: not-needed +Last-Update: 2013-11-19 + +Patch-Name: ignore-grub_func_test-failures.patch +--- + tests/grub_func_test.in | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/tests/grub_func_test.in b/tests/grub_func_test.in +index c67f9e422..728cd6e06 100644 +--- a/tests/grub_func_test.in ++++ b/tests/grub_func_test.in +@@ -16,6 +16,8 @@ out=`echo all_functional_test | @builddir@/grub-shell --timeout=3600 --files="/b + + if [ "$(echo "$out" | tail -n 1)" != "ALL TESTS PASSED" ]; then + echo "Functional test failure: $out" +- exit 1 ++ # Disabled temporarily due to unrecognised video checksum failures. ++ #exit 1 ++ exit 0 + fi + diff --git a/debian/patches/insmod-xzio-and-lzopio-on-xen.patch b/debian/patches/insmod-xzio-and-lzopio-on-xen.patch new file mode 100644 index 0000000..fb48118 --- /dev/null +++ b/debian/patches/insmod-xzio-and-lzopio-on-xen.patch @@ -0,0 +1,33 @@ +From bc8ec86089a4f6eb2ea19499a2b335dccdebd577 Mon Sep 17 00:00:00 2001 +From: Ian Campbell <ijc@debian.org> +Date: Sun, 30 Nov 2014 12:12:52 +0000 +Subject: Arrange to insmod xzio and lzopio when booting a kernel as a Xen + guest + +This is needed in case the Linux kernel is compiled with CONFIG_KERNEL_XZ or +CONFIG_KERNEL_LZO rather than CONFIG_KERNEL_GZ (gzio is already loaded by +grub.cfg today). + +Signed-off-by: Ian Campbell <ijc@debian.org> + +Bug-Debian: https://bugs.debian.org/755256 +Forwarded: http://lists.gnu.org/archive/html/grub-devel/2014-11/msg00091.html +Last-Update: 2014-11-30 + +Patch-Name: insmod-xzio-and-lzopio-on-xen.patch +--- + util/grub.d/10_linux.in | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index f88a2de10..635c609d6 100644 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -162,6 +162,7 @@ linux_entry () + fi + + echo " insmod gzio" | sed "s/^/$submenu_indentation/" ++ echo " if [ x\$grub_platform = xxen ]; then insmod xzio; insmod lzopio; fi" | sed "s/^/$submenu_indentation/" + + if [ x$dirname = x/ ]; then + if [ -z "${prepare_root_cache}" ]; then diff --git a/debian/patches/install-efi-adjust-distributor.patch b/debian/patches/install-efi-adjust-distributor.patch new file mode 100644 index 0000000..f802618 --- /dev/null +++ b/debian/patches/install-efi-adjust-distributor.patch @@ -0,0 +1,34 @@ +From 11ea79546da850296fabeb94bfc8c110a98fe7f6 Mon Sep 17 00:00:00 2001 +From: Colin Watson <cjwatson@ubuntu.com> +Date: Mon, 13 Jan 2014 12:13:27 +0000 +Subject: Adjust efi_distributor for some distributions + +This is not a very good approach, and certainly not sanely upstreamable; +we probably need to split GRUB_DISTRIBUTOR into a couple of different +variables. + +Bug-Ubuntu: https://bugs.launchpad.net/bugs/1242417 +Bug-Debian: https://bugs.debian.org/932966 +Forwarded: not-needed +Last-Update: 2019-08-06 + +Patch-Name: install-efi-adjust-distributor.patch +--- + util/grub-install.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/util/grub-install.c b/util/grub-install.c +index f49c78d0b..48c8c0364 100644 +--- a/util/grub-install.c ++++ b/util/grub-install.c +@@ -1123,6 +1123,10 @@ main (int argc, char *argv[]) + */ + char *t; + efi_distributor = bootloader_id; ++ if (strcmp (efi_distributor, "kubuntu") == 0) ++ efi_distributor = "ubuntu"; ++ else if (strcmp (efi_distributor, "devuan") == 0) ++ efi_distributor = "debian"; + switch (platform) + { + case GRUB_INSTALL_PLATFORM_I386_EFI: diff --git a/debian/patches/install-efi-fallback.patch b/debian/patches/install-efi-fallback.patch new file mode 100644 index 0000000..6501d8a --- /dev/null +++ b/debian/patches/install-efi-fallback.patch @@ -0,0 +1,91 @@ +From 7cf3ac7be59ef377a98ead5c7d3d5cb537c159c4 Mon Sep 17 00:00:00 2001 +From: Colin Watson <cjwatson@ubuntu.com> +Date: Mon, 13 Jan 2014 12:13:05 +0000 +Subject: Fall back to non-EFI if booted using EFI but -efi is missing + +It may be possible, particularly in recovery situations, to be booted +using EFI on x86 when only the i386-pc target is installed, or on ARM +when only the arm-uboot target is installed. There's nothing actually +stopping us installing i386-pc or arm-uboot from an EFI environment, and +it's better than returning a confusing error. + +Author: Steve McIntyre <93sam@debian.org> +Forwarded: no +Last-Update: 2019-05-24 + +Patch-Name: install-efi-fallback.patch +--- + grub-core/osdep/linux/platform.c | 40 ++++++++++++++++++++++++++++---- + 1 file changed, 35 insertions(+), 5 deletions(-) + +diff --git a/grub-core/osdep/linux/platform.c b/grub-core/osdep/linux/platform.c +index e28a79dab..2e7f72086 100644 +--- a/grub-core/osdep/linux/platform.c ++++ b/grub-core/osdep/linux/platform.c +@@ -19,10 +19,12 @@ + #include <config.h> + + #include <grub/util/install.h> ++#include <grub/emu/config.h> + #include <grub/emu/exec.h> + #include <grub/emu/misc.h> + #include <sys/types.h> + #include <dirent.h> ++#include <stdlib.h> + #include <string.h> + + #include <sys/utsname.h> +@@ -128,9 +130,24 @@ const char * + grub_install_get_default_arm_platform (void) + { + if (is_efi_system()) +- return "arm-efi"; +- else +- return "arm-uboot"; ++ { ++ const char *pkglibdir = grub_util_get_pkglibdir (); ++ const char *platform; ++ char *pd; ++ int found; ++ ++ platform = "arm-efi"; ++ ++ pd = grub_util_path_concat (2, pkglibdir, platform); ++ found = grub_util_is_directory (pd); ++ free (pd); ++ if (found) ++ return platform; ++ else ++ grub_util_info ("... but %s platform not available", platform); ++ } ++ ++ return "arm-uboot"; + } + + const char * +@@ -138,10 +155,23 @@ grub_install_get_default_x86_platform (void) + { + if (is_efi_system()) + { ++ const char *pkglibdir = grub_util_get_pkglibdir (); ++ const char *platform; ++ char *pd; ++ int found; ++ + if (read_platform_size() == 64) +- return "x86_64-efi"; ++ platform = "x86_64-efi"; ++ else ++ platform = "i386-efi"; ++ ++ pd = grub_util_path_concat (2, pkglibdir, platform); ++ found = grub_util_is_directory (pd); ++ free (pd); ++ if (found) ++ return platform; + else +- return "i386-efi"; ++ grub_util_info ("... but %s platform not available", platform); + } + + grub_util_info ("Looking for /proc/device-tree .."); diff --git a/debian/patches/install-locale-langpack.patch b/debian/patches/install-locale-langpack.patch new file mode 100644 index 0000000..ae96bab --- /dev/null +++ b/debian/patches/install-locale-langpack.patch @@ -0,0 +1,116 @@ +From 31e9c5eaec14e18251db1fb7e6e44add22e56526 Mon Sep 17 00:00:00 2001 +From: Colin Watson <cjwatson@ubuntu.com> +Date: Mon, 13 Jan 2014 12:13:07 +0000 +Subject: Prefer translations from Ubuntu language packs if available + +Bug-Ubuntu: https://bugs.launchpad.net/bugs/537998 +Forwarded: not-needed +Last-Update: 2013-12-25 + +Patch-Name: install-locale-langpack.patch +--- + util/grub-install-common.c | 37 ++++++++++++++++++++++++++++++------- + 1 file changed, 30 insertions(+), 7 deletions(-) + +diff --git a/util/grub-install-common.c b/util/grub-install-common.c +index 4e212e690..e53730485 100644 +--- a/util/grub-install-common.c ++++ b/util/grub-install-common.c +@@ -774,17 +774,25 @@ get_localedir (void) + } + + static void +-copy_locales (const char *dstd) ++copy_locales (const char *dstd, int langpack) + { + grub_util_fd_dir_t d; + grub_util_fd_dirent_t de; + const char *locale_dir = get_localedir (); ++ char *dir; + +- d = grub_util_fd_opendir (locale_dir); ++ if (langpack) ++ dir = xasprintf ("%s-langpack", locale_dir); ++ else ++ dir = xstrdup (locale_dir); ++ ++ d = grub_util_fd_opendir (dir); + if (!d) + { +- grub_util_warn (_("cannot open directory `%s': %s"), +- locale_dir, grub_util_fd_strerror ()); ++ if (!langpack) ++ grub_util_warn (_("cannot open directory `%s': %s"), ++ dir, grub_util_fd_strerror ()); ++ free (dir); + return; + } + +@@ -801,14 +809,14 @@ copy_locales (const char *dstd) + if (ext && (grub_strcmp (ext, ".mo") == 0 + || grub_strcmp (ext, ".gmo") == 0)) + { +- srcf = grub_util_path_concat (2, locale_dir, de->d_name); ++ srcf = grub_util_path_concat (2, dir, de->d_name); + dstf = grub_util_path_concat (2, dstd, de->d_name); + ext = grub_strrchr (dstf, '.'); + grub_strcpy (ext, ".mo"); + } + else + { +- srcf = grub_util_path_concat_ext (4, locale_dir, de->d_name, ++ srcf = grub_util_path_concat_ext (4, dir, de->d_name, + "LC_MESSAGES", PACKAGE, ".mo"); + dstf = grub_util_path_concat_ext (2, dstd, de->d_name, ".mo"); + } +@@ -817,6 +825,7 @@ copy_locales (const char *dstd) + free (dstf); + } + grub_util_fd_closedir (d); ++ free (dir); + } + #endif + +@@ -835,13 +844,15 @@ grub_install_copy_nls(const char *src __attribute__ ((unused)), + { + char *srcd = grub_util_path_concat (2, src, "po"); + copy_by_ext (srcd, dst_locale, ".mo", 0); +- copy_locales (dst_locale); ++ copy_locales (dst_locale, 0); ++ copy_locales (dst_locale, 1); + free (srcd); + } + else + { + size_t i; + const char *locale_dir = get_localedir (); ++ char *locale_langpack_dir = xasprintf ("%s-langpack", locale_dir); + + for (i = 0; i < install_locales.n_entries; i++) + { +@@ -858,6 +869,16 @@ grub_install_copy_nls(const char *src __attribute__ ((unused)), + continue; + } + free (srcf); ++ srcf = grub_util_path_concat_ext (4, locale_langpack_dir, ++ install_locales.entries[i], ++ "LC_MESSAGES", PACKAGE, ".mo"); ++ if (grub_install_compress_file (srcf, dstf, 0)) ++ { ++ free (srcf); ++ free (dstf); ++ continue; ++ } ++ free (srcf); + srcf = grub_util_path_concat_ext (4, locale_dir, + install_locales.entries[i], + "LC_MESSAGES", PACKAGE, ".mo"); +@@ -867,6 +888,8 @@ grub_install_copy_nls(const char *src __attribute__ ((unused)), + free (srcf); + free (dstf); + } ++ ++ free (locale_langpack_dir); + } + free (dst_locale); + #endif diff --git a/debian/patches/install-powerpc-machtypes.patch b/debian/patches/install-powerpc-machtypes.patch new file mode 100644 index 0000000..385174f --- /dev/null +++ b/debian/patches/install-powerpc-machtypes.patch @@ -0,0 +1,220 @@ +From 4b6f846398109576c218394c3d10bcb075c065a7 Mon Sep 17 00:00:00 2001 +From: Colin Watson <cjwatson@debian.org> +Date: Tue, 28 Jan 2014 14:40:02 +0000 +Subject: Port yaboot logic for various powerpc machine types + +Some powerpc machines require not updating the NVRAM. This can be handled +by existing grub-install command-line options, but it's friendlier to detect +this automatically. + +On chrp_ibm machines, use the nvram utility rather than nvsetenv. (This +is possibly suitable for other machines too, but that needs to be +verified.) + +Forwarded: no +Last-Update: 2014-10-15 + +Patch-Name: install-powerpc-machtypes.patch +--- + grub-core/osdep/basic/platform.c | 5 +++ + grub-core/osdep/linux/platform.c | 72 ++++++++++++++++++++++++++++++ + grub-core/osdep/unix/platform.c | 28 +++++++++--- + grub-core/osdep/windows/platform.c | 6 +++ + include/grub/util/install.h | 3 ++ + util/grub-install.c | 11 +++++ + 6 files changed, 119 insertions(+), 6 deletions(-) + +diff --git a/grub-core/osdep/basic/platform.c b/grub-core/osdep/basic/platform.c +index a7dafd85a..6c293ed2d 100644 +--- a/grub-core/osdep/basic/platform.c ++++ b/grub-core/osdep/basic/platform.c +@@ -30,3 +30,8 @@ grub_install_get_default_x86_platform (void) + return "i386-pc"; + } + ++const char * ++grub_install_get_default_powerpc_machtype (void) ++{ ++ return "generic"; ++} +diff --git a/grub-core/osdep/linux/platform.c b/grub-core/osdep/linux/platform.c +index 2e7f72086..5b37366d4 100644 +--- a/grub-core/osdep/linux/platform.c ++++ b/grub-core/osdep/linux/platform.c +@@ -24,6 +24,7 @@ + #include <grub/emu/misc.h> + #include <sys/types.h> + #include <dirent.h> ++#include <stdio.h> + #include <stdlib.h> + #include <string.h> + +@@ -184,3 +185,74 @@ grub_install_get_default_x86_platform (void) + grub_util_info ("... not found"); + return "i386-pc"; + } ++ ++const char * ++grub_install_get_default_powerpc_machtype (void) ++{ ++ FILE *fp; ++ char *buf = NULL; ++ size_t len = 0; ++ const char *machtype = "generic"; ++ ++ fp = grub_util_fopen ("/proc/cpuinfo", "r"); ++ if (! fp) ++ return machtype; ++ ++ while (getline (&buf, &len, fp) > 0) ++ { ++ if (strncmp (buf, "pmac-generation", ++ sizeof ("pmac-generation") - 1) == 0) ++ { ++ if (strstr (buf, "NewWorld")) ++ { ++ machtype = "pmac_newworld"; ++ break; ++ } ++ if (strstr (buf, "OldWorld")) ++ { ++ machtype = "pmac_oldworld"; ++ break; ++ } ++ } ++ ++ if (strncmp (buf, "motherboard", sizeof ("motherboard") - 1) == 0 && ++ strstr (buf, "AAPL")) ++ { ++ machtype = "pmac_oldworld"; ++ break; ++ } ++ ++ if (strncmp (buf, "machine", sizeof ("machine") - 1) == 0 && ++ strstr (buf, "CHRP IBM")) ++ { ++ if (strstr (buf, "qemu")) ++ { ++ machtype = "chrp_ibm_qemu"; ++ break; ++ } ++ else ++ { ++ machtype = "chrp_ibm"; ++ break; ++ } ++ } ++ ++ if (strncmp (buf, "platform", sizeof ("platform") - 1) == 0) ++ { ++ if (strstr (buf, "Maple")) ++ { ++ machtype = "maple"; ++ break; ++ } ++ if (strstr (buf, "Cell")) ++ { ++ machtype = "cell"; ++ break; ++ } ++ } ++ } ++ ++ free (buf); ++ fclose (fp); ++ return machtype; ++} +diff --git a/grub-core/osdep/unix/platform.c b/grub-core/osdep/unix/platform.c +index 55b8f4016..9c439326a 100644 +--- a/grub-core/osdep/unix/platform.c ++++ b/grub-core/osdep/unix/platform.c +@@ -218,13 +218,29 @@ grub_install_register_ieee1275 (int is_prep, const char *install_device, + else + boot_device = get_ofpathname (install_device); + +- if (grub_util_exec ((const char * []){ "nvsetenv", "boot-device", +- boot_device, NULL })) ++ if (strcmp (grub_install_get_default_powerpc_machtype (), "chrp_ibm") == 0) + { +- char *cmd = xasprintf ("setenv boot-device %s", boot_device); +- grub_util_error (_("`nvsetenv' failed. \nYou will have to set `boot-device' variable manually. At the IEEE1275 prompt, type:\n %s\n"), +- cmd); +- free (cmd); ++ char *arg = xasprintf ("boot-device=%s", boot_device); ++ if (grub_util_exec ((const char * []){ "nvram", ++ "--update-config", arg, NULL })) ++ { ++ char *cmd = xasprintf ("setenv boot-device %s", boot_device); ++ grub_util_error (_("`nvram' failed. \nYou will have to set `boot-device' variable manually. At the IEEE1275 prompt, type:\n %s\n"), ++ cmd); ++ free (cmd); ++ } ++ free (arg); ++ } ++ else ++ { ++ if (grub_util_exec ((const char * []){ "nvsetenv", "boot-device", ++ boot_device, NULL })) ++ { ++ char *cmd = xasprintf ("setenv boot-device %s", boot_device); ++ grub_util_error (_("`nvsetenv' failed. \nYou will have to set `boot-device' variable manually. At the IEEE1275 prompt, type:\n %s\n"), ++ cmd); ++ free (cmd); ++ } + } + + free (boot_device); +diff --git a/grub-core/osdep/windows/platform.c b/grub-core/osdep/windows/platform.c +index 253f8d101..d18488f20 100644 +--- a/grub-core/osdep/windows/platform.c ++++ b/grub-core/osdep/windows/platform.c +@@ -128,6 +128,12 @@ grub_install_get_default_x86_platform (void) + return "i386-efi"; + } + ++const char * ++grub_install_get_default_powerpc_machtype (void) ++{ ++ return "generic"; ++} ++ + static void * + get_efi_variable (const wchar_t *varname, ssize_t *len) + { +diff --git a/include/grub/util/install.h b/include/grub/util/install.h +index 7df3191f4..135ba48d2 100644 +--- a/include/grub/util/install.h ++++ b/include/grub/util/install.h +@@ -223,6 +223,9 @@ grub_install_get_default_arm_platform (void); + const char * + grub_install_get_default_x86_platform (void); + ++const char * ++grub_install_get_default_powerpc_machtype (void); ++ + int + grub_install_register_efi (grub_device_t efidir_grub_dev, + const char *efifile_path, +diff --git a/util/grub-install.c b/util/grub-install.c +index 48c8c0364..d02bd488a 100644 +--- a/util/grub-install.c ++++ b/util/grub-install.c +@@ -1187,7 +1187,18 @@ main (int argc, char *argv[]) + + if (platform == GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275) + { ++ const char *machtype = grub_install_get_default_powerpc_machtype (); + int is_guess = 0; ++ ++ if (strcmp (machtype, "pmac_oldworld") == 0) ++ update_nvram = 0; ++ else if (strcmp (machtype, "cell") == 0) ++ update_nvram = 0; ++ else if (strcmp (machtype, "generic") == 0) ++ update_nvram = 0; ++ else if (strcmp (machtype, "chrp_ibm_qemu") == 0) ++ update_nvram = 0; ++ + if (!macppcdir) + { + char *d; diff --git a/debian/patches/install-signed.patch b/debian/patches/install-signed.patch new file mode 100644 index 0000000..bfeb3a9 --- /dev/null +++ b/debian/patches/install-signed.patch @@ -0,0 +1,311 @@ +From 0bd31f4c7468f0b42ff6673f47112b9167c6381c Mon Sep 17 00:00:00 2001 +From: Colin Watson <cjwatson@ubuntu.com> +Date: Mon, 13 Jan 2014 12:13:22 +0000 +Subject: Install signed images if UEFI Secure Boot is enabled +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Author: Stéphane Graber <stgraber@ubuntu.com> +Author: Steve Langasek <steve.langasek@ubuntu.com> +Author: Linn Crosetto <linn@hpe.com> +Author: Mathieu Trudel-Lapierre <cyphermox@ubuntu.com> +Forwarded: no +Last-Update: 2021-09-24 + +Patch-Name: install-signed.patch +--- + util/grub-install.c | 212 ++++++++++++++++++++++++++++++++------------ + 1 file changed, 153 insertions(+), 59 deletions(-) + +diff --git a/util/grub-install.c b/util/grub-install.c +index 48e2d3779..f49c78d0b 100644 +--- a/util/grub-install.c ++++ b/util/grub-install.c +@@ -80,6 +80,7 @@ static char *label_color; + static char *label_bgcolor; + static char *product_version; + static int add_rs_codes = 1; ++static int uefi_secure_boot = 1; + + enum + { +@@ -110,7 +111,9 @@ enum + OPTION_LABEL_FONT, + OPTION_LABEL_COLOR, + OPTION_LABEL_BGCOLOR, +- OPTION_PRODUCT_VERSION ++ OPTION_PRODUCT_VERSION, ++ OPTION_UEFI_SECURE_BOOT, ++ OPTION_NO_UEFI_SECURE_BOOT + }; + + static int fs_probe = 1; +@@ -234,6 +237,14 @@ argp_parser (int key, char *arg, struct argp_state *state) + bootloader_id = xstrdup (arg); + return 0; + ++ case OPTION_UEFI_SECURE_BOOT: ++ uefi_secure_boot = 1; ++ return 0; ++ ++ case OPTION_NO_UEFI_SECURE_BOOT: ++ uefi_secure_boot = 0; ++ return 0; ++ + case ARGP_KEY_ARG: + if (install_device) + grub_util_error ("%s", _("More than one install device?")); +@@ -303,6 +314,14 @@ static struct argp_option options[] = { + {"label-color", OPTION_LABEL_COLOR, N_("COLOR"), 0, N_("use COLOR for label"), 2}, + {"label-bgcolor", OPTION_LABEL_BGCOLOR, N_("COLOR"), 0, N_("use COLOR for label background"), 2}, + {"product-version", OPTION_PRODUCT_VERSION, N_("STRING"), 0, N_("use STRING as product version"), 2}, ++ {"uefi-secure-boot", OPTION_UEFI_SECURE_BOOT, 0, 0, ++ N_("install an image usable with UEFI Secure Boot. " ++ "This option is only available on EFI and if the grub-efi-amd64-signed " ++ "package is installed."), 2}, ++ {"no-uefi-secure-boot", OPTION_NO_UEFI_SECURE_BOOT, 0, 0, ++ N_("do not install an image usable with UEFI Secure Boot, even if the " ++ "system was currently started using it. " ++ "This option is only available on EFI."), 2}, + {0, 0, 0, 0, 0, 0} + }; + +@@ -833,7 +852,8 @@ main (int argc, char *argv[]) + { + int is_efi = 0; + const char *efi_distributor = NULL; +- const char *efi_file = NULL; ++ const char *efi_suffix = NULL, *efi_suffix_upper = NULL; ++ char *efi_file = NULL; + char **grub_devices; + grub_fs_t grub_fs; + grub_device_t grub_dev = NULL; +@@ -1103,6 +1123,39 @@ main (int argc, char *argv[]) + */ + char *t; + efi_distributor = bootloader_id; ++ switch (platform) ++ { ++ case GRUB_INSTALL_PLATFORM_I386_EFI: ++ efi_suffix = "ia32"; ++ efi_suffix_upper = "IA32"; ++ break; ++ case GRUB_INSTALL_PLATFORM_X86_64_EFI: ++ efi_suffix = "x64"; ++ efi_suffix_upper = "X64"; ++ break; ++ case GRUB_INSTALL_PLATFORM_IA64_EFI: ++ efi_suffix = "ia64"; ++ efi_suffix_upper = "IA64"; ++ break; ++ case GRUB_INSTALL_PLATFORM_ARM_EFI: ++ efi_suffix = "arm"; ++ efi_suffix_upper = "ARM"; ++ break; ++ case GRUB_INSTALL_PLATFORM_ARM64_EFI: ++ efi_suffix = "aa64"; ++ efi_suffix_upper = "AA64"; ++ break; ++ case GRUB_INSTALL_PLATFORM_RISCV32_EFI: ++ efi_suffix = "riscv32"; ++ efi_suffix_upper = "RISCV32"; ++ break; ++ case GRUB_INSTALL_PLATFORM_RISCV64_EFI: ++ efi_suffix = "riscv64"; ++ efi_suffix_upper = "RISCV64"; ++ break; ++ default: ++ break; ++ } + if (removable) + { + /* The specification makes stricter requirements of removable +@@ -1111,66 +1164,16 @@ main (int argc, char *argv[]) + must have a specific file name depending on the architecture. + */ + efi_distributor = "BOOT"; +- switch (platform) +- { +- case GRUB_INSTALL_PLATFORM_I386_EFI: +- efi_file = "BOOTIA32.EFI"; +- break; +- case GRUB_INSTALL_PLATFORM_X86_64_EFI: +- efi_file = "BOOTX64.EFI"; +- break; +- case GRUB_INSTALL_PLATFORM_IA64_EFI: +- efi_file = "BOOTIA64.EFI"; +- break; +- case GRUB_INSTALL_PLATFORM_ARM_EFI: +- efi_file = "BOOTARM.EFI"; +- break; +- case GRUB_INSTALL_PLATFORM_ARM64_EFI: +- efi_file = "BOOTAA64.EFI"; +- break; +- case GRUB_INSTALL_PLATFORM_RISCV32_EFI: +- efi_file = "BOOTRISCV32.EFI"; +- break; +- case GRUB_INSTALL_PLATFORM_RISCV64_EFI: +- efi_file = "BOOTRISCV64.EFI"; +- break; +- default: +- grub_util_error ("%s", _("You've found a bug")); +- break; +- } ++ if (!efi_suffix) ++ grub_util_error ("%s", _("You've found a bug")); ++ efi_file = xasprintf ("BOOT%s.EFI", efi_suffix_upper); + } + else + { + /* It is convenient for each architecture to have a different + efi_file, so that different versions can be installed in parallel. + */ +- switch (platform) +- { +- case GRUB_INSTALL_PLATFORM_I386_EFI: +- efi_file = "grubia32.efi"; +- break; +- case GRUB_INSTALL_PLATFORM_X86_64_EFI: +- efi_file = "grubx64.efi"; +- break; +- case GRUB_INSTALL_PLATFORM_IA64_EFI: +- efi_file = "grubia64.efi"; +- break; +- case GRUB_INSTALL_PLATFORM_ARM_EFI: +- efi_file = "grubarm.efi"; +- break; +- case GRUB_INSTALL_PLATFORM_ARM64_EFI: +- efi_file = "grubaa64.efi"; +- break; +- case GRUB_INSTALL_PLATFORM_RISCV32_EFI: +- efi_file = "grubriscv32.efi"; +- break; +- case GRUB_INSTALL_PLATFORM_RISCV64_EFI: +- efi_file = "grubriscv64.efi"; +- break; +- default: +- efi_file = "grub.efi"; +- break; +- } ++ efi_file = xasprintf ("grub%s.efi", efi_suffix); + } + t = grub_util_path_concat (3, efidir, "EFI", efi_distributor); + free (efidir); +@@ -1376,14 +1379,41 @@ main (int argc, char *argv[]) + } + } + +- if (!have_abstractions) ++ char *efi_signed = NULL; ++ switch (platform) ++ { ++ case GRUB_INSTALL_PLATFORM_I386_EFI: ++ case GRUB_INSTALL_PLATFORM_X86_64_EFI: ++ case GRUB_INSTALL_PLATFORM_ARM_EFI: ++ case GRUB_INSTALL_PLATFORM_ARM64_EFI: ++ case GRUB_INSTALL_PLATFORM_IA64_EFI: ++ { ++ char *dir = xasprintf ("%s-signed", grub_install_source_directory); ++ char *signed_image; ++ if (removable) ++ signed_image = xasprintf ("gcd%s.efi.signed", efi_suffix); ++ else ++ signed_image = xasprintf ("grub%s.efi.signed", efi_suffix); ++ efi_signed = grub_util_path_concat (2, dir, signed_image); ++ break; ++ } ++ ++ default: ++ break; ++ } ++ ++ if (!efi_signed || !grub_util_is_regular (efi_signed)) ++ uefi_secure_boot = 0; ++ ++ if (!have_abstractions || uefi_secure_boot) + { + if ((disk_module && grub_strcmp (disk_module, "biosdisk") != 0) + || grub_drives[1] + || (!install_drive + && platform != GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275) + || (install_drive && !is_same_disk (grub_drives[0], install_drive)) +- || !have_bootdev (platform)) ++ || !have_bootdev (platform) ++ || uefi_secure_boot) + { + char *uuid = NULL; + /* generic method (used on coreboot and ata mod). */ +@@ -1941,7 +1971,71 @@ main (int argc, char *argv[]) + case GRUB_INSTALL_PLATFORM_IA64_EFI: + { + char *dst = grub_util_path_concat (2, efidir, efi_file); +- grub_install_copy_file (imgfile, dst, 1); ++ if (uefi_secure_boot) ++ { ++ char *shim_signed = NULL; ++ char *mok_signed = NULL, *mok_file = NULL; ++ char *fb_signed = NULL, *fb_file = NULL; ++ char *config_dst; ++ FILE *config_dst_f; ++ ++ shim_signed = xasprintf ("/usr/lib/shim/shim%s.efi.signed", efi_suffix); ++ mok_signed = xasprintf ("mm%s.efi.signed", efi_suffix); ++ mok_file = xasprintf ("mm%s.efi", efi_suffix); ++ fb_signed = xasprintf ("fb%s.efi.signed", efi_suffix); ++ fb_file = xasprintf ("fb%s.efi", efi_suffix); ++ ++ if (grub_util_is_regular (shim_signed)) ++ { ++ char *chained_base, *chained_dst; ++ char *mok_src, *mok_dst, *fb_src, *fb_dst; ++ if (!removable) ++ { ++ free (efi_file); ++ efi_file = xasprintf ("shim%s.efi", efi_suffix); ++ free (dst); ++ dst = grub_util_path_concat (2, efidir, efi_file); ++ } ++ grub_install_copy_file (shim_signed, dst, 1); ++ chained_base = xasprintf ("grub%s.efi", efi_suffix); ++ chained_dst = grub_util_path_concat (2, efidir, chained_base); ++ grub_install_copy_file (efi_signed, chained_dst, 1); ++ free (chained_dst); ++ free (chained_base); ++ ++ /* Not critical, so not an error if they are not present (as it ++ won't be for older releases); but if we have them, make ++ sure they are installed. */ ++ mok_src = grub_util_path_concat (2, "/usr/lib/shim/", ++ mok_signed); ++ mok_dst = grub_util_path_concat (2, efidir, ++ mok_file); ++ grub_install_copy_file (mok_src, ++ mok_dst, 0); ++ free (mok_src); ++ free (mok_dst); ++ ++ fb_src = grub_util_path_concat (2, "/usr/lib/shim/", ++ fb_signed); ++ fb_dst = grub_util_path_concat (2, efidir, ++ fb_file); ++ grub_install_copy_file (fb_src, ++ fb_dst, 0); ++ free (fb_src); ++ free (fb_dst); ++ } ++ else ++ grub_install_copy_file (efi_signed, dst, 1); ++ ++ config_dst = grub_util_path_concat (2, efidir, "grub.cfg"); ++ grub_install_copy_file (load_cfg, config_dst, 1); ++ config_dst_f = grub_util_fopen (config_dst, "ab"); ++ fprintf (config_dst_f, "configfile $prefix/grub.cfg\n"); ++ fclose (config_dst_f); ++ free (config_dst); ++ } ++ else ++ grub_install_copy_file (imgfile, dst, 1); + + grub_set_install_backup_ponr (); + diff --git a/debian/patches/install-stage2-confusion.patch b/debian/patches/install-stage2-confusion.patch new file mode 100644 index 0000000..d7e60d3 --- /dev/null +++ b/debian/patches/install-stage2-confusion.patch @@ -0,0 +1,46 @@ +From 07ebcd8f769c2522b9a3a79c3d92082747f83781 Mon Sep 17 00:00:00 2001 +From: Colin Watson <cjwatson@debian.org> +Date: Mon, 13 Jan 2014 12:12:58 +0000 +Subject: If GRUB Legacy is still around, tell packaging to ignore it + +Bug-Debian: http://bugs.debian.org/586143 +Forwarded: not-needed +Last-Update: 2021-09-24 + +Patch-Name: install-stage2-confusion.patch +--- + util/grub-install.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/util/grub-install.c b/util/grub-install.c +index 0fbe7f78c..48e2d3779 100644 +--- a/util/grub-install.c ++++ b/util/grub-install.c +@@ -42,6 +42,7 @@ + #include <grub/emu/config.h> + #include <grub/util/ofpath.h> + #include <grub/hfsplus.h> ++#include <grub/emu/hostfile.h> + + #include <string.h> + +@@ -1727,6 +1728,19 @@ main (int argc, char *argv[]) + + grub_set_install_backup_ponr (); + } ++ ++ /* If vestiges of GRUB Legacy still exist, tell the Debian packaging ++ that they can ignore them. */ ++ if (!rootdir && grub_util_is_regular ("/boot/grub/stage2") && ++ grub_util_is_regular ("/boot/grub/menu.lst")) ++ { ++ grub_util_fd_t fd; ++ ++ fd = grub_util_fd_open ("/boot/grub/grub2-installed", ++ GRUB_UTIL_FD_O_WRONLY); ++ grub_util_fd_close (fd); ++ } ++ + break; + } + case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275: diff --git a/debian/patches/kern-file-Fix-error-handling-in-grub_file_open.patch b/debian/patches/kern-file-Fix-error-handling-in-grub_file_open.patch new file mode 100644 index 0000000..d64c88e --- /dev/null +++ b/debian/patches/kern-file-Fix-error-handling-in-grub_file_open.patch @@ -0,0 +1,37 @@ +From aee575ddefd35f0fd6592171ae48ab6a4bb27464 Mon Sep 17 00:00:00 2001 +From: Steve McIntyre <steve@einval.com> +Date: Mon, 5 Dec 2022 23:14:10 +0000 +Subject: [PATCH] kern/file: Fix error handling in grub_file_open() + +grub_file_open() calls grub_file_get_device_name(), but doesn't check +the return. Instead, it checks if grub_errno is set. + +However, nothing initialises grub_errno here when grub_file_open() +starts. This means that trying to open one file that doesn't exist and +then trying to open another file that does will (incorrectly) also +fail to open that second file. + +Let's fix that. + +Signed-off-by: Steve McIntyre <steve@einval.com> +--- + grub-core/kern/file.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c +index 8d48fd50d..668b149c3 100644 +--- a/grub-core/kern/file.c ++++ b/grub-core/kern/file.c +@@ -66,6 +66,9 @@ grub_file_open (const char *name, enum grub_file_type type) + const char *file_name; + grub_file_filter_id_t filter; + ++ /* Reset grub_errno before we start */ ++ grub_errno = GRUB_ERR_NONE; ++ + device_name = grub_file_get_device_name (name); + if (grub_errno) + goto fail; +-- +2.30.2 + diff --git a/debian/patches/linuxefi.patch b/debian/patches/linuxefi.patch new file mode 100644 index 0000000..20fe4de --- /dev/null +++ b/debian/patches/linuxefi.patch @@ -0,0 +1,552 @@ +From fc550c31c25dcf9eb58ca1e987f3ce2be8ebac28 Mon Sep 17 00:00:00 2001 +From: Matthew Garrett <mjg@redhat.com> +Date: Mon, 13 Jan 2014 12:13:15 +0000 +Subject: Add "linuxefi" loader which avoids ExitBootServices + +Origin: vendor, http://pkgs.fedoraproject.org/cgit/grub2.git/tree/grub2-linuxefi.patch +Author: Colin Watson <cjwatson@ubuntu.com> +Author: Steve Langasek <steve.langasek@canonical.com> +Author: Linn Crosetto <linn@hpe.com> +Forwarded: no +Last-Update: 2021-09-24 + +Patch-Name: linuxefi.patch +--- + grub-core/Makefile.core.def | 7 + + grub-core/kern/efi/mm.c | 32 +++ + grub-core/loader/i386/efi/linux.c | 383 ++++++++++++++++++++++++++++++ + grub-core/loader/i386/linux.c | 41 ++++ + include/grub/efi/efi.h | 3 + + 5 files changed, 466 insertions(+) + create mode 100644 grub-core/loader/i386/efi/linux.c + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 8022e1c0a..e5b3d27f5 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -1874,6 +1874,13 @@ module = { + enable = x86_64_efi; + }; + ++module = { ++ name = linuxefi; ++ efi = loader/i386/efi/linux.c; ++ enable = i386_efi; ++ enable = x86_64_efi; ++}; ++ + module = { + name = chain; + efi = loader/efi/chainloader.c; +diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c +index 9838fb2f5..f6aef0ef6 100644 +--- a/grub-core/kern/efi/mm.c ++++ b/grub-core/kern/efi/mm.c +@@ -113,6 +113,38 @@ grub_efi_drop_alloc (grub_efi_physical_address_t address, + } + } + ++/* Allocate pages below a specified address */ ++void * ++grub_efi_allocate_pages_max (grub_efi_physical_address_t max, ++ grub_efi_uintn_t pages) ++{ ++ grub_efi_status_t status; ++ grub_efi_boot_services_t *b; ++ grub_efi_physical_address_t address = max; ++ ++ if (max > 0xffffffff) ++ return 0; ++ ++ b = grub_efi_system_table->boot_services; ++ status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_MAX_ADDRESS, GRUB_EFI_LOADER_DATA, pages, &address); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ ++ if (address == 0) ++ { ++ /* Uggh, the address 0 was allocated... This is too annoying, ++ so reallocate another one. */ ++ address = max; ++ status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_MAX_ADDRESS, GRUB_EFI_LOADER_DATA, pages, &address); ++ grub_efi_free_pages (0, pages); ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ } ++ ++ return (void *) ((grub_addr_t) address); ++} ++ + /* Allocate pages. Return the pointer to the first of allocated pages. */ + void * + grub_efi_allocate_pages_real (grub_efi_physical_address_t address, +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +new file mode 100644 +index 000000000..45b68c05a +--- /dev/null ++++ b/grub-core/loader/i386/efi/linux.c +@@ -0,0 +1,383 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2012 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++#include <grub/loader.h> ++#include <grub/file.h> ++#include <grub/err.h> ++#include <grub/misc.h> ++#include <grub/types.h> ++#include <grub/mm.h> ++#include <grub/cpu/linux.h> ++#include <grub/command.h> ++#include <grub/i18n.h> ++#include <grub/lib/cmdline.h> ++#include <grub/linux.h> ++#include <grub/efi/efi.h> ++#include <grub/efi/sb.h> ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++static grub_dl_t my_mod; ++static int loaded; ++static void *kernel_mem; ++static grub_uint64_t kernel_size; ++static grub_uint8_t *initrd_mem; ++static grub_uint32_t handover_offset; ++struct linux_kernel_params *params; ++static char *linux_cmdline; ++ ++#define BYTES_TO_PAGES(bytes) (((bytes) + 0xfff) >> 12) ++ ++#define SHIM_LOCK_GUID \ ++ { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} } ++ ++struct grub_efi_shim_lock ++{ ++ grub_efi_status_t (*verify) (void *buffer, grub_uint32_t size); ++}; ++typedef struct grub_efi_shim_lock grub_efi_shim_lock_t; ++ ++static grub_efi_boolean_t ++grub_linuxefi_secure_validate (void *data, grub_uint32_t size) ++{ ++ grub_efi_guid_t guid = SHIM_LOCK_GUID; ++ grub_efi_shim_lock_t *shim_lock; ++ grub_efi_status_t status; ++ ++ if (grub_efi_get_secureboot () != GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ { ++ grub_dprintf ("linuxefi", "secure boot not enabled, not validating"); ++ return 1; ++ } ++ ++ grub_dprintf ("linuxefi", "Locating shim protocol\n"); ++ shim_lock = grub_efi_locate_protocol(&guid, NULL); ++ ++ if (!shim_lock) ++ { ++ grub_dprintf ("linuxefi", "shim not available\n"); ++ return 0; ++ } ++ ++ grub_dprintf ("linuxefi", "Asking shim to verify kernel signature\n"); ++ status = shim_lock->verify(data, size); ++ if (status == GRUB_EFI_SUCCESS) ++ { ++ grub_dprintf ("linuxefi", "Kernel signature verification passed\n"); ++ return 1; ++ } ++ ++ grub_dprintf ("linuxefi", "Kernel signature verification failed (0x%lx)\n", ++ (unsigned long) status); ++ return 0; ++} ++ ++typedef void(*handover_func)(void *, grub_efi_system_table_t *, struct linux_kernel_params *); ++ ++static grub_err_t ++grub_linuxefi_boot (void) ++{ ++ handover_func hf; ++ int offset = 0; ++ ++#ifdef __x86_64__ ++ offset = 512; ++#endif ++ ++ hf = (handover_func)((char *)kernel_mem + handover_offset + offset); ++ ++ asm volatile ("cli"); ++ ++ hf (grub_efi_image_handle, grub_efi_system_table, params); ++ ++ /* Not reached */ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_linuxefi_unload (void) ++{ ++ grub_dl_unref (my_mod); ++ loaded = 0; ++ if (initrd_mem) ++ grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)initrd_mem, BYTES_TO_PAGES(params->ramdisk_size)); ++ if (linux_cmdline) ++ grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)linux_cmdline, BYTES_TO_PAGES(params->cmdline_size + 1)); ++ if (kernel_mem) ++ grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)kernel_mem, BYTES_TO_PAGES(kernel_size)); ++ if (params) ++ grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)params, BYTES_TO_PAGES(16384)); ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), ++ int argc, char *argv[]) ++{ ++ grub_size_t size = 0; ++ struct grub_linux_initrd_context initrd_ctx; ++ ++ if (argc == 0) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); ++ goto fail; ++ } ++ ++ if (!loaded) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first")); ++ goto fail; ++ } ++ ++ if (grub_initrd_init (argc, argv, &initrd_ctx)) ++ goto fail; ++ ++ size = grub_get_initrd_size (&initrd_ctx); ++ ++ initrd_mem = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(size)); ++ ++ if (!initrd_mem) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate initrd")); ++ goto fail; ++ } ++ ++ grub_dprintf ("linuxefi", "initrd_mem = %lx\n", (unsigned long) initrd_mem); ++ ++ params->ramdisk_size = size; ++ params->ramdisk_image = (grub_uint32_t)(grub_addr_t) initrd_mem; ++ ++ if (grub_initrd_load (&initrd_ctx, argv, initrd_mem)) ++ goto fail; ++ ++ params->ramdisk_size = size; ++ ++ fail: ++ grub_initrd_close (&initrd_ctx); ++ ++ if (initrd_mem && grub_errno) ++ grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)initrd_mem, BYTES_TO_PAGES(size)); ++ ++ return grub_errno; ++} ++ ++static grub_err_t ++grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), ++ int argc, char *argv[]) ++{ ++ grub_file_t file = 0; ++ struct linux_i386_kernel_header lh; ++ grub_ssize_t len, start, filelen; ++ void *kernel; ++ ++ grub_dl_ref (my_mod); ++ ++ if (argc == 0) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); ++ goto fail; ++ } ++ ++ file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL); ++ if (! file) ++ goto fail; ++ ++ filelen = grub_file_size (file); ++ ++ kernel = grub_malloc(filelen); ++ ++ if (!kernel) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel buffer")); ++ goto fail; ++ } ++ ++ if (grub_file_read (file, kernel, filelen) != filelen) ++ { ++ grub_error (GRUB_ERR_FILE_READ_ERROR, N_("Can't read kernel %s"), argv[0]); ++ goto fail; ++ } ++ ++ if (! grub_linuxefi_secure_validate (kernel, filelen)) ++ { ++ grub_error (GRUB_ERR_ACCESS_DENIED, N_("%s has invalid signature"), argv[0]); ++ grub_free (kernel); ++ goto fail; ++ } ++ ++ grub_file_seek (file, 0); ++ ++ grub_free(kernel); ++ ++ params = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(16384)); ++ ++ if (! params) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters"); ++ goto fail; ++ } ++ ++ grub_dprintf ("linuxefi", "params = %lx\n", (unsigned long) params); ++ ++ grub_memset (params, 0, 16384); ++ ++ if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh)) ++ { ++ if (!grub_errno) ++ grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), ++ argv[0]); ++ goto fail; ++ } ++ ++ if (lh.boot_flag != grub_cpu_to_le16 (0xaa55)) ++ { ++ grub_error (GRUB_ERR_BAD_OS, N_("invalid magic number")); ++ goto fail; ++ } ++ ++ if (lh.setup_sects > GRUB_LINUX_MAX_SETUP_SECTS) ++ { ++ grub_error (GRUB_ERR_BAD_OS, N_("too many setup sectors")); ++ goto fail; ++ } ++ ++ if (lh.version < grub_cpu_to_le16 (0x020b)) ++ { ++ grub_error (GRUB_ERR_BAD_OS, N_("kernel too old")); ++ goto fail; ++ } ++ ++ if (!lh.handover_offset) ++ { ++ grub_error (GRUB_ERR_BAD_OS, N_("kernel doesn't support EFI handover")); ++ goto fail; ++ } ++ ++ linux_cmdline = grub_efi_allocate_pages_max(0x3fffffff, ++ BYTES_TO_PAGES(lh.cmdline_size + 1)); ++ ++ if (!linux_cmdline) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate cmdline")); ++ goto fail; ++ } ++ ++ grub_dprintf ("linuxefi", "linux_cmdline = %lx\n", ++ (unsigned long) linux_cmdline); ++ ++ grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE)); ++ { ++ grub_err_t err; ++ err = grub_create_loader_cmdline (argc, argv, ++ linux_cmdline ++ + sizeof (LINUX_IMAGE) - 1, ++ lh.cmdline_size ++ - (sizeof (LINUX_IMAGE) - 1), ++ GRUB_VERIFY_KERNEL_CMDLINE); ++ if (err) ++ goto fail; ++ } ++ ++ lh.cmd_line_ptr = (grub_uint32_t)(grub_addr_t)linux_cmdline; ++ ++ handover_offset = lh.handover_offset; ++ ++ start = (lh.setup_sects + 1) * 512; ++ len = grub_file_size(file) - start; ++ ++ kernel_mem = grub_efi_allocate_fixed(lh.pref_address, ++ BYTES_TO_PAGES(lh.init_size)); ++ ++ if (!kernel_mem) ++ kernel_mem = grub_efi_allocate_pages_max(0x3fffffff, ++ BYTES_TO_PAGES(lh.init_size)); ++ ++ if (!kernel_mem) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate kernel")); ++ goto fail; ++ } ++ grub_errno = GRUB_ERR_NONE; ++ ++ grub_dprintf ("linuxefi", "kernel_mem = %lx\n", (unsigned long) kernel_mem); ++ ++ if (grub_file_seek (file, start) == (grub_off_t) -1) ++ { ++ grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), ++ argv[0]); ++ goto fail; ++ } ++ ++ if (grub_file_read (file, kernel_mem, len) != len && !grub_errno) ++ { ++ grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), ++ argv[0]); ++ } ++ ++ if (grub_errno == GRUB_ERR_NONE) ++ { ++ grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0); ++ loaded = 1; ++ lh.code32_start = (grub_uint32_t)(grub_addr_t) kernel_mem; ++ } ++ ++ grub_memcpy (params, &lh, 2 * 512); ++ ++ params->type_of_loader = 0x21; ++ ++ fail: ++ ++ if (file) ++ grub_file_close (file); ++ ++ if (grub_errno != GRUB_ERR_NONE) ++ { ++ grub_dl_unref (my_mod); ++ loaded = 0; ++ } ++ ++ if (linux_cmdline && !loaded) ++ grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)linux_cmdline, BYTES_TO_PAGES(lh.cmdline_size + 1)); ++ ++ if (kernel_mem && !loaded) ++ grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)kernel_mem, BYTES_TO_PAGES(kernel_size)); ++ ++ if (params && !loaded) ++ grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)params, BYTES_TO_PAGES(16384)); ++ ++ return grub_errno; ++} ++ ++static grub_command_t cmd_linux, cmd_initrd; ++ ++GRUB_MOD_INIT(linuxefi) ++{ ++ cmd_linux = ++ grub_register_command ("linuxefi", grub_cmd_linux, ++ 0, N_("Load Linux.")); ++ cmd_initrd = ++ grub_register_command ("initrdefi", grub_cmd_initrd, ++ 0, N_("Load initrd.")); ++ my_mod = mod; ++} ++ ++GRUB_MOD_FINI(linuxefi) ++{ ++ grub_unregister_command (cmd_linux); ++ grub_unregister_command (cmd_initrd); ++} +diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c +index 9f74a96b1..be37a1640 100644 +--- a/grub-core/loader/i386/linux.c ++++ b/grub-core/loader/i386/linux.c +@@ -78,6 +78,8 @@ static grub_size_t maximal_cmdline_size; + static struct linux_kernel_params linux_params; + static char *linux_cmdline; + #ifdef GRUB_MACHINE_EFI ++static int using_linuxefi; ++static grub_command_t initrdefi_cmd; + static grub_efi_uintn_t efi_mmap_size; + #else + static const grub_size_t efi_mmap_size = 0; +@@ -659,6 +661,39 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + grub_dl_ref (my_mod); + ++#ifdef GRUB_MACHINE_EFI ++ using_linuxefi = 0; ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ { ++ /* linuxefi requires a successful signature check and then hand over ++ to the kernel without calling ExitBootServices. */ ++ grub_dl_t mod; ++ grub_command_t linuxefi_cmd; ++ ++ grub_dprintf ("linux", "Secure Boot enabled: trying linuxefi\n"); ++ ++ mod = grub_dl_load ("linuxefi"); ++ if (mod) ++ { ++ grub_dl_ref (mod); ++ linuxefi_cmd = grub_command_find ("linuxefi"); ++ initrdefi_cmd = grub_command_find ("initrdefi"); ++ if (linuxefi_cmd && initrdefi_cmd) ++ { ++ (linuxefi_cmd->func) (linuxefi_cmd, argc, argv); ++ if (grub_errno == GRUB_ERR_NONE) ++ { ++ grub_dprintf ("linux", "Handing off to linuxefi\n"); ++ using_linuxefi = 1; ++ return GRUB_ERR_NONE; ++ } ++ grub_dprintf ("linux", "linuxefi failed (%d)\n", grub_errno); ++ goto fail; ++ } ++ } ++ } ++#endif ++ + if (argc == 0) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); +@@ -1042,6 +1077,12 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + grub_err_t err; + struct grub_linux_initrd_context initrd_ctx = { 0, 0, 0 }; + ++#ifdef GRUB_MACHINE_EFI ++ /* If we're using linuxefi, just forward to initrdefi. */ ++ if (using_linuxefi && initrdefi_cmd) ++ return (initrdefi_cmd->func) (initrdefi_cmd, argc, argv); ++#endif ++ + if (argc == 0) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); +diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h +index 83d958f99..08f6ee00a 100644 +--- a/include/grub/efi/efi.h ++++ b/include/grub/efi/efi.h +@@ -47,6 +47,9 @@ EXPORT_FUNC(grub_efi_allocate_fixed) (grub_efi_physical_address_t address, + grub_efi_uintn_t pages); + void * + EXPORT_FUNC(grub_efi_allocate_any_pages) (grub_efi_uintn_t pages); ++void * ++EXPORT_FUNC(grub_efi_allocate_pages_max) (grub_efi_physical_address_t max, ++ grub_efi_uintn_t pages); + void EXPORT_FUNC(grub_efi_free_pages) (grub_efi_physical_address_t address, + grub_efi_uintn_t pages); + grub_efi_uintn_t EXPORT_FUNC(grub_efi_find_mmap_size) (void); diff --git a/debian/patches/maybe-quiet.patch b/debian/patches/maybe-quiet.patch new file mode 100644 index 0000000..33d1e0f --- /dev/null +++ b/debian/patches/maybe-quiet.patch @@ -0,0 +1,386 @@ +From 0b33def5d9ace3488fa612e09a5bb813c5e3cd90 Mon Sep 17 00:00:00 2001 +From: Colin Watson <cjwatson@ubuntu.com> +Date: Mon, 13 Jan 2014 12:13:26 +0000 +Subject: Add configure option to reduce visual clutter at boot time + +If this option is enabled, then do all of the following: + +Don't display introductory message about line editing unless we're +actually offering a shell prompt. (This is believed to be a workaround +for a different bug. We'll go with this for now, but will drop this in +favour of a better fix upstream if somebody figures out what that is.) + +Don't clear the screen just before booting if we never drew the menu in +the first place. + +Remove verbose messages printed before reading configuration. In some +ways this is awkward because it makes debugging harder, but it's a +requirement for a smooth-looking boot process; we may be able to do +better in future. Upstream doesn't want this, though. + +Disable the cursor as well, for similar reasons of tidiness. + +Suppress kernel/initrd progress messages, except in recovery mode. + +Suppress "GRUB loading" message unless Shift is held down. Upstream +doesn't want this, as it makes debugging harder. Ubuntu wants it to +provide a cleaner boot experience. + +Author: Will Thompson <will@willthompson.co.uk> +Bug-Ubuntu: https://bugs.launchpad.net/bugs/386922 +Bug-Ubuntu: https://bugs.launchpad.net/bugs/861048 +Forwarded: (partial) http://lists.gnu.org/archive/html/grub-devel/2009-09/msg00056.html +Last-Update: 2021-09-24 + +Patch-Name: maybe-quiet.patch +--- + config.h.in | 2 ++ + configure.ac | 16 ++++++++++++++++ + grub-core/boot/i386/pc/boot.S | 11 +++++++++++ + grub-core/boot/i386/pc/diskboot.S | 26 ++++++++++++++++++++++++++ + grub-core/kern/main.c | 17 +++++++++++++++++ + grub-core/kern/rescue_reader.c | 2 ++ + grub-core/normal/main.c | 11 +++++++++++ + grub-core/normal/menu.c | 17 +++++++++++++++-- + util/grub.d/10_linux.in | 15 +++++++++++---- + 9 files changed, 111 insertions(+), 6 deletions(-) + +diff --git a/config.h.in b/config.h.in +index 9e8f9911b..d2c4ce8e5 100644 +--- a/config.h.in ++++ b/config.h.in +@@ -12,6 +12,8 @@ + /* Define to 1 to enable disk cache statistics. */ + #define DISK_CACHE_STATS @DISK_CACHE_STATS@ + #define BOOT_TIME_STATS @BOOT_TIME_STATS@ ++/* Define to 1 to make GRUB quieter at boot time. */ ++#define QUIET_BOOT @QUIET_BOOT@ + + /* We don't need those. */ + #define MINILZO_CFG_SKIP_LZO_PTR 1 +diff --git a/configure.ac b/configure.ac +index 74778a6f8..256fc44ef 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1915,6 +1915,17 @@ else + fi + AC_SUBST([UBUNTU_RECOVERY]) + ++AC_ARG_ENABLE([quiet-boot], ++ [AS_HELP_STRING([--enable-quiet-boot], ++ [emit fewer messages at boot time (default=no)])], ++ [], [enable_quiet_boot=no]) ++if test x"$enable_quiet_boot" = xyes ; then ++ QUIET_BOOT=1 ++else ++ QUIET_BOOT=0 ++fi ++AC_SUBST([QUIET_BOOT]) ++ + LIBS="" + + AC_SUBST([FONT_SOURCE]) +@@ -2177,5 +2188,10 @@ echo "With stack smashing protector: Yes" + else + echo "With stack smashing protector: No" + fi ++if [ x"$enable_quiet_boot" = xyes ]; then ++echo With quiet boot: Yes ++else ++echo With quiet boot: No ++fi + echo "*******************************************************" + ] +diff --git a/grub-core/boot/i386/pc/boot.S b/grub-core/boot/i386/pc/boot.S +index 2bd0b2d28..b0c0f2225 100644 +--- a/grub-core/boot/i386/pc/boot.S ++++ b/grub-core/boot/i386/pc/boot.S +@@ -19,6 +19,9 @@ + + #include <grub/symbol.h> + #include <grub/machine/boot.h> ++#if QUIET_BOOT && !defined(HYBRID_BOOT) ++#include <grub/machine/memory.h> ++#endif + + /* + * defines for the code go here +@@ -249,9 +252,17 @@ real_start: + /* save drive reference first thing! */ + pushw %dx + ++#if QUIET_BOOT && !defined(HYBRID_BOOT) ++ /* is either shift key held down? */ ++ movw $(GRUB_MEMORY_MACHINE_BIOS_DATA_AREA_ADDR + 0x17), %bx ++ testb $3, (%bx) ++ jz 2f ++#endif ++ + /* print a notification message on the screen */ + MSG(notification_string) + ++2: + /* set %si to the disk address packet */ + movw $disk_address_packet, %si + +diff --git a/grub-core/boot/i386/pc/diskboot.S b/grub-core/boot/i386/pc/diskboot.S +index c1addc0df..9b6d7a7ed 100644 +--- a/grub-core/boot/i386/pc/diskboot.S ++++ b/grub-core/boot/i386/pc/diskboot.S +@@ -18,6 +18,9 @@ + + #include <grub/symbol.h> + #include <grub/machine/boot.h> ++#if QUIET_BOOT ++#include <grub/machine/memory.h> ++#endif + + /* + * defines for the code go here +@@ -25,6 +28,12 @@ + + #define MSG(x) movw $x, %si; call LOCAL(message) + ++#if QUIET_BOOT ++#define SILENT(x) call LOCAL(check_silent); jz LOCAL(x) ++#else ++#define SILENT(x) ++#endif ++ + .file "diskboot.S" + + .text +@@ -50,11 +59,14 @@ _start: + /* save drive reference first thing! */ + pushw %dx + ++ SILENT(after_notification_string) ++ + /* print a notification message on the screen */ + pushw %si + MSG(notification_string) + popw %si + ++LOCAL(after_notification_string): + /* this sets up for the first run through "bootloop" */ + movw $LOCAL(firstlist), %di + +@@ -279,7 +291,10 @@ LOCAL(copy_buffer): + /* restore addressing regs and print a dot with correct DS + (MSG modifies SI, which is saved, and unused AX and BX) */ + popw %ds ++ SILENT(after_notification_step) + MSG(notification_step) ++ ++LOCAL(after_notification_step): + popa + + /* check if finished with this dataset */ +@@ -295,8 +310,11 @@ LOCAL(copy_buffer): + /* END OF MAIN LOOP */ + + LOCAL(bootit): ++ SILENT(after_notification_done) + /* print a newline */ + MSG(notification_done) ++ ++LOCAL(after_notification_done): + popw %dx /* this makes sure %dl is our "boot" drive */ + ljmp $0, $(GRUB_BOOT_MACHINE_KERNEL_ADDR + 0x200) + +@@ -320,6 +338,14 @@ LOCAL(general_error): + /* go here when you need to stop the machine hard after an error condition */ + LOCAL(stop): jmp LOCAL(stop) + ++#if QUIET_BOOT ++LOCAL(check_silent): ++ /* is either shift key held down? */ ++ movw $(GRUB_MEMORY_MACHINE_BIOS_DATA_AREA_ADDR + 0x17), %bx ++ testb $3, (%bx) ++ ret ++#endif ++ + notification_string: .asciz "loading" + + notification_step: .asciz "." +diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c +index 73967e2f5..2879d644a 100644 +--- a/grub-core/kern/main.c ++++ b/grub-core/kern/main.c +@@ -265,15 +265,25 @@ reclaim_module_space (void) + void __attribute__ ((noreturn)) + grub_main (void) + { ++#if QUIET_BOOT ++ struct grub_term_output *term; ++#endif ++ + /* First of all, initialize the machine. */ + grub_machine_init (); + + grub_boot_time ("After machine init."); + ++#if QUIET_BOOT ++ /* Disable the cursor until we need it. */ ++ FOR_ACTIVE_TERM_OUTPUTS(term) ++ grub_term_setcursor (term, 0); ++#else + /* Hello. */ + grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT); + grub_printf ("Welcome to GRUB!\n\n"); + grub_setcolorstate (GRUB_TERM_COLOR_STANDARD); ++#endif + + /* Init verifiers API. */ + grub_verifiers_init (); +@@ -312,5 +322,12 @@ grub_main (void) + grub_boot_time ("After execution of embedded config. Attempt to go to normal mode"); + + grub_load_normal_mode (); ++ ++#if QUIET_BOOT ++ /* If we have to enter rescue mode, enable the cursor again. */ ++ FOR_ACTIVE_TERM_OUTPUTS(term) ++ grub_term_setcursor (term, 1); ++#endif ++ + grub_rescue_run (); + } +diff --git a/grub-core/kern/rescue_reader.c b/grub-core/kern/rescue_reader.c +index dcd7d4439..a93524eab 100644 +--- a/grub-core/kern/rescue_reader.c ++++ b/grub-core/kern/rescue_reader.c +@@ -78,7 +78,9 @@ grub_rescue_read_line (char **line, int cont, + void __attribute__ ((noreturn)) + grub_rescue_run (void) + { ++#if QUIET_BOOT + grub_printf ("Entering rescue mode...\n"); ++#endif + + while (1) + { +diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c +index c4ebe9e22..a1750e09c 100644 +--- a/grub-core/normal/main.c ++++ b/grub-core/normal/main.c +@@ -407,6 +407,15 @@ static grub_err_t + grub_normal_read_line_real (char **line, int cont, int nested) + { + const char *prompt; ++#if QUIET_BOOT ++ static int displayed_intro; ++ ++ if (! displayed_intro) ++ { ++ grub_normal_reader_init (nested); ++ displayed_intro = 1; ++ } ++#endif + + if (cont) + /* TRANSLATORS: it's command line prompt. */ +@@ -459,7 +468,9 @@ grub_cmdline_run (int nested, int force_auth) + return; + } + ++#if !QUIET_BOOT + grub_normal_reader_init (nested); ++#endif + + while (1) + { +diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c +index 8397886fa..e9d8444b5 100644 +--- a/grub-core/normal/menu.c ++++ b/grub-core/normal/menu.c +@@ -807,12 +807,18 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot) + + /* Callback invoked immediately before a menu entry is executed. */ + static void +-notify_booting (grub_menu_entry_t entry, ++notify_booting (grub_menu_entry_t entry ++#if QUIET_BOOT ++ __attribute__((unused)) ++#endif ++ , + void *userdata __attribute__((unused))) + { ++#if !QUIET_BOOT + grub_printf (" "); + grub_printf_ (N_("Booting `%s'"), entry->title); + grub_printf ("\n\n"); ++#endif + } + + /* Callback invoked when a default menu entry executed because of a timeout +@@ -860,6 +866,9 @@ show_menu (grub_menu_t menu, int nested, int autobooted) + int boot_entry; + grub_menu_entry_t e; + int auto_boot; ++#if QUIET_BOOT ++ int initial_timeout = grub_menu_get_timeout (); ++#endif + + boot_entry = run_menu (menu, nested, &auto_boot); + if (boot_entry < 0) +@@ -869,7 +878,11 @@ show_menu (grub_menu_t menu, int nested, int autobooted) + if (! e) + continue; /* Menu is empty. */ + +- grub_cls (); ++#if QUIET_BOOT ++ /* Only clear the screen if we drew the menu in the first place. */ ++ if (initial_timeout != 0) ++#endif ++ grub_cls (); + + if (auto_boot) + grub_menu_execute_with_fallback (menu, e, autobooted, +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index 1b8c6e146..869a7eec5 100644 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -21,6 +21,7 @@ prefix="@prefix@" + exec_prefix="@exec_prefix@" + datarootdir="@datarootdir@" + ubuntu_recovery="@UBUNTU_RECOVERY@" ++quiet_boot="@QUIET_BOOT@" + + . "$pkgdatadir/grub-mkconfig_lib" + +@@ -158,10 +159,12 @@ linux_entry () + fi + printf '%s\n' "${prepare_boot_cache}" | sed "s/^/$submenu_indentation/" + fi +- message="$(gettext_printf "Loading Linux %s ..." ${version})" +- sed "s/^/$submenu_indentation/" << EOF ++ if [ x"$quiet_boot" = x0 ] || [ x"$type" != xsimple ]; then ++ message="$(gettext_printf "Loading Linux %s ..." ${version})" ++ sed "s/^/$submenu_indentation/" << EOF + echo '$(echo "$message" | grub_quote)' + EOF ++ fi + if test -d /sys/firmware/efi && test -e "${linux}.efi.signed"; then + sed "s/^/$submenu_indentation/" << EOF + linux ${rel_dirname}/${basename}.efi.signed root=${linux_root_device_thisversion} ro ${args} +@@ -173,13 +176,17 @@ EOF + fi + if test -n "${initrd}" ; then + # TRANSLATORS: ramdisk isn't identifier. Should be translated. +- message="$(gettext_printf "Loading initial ramdisk ...")" ++ if [ x"$quiet_boot" = x0 ] || [ x"$type" != xsimple ]; then ++ message="$(gettext_printf "Loading initial ramdisk ...")" ++ sed "s/^/$submenu_indentation/" << EOF ++ echo '$(echo "$message" | grub_quote)' ++EOF ++ fi + initrd_path= + for i in ${initrd}; do + initrd_path="${initrd_path} ${rel_dirname}/${i}" + done + sed "s/^/$submenu_indentation/" << EOF +- echo '$(echo "$message" | grub_quote)' + initrd $(echo $initrd_path) + EOF + fi diff --git a/debian/patches/minilzo-2.10.patch b/debian/patches/minilzo-2.10.patch new file mode 100644 index 0000000..9dfce7c --- /dev/null +++ b/debian/patches/minilzo-2.10.patch @@ -0,0 +1,2539 @@ +From dbcbb3e5b9fac665b92d630eb24de7bd8c43652e Mon Sep 17 00:00:00 2001 +From: Colin Watson <cjwatson@debian.org> +Date: Sun, 28 Nov 2021 23:42:30 +0000 +Subject: minilzo: Update to minilzo-2.10 + +minilzo fails to build on a number of Debian release architectures +(armel, mips64el, mipsel, ppc64el) with errors such as: + + ../../grub-core/lib/minilzo/minilzo.c: In function 'lzo_memops_get_le16': + ../../grub-core/lib/minilzo/minilzo.c:3479:11: error: dereferencing type-punned pointer will break strict-aliasing rules [-Werror=strict-aliasing] + 3479 | * (lzo_memops_TU2p) (lzo_memops_TU0p) (dd) = * (const lzo_memops_TU2p) (const lzo_memops_TU0p) (ss); \ + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ../../grub-core/lib/minilzo/minilzo.c:3530:5: note: in expansion of macro 'LZO_MEMOPS_COPY2' + 3530 | LZO_MEMOPS_COPY2(&v, ss); + | ^~~~~~~~~~~~~~~~ + +The latest upstream version is 2.10, so updating to it seems like a good +idea on general principles, and it fixes builds on all the above +architectures. + +The update procedure documented in the GRUB Developers Manual worked; I +just updated the version numbers to make it clear that it's been +executed recently. + +Signed-off-by: Colin Watson <cjwatson@debian.org> + +Forwarded: https://lists.gnu.org/archive/html/grub-devel/2021-11/msg00095.html +Last-Update: 2021-11-29 + +Patch-Name: minilzo-2.10.patch +--- + docs/grub-dev.texi | 10 +- + grub-core/lib/minilzo/lzoconf.h | 41 ++- + grub-core/lib/minilzo/lzodefs.h | 416 +++++++++++++++++++----- + grub-core/lib/minilzo/minilzo.c | 542 +++++++++++++++++++++++++------- + grub-core/lib/minilzo/minilzo.h | 22 +- + 5 files changed, 817 insertions(+), 214 deletions(-) + +diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi +index 6c629a23e..eb755d998 100644 +--- a/docs/grub-dev.texi ++++ b/docs/grub-dev.texi +@@ -575,12 +575,12 @@ To upgrade to a new version of the miniLZO library, download the release + tarball and copy the files into the target directory: + + @example +-curl -L -O http://www.oberhumer.com/opensource/lzo/download/minilzo-2.08.tar.gz +-tar -zxf minilzo-2.08.tar.gz +-rm minilzo-2.08/testmini.c ++curl -L -O http://www.oberhumer.com/opensource/lzo/download/minilzo-2.10.tar.gz ++tar -zxf minilzo-2.10.tar.gz ++rm minilzo-2.10/testmini.c + rm -r grub-core/lib/minilzo/* +-cp minilzo-2.08/*.[hc] grub-core/lib/minilzo +-rm -r minilzo-2.08* ++cp minilzo-2.10/*.[hc] grub-core/lib/minilzo ++rm -r minilzo-2.10* + @end example + + @node Porting +diff --git a/grub-core/lib/minilzo/lzoconf.h b/grub-core/lib/minilzo/lzoconf.h +index 61be29c5d..f9a8bdbee 100644 +--- a/grub-core/lib/minilzo/lzoconf.h ++++ b/grub-core/lib/minilzo/lzoconf.h +@@ -2,7 +2,7 @@ + + This file is part of the LZO real-time data compression library. + +- Copyright (C) 1996-2014 Markus Franz Xaver Johannes Oberhumer ++ Copyright (C) 1996-2017 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + The LZO library is free software; you can redistribute it and/or +@@ -29,9 +29,9 @@ + #ifndef __LZOCONF_H_INCLUDED + #define __LZOCONF_H_INCLUDED 1 + +-#define LZO_VERSION 0x2080 +-#define LZO_VERSION_STRING "2.08" +-#define LZO_VERSION_DATE "Jun 29 2014" ++#define LZO_VERSION 0x20a0 /* 2.10 */ ++#define LZO_VERSION_STRING "2.10" ++#define LZO_VERSION_DATE "Mar 01 2017" + + /* internal Autoconf configuration file - only used when building LZO */ + #if defined(LZO_HAVE_CONFIG_H) +@@ -57,7 +57,7 @@ + + /* get OS and architecture defines */ + #ifndef __LZODEFS_H_INCLUDED +-#include "lzodefs.h" ++#include <lzo/lzodefs.h> + #endif + + +@@ -94,25 +94,29 @@ extern "C" { + # if (LZO_OS_WIN64) + typedef unsigned __int64 lzo_uint; + typedef __int64 lzo_int; ++# define LZO_TYPEOF_LZO_INT LZO_TYPEOF___INT64 + # else + typedef lzo_ullong_t lzo_uint; + typedef lzo_llong_t lzo_int; ++# define LZO_TYPEOF_LZO_INT LZO_TYPEOF_LONG_LONG + # endif +-# define LZO_SIZEOF_LZO_UINT 8 ++# define LZO_SIZEOF_LZO_INT 8 + # define LZO_UINT_MAX 0xffffffffffffffffull + # define LZO_INT_MAX 9223372036854775807LL + # define LZO_INT_MIN (-1LL - LZO_INT_MAX) + # elif (LZO_ABI_IP32L64) /* MIPS R5900 */ + typedef unsigned int lzo_uint; + typedef int lzo_int; +-# define LZO_SIZEOF_LZO_UINT LZO_SIZEOF_INT ++# define LZO_SIZEOF_LZO_INT LZO_SIZEOF_INT ++# define LZO_TYPEOF_LZO_INT LZO_TYPEOF_INT + # define LZO_UINT_MAX UINT_MAX + # define LZO_INT_MAX INT_MAX + # define LZO_INT_MIN INT_MIN + # elif (ULONG_MAX >= LZO_0xffffffffL) + typedef unsigned long lzo_uint; + typedef long lzo_int; +-# define LZO_SIZEOF_LZO_UINT LZO_SIZEOF_LONG ++# define LZO_SIZEOF_LZO_INT LZO_SIZEOF_LONG ++# define LZO_TYPEOF_LZO_INT LZO_TYPEOF_LONG + # define LZO_UINT_MAX ULONG_MAX + # define LZO_INT_MAX LONG_MAX + # define LZO_INT_MIN LONG_MIN +@@ -122,7 +126,7 @@ extern "C" { + #endif + + /* The larger type of lzo_uint and lzo_uint32_t. */ +-#if (LZO_SIZEOF_LZO_UINT >= 4) ++#if (LZO_SIZEOF_LZO_INT >= 4) + # define lzo_xint lzo_uint + #else + # define lzo_xint lzo_uint32_t +@@ -131,7 +135,8 @@ extern "C" { + typedef int lzo_bool; + + /* sanity checks */ +-LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint) == LZO_SIZEOF_LZO_UINT) ++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int) == LZO_SIZEOF_LZO_INT) ++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint) == LZO_SIZEOF_LZO_INT) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_xint) >= sizeof(lzo_uint)) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_xint) >= sizeof(lzo_uint32_t)) + +@@ -163,14 +168,14 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_xint) >= sizeof(lzo_uint32_t)) + #endif + + /* Older LZO versions used to support ancient systems and memory models +- * like 16-bit MSDOS with __huge pointers and Cray PVP, but these ++ * such as 16-bit MSDOS with __huge pointers or Cray PVP, but these + * obsolete configurations are not supported any longer. + */ + #if defined(__LZO_MMODEL_HUGE) +-#error "__LZO_MMODEL_HUGE is unsupported" ++#error "__LZO_MMODEL_HUGE memory model is unsupported" + #endif + #if (LZO_MM_PVP) +-#error "LZO_MM_PVP is unsupported" ++#error "LZO_MM_PVP memory model is unsupported" + #endif + #if (LZO_SIZEOF_INT < 4) + #error "LZO_SIZEOF_INT < 4 is unsupported" +@@ -221,13 +226,13 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(char *) == sizeof(lzo_bytep)) + + /* __cdecl calling convention for public C and assembly functions */ + #if !defined(LZO_PUBLIC) +-# define LZO_PUBLIC(_rettype) __LZO_EXPORT1 _rettype __LZO_EXPORT2 __LZO_CDECL ++# define LZO_PUBLIC(r) __LZO_EXPORT1 r __LZO_EXPORT2 __LZO_CDECL + #endif + #if !defined(LZO_EXTERN) +-# define LZO_EXTERN(_rettype) __LZO_EXTERN_C LZO_PUBLIC(_rettype) ++# define LZO_EXTERN(r) __LZO_EXTERN_C LZO_PUBLIC(r) + #endif + #if !defined(LZO_PRIVATE) +-# define LZO_PRIVATE(_rettype) static _rettype __LZO_CDECL ++# define LZO_PRIVATE(r) static r __LZO_CDECL + #endif + + /* function types */ +@@ -399,6 +404,10 @@ LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp p, lzo_uint size); + /* deprecated types */ + typedef union { lzo_bytep a; lzo_uint b; } __lzo_pu_u; + typedef union { lzo_bytep a; lzo_uint32_t b; } __lzo_pu32_u; ++/* deprecated defines */ ++#if !defined(LZO_SIZEOF_LZO_UINT) ++# define LZO_SIZEOF_LZO_UINT LZO_SIZEOF_LZO_INT ++#endif + + #if defined(LZO_CFG_COMPAT) + +diff --git a/grub-core/lib/minilzo/lzodefs.h b/grub-core/lib/minilzo/lzodefs.h +index f4ae9487e..c3e2bcf5d 100644 +--- a/grub-core/lib/minilzo/lzodefs.h ++++ b/grub-core/lib/minilzo/lzodefs.h +@@ -2,7 +2,7 @@ + + This file is part of the LZO real-time data compression library. + +- Copyright (C) 1996-2014 Markus Franz Xaver Johannes Oberhumer ++ Copyright (C) 1996-2017 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + The LZO library is free software; you can redistribute it and/or +@@ -40,6 +40,33 @@ + # define __LONG_MAX__ 9223372036854775807L + # endif + #endif ++#if 0 ++#elif !defined(__LZO_LANG_OVERRIDE) ++#if (defined(__clang__) || defined(__GNUC__)) && defined(__ASSEMBLER__) ++# if (__ASSEMBLER__+0) <= 0 ++# error "__ASSEMBLER__" ++# else ++# define LZO_LANG_ASSEMBLER 1 ++# endif ++#elif defined(__cplusplus) ++# if (__cplusplus+0) <= 0 ++# error "__cplusplus" ++# elif (__cplusplus < 199711L) ++# define LZO_LANG_CXX 1 ++# elif defined(_MSC_VER) && defined(_MSVC_LANG) && (_MSVC_LANG+0 >= 201402L) && 1 ++# define LZO_LANG_CXX _MSVC_LANG ++# else ++# define LZO_LANG_CXX __cplusplus ++# endif ++# define LZO_LANG_CPLUSPLUS LZO_LANG_CXX ++#else ++# if defined(__STDC_VERSION__) && (__STDC_VERSION__+0 >= 199409L) ++# define LZO_LANG_C __STDC_VERSION__ ++# else ++# define LZO_LANG_C 1 ++# endif ++#endif ++#endif + #if !defined(LZO_CFG_NO_DISABLE_WUNDEF) + #if defined(__ARMCC_VERSION) + # pragma diag_suppress 193 +@@ -135,10 +162,12 @@ + # endif + #endif + #endif +-#if defined(_MSC_VER) && defined(M_I86HM) && (UINT_MAX == LZO_0xffffL) ++#if (UINT_MAX == LZO_0xffffL) ++#if defined(_MSC_VER) && defined(M_I86HM) + # define ptrdiff_t long + # define _PTRDIFF_T_DEFINED 1 + #endif ++#endif + #if (UINT_MAX == LZO_0xffffL) + # undef __LZO_RENAME_A + # undef __LZO_RENAME_B +@@ -287,7 +316,7 @@ + #define LZO_CPP_ECONCAT6(a,b,c,d,e,f) LZO_CPP_CONCAT6(a,b,c,d,e,f) + #define LZO_CPP_ECONCAT7(a,b,c,d,e,f,g) LZO_CPP_CONCAT7(a,b,c,d,e,f,g) + #endif +-#define __LZO_MASK_GEN(o,b) (((((o) << ((b)-!!(b))) - (o)) << 1) + (o)*!!(b)) ++#define __LZO_MASK_GEN(o,b) (((((o) << ((b)-((b)!=0))) - (o)) << 1) + (o)*((b)!=0)) + #if 1 && defined(__cplusplus) + # if !defined(__STDC_CONSTANT_MACROS) + # define __STDC_CONSTANT_MACROS 1 +@@ -398,7 +427,7 @@ + #elif defined(__TOS__) || defined(__atarist__) + # define LZO_OS_TOS 1 + # define LZO_INFO_OS "tos" +-#elif defined(macintosh) && !defined(__ppc__) ++#elif defined(macintosh) && !defined(__arm__) && !defined(__i386__) && !defined(__ppc__) && !defined(__x64_64__) + # define LZO_OS_MACCLASSIC 1 + # define LZO_INFO_OS "macclassic" + #elif defined(__VMS) +@@ -538,6 +567,12 @@ + # define LZO_CC_ARMCC __ARMCC_VERSION + # define LZO_INFO_CC "ARM C Compiler" + # define LZO_INFO_CCVER __VERSION__ ++#elif defined(__clang__) && defined(__c2__) && defined(__c2_version__) && defined(_MSC_VER) ++# define LZO_CC_CLANG (__clang_major__ * 0x10000L + (__clang_minor__-0) * 0x100 + (__clang_patchlevel__-0)) ++# define LZO_CC_CLANG_C2 _MSC_VER ++# define LZO_CC_CLANG_VENDOR_MICROSOFT 1 ++# define LZO_INFO_CC "clang/c2" ++# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__c2_version__) + #elif defined(__clang__) && defined(__llvm__) && defined(__VERSION__) + # if defined(__clang_major__) && defined(__clang_minor__) && defined(__clang_patchlevel__) + # define LZO_CC_CLANG (__clang_major__ * 0x10000L + (__clang_minor__-0) * 0x100 + (__clang_patchlevel__-0)) +@@ -549,8 +584,18 @@ + # elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__) + # define LZO_CC_CLANG_GNUC (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0)) + # endif +-# define LZO_INFO_CC "clang" +-# define LZO_INFO_CCVER __VERSION__ ++# if defined(__APPLE_CC__) ++# define LZO_CC_CLANG_VENDOR_APPLE 1 ++# define LZO_INFO_CC "clang/apple" ++# else ++# define LZO_CC_CLANG_VENDOR_LLVM 1 ++# define LZO_INFO_CC "clang" ++# endif ++# if defined(__clang_version__) ++# define LZO_INFO_CCVER __clang_version__ ++# else ++# define LZO_INFO_CCVER __VERSION__ ++# endif + #elif defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__) + # if defined(__GNUC_PATCHLEVEL__) + # define LZO_CC_LLVM_GNUC (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0)) +@@ -770,7 +815,7 @@ + #elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) + # define LZO_ARCH_I086 1 + # define LZO_INFO_ARCH "i086" +-#elif defined(__aarch64__) ++#elif defined(__aarch64__) || defined(_M_ARM64) + # define LZO_ARCH_ARM64 1 + # define LZO_INFO_ARCH "arm64" + #elif defined(__alpha__) || defined(__alpha) || defined(_M_ALPHA) +@@ -782,22 +827,11 @@ + #elif defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64) + # define LZO_ARCH_AMD64 1 + # define LZO_INFO_ARCH "amd64" +-#elif defined(__thumb__) || (defined(_M_ARM) && defined(_M_THUMB)) ++#elif defined(__arm__) || defined(_M_ARM) + # define LZO_ARCH_ARM 1 +-# define LZO_ARCH_ARM_THUMB 1 +-# define LZO_INFO_ARCH "arm_thumb" ++# define LZO_INFO_ARCH "arm" + #elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCARM__) + # define LZO_ARCH_ARM 1 +-# if defined(__CPU_MODE__) && ((__CPU_MODE__-0) == 1) +-# define LZO_ARCH_ARM_THUMB 1 +-# define LZO_INFO_ARCH "arm_thumb" +-# elif defined(__CPU_MODE__) && ((__CPU_MODE__-0) == 2) +-# define LZO_INFO_ARCH "arm" +-# else +-# define LZO_INFO_ARCH "arm" +-# endif +-#elif defined(__arm__) || defined(_M_ARM) +-# define LZO_ARCH_ARM 1 + # define LZO_INFO_ARCH "arm" + #elif (UINT_MAX <= LZO_0xffffL) && defined(__AVR__) + # define LZO_ARCH_AVR 1 +@@ -871,6 +905,15 @@ + #elif defined(__powerpc__) || defined(__powerpc) || defined(__ppc__) || defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PWR) + # define LZO_ARCH_POWERPC 1 + # define LZO_INFO_ARCH "powerpc" ++#elif defined(__powerpc64__) || defined(__powerpc64) || defined(__ppc64__) || defined(__PPC64__) ++# define LZO_ARCH_POWERPC 1 ++# define LZO_INFO_ARCH "powerpc" ++#elif defined(__powerpc64le__) || defined(__powerpc64le) || defined(__ppc64le__) || defined(__PPC64LE__) ++# define LZO_ARCH_POWERPC 1 ++# define LZO_INFO_ARCH "powerpc" ++#elif defined(__riscv) ++# define LZO_ARCH_RISCV 1 ++# define LZO_INFO_ARCH "riscv" + #elif defined(__s390__) || defined(__s390) || defined(__s390x__) || defined(__s390x) + # define LZO_ARCH_S390 1 + # define LZO_INFO_ARCH "s390" +@@ -905,6 +948,23 @@ + # define LZO_INFO_ARCH "unknown" + #endif + #endif ++#if !defined(LZO_ARCH_ARM_THUMB2) ++#if (LZO_ARCH_ARM) ++# if defined(__thumb__) || defined(__thumb) || defined(_M_THUMB) ++# if defined(__thumb2__) ++# define LZO_ARCH_ARM_THUMB2 1 ++# elif 1 && defined(__TARGET_ARCH_THUMB) && ((__TARGET_ARCH_THUMB)+0 >= 4) ++# define LZO_ARCH_ARM_THUMB2 1 ++# elif 1 && defined(_MSC_VER) && defined(_M_THUMB) && ((_M_THUMB)+0 >= 7) ++# define LZO_ARCH_ARM_THUMB2 1 ++# endif ++# endif ++#endif ++#endif ++#if (LZO_ARCH_ARM_THUMB2) ++# undef LZO_INFO_ARCH ++# define LZO_INFO_ARCH "arm_thumb2" ++#endif + #if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_DOS32 || LZO_OS_OS2) + # error "FIXME - missing define for CPU architecture" + #endif +@@ -947,13 +1007,10 @@ + #if (LZO_ARCH_I386 && !LZO_ARCH_X86) || (!LZO_ARCH_I386 && LZO_ARCH_X86) + # error "unexpected configuration - check your compiler defines" + #endif +-#if (LZO_ARCH_ARM_THUMB && !LZO_ARCH_ARM) +-# error "unexpected configuration - check your compiler defines" +-#endif +-#if (LZO_ARCH_ARM_THUMB1 && !LZO_ARCH_ARM_THUMB) ++#if (LZO_ARCH_ARM_THUMB1 && !LZO_ARCH_ARM) + # error "unexpected configuration - check your compiler defines" + #endif +-#if (LZO_ARCH_ARM_THUMB2 && !LZO_ARCH_ARM_THUMB) ++#if (LZO_ARCH_ARM_THUMB2 && !LZO_ARCH_ARM) + # error "unexpected configuration - check your compiler defines" + #endif + #if (LZO_ARCH_ARM_THUMB1 && LZO_ARCH_ARM_THUMB2) +@@ -985,7 +1042,9 @@ + # if !defined(LZO_TARGET_FEATURE_SSE2) + # if defined(__SSE2__) + # define LZO_TARGET_FEATURE_SSE2 1 +-# elif defined(_MSC_VER) && ((defined(_M_IX86_FP) && ((_M_IX86_FP)+0 >= 2)) || defined(_M_AMD64)) ++# elif defined(_MSC_VER) && (defined(_M_IX86_FP) && ((_M_IX86_FP)+0 >= 2)) ++# define LZO_TARGET_FEATURE_SSE2 1 ++# elif (LZO_CC_INTELC_MSC || LZO_CC_MSC) && defined(_M_AMD64) + # define LZO_TARGET_FEATURE_SSE2 1 + # endif + # endif +@@ -1034,7 +1093,11 @@ + #endif + #if (LZO_ARCH_ARM) + # if !defined(LZO_TARGET_FEATURE_NEON) +-# if defined(__ARM_NEON__) ++# if defined(__ARM_NEON) && ((__ARM_NEON)+0) ++# define LZO_TARGET_FEATURE_NEON 1 ++# elif 1 && defined(__ARM_NEON__) && ((__ARM_NEON__)+0) ++# define LZO_TARGET_FEATURE_NEON 1 ++# elif 1 && defined(__TARGET_FEATURE_NEON) && ((__TARGET_FEATURE_NEON)+0) + # define LZO_TARGET_FEATURE_NEON 1 + # endif + # endif +@@ -1105,7 +1168,7 @@ + # error "unexpected configuration - check your compiler defines" + # endif + #endif +-#ifdef __cplusplus ++#if defined(__cplusplus) + extern "C" { + #endif + #if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0200)) +@@ -1128,7 +1191,7 @@ extern "C" { + #else + # error "FIXME - implement LZO_MM_AHSHIFT" + #endif +-#ifdef __cplusplus ++#if defined(__cplusplus) + } + #endif + #endif +@@ -1214,12 +1277,53 @@ extern "C" { + # define __lzo_gnuc_extension__ __extension__ + #elif (LZO_CC_IBMC >= 600) + # define __lzo_gnuc_extension__ __extension__ +-#else + #endif + #endif + #if !defined(__lzo_gnuc_extension__) + # define __lzo_gnuc_extension__ /*empty*/ + #endif ++#if !defined(lzo_has_builtin) ++#if (LZO_CC_CLANG) && defined(__has_builtin) ++# define lzo_has_builtin __has_builtin ++#endif ++#endif ++#if !defined(lzo_has_builtin) ++# define lzo_has_builtin(x) 0 ++#endif ++#if !defined(lzo_has_attribute) ++#if (LZO_CC_CLANG) && defined(__has_attribute) ++# define lzo_has_attribute __has_attribute ++#endif ++#endif ++#if !defined(lzo_has_attribute) ++# define lzo_has_attribute(x) 0 ++#endif ++#if !defined(lzo_has_declspec_attribute) ++#if (LZO_CC_CLANG) && defined(__has_declspec_attribute) ++# define lzo_has_declspec_attribute __has_declspec_attribute ++#endif ++#endif ++#if !defined(lzo_has_declspec_attribute) ++# define lzo_has_declspec_attribute(x) 0 ++#endif ++#if !defined(lzo_has_feature) ++#if (LZO_CC_CLANG) && defined(__has_feature) ++# define lzo_has_feature __has_feature ++#endif ++#endif ++#if !defined(lzo_has_feature) ++# define lzo_has_feature(x) 0 ++#endif ++#if !defined(lzo_has_extension) ++#if (LZO_CC_CLANG) && defined(__has_extension) ++# define lzo_has_extension __has_extension ++#elif (LZO_CC_CLANG) && defined(__has_feature) ++# define lzo_has_extension __has_feature ++#endif ++#endif ++#if !defined(lzo_has_extension) ++# define lzo_has_extension(x) 0 ++#endif + #if !defined(LZO_CFG_USE_NEW_STYLE_CASTS) && defined(__cplusplus) && 0 + # if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x020800ul)) + # define LZO_CFG_USE_NEW_STYLE_CASTS 0 +@@ -1356,7 +1460,7 @@ extern "C" { + # elif (LZO_CC_MSC && (_MSC_VER < 900)) + # define LZO_UNUSED(var) if (&var) ; else + # elif (LZO_CC_KEILC) +-# define LZO_UNUSED(var) {LZO_EXTERN_C int lzo_unused__[1-2*!(sizeof(var)>0)];} ++# define LZO_UNUSED(var) {extern int lzo_unused__[1-2*!(sizeof(var)>0)]; (void)lzo_unused__;} + # elif (LZO_CC_PACIFICC) + # define LZO_UNUSED(var) ((void) sizeof(var)) + # elif (LZO_CC_WATCOMC) && defined(__cplusplus) +@@ -1365,6 +1469,9 @@ extern "C" { + # define LZO_UNUSED(var) ((void) &var) + # endif + #endif ++#if !defined(LZO_UNUSED_RESULT) ++# define LZO_UNUSED_RESULT(var) LZO_UNUSED(var) ++#endif + #if !defined(LZO_UNUSED_FUNC) + # if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600)) + # define LZO_UNUSED_FUNC(func) ((void) func) +@@ -1377,7 +1484,7 @@ extern "C" { + # elif (LZO_CC_MSC) + # define LZO_UNUSED_FUNC(func) ((void) &func) + # elif (LZO_CC_KEILC || LZO_CC_PELLESC) +-# define LZO_UNUSED_FUNC(func) {LZO_EXTERN_C int lzo_unused_func__[1-2*!(sizeof((int)func)>0)];} ++# define LZO_UNUSED_FUNC(func) {extern int lzo_unused__[1-2*!(sizeof((int)func)>0)]; (void)lzo_unused__;} + # else + # define LZO_UNUSED_FUNC(func) ((void) func) + # endif +@@ -1783,6 +1890,7 @@ extern "C" { + #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800)) + # define __lzo_likely(e) (__builtin_expect(!!(e),1)) + # define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) ++#elif (LZO_CC_CLANG && LZO_CC_CLANG_C2) + #elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) + # define __lzo_likely(e) (__builtin_expect(!!(e),1)) + # define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) +@@ -1793,21 +1901,28 @@ extern "C" { + # define __lzo_HAVE_likely 1 + # endif + #else +-# define __lzo_likely(e) (e) ++# define __lzo_likely(e) (e) ++#endif ++#if defined(__lzo_very_likely) ++# ifndef __lzo_HAVE_very_likely ++# define __lzo_HAVE_very_likely 1 ++# endif ++#else ++# define __lzo_very_likely(e) __lzo_likely(e) + #endif + #if defined(__lzo_unlikely) + # ifndef __lzo_HAVE_unlikely + # define __lzo_HAVE_unlikely 1 + # endif + #else +-# define __lzo_unlikely(e) (e) ++# define __lzo_unlikely(e) (e) + #endif +-#if !defined(__lzo_static_unused_void_func) +-# if 1 && (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || (LZO_CC_GNUC >= 0x020700ul) || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) +-# define __lzo_static_unused_void_func(f) static void __attribute__((__unused__)) f(void) +-# else +-# define __lzo_static_unused_void_func(f) static __lzo_inline void f(void) ++#if defined(__lzo_very_unlikely) ++# ifndef __lzo_HAVE_very_unlikely ++# define __lzo_HAVE_very_unlikely 1 + # endif ++#else ++# define __lzo_very_unlikely(e) __lzo_unlikely(e) + #endif + #if !defined(__lzo_loop_forever) + # if (LZO_CC_IBMC) +@@ -1817,7 +1932,7 @@ extern "C" { + # endif + #endif + #if !defined(__lzo_unreachable) +-#if (LZO_CC_CLANG && (LZO_CC_CLANG >= 0x020800ul)) ++#if (LZO_CC_CLANG && (LZO_CC_CLANG >= 0x020800ul)) && lzo_has_builtin(__builtin_unreachable) + # define __lzo_unreachable() __builtin_unreachable(); + #elif (LZO_CC_GNUC >= 0x040500ul) + # define __lzo_unreachable() __builtin_unreachable(); +@@ -1836,6 +1951,15 @@ extern "C" { + # define __lzo_unreachable() __lzo_loop_forever(); + # endif + #endif ++#if !defined(lzo_unused_funcs_impl) ++# if 1 && (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || (LZO_CC_GNUC >= 0x020700ul) || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) ++# define lzo_unused_funcs_impl(r,f) static r __attribute__((__unused__)) f ++# elif 1 && (LZO_CC_BORLANDC || LZO_CC_GNUC) ++# define lzo_unused_funcs_impl(r,f) static r f ++# else ++# define lzo_unused_funcs_impl(r,f) __lzo_static_forceinline r f ++# endif ++#endif + #ifndef __LZO_CTA_NAME + #if (LZO_CFG_USE_COUNTER) + # define __LZO_CTA_NAME(a) LZO_PP_ECONCAT2(a,__COUNTER__) +@@ -1861,6 +1985,8 @@ extern "C" { + #if !defined(LZO_COMPILE_TIME_ASSERT) + # if (LZO_CC_AZTECC) + # define LZO_COMPILE_TIME_ASSERT(e) {typedef int __LZO_CTA_NAME(lzo_cta_t__)[1-!(e)];} ++# elif (LZO_CC_CLANG && (LZO_CC_CLANG >= 0x030000ul)) ++# define LZO_COMPILE_TIME_ASSERT(e) {typedef int __LZO_CTA_NAME(lzo_cta_t__)[1-2*!(e)] __attribute__((__unused__));} + # elif (LZO_CC_DMC || LZO_CC_PACIFICC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) + # define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; + # elif (LZO_CC_GNUC) && defined(__CHECKER__) && defined(__SPARSE_CHECKER__) +@@ -1877,11 +2003,16 @@ extern "C" { + # define LZO_COMPILE_TIME_ASSERT(e) {typedef int __LZO_CTA_NAME(lzo_cta_t__)[1-2*!(e)];} + # endif + #endif ++#if (LZO_LANG_ASSEMBLER) ++# undef LZO_COMPILE_TIME_ASSERT_HEADER ++# define LZO_COMPILE_TIME_ASSERT_HEADER(e) /*empty*/ ++#else + LZO_COMPILE_TIME_ASSERT_HEADER(1 == 1) + #if defined(__cplusplus) + extern "C" { LZO_COMPILE_TIME_ASSERT_HEADER(2 == 2) } + #endif + LZO_COMPILE_TIME_ASSERT_HEADER(3 == 3) ++#endif + #if (LZO_ARCH_I086 || LZO_ARCH_I386) && (LZO_OS_DOS16 || LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_OS216 || LZO_OS_WIN16 || LZO_OS_WIN32 || LZO_OS_WIN64) + # if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC) + # elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) +@@ -1948,7 +2079,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(3 == 3) + #if !defined(LZO_HAVE_WINDOWS_H) + #if (LZO_OS_CYGWIN || (LZO_OS_EMX && defined(__RSXNT__)) || LZO_OS_WIN32 || LZO_OS_WIN64) + # if (LZO_CC_WATCOMC && (__WATCOMC__ < 1000)) +-# elif (LZO_OS_WIN32 && LZO_CC_GNUC) && defined(__PW32__) ++# elif ((LZO_OS_WIN32 && defined(__PW32__)) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x030000ul))) + # elif ((LZO_OS_CYGWIN || defined(__MINGW32__)) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x025f00ul))) + # else + # define LZO_HAVE_WINDOWS_H 1 +@@ -1956,6 +2087,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(3 == 3) + #endif + #endif + #endif ++#define LZO_SIZEOF_CHAR 1 + #ifndef LZO_SIZEOF_SHORT + #if defined(SIZEOF_SHORT) + # define LZO_SIZEOF_SHORT (SIZEOF_SHORT) +@@ -2154,12 +2286,12 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_LONG == sizeof(long)) + # define LZO_WORDSIZE 8 + #elif (LZO_ARCH_AMD64) + # define LZO_WORDSIZE 8 ++#elif (LZO_ARCH_ARM64) ++# define LZO_WORDSIZE 8 + #elif (LZO_ARCH_AVR) + # define LZO_WORDSIZE 1 + #elif (LZO_ARCH_H8300) +-# if defined(__NORMAL_MODE__) +-# define LZO_WORDSIZE 4 +-# elif defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) ++# if defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) + # define LZO_WORDSIZE 4 + # else + # define LZO_WORDSIZE 2 +@@ -2202,11 +2334,15 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(long) == 8) + #elif (LZO_ARCH_C166 || LZO_ARCH_MCS51 || LZO_ARCH_MCS251 || LZO_ARCH_MSP430) + # define LZO_SIZEOF_VOID_P 2 + #elif (LZO_ARCH_H8300) +-# if defined(__NORMAL_MODE__) +-# define LZO_SIZEOF_VOID_P 2 +-# elif defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) +-# define LZO_SIZEOF_VOID_P 4 ++# if defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) ++ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_WORDSIZE == 4) ++# if defined(__NORMAL_MODE__) ++# define LZO_SIZEOF_VOID_P 2 ++# else ++# define LZO_SIZEOF_VOID_P 4 ++# endif + # else ++ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_WORDSIZE == 2) + # define LZO_SIZEOF_VOID_P 2 + # endif + # if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x040000ul)) && (LZO_SIZEOF_INT == 4) +@@ -2296,7 +2432,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t)) + # define LZO_ABI_BIG_ENDIAN 1 + #elif (LZO_ARCH_IA64) && (LZO_OS_POSIX_LINUX || LZO_OS_WIN64) + # define LZO_ABI_LITTLE_ENDIAN 1 +-#elif (LZO_ARCH_ALPHA || LZO_ARCH_AMD64 || LZO_ARCH_BLACKFIN || LZO_ARCH_CRIS || LZO_ARCH_I086 || LZO_ARCH_I386 || LZO_ARCH_MSP430) ++#elif (LZO_ARCH_ALPHA || LZO_ARCH_AMD64 || LZO_ARCH_BLACKFIN || LZO_ARCH_CRIS || LZO_ARCH_I086 || LZO_ARCH_I386 || LZO_ARCH_MSP430 || LZO_ARCH_RISCV) + # define LZO_ABI_LITTLE_ENDIAN 1 + #elif (LZO_ARCH_AVR32 || LZO_ARCH_M68K || LZO_ARCH_S390 || LZO_ARCH_SPU) + # define LZO_ABI_BIG_ENDIAN 1 +@@ -2310,10 +2446,14 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t)) + # define LZO_ABI_BIG_ENDIAN 1 + #elif 1 && defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__) + # define LZO_ABI_LITTLE_ENDIAN 1 ++#elif 1 && (LZO_ARCH_ARM) && defined(__ARM_BIG_ENDIAN) && ((__ARM_BIG_ENDIAN)+0) ++# define LZO_ABI_BIG_ENDIAN 1 + #elif 1 && (LZO_ARCH_ARM) && defined(__ARMEB__) && !defined(__ARMEL__) + # define LZO_ABI_BIG_ENDIAN 1 + #elif 1 && (LZO_ARCH_ARM) && defined(__ARMEL__) && !defined(__ARMEB__) + # define LZO_ABI_LITTLE_ENDIAN 1 ++#elif 1 && (LZO_ARCH_ARM) && defined(_MSC_VER) && defined(_WIN32) ++# define LZO_ABI_LITTLE_ENDIAN 1 + #elif 1 && (LZO_ARCH_ARM && LZO_CC_ARMCC_ARMCC) + # if defined(__BIG_ENDIAN) && defined(__LITTLE_ENDIAN) + # error "unexpected configuration - check your compiler defines" +@@ -2323,10 +2463,14 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t)) + # define LZO_ABI_LITTLE_ENDIAN 1 + # endif + # define LZO_ABI_LITTLE_ENDIAN 1 ++#elif 1 && (LZO_ARCH_ARM64) && defined(__ARM_BIG_ENDIAN) && ((__ARM_BIG_ENDIAN)+0) ++# define LZO_ABI_BIG_ENDIAN 1 + #elif 1 && (LZO_ARCH_ARM64) && defined(__AARCH64EB__) && !defined(__AARCH64EL__) + # define LZO_ABI_BIG_ENDIAN 1 + #elif 1 && (LZO_ARCH_ARM64) && defined(__AARCH64EL__) && !defined(__AARCH64EB__) + # define LZO_ABI_LITTLE_ENDIAN 1 ++#elif 1 && (LZO_ARCH_ARM64) && defined(_MSC_VER) && defined(_WIN32) ++# define LZO_ABI_LITTLE_ENDIAN 1 + #elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEB__) && !defined(__MIPSEL__) + # define LZO_ABI_BIG_ENDIAN 1 + #elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEL__) && !defined(__MIPSEB__) +@@ -2368,6 +2512,12 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t)) + # define LZO_ABI_IP32L64 1 + # define LZO_INFO_ABI_PM "ip32l64" + #endif ++#if (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_VOID_P == 4 && LZO_WORDSIZE == 8) ++# define LZO_ABI_IP32W64 1 ++# ifndef LZO_INFO_ABI_PM ++# define LZO_INFO_ABI_PM "ip32w64" ++# endif ++#endif + #if 0 + #elif !defined(__LZO_LIBC_OVERRIDE) + #if (LZO_LIBC_NAKED) +@@ -2455,20 +2605,43 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t)) + # endif + #elif (LZO_ARCH_ARM) + # if defined(__ARM_FEATURE_UNALIGNED) ++# if ((__ARM_FEATURE_UNALIGNED)+0) ++# ifndef LZO_OPT_UNALIGNED16 ++# define LZO_OPT_UNALIGNED16 1 ++# endif ++# ifndef LZO_OPT_UNALIGNED32 ++# define LZO_OPT_UNALIGNED32 1 ++# endif ++# endif ++# elif 1 && (LZO_ARCH_ARM_THUMB2) ++# ifndef LZO_OPT_UNALIGNED16 ++# define LZO_OPT_UNALIGNED16 1 ++# endif ++# ifndef LZO_OPT_UNALIGNED32 ++# define LZO_OPT_UNALIGNED32 1 ++# endif ++# elif 1 && defined(__ARM_ARCH) && ((__ARM_ARCH)+0 >= 7) ++# ifndef LZO_OPT_UNALIGNED16 ++# define LZO_OPT_UNALIGNED16 1 ++# endif ++# ifndef LZO_OPT_UNALIGNED32 ++# define LZO_OPT_UNALIGNED32 1 ++# endif ++# elif 1 && defined(__TARGET_ARCH_ARM) && ((__TARGET_ARCH_ARM)+0 >= 7) + # ifndef LZO_OPT_UNALIGNED16 + # define LZO_OPT_UNALIGNED16 1 + # endif + # ifndef LZO_OPT_UNALIGNED32 + # define LZO_OPT_UNALIGNED32 1 + # endif +-# elif defined(__TARGET_ARCH_ARM) && ((__TARGET_ARCH_ARM+0) >= 7) ++# elif 1 && defined(__TARGET_ARCH_ARM) && ((__TARGET_ARCH_ARM)+0 >= 6) && (defined(__TARGET_PROFILE_A) || defined(__TARGET_PROFILE_R)) + # ifndef LZO_OPT_UNALIGNED16 + # define LZO_OPT_UNALIGNED16 1 + # endif + # ifndef LZO_OPT_UNALIGNED32 + # define LZO_OPT_UNALIGNED32 1 + # endif +-# elif defined(__TARGET_ARCH_ARM) && ((__TARGET_ARCH_ARM+0) >= 6) && !defined(__TARGET_PROFILE_M) ++# elif 1 && defined(_MSC_VER) && defined(_M_ARM) && ((_M_ARM)+0 >= 7) + # ifndef LZO_OPT_UNALIGNED16 + # define LZO_OPT_UNALIGNED16 1 + # endif +@@ -2520,7 +2693,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t)) + #elif (LZO_ARCH_POWERPC) + # define LZO_OPT_PREFER_PREINC 1 + # define LZO_OPT_PREFER_PREDEC 1 +-# if (LZO_ABI_BIG_ENDIAN) ++# if (LZO_ABI_BIG_ENDIAN) || (LZO_WORDSIZE == 8) + # ifndef LZO_OPT_UNALIGNED16 + # define LZO_OPT_UNALIGNED16 1 + # endif +@@ -2533,6 +2706,19 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t)) + # endif + # endif + # endif ++#elif (LZO_ARCH_RISCV) ++# define LZO_OPT_AVOID_UINT_INDEX 1 ++# ifndef LZO_OPT_UNALIGNED16 ++# define LZO_OPT_UNALIGNED16 1 ++# endif ++# ifndef LZO_OPT_UNALIGNED32 ++# define LZO_OPT_UNALIGNED32 1 ++# endif ++# if (LZO_WORDSIZE == 8) ++# ifndef LZO_OPT_UNALIGNED64 ++# define LZO_OPT_UNALIGNED64 1 ++# endif ++# endif + #elif (LZO_ARCH_S390) + # ifndef LZO_OPT_UNALIGNED16 + # define LZO_OPT_UNALIGNED16 1 +@@ -2624,32 +2810,61 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t)) + #if (!(LZO_SIZEOF_PTRDIFF_T+0 > 0 && LZO_SIZEOF_SIZE_T+0 > 0 && LZO_SIZEOF_VOID_P+0 > 0)) + # error "missing defines for sizes" + #endif ++#define LZO_TYPEOF_CHAR 1u ++#define LZO_TYPEOF_SHORT 2u ++#define LZO_TYPEOF_INT 3u ++#define LZO_TYPEOF_LONG 4u ++#define LZO_TYPEOF_LONG_LONG 5u ++#define LZO_TYPEOF___INT8 17u ++#define LZO_TYPEOF___INT16 18u ++#define LZO_TYPEOF___INT32 19u ++#define LZO_TYPEOF___INT64 20u ++#define LZO_TYPEOF___INT128 21u ++#define LZO_TYPEOF___INT256 22u ++#define LZO_TYPEOF___MODE_QI 33u ++#define LZO_TYPEOF___MODE_HI 34u ++#define LZO_TYPEOF___MODE_SI 35u ++#define LZO_TYPEOF___MODE_DI 36u ++#define LZO_TYPEOF___MODE_TI 37u ++#define LZO_TYPEOF_CHAR_P 129u + #if !defined(lzo_llong_t) + #if (LZO_SIZEOF_LONG_LONG+0 > 0) +-__lzo_gnuc_extension__ typedef long long lzo_llong_t__; +-__lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__; ++# if !(LZO_LANG_ASSEMBLER) ++ __lzo_gnuc_extension__ typedef long long lzo_llong_t__; ++ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__; ++# endif + # define lzo_llong_t lzo_llong_t__ + # define lzo_ullong_t lzo_ullong_t__ + #endif + #endif + #if !defined(lzo_int16e_t) +-#if (LZO_SIZEOF_LONG == 2) ++#if (LZO_CFG_PREFER_TYPEOF_ACC_INT16E_T == LZO_TYPEOF_SHORT) && (LZO_SIZEOF_SHORT != 2) ++# undef LZO_CFG_PREFER_TYPEOF_ACC_INT16E_T ++#endif ++#if (LZO_SIZEOF_LONG == 2) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT16E_T == LZO_TYPEOF_SHORT) + # define lzo_int16e_t long + # define lzo_uint16e_t unsigned long +-#elif (LZO_SIZEOF_INT == 2) ++# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF_LONG ++#elif (LZO_SIZEOF_INT == 2) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT16E_T == LZO_TYPEOF_SHORT) + # define lzo_int16e_t int + # define lzo_uint16e_t unsigned int ++# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF_INT + #elif (LZO_SIZEOF_SHORT == 2) + # define lzo_int16e_t short int + # define lzo_uint16e_t unsigned short int ++# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF_SHORT + #elif 1 && !(LZO_CFG_TYPE_NO_MODE_HI) && (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x025f00ul) || LZO_CC_LLVM) ++# if !(LZO_LANG_ASSEMBLER) + typedef int lzo_int16e_hi_t__ __attribute__((__mode__(__HI__))); + typedef unsigned int lzo_uint16e_hi_t__ __attribute__((__mode__(__HI__))); ++# endif + # define lzo_int16e_t lzo_int16e_hi_t__ + # define lzo_uint16e_t lzo_uint16e_hi_t__ ++# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF___MODE_HI + #elif (LZO_SIZEOF___INT16 == 2) + # define lzo_int16e_t __int16 + # define lzo_uint16e_t unsigned __int16 ++# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF___INT16 + #else + #endif + #endif +@@ -2659,33 +2874,47 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__; + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16e_t) == LZO_SIZEOF_LZO_INT16E_T) + #endif + #if !defined(lzo_int32e_t) +-#if (LZO_SIZEOF_LONG == 4) ++#if (LZO_CFG_PREFER_TYPEOF_ACC_INT32E_T == LZO_TYPEOF_INT) && (LZO_SIZEOF_INT != 4) ++# undef LZO_CFG_PREFER_TYPEOF_ACC_INT32E_T ++#endif ++#if (LZO_SIZEOF_LONG == 4) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT32E_T == LZO_TYPEOF_INT) + # define lzo_int32e_t long int + # define lzo_uint32e_t unsigned long int ++# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF_LONG + #elif (LZO_SIZEOF_INT == 4) + # define lzo_int32e_t int + # define lzo_uint32e_t unsigned int ++# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF_INT + #elif (LZO_SIZEOF_SHORT == 4) + # define lzo_int32e_t short int + # define lzo_uint32e_t unsigned short int ++# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF_SHORT + #elif (LZO_SIZEOF_LONG_LONG == 4) + # define lzo_int32e_t lzo_llong_t + # define lzo_uint32e_t lzo_ullong_t ++# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF_LONG_LONG + #elif 1 && !(LZO_CFG_TYPE_NO_MODE_SI) && (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x025f00ul) || LZO_CC_LLVM) && (__INT_MAX__+0 > 2147483647L) ++# if !(LZO_LANG_ASSEMBLER) + typedef int lzo_int32e_si_t__ __attribute__((__mode__(__SI__))); + typedef unsigned int lzo_uint32e_si_t__ __attribute__((__mode__(__SI__))); ++# endif + # define lzo_int32e_t lzo_int32e_si_t__ + # define lzo_uint32e_t lzo_uint32e_si_t__ ++# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF___MODE_SI + #elif 1 && !(LZO_CFG_TYPE_NO_MODE_SI) && (LZO_CC_GNUC >= 0x025f00ul) && defined(__AVR__) && (__LONG_MAX__+0 == 32767L) ++# if !(LZO_LANG_ASSEMBLER) + typedef int lzo_int32e_si_t__ __attribute__((__mode__(__SI__))); + typedef unsigned int lzo_uint32e_si_t__ __attribute__((__mode__(__SI__))); ++# endif + # define lzo_int32e_t lzo_int32e_si_t__ + # define lzo_uint32e_t lzo_uint32e_si_t__ + # define LZO_INT32_C(c) (c##LL) + # define LZO_UINT32_C(c) (c##ULL) ++# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF___MODE_SI + #elif (LZO_SIZEOF___INT32 == 4) + # define lzo_int32e_t __int32 + # define lzo_uint32e_t unsigned __int32 ++# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF___INT32 + #else + #endif + #endif +@@ -2696,21 +2925,28 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__; + #endif + #if !defined(lzo_int64e_t) + #if (LZO_SIZEOF___INT64 == 8) +-# if (LZO_CC_BORLANDC) && !(LZO_CFG_TYPE_PREFER___INT64) +-# define LZO_CFG_TYPE_PREFER___INT64 1 ++# if (LZO_CC_BORLANDC) && !defined(LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T) ++# define LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T LZO_TYPEOF___INT64 + # endif + #endif ++#if (LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF_LONG_LONG) && (LZO_SIZEOF_LONG_LONG != 8) ++# undef LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T ++#endif ++#if (LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF___INT64) && (LZO_SIZEOF___INT64 != 8) ++# undef LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T ++#endif + #if (LZO_SIZEOF_INT == 8) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG) + # define lzo_int64e_t int + # define lzo_uint64e_t unsigned int +-# define LZO_SIZEOF_LZO_INT64E_T LZO_SIZEOF_INT +-#elif (LZO_SIZEOF_LONG == 8) ++# define LZO_TYPEOF_LZO_INT64E_T LZO_TYPEOF_INT ++#elif (LZO_SIZEOF_LONG == 8) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF_LONG_LONG) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF___INT64) + # define lzo_int64e_t long int + # define lzo_uint64e_t unsigned long int +-# define LZO_SIZEOF_LZO_INT64E_T LZO_SIZEOF_LONG +-#elif (LZO_SIZEOF_LONG_LONG == 8) && !(LZO_CFG_TYPE_PREFER___INT64) ++# define LZO_TYPEOF_LZO_INT64E_T LZO_TYPEOF_LONG ++#elif (LZO_SIZEOF_LONG_LONG == 8) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF___INT64) + # define lzo_int64e_t lzo_llong_t + # define lzo_uint64e_t lzo_ullong_t ++# define LZO_TYPEOF_LZO_INT64E_T LZO_TYPEOF_LONG_LONG + # if (LZO_CC_BORLANDC) + # define LZO_INT64_C(c) ((c) + 0ll) + # define LZO_UINT64_C(c) ((c) + 0ull) +@@ -2721,10 +2957,10 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__; + # define LZO_INT64_C(c) (c##LL) + # define LZO_UINT64_C(c) (c##ULL) + # endif +-# define LZO_SIZEOF_LZO_INT64E_T LZO_SIZEOF_LONG_LONG + #elif (LZO_SIZEOF___INT64 == 8) + # define lzo_int64e_t __int64 + # define lzo_uint64e_t unsigned __int64 ++# define LZO_TYPEOF_LZO_INT64E_T LZO_TYPEOF___INT64 + # if (LZO_CC_BORLANDC) + # define LZO_INT64_C(c) ((c) + 0i64) + # define LZO_UINT64_C(c) ((c) + 0ui64) +@@ -2732,11 +2968,11 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__; + # define LZO_INT64_C(c) (c##i64) + # define LZO_UINT64_C(c) (c##ui64) + # endif +-# define LZO_SIZEOF_LZO_INT64E_T LZO_SIZEOF___INT64 + #else + #endif + #endif + #if defined(lzo_int64e_t) ++# define LZO_SIZEOF_LZO_INT64E_T 8 + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64e_t) == 8) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64e_t) == LZO_SIZEOF_LZO_INT64E_T) + #endif +@@ -2745,14 +2981,17 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__; + # define lzo_int32l_t lzo_int32e_t + # define lzo_uint32l_t lzo_uint32e_t + # define LZO_SIZEOF_LZO_INT32L_T LZO_SIZEOF_LZO_INT32E_T ++# define LZO_TYPEOF_LZO_INT32L_T LZO_TYPEOF_LZO_INT32E_T + #elif (LZO_SIZEOF_INT >= 4) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG) + # define lzo_int32l_t int + # define lzo_uint32l_t unsigned int + # define LZO_SIZEOF_LZO_INT32L_T LZO_SIZEOF_INT ++# define LZO_TYPEOF_LZO_INT32L_T LZO_SIZEOF_INT + #elif (LZO_SIZEOF_LONG >= 4) + # define lzo_int32l_t long int + # define lzo_uint32l_t unsigned long int + # define LZO_SIZEOF_LZO_INT32L_T LZO_SIZEOF_LONG ++# define LZO_TYPEOF_LZO_INT32L_T LZO_SIZEOF_LONG + #else + # error "lzo_int32l_t" + #endif +@@ -2766,6 +3005,7 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__; + # define lzo_int64l_t lzo_int64e_t + # define lzo_uint64l_t lzo_uint64e_t + # define LZO_SIZEOF_LZO_INT64L_T LZO_SIZEOF_LZO_INT64E_T ++# define LZO_TYPEOF_LZO_INT64L_T LZO_TYPEOF_LZO_INT64E_T + #else + #endif + #endif +@@ -2778,10 +3018,12 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__; + # define lzo_int32f_t lzo_int64l_t + # define lzo_uint32f_t lzo_uint64l_t + # define LZO_SIZEOF_LZO_INT32F_T LZO_SIZEOF_LZO_INT64L_T ++# define LZO_TYPEOF_LZO_INT32F_T LZO_TYPEOF_LZO_INT64L_T + #else + # define lzo_int32f_t lzo_int32l_t + # define lzo_uint32f_t lzo_uint32l_t + # define LZO_SIZEOF_LZO_INT32F_T LZO_SIZEOF_LZO_INT32L_T ++# define LZO_TYPEOF_LZO_INT32F_T LZO_TYPEOF_LZO_INT32L_T + #endif + #endif + #if 1 +@@ -2793,6 +3035,7 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__; + # define lzo_int64f_t lzo_int64l_t + # define lzo_uint64f_t lzo_uint64l_t + # define LZO_SIZEOF_LZO_INT64F_T LZO_SIZEOF_LZO_INT64L_T ++# define LZO_TYPEOF_LZO_INT64F_T LZO_TYPEOF_LZO_INT64L_T + #else + #endif + #endif +@@ -2803,33 +3046,43 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__; + #if !defined(lzo_intptr_t) + #if 1 && (LZO_OS_OS400 && (LZO_SIZEOF_VOID_P == 16)) + # define __LZO_INTPTR_T_IS_POINTER 1 +- typedef char* lzo_intptr_t; +- typedef char* lzo_uintptr_t; ++# if !(LZO_LANG_ASSEMBLER) ++ typedef char * lzo_intptr_t; ++ typedef char * lzo_uintptr_t; ++# endif + # define lzo_intptr_t lzo_intptr_t + # define lzo_uintptr_t lzo_uintptr_t + # define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_VOID_P ++# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_CHAR_P + #elif (LZO_CC_MSC && (_MSC_VER >= 1300) && (LZO_SIZEOF_VOID_P == 4) && (LZO_SIZEOF_INT == 4)) ++# if !(LZO_LANG_ASSEMBLER) + typedef __w64 int lzo_intptr_t; + typedef __w64 unsigned int lzo_uintptr_t; ++# endif + # define lzo_intptr_t lzo_intptr_t + # define lzo_uintptr_t lzo_uintptr_t + # define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_INT ++# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_INT + #elif (LZO_SIZEOF_SHORT == LZO_SIZEOF_VOID_P) && (LZO_SIZEOF_INT > LZO_SIZEOF_VOID_P) + # define lzo_intptr_t short + # define lzo_uintptr_t unsigned short + # define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_SHORT ++# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_SHORT + #elif (LZO_SIZEOF_INT >= LZO_SIZEOF_VOID_P) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG) + # define lzo_intptr_t int + # define lzo_uintptr_t unsigned int + # define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_INT ++# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_INT + #elif (LZO_SIZEOF_LONG >= LZO_SIZEOF_VOID_P) + # define lzo_intptr_t long + # define lzo_uintptr_t unsigned long + # define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_LONG ++# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_LONG + #elif (LZO_SIZEOF_LZO_INT64L_T >= LZO_SIZEOF_VOID_P) + # define lzo_intptr_t lzo_int64l_t + # define lzo_uintptr_t lzo_uint64l_t + # define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_LZO_INT64L_T ++# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_LZO_INT64L_T + #else + # error "lzo_intptr_t" + #endif +@@ -2843,34 +3096,43 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__; + #if (LZO_WORDSIZE == LZO_SIZEOF_LZO_INTPTR_T) && !(__LZO_INTPTR_T_IS_POINTER) + # define lzo_word_t lzo_uintptr_t + # define lzo_sword_t lzo_intptr_t +-# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LZO_INTPTR_T ++# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LZO_INTPTR_T ++# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_LZO_INTPTR_T + #elif (LZO_WORDSIZE == LZO_SIZEOF_LONG) + # define lzo_word_t unsigned long + # define lzo_sword_t long +-# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LONG ++# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LONG ++# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_LONG + #elif (LZO_WORDSIZE == LZO_SIZEOF_INT) + # define lzo_word_t unsigned int + # define lzo_sword_t int +-# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_INT ++# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_INT ++# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_INT + #elif (LZO_WORDSIZE == LZO_SIZEOF_SHORT) + # define lzo_word_t unsigned short + # define lzo_sword_t short +-# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_SHORT ++# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_SHORT ++# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_SHORT + #elif (LZO_WORDSIZE == 1) + # define lzo_word_t unsigned char + # define lzo_sword_t signed char +-# define LZO_SIZEOF_LZO_WORD_T 1 ++# define LZO_SIZEOF_LZO_WORD_T 1 ++# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_CHAR + #elif (LZO_WORDSIZE == LZO_SIZEOF_LZO_INT64L_T) + # define lzo_word_t lzo_uint64l_t + # define lzo_sword_t lzo_int64l_t +-# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LZO_INT64L_T ++# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LZO_INT64L_T ++# define LZO_TYPEOF_LZO_WORD_T LZO_SIZEOF_LZO_INT64L_T + #elif (LZO_ARCH_SPU) && (LZO_CC_GNUC) + #if 0 ++# if !(LZO_LANG_ASSEMBLER) + typedef unsigned lzo_word_t __attribute__((__mode__(__V16QI__))); + typedef int lzo_sword_t __attribute__((__mode__(__V16QI__))); ++# endif + # define lzo_word_t lzo_word_t + # define lzo_sword_t lzo_sword_t + # define LZO_SIZEOF_LZO_WORD_T 16 ++# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF___MODE_V16QI + #endif + #else + # error "lzo_word_t" +@@ -2885,6 +3147,7 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__; + #define lzo_int8_t signed char + #define lzo_uint8_t unsigned char + #define LZO_SIZEOF_LZO_INT8_T 1 ++#define LZO_TYPEOF_LZO_INT8_T LZO_TYPEOF_CHAR + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int8_t) == 1) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int8_t) == sizeof(lzo_uint8_t)) + #endif +@@ -2892,6 +3155,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int8_t) == sizeof(lzo_uint8_t)) + #define lzo_int16_t lzo_int16e_t + #define lzo_uint16_t lzo_uint16e_t + #define LZO_SIZEOF_LZO_INT16_T LZO_SIZEOF_LZO_INT16E_T ++#define LZO_TYPEOF_LZO_INT16_T LZO_TYPEOF_LZO_INT16E_T + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16_t) == 2) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16_t) == sizeof(lzo_uint16_t)) + #endif +@@ -2899,6 +3163,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16_t) == sizeof(lzo_uint16_t)) + #define lzo_int32_t lzo_int32e_t + #define lzo_uint32_t lzo_uint32e_t + #define LZO_SIZEOF_LZO_INT32_T LZO_SIZEOF_LZO_INT32E_T ++#define LZO_TYPEOF_LZO_INT32_T LZO_TYPEOF_LZO_INT32E_T + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32_t) == 4) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32_t) == sizeof(lzo_uint32_t)) + #endif +@@ -2906,6 +3171,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32_t) == sizeof(lzo_uint32_t)) + #define lzo_int64_t lzo_int64e_t + #define lzo_uint64_t lzo_uint64e_t + #define LZO_SIZEOF_LZO_INT64_T LZO_SIZEOF_LZO_INT64E_T ++#define LZO_TYPEOF_LZO_INT64_T LZO_TYPEOF_LZO_INT64E_T + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64_t) == 8) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64_t) == sizeof(lzo_uint64_t)) + #endif +@@ -2913,6 +3179,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64_t) == sizeof(lzo_uint64_t)) + #define lzo_int_least32_t lzo_int32l_t + #define lzo_uint_least32_t lzo_uint32l_t + #define LZO_SIZEOF_LZO_INT_LEAST32_T LZO_SIZEOF_LZO_INT32L_T ++#define LZO_TYPEOF_LZO_INT_LEAST32_T LZO_TYPEOF_LZO_INT32L_T + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least32_t) >= 4) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least32_t) == sizeof(lzo_uint_least32_t)) + #endif +@@ -2920,6 +3187,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least32_t) == sizeof(lzo_uint_leas + #define lzo_int_least64_t lzo_int64l_t + #define lzo_uint_least64_t lzo_uint64l_t + #define LZO_SIZEOF_LZO_INT_LEAST64_T LZO_SIZEOF_LZO_INT64L_T ++#define LZO_TYPEOF_LZO_INT_LEAST64_T LZO_TYPEOF_LZO_INT64L_T + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least64_t) >= 8) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least64_t) == sizeof(lzo_uint_least64_t)) + #endif +@@ -2927,6 +3195,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least64_t) == sizeof(lzo_uint_leas + #define lzo_int_fast32_t lzo_int32f_t + #define lzo_uint_fast32_t lzo_uint32f_t + #define LZO_SIZEOF_LZO_INT_FAST32_T LZO_SIZEOF_LZO_INT32F_T ++#define LZO_TYPEOF_LZO_INT_FAST32_T LZO_TYPEOF_LZO_INT32F_T + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast32_t) >= 4) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast32_t) == sizeof(lzo_uint_fast32_t)) + #endif +@@ -2934,6 +3203,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast32_t) == sizeof(lzo_uint_fast3 + #define lzo_int_fast64_t lzo_int64f_t + #define lzo_uint_fast64_t lzo_uint64f_t + #define LZO_SIZEOF_LZO_INT_FAST64_T LZO_SIZEOF_LZO_INT64F_T ++#define LZO_TYPEOF_LZO_INT_FAST64_T LZO_TYPEOF_LZO_INT64F_T + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast64_t) >= 8) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast64_t) == sizeof(lzo_uint_fast64_t)) + #endif +diff --git a/grub-core/lib/minilzo/minilzo.c b/grub-core/lib/minilzo/minilzo.c +index ab2be5f4f..8fd866450 100644 +--- a/grub-core/lib/minilzo/minilzo.c ++++ b/grub-core/lib/minilzo/minilzo.c +@@ -2,7 +2,7 @@ + + This file is part of the LZO real-time data compression library. + +- Copyright (C) 1996-2014 Markus Franz Xaver Johannes Oberhumer ++ Copyright (C) 1996-2017 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + The LZO library is free software; you can redistribute it and/or +@@ -60,6 +60,33 @@ + # define __LONG_MAX__ 9223372036854775807L + # endif + #endif ++#if 0 ++#elif !defined(__LZO_LANG_OVERRIDE) ++#if (defined(__clang__) || defined(__GNUC__)) && defined(__ASSEMBLER__) ++# if (__ASSEMBLER__+0) <= 0 ++# error "__ASSEMBLER__" ++# else ++# define LZO_LANG_ASSEMBLER 1 ++# endif ++#elif defined(__cplusplus) ++# if (__cplusplus+0) <= 0 ++# error "__cplusplus" ++# elif (__cplusplus < 199711L) ++# define LZO_LANG_CXX 1 ++# elif defined(_MSC_VER) && defined(_MSVC_LANG) && (_MSVC_LANG+0 >= 201402L) && 1 ++# define LZO_LANG_CXX _MSVC_LANG ++# else ++# define LZO_LANG_CXX __cplusplus ++# endif ++# define LZO_LANG_CPLUSPLUS LZO_LANG_CXX ++#else ++# if defined(__STDC_VERSION__) && (__STDC_VERSION__+0 >= 199409L) ++# define LZO_LANG_C __STDC_VERSION__ ++# else ++# define LZO_LANG_C 1 ++# endif ++#endif ++#endif + #if !defined(LZO_CFG_NO_DISABLE_WUNDEF) + #if defined(__ARMCC_VERSION) + # pragma diag_suppress 193 +@@ -155,10 +182,12 @@ + # endif + #endif + #endif +-#if defined(_MSC_VER) && defined(M_I86HM) && (UINT_MAX == LZO_0xffffL) ++#if (UINT_MAX == LZO_0xffffL) ++#if defined(_MSC_VER) && defined(M_I86HM) + # define ptrdiff_t long + # define _PTRDIFF_T_DEFINED 1 + #endif ++#endif + #if (UINT_MAX == LZO_0xffffL) + # undef __LZO_RENAME_A + # undef __LZO_RENAME_B +@@ -307,7 +336,7 @@ + #define LZO_CPP_ECONCAT6(a,b,c,d,e,f) LZO_CPP_CONCAT6(a,b,c,d,e,f) + #define LZO_CPP_ECONCAT7(a,b,c,d,e,f,g) LZO_CPP_CONCAT7(a,b,c,d,e,f,g) + #endif +-#define __LZO_MASK_GEN(o,b) (((((o) << ((b)-!!(b))) - (o)) << 1) + (o)*!!(b)) ++#define __LZO_MASK_GEN(o,b) (((((o) << ((b)-((b)!=0))) - (o)) << 1) + (o)*((b)!=0)) + #if 1 && defined(__cplusplus) + # if !defined(__STDC_CONSTANT_MACROS) + # define __STDC_CONSTANT_MACROS 1 +@@ -418,7 +447,7 @@ + #elif defined(__TOS__) || defined(__atarist__) + # define LZO_OS_TOS 1 + # define LZO_INFO_OS "tos" +-#elif defined(macintosh) && !defined(__ppc__) ++#elif defined(macintosh) && !defined(__arm__) && !defined(__i386__) && !defined(__ppc__) && !defined(__x64_64__) + # define LZO_OS_MACCLASSIC 1 + # define LZO_INFO_OS "macclassic" + #elif defined(__VMS) +@@ -558,6 +587,12 @@ + # define LZO_CC_ARMCC __ARMCC_VERSION + # define LZO_INFO_CC "ARM C Compiler" + # define LZO_INFO_CCVER __VERSION__ ++#elif defined(__clang__) && defined(__c2__) && defined(__c2_version__) && defined(_MSC_VER) ++# define LZO_CC_CLANG (__clang_major__ * 0x10000L + (__clang_minor__-0) * 0x100 + (__clang_patchlevel__-0)) ++# define LZO_CC_CLANG_C2 _MSC_VER ++# define LZO_CC_CLANG_VENDOR_MICROSOFT 1 ++# define LZO_INFO_CC "clang/c2" ++# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__c2_version__) + #elif defined(__clang__) && defined(__llvm__) && defined(__VERSION__) + # if defined(__clang_major__) && defined(__clang_minor__) && defined(__clang_patchlevel__) + # define LZO_CC_CLANG (__clang_major__ * 0x10000L + (__clang_minor__-0) * 0x100 + (__clang_patchlevel__-0)) +@@ -569,8 +604,18 @@ + # elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__) + # define LZO_CC_CLANG_GNUC (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0)) + # endif +-# define LZO_INFO_CC "clang" +-# define LZO_INFO_CCVER __VERSION__ ++# if defined(__APPLE_CC__) ++# define LZO_CC_CLANG_VENDOR_APPLE 1 ++# define LZO_INFO_CC "clang/apple" ++# else ++# define LZO_CC_CLANG_VENDOR_LLVM 1 ++# define LZO_INFO_CC "clang" ++# endif ++# if defined(__clang_version__) ++# define LZO_INFO_CCVER __clang_version__ ++# else ++# define LZO_INFO_CCVER __VERSION__ ++# endif + #elif defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__) + # if defined(__GNUC_PATCHLEVEL__) + # define LZO_CC_LLVM_GNUC (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0)) +@@ -790,7 +835,7 @@ + #elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) + # define LZO_ARCH_I086 1 + # define LZO_INFO_ARCH "i086" +-#elif defined(__aarch64__) ++#elif defined(__aarch64__) || defined(_M_ARM64) + # define LZO_ARCH_ARM64 1 + # define LZO_INFO_ARCH "arm64" + #elif defined(__alpha__) || defined(__alpha) || defined(_M_ALPHA) +@@ -802,22 +847,11 @@ + #elif defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64) + # define LZO_ARCH_AMD64 1 + # define LZO_INFO_ARCH "amd64" +-#elif defined(__thumb__) || (defined(_M_ARM) && defined(_M_THUMB)) ++#elif defined(__arm__) || defined(_M_ARM) + # define LZO_ARCH_ARM 1 +-# define LZO_ARCH_ARM_THUMB 1 +-# define LZO_INFO_ARCH "arm_thumb" ++# define LZO_INFO_ARCH "arm" + #elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCARM__) + # define LZO_ARCH_ARM 1 +-# if defined(__CPU_MODE__) && ((__CPU_MODE__-0) == 1) +-# define LZO_ARCH_ARM_THUMB 1 +-# define LZO_INFO_ARCH "arm_thumb" +-# elif defined(__CPU_MODE__) && ((__CPU_MODE__-0) == 2) +-# define LZO_INFO_ARCH "arm" +-# else +-# define LZO_INFO_ARCH "arm" +-# endif +-#elif defined(__arm__) || defined(_M_ARM) +-# define LZO_ARCH_ARM 1 + # define LZO_INFO_ARCH "arm" + #elif (UINT_MAX <= LZO_0xffffL) && defined(__AVR__) + # define LZO_ARCH_AVR 1 +@@ -891,6 +925,15 @@ + #elif defined(__powerpc__) || defined(__powerpc) || defined(__ppc__) || defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PWR) + # define LZO_ARCH_POWERPC 1 + # define LZO_INFO_ARCH "powerpc" ++#elif defined(__powerpc64__) || defined(__powerpc64) || defined(__ppc64__) || defined(__PPC64__) ++# define LZO_ARCH_POWERPC 1 ++# define LZO_INFO_ARCH "powerpc" ++#elif defined(__powerpc64le__) || defined(__powerpc64le) || defined(__ppc64le__) || defined(__PPC64LE__) ++# define LZO_ARCH_POWERPC 1 ++# define LZO_INFO_ARCH "powerpc" ++#elif defined(__riscv) ++# define LZO_ARCH_RISCV 1 ++# define LZO_INFO_ARCH "riscv" + #elif defined(__s390__) || defined(__s390) || defined(__s390x__) || defined(__s390x) + # define LZO_ARCH_S390 1 + # define LZO_INFO_ARCH "s390" +@@ -925,6 +968,23 @@ + # define LZO_INFO_ARCH "unknown" + #endif + #endif ++#if !defined(LZO_ARCH_ARM_THUMB2) ++#if (LZO_ARCH_ARM) ++# if defined(__thumb__) || defined(__thumb) || defined(_M_THUMB) ++# if defined(__thumb2__) ++# define LZO_ARCH_ARM_THUMB2 1 ++# elif 1 && defined(__TARGET_ARCH_THUMB) && ((__TARGET_ARCH_THUMB)+0 >= 4) ++# define LZO_ARCH_ARM_THUMB2 1 ++# elif 1 && defined(_MSC_VER) && defined(_M_THUMB) && ((_M_THUMB)+0 >= 7) ++# define LZO_ARCH_ARM_THUMB2 1 ++# endif ++# endif ++#endif ++#endif ++#if (LZO_ARCH_ARM_THUMB2) ++# undef LZO_INFO_ARCH ++# define LZO_INFO_ARCH "arm_thumb2" ++#endif + #if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_DOS32 || LZO_OS_OS2) + # error "FIXME - missing define for CPU architecture" + #endif +@@ -967,13 +1027,10 @@ + #if (LZO_ARCH_I386 && !LZO_ARCH_X86) || (!LZO_ARCH_I386 && LZO_ARCH_X86) + # error "unexpected configuration - check your compiler defines" + #endif +-#if (LZO_ARCH_ARM_THUMB && !LZO_ARCH_ARM) +-# error "unexpected configuration - check your compiler defines" +-#endif +-#if (LZO_ARCH_ARM_THUMB1 && !LZO_ARCH_ARM_THUMB) ++#if (LZO_ARCH_ARM_THUMB1 && !LZO_ARCH_ARM) + # error "unexpected configuration - check your compiler defines" + #endif +-#if (LZO_ARCH_ARM_THUMB2 && !LZO_ARCH_ARM_THUMB) ++#if (LZO_ARCH_ARM_THUMB2 && !LZO_ARCH_ARM) + # error "unexpected configuration - check your compiler defines" + #endif + #if (LZO_ARCH_ARM_THUMB1 && LZO_ARCH_ARM_THUMB2) +@@ -1005,7 +1062,9 @@ + # if !defined(LZO_TARGET_FEATURE_SSE2) + # if defined(__SSE2__) + # define LZO_TARGET_FEATURE_SSE2 1 +-# elif defined(_MSC_VER) && ((defined(_M_IX86_FP) && ((_M_IX86_FP)+0 >= 2)) || defined(_M_AMD64)) ++# elif defined(_MSC_VER) && (defined(_M_IX86_FP) && ((_M_IX86_FP)+0 >= 2)) ++# define LZO_TARGET_FEATURE_SSE2 1 ++# elif (LZO_CC_INTELC_MSC || LZO_CC_MSC) && defined(_M_AMD64) + # define LZO_TARGET_FEATURE_SSE2 1 + # endif + # endif +@@ -1054,7 +1113,11 @@ + #endif + #if (LZO_ARCH_ARM) + # if !defined(LZO_TARGET_FEATURE_NEON) +-# if defined(__ARM_NEON__) ++# if defined(__ARM_NEON) && ((__ARM_NEON)+0) ++# define LZO_TARGET_FEATURE_NEON 1 ++# elif 1 && defined(__ARM_NEON__) && ((__ARM_NEON__)+0) ++# define LZO_TARGET_FEATURE_NEON 1 ++# elif 1 && defined(__TARGET_FEATURE_NEON) && ((__TARGET_FEATURE_NEON)+0) + # define LZO_TARGET_FEATURE_NEON 1 + # endif + # endif +@@ -1125,7 +1188,7 @@ + # error "unexpected configuration - check your compiler defines" + # endif + #endif +-#ifdef __cplusplus ++#if defined(__cplusplus) + extern "C" { + #endif + #if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0200)) +@@ -1148,7 +1211,7 @@ extern "C" { + #else + # error "FIXME - implement LZO_MM_AHSHIFT" + #endif +-#ifdef __cplusplus ++#if defined(__cplusplus) + } + #endif + #endif +@@ -1234,12 +1297,53 @@ extern "C" { + # define __lzo_gnuc_extension__ __extension__ + #elif (LZO_CC_IBMC >= 600) + # define __lzo_gnuc_extension__ __extension__ +-#else + #endif + #endif + #if !defined(__lzo_gnuc_extension__) + # define __lzo_gnuc_extension__ /*empty*/ + #endif ++#if !defined(lzo_has_builtin) ++#if (LZO_CC_CLANG) && defined(__has_builtin) ++# define lzo_has_builtin __has_builtin ++#endif ++#endif ++#if !defined(lzo_has_builtin) ++# define lzo_has_builtin(x) 0 ++#endif ++#if !defined(lzo_has_attribute) ++#if (LZO_CC_CLANG) && defined(__has_attribute) ++# define lzo_has_attribute __has_attribute ++#endif ++#endif ++#if !defined(lzo_has_attribute) ++# define lzo_has_attribute(x) 0 ++#endif ++#if !defined(lzo_has_declspec_attribute) ++#if (LZO_CC_CLANG) && defined(__has_declspec_attribute) ++# define lzo_has_declspec_attribute __has_declspec_attribute ++#endif ++#endif ++#if !defined(lzo_has_declspec_attribute) ++# define lzo_has_declspec_attribute(x) 0 ++#endif ++#if !defined(lzo_has_feature) ++#if (LZO_CC_CLANG) && defined(__has_feature) ++# define lzo_has_feature __has_feature ++#endif ++#endif ++#if !defined(lzo_has_feature) ++# define lzo_has_feature(x) 0 ++#endif ++#if !defined(lzo_has_extension) ++#if (LZO_CC_CLANG) && defined(__has_extension) ++# define lzo_has_extension __has_extension ++#elif (LZO_CC_CLANG) && defined(__has_feature) ++# define lzo_has_extension __has_feature ++#endif ++#endif ++#if !defined(lzo_has_extension) ++# define lzo_has_extension(x) 0 ++#endif + #if !defined(LZO_CFG_USE_NEW_STYLE_CASTS) && defined(__cplusplus) && 0 + # if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x020800ul)) + # define LZO_CFG_USE_NEW_STYLE_CASTS 0 +@@ -1376,7 +1480,7 @@ extern "C" { + # elif (LZO_CC_MSC && (_MSC_VER < 900)) + # define LZO_UNUSED(var) if (&var) ; else + # elif (LZO_CC_KEILC) +-# define LZO_UNUSED(var) {LZO_EXTERN_C int lzo_unused__[1-2*!(sizeof(var)>0)];} ++# define LZO_UNUSED(var) {extern int lzo_unused__[1-2*!(sizeof(var)>0)]; (void)lzo_unused__;} + # elif (LZO_CC_PACIFICC) + # define LZO_UNUSED(var) ((void) sizeof(var)) + # elif (LZO_CC_WATCOMC) && defined(__cplusplus) +@@ -1385,6 +1489,9 @@ extern "C" { + # define LZO_UNUSED(var) ((void) &var) + # endif + #endif ++#if !defined(LZO_UNUSED_RESULT) ++# define LZO_UNUSED_RESULT(var) LZO_UNUSED(var) ++#endif + #if !defined(LZO_UNUSED_FUNC) + # if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600)) + # define LZO_UNUSED_FUNC(func) ((void) func) +@@ -1397,7 +1504,7 @@ extern "C" { + # elif (LZO_CC_MSC) + # define LZO_UNUSED_FUNC(func) ((void) &func) + # elif (LZO_CC_KEILC || LZO_CC_PELLESC) +-# define LZO_UNUSED_FUNC(func) {LZO_EXTERN_C int lzo_unused_func__[1-2*!(sizeof((int)func)>0)];} ++# define LZO_UNUSED_FUNC(func) {extern int lzo_unused__[1-2*!(sizeof((int)func)>0)]; (void)lzo_unused__;} + # else + # define LZO_UNUSED_FUNC(func) ((void) func) + # endif +@@ -1803,6 +1910,7 @@ extern "C" { + #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800)) + # define __lzo_likely(e) (__builtin_expect(!!(e),1)) + # define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) ++#elif (LZO_CC_CLANG && LZO_CC_CLANG_C2) + #elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) + # define __lzo_likely(e) (__builtin_expect(!!(e),1)) + # define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) +@@ -1813,21 +1921,28 @@ extern "C" { + # define __lzo_HAVE_likely 1 + # endif + #else +-# define __lzo_likely(e) (e) ++# define __lzo_likely(e) (e) ++#endif ++#if defined(__lzo_very_likely) ++# ifndef __lzo_HAVE_very_likely ++# define __lzo_HAVE_very_likely 1 ++# endif ++#else ++# define __lzo_very_likely(e) __lzo_likely(e) + #endif + #if defined(__lzo_unlikely) + # ifndef __lzo_HAVE_unlikely + # define __lzo_HAVE_unlikely 1 + # endif + #else +-# define __lzo_unlikely(e) (e) ++# define __lzo_unlikely(e) (e) + #endif +-#if !defined(__lzo_static_unused_void_func) +-# if 1 && (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || (LZO_CC_GNUC >= 0x020700ul) || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) +-# define __lzo_static_unused_void_func(f) static void __attribute__((__unused__)) f(void) +-# else +-# define __lzo_static_unused_void_func(f) static __lzo_inline void f(void) ++#if defined(__lzo_very_unlikely) ++# ifndef __lzo_HAVE_very_unlikely ++# define __lzo_HAVE_very_unlikely 1 + # endif ++#else ++# define __lzo_very_unlikely(e) __lzo_unlikely(e) + #endif + #if !defined(__lzo_loop_forever) + # if (LZO_CC_IBMC) +@@ -1837,7 +1952,7 @@ extern "C" { + # endif + #endif + #if !defined(__lzo_unreachable) +-#if (LZO_CC_CLANG && (LZO_CC_CLANG >= 0x020800ul)) ++#if (LZO_CC_CLANG && (LZO_CC_CLANG >= 0x020800ul)) && lzo_has_builtin(__builtin_unreachable) + # define __lzo_unreachable() __builtin_unreachable(); + #elif (LZO_CC_GNUC >= 0x040500ul) + # define __lzo_unreachable() __builtin_unreachable(); +@@ -1856,6 +1971,15 @@ extern "C" { + # define __lzo_unreachable() __lzo_loop_forever(); + # endif + #endif ++#if !defined(lzo_unused_funcs_impl) ++# if 1 && (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || (LZO_CC_GNUC >= 0x020700ul) || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) ++# define lzo_unused_funcs_impl(r,f) static r __attribute__((__unused__)) f ++# elif 1 && (LZO_CC_BORLANDC || LZO_CC_GNUC) ++# define lzo_unused_funcs_impl(r,f) static r f ++# else ++# define lzo_unused_funcs_impl(r,f) __lzo_static_forceinline r f ++# endif ++#endif + #ifndef __LZO_CTA_NAME + #if (LZO_CFG_USE_COUNTER) + # define __LZO_CTA_NAME(a) LZO_PP_ECONCAT2(a,__COUNTER__) +@@ -1881,6 +2005,8 @@ extern "C" { + #if !defined(LZO_COMPILE_TIME_ASSERT) + # if (LZO_CC_AZTECC) + # define LZO_COMPILE_TIME_ASSERT(e) {typedef int __LZO_CTA_NAME(lzo_cta_t__)[1-!(e)];} ++# elif (LZO_CC_CLANG && (LZO_CC_CLANG >= 0x030000ul)) ++# define LZO_COMPILE_TIME_ASSERT(e) {typedef int __LZO_CTA_NAME(lzo_cta_t__)[1-2*!(e)] __attribute__((__unused__));} + # elif (LZO_CC_DMC || LZO_CC_PACIFICC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) + # define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; + # elif (LZO_CC_GNUC) && defined(__CHECKER__) && defined(__SPARSE_CHECKER__) +@@ -1897,11 +2023,16 @@ extern "C" { + # define LZO_COMPILE_TIME_ASSERT(e) {typedef int __LZO_CTA_NAME(lzo_cta_t__)[1-2*!(e)];} + # endif + #endif ++#if (LZO_LANG_ASSEMBLER) ++# undef LZO_COMPILE_TIME_ASSERT_HEADER ++# define LZO_COMPILE_TIME_ASSERT_HEADER(e) /*empty*/ ++#else + LZO_COMPILE_TIME_ASSERT_HEADER(1 == 1) + #if defined(__cplusplus) + extern "C" { LZO_COMPILE_TIME_ASSERT_HEADER(2 == 2) } + #endif + LZO_COMPILE_TIME_ASSERT_HEADER(3 == 3) ++#endif + #if (LZO_ARCH_I086 || LZO_ARCH_I386) && (LZO_OS_DOS16 || LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_OS216 || LZO_OS_WIN16 || LZO_OS_WIN32 || LZO_OS_WIN64) + # if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC) + # elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) +@@ -1968,7 +2099,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(3 == 3) + #if !defined(LZO_HAVE_WINDOWS_H) + #if (LZO_OS_CYGWIN || (LZO_OS_EMX && defined(__RSXNT__)) || LZO_OS_WIN32 || LZO_OS_WIN64) + # if (LZO_CC_WATCOMC && (__WATCOMC__ < 1000)) +-# elif (LZO_OS_WIN32 && LZO_CC_GNUC) && defined(__PW32__) ++# elif ((LZO_OS_WIN32 && defined(__PW32__)) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x030000ul))) + # elif ((LZO_OS_CYGWIN || defined(__MINGW32__)) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x025f00ul))) + # else + # define LZO_HAVE_WINDOWS_H 1 +@@ -1976,6 +2107,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(3 == 3) + #endif + #endif + #endif ++#define LZO_SIZEOF_CHAR 1 + #ifndef LZO_SIZEOF_SHORT + #if defined(SIZEOF_SHORT) + # define LZO_SIZEOF_SHORT (SIZEOF_SHORT) +@@ -2174,12 +2306,12 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_LONG == sizeof(long)) + # define LZO_WORDSIZE 8 + #elif (LZO_ARCH_AMD64) + # define LZO_WORDSIZE 8 ++#elif (LZO_ARCH_ARM64) ++# define LZO_WORDSIZE 8 + #elif (LZO_ARCH_AVR) + # define LZO_WORDSIZE 1 + #elif (LZO_ARCH_H8300) +-# if defined(__NORMAL_MODE__) +-# define LZO_WORDSIZE 4 +-# elif defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) ++# if defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) + # define LZO_WORDSIZE 4 + # else + # define LZO_WORDSIZE 2 +@@ -2222,11 +2354,15 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(long) == 8) + #elif (LZO_ARCH_C166 || LZO_ARCH_MCS51 || LZO_ARCH_MCS251 || LZO_ARCH_MSP430) + # define LZO_SIZEOF_VOID_P 2 + #elif (LZO_ARCH_H8300) +-# if defined(__NORMAL_MODE__) +-# define LZO_SIZEOF_VOID_P 2 +-# elif defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) +-# define LZO_SIZEOF_VOID_P 4 ++# if defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) ++ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_WORDSIZE == 4) ++# if defined(__NORMAL_MODE__) ++# define LZO_SIZEOF_VOID_P 2 ++# else ++# define LZO_SIZEOF_VOID_P 4 ++# endif + # else ++ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_WORDSIZE == 2) + # define LZO_SIZEOF_VOID_P 2 + # endif + # if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x040000ul)) && (LZO_SIZEOF_INT == 4) +@@ -2316,7 +2452,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t)) + # define LZO_ABI_BIG_ENDIAN 1 + #elif (LZO_ARCH_IA64) && (LZO_OS_POSIX_LINUX || LZO_OS_WIN64) + # define LZO_ABI_LITTLE_ENDIAN 1 +-#elif (LZO_ARCH_ALPHA || LZO_ARCH_AMD64 || LZO_ARCH_BLACKFIN || LZO_ARCH_CRIS || LZO_ARCH_I086 || LZO_ARCH_I386 || LZO_ARCH_MSP430) ++#elif (LZO_ARCH_ALPHA || LZO_ARCH_AMD64 || LZO_ARCH_BLACKFIN || LZO_ARCH_CRIS || LZO_ARCH_I086 || LZO_ARCH_I386 || LZO_ARCH_MSP430 || LZO_ARCH_RISCV) + # define LZO_ABI_LITTLE_ENDIAN 1 + #elif (LZO_ARCH_AVR32 || LZO_ARCH_M68K || LZO_ARCH_S390 || LZO_ARCH_SPU) + # define LZO_ABI_BIG_ENDIAN 1 +@@ -2330,10 +2466,14 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t)) + # define LZO_ABI_BIG_ENDIAN 1 + #elif 1 && defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__) + # define LZO_ABI_LITTLE_ENDIAN 1 ++#elif 1 && (LZO_ARCH_ARM) && defined(__ARM_BIG_ENDIAN) && ((__ARM_BIG_ENDIAN)+0) ++# define LZO_ABI_BIG_ENDIAN 1 + #elif 1 && (LZO_ARCH_ARM) && defined(__ARMEB__) && !defined(__ARMEL__) + # define LZO_ABI_BIG_ENDIAN 1 + #elif 1 && (LZO_ARCH_ARM) && defined(__ARMEL__) && !defined(__ARMEB__) + # define LZO_ABI_LITTLE_ENDIAN 1 ++#elif 1 && (LZO_ARCH_ARM) && defined(_MSC_VER) && defined(_WIN32) ++# define LZO_ABI_LITTLE_ENDIAN 1 + #elif 1 && (LZO_ARCH_ARM && LZO_CC_ARMCC_ARMCC) + # if defined(__BIG_ENDIAN) && defined(__LITTLE_ENDIAN) + # error "unexpected configuration - check your compiler defines" +@@ -2343,10 +2483,14 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t)) + # define LZO_ABI_LITTLE_ENDIAN 1 + # endif + # define LZO_ABI_LITTLE_ENDIAN 1 ++#elif 1 && (LZO_ARCH_ARM64) && defined(__ARM_BIG_ENDIAN) && ((__ARM_BIG_ENDIAN)+0) ++# define LZO_ABI_BIG_ENDIAN 1 + #elif 1 && (LZO_ARCH_ARM64) && defined(__AARCH64EB__) && !defined(__AARCH64EL__) + # define LZO_ABI_BIG_ENDIAN 1 + #elif 1 && (LZO_ARCH_ARM64) && defined(__AARCH64EL__) && !defined(__AARCH64EB__) + # define LZO_ABI_LITTLE_ENDIAN 1 ++#elif 1 && (LZO_ARCH_ARM64) && defined(_MSC_VER) && defined(_WIN32) ++# define LZO_ABI_LITTLE_ENDIAN 1 + #elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEB__) && !defined(__MIPSEL__) + # define LZO_ABI_BIG_ENDIAN 1 + #elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEL__) && !defined(__MIPSEB__) +@@ -2388,6 +2532,12 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t)) + # define LZO_ABI_IP32L64 1 + # define LZO_INFO_ABI_PM "ip32l64" + #endif ++#if (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_VOID_P == 4 && LZO_WORDSIZE == 8) ++# define LZO_ABI_IP32W64 1 ++# ifndef LZO_INFO_ABI_PM ++# define LZO_INFO_ABI_PM "ip32w64" ++# endif ++#endif + #if 0 + #elif !defined(__LZO_LIBC_OVERRIDE) + #if (LZO_LIBC_NAKED) +@@ -2475,20 +2625,43 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t)) + # endif + #elif (LZO_ARCH_ARM) + # if defined(__ARM_FEATURE_UNALIGNED) ++# if ((__ARM_FEATURE_UNALIGNED)+0) ++# ifndef LZO_OPT_UNALIGNED16 ++# define LZO_OPT_UNALIGNED16 1 ++# endif ++# ifndef LZO_OPT_UNALIGNED32 ++# define LZO_OPT_UNALIGNED32 1 ++# endif ++# endif ++# elif 1 && (LZO_ARCH_ARM_THUMB2) ++# ifndef LZO_OPT_UNALIGNED16 ++# define LZO_OPT_UNALIGNED16 1 ++# endif ++# ifndef LZO_OPT_UNALIGNED32 ++# define LZO_OPT_UNALIGNED32 1 ++# endif ++# elif 1 && defined(__ARM_ARCH) && ((__ARM_ARCH)+0 >= 7) + # ifndef LZO_OPT_UNALIGNED16 + # define LZO_OPT_UNALIGNED16 1 + # endif + # ifndef LZO_OPT_UNALIGNED32 + # define LZO_OPT_UNALIGNED32 1 + # endif +-# elif defined(__TARGET_ARCH_ARM) && ((__TARGET_ARCH_ARM+0) >= 7) ++# elif 1 && defined(__TARGET_ARCH_ARM) && ((__TARGET_ARCH_ARM)+0 >= 7) + # ifndef LZO_OPT_UNALIGNED16 + # define LZO_OPT_UNALIGNED16 1 + # endif + # ifndef LZO_OPT_UNALIGNED32 + # define LZO_OPT_UNALIGNED32 1 + # endif +-# elif defined(__TARGET_ARCH_ARM) && ((__TARGET_ARCH_ARM+0) >= 6) && !defined(__TARGET_PROFILE_M) ++# elif 1 && defined(__TARGET_ARCH_ARM) && ((__TARGET_ARCH_ARM)+0 >= 6) && (defined(__TARGET_PROFILE_A) || defined(__TARGET_PROFILE_R)) ++# ifndef LZO_OPT_UNALIGNED16 ++# define LZO_OPT_UNALIGNED16 1 ++# endif ++# ifndef LZO_OPT_UNALIGNED32 ++# define LZO_OPT_UNALIGNED32 1 ++# endif ++# elif 1 && defined(_MSC_VER) && defined(_M_ARM) && ((_M_ARM)+0 >= 7) + # ifndef LZO_OPT_UNALIGNED16 + # define LZO_OPT_UNALIGNED16 1 + # endif +@@ -2540,7 +2713,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t)) + #elif (LZO_ARCH_POWERPC) + # define LZO_OPT_PREFER_PREINC 1 + # define LZO_OPT_PREFER_PREDEC 1 +-# if (LZO_ABI_BIG_ENDIAN) ++# if (LZO_ABI_BIG_ENDIAN) || (LZO_WORDSIZE == 8) + # ifndef LZO_OPT_UNALIGNED16 + # define LZO_OPT_UNALIGNED16 1 + # endif +@@ -2553,6 +2726,19 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t)) + # endif + # endif + # endif ++#elif (LZO_ARCH_RISCV) ++# define LZO_OPT_AVOID_UINT_INDEX 1 ++# ifndef LZO_OPT_UNALIGNED16 ++# define LZO_OPT_UNALIGNED16 1 ++# endif ++# ifndef LZO_OPT_UNALIGNED32 ++# define LZO_OPT_UNALIGNED32 1 ++# endif ++# if (LZO_WORDSIZE == 8) ++# ifndef LZO_OPT_UNALIGNED64 ++# define LZO_OPT_UNALIGNED64 1 ++# endif ++# endif + #elif (LZO_ARCH_S390) + # ifndef LZO_OPT_UNALIGNED16 + # define LZO_OPT_UNALIGNED16 1 +@@ -2644,32 +2830,61 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t)) + #if (!(LZO_SIZEOF_PTRDIFF_T+0 > 0 && LZO_SIZEOF_SIZE_T+0 > 0 && LZO_SIZEOF_VOID_P+0 > 0)) + # error "missing defines for sizes" + #endif ++#define LZO_TYPEOF_CHAR 1u ++#define LZO_TYPEOF_SHORT 2u ++#define LZO_TYPEOF_INT 3u ++#define LZO_TYPEOF_LONG 4u ++#define LZO_TYPEOF_LONG_LONG 5u ++#define LZO_TYPEOF___INT8 17u ++#define LZO_TYPEOF___INT16 18u ++#define LZO_TYPEOF___INT32 19u ++#define LZO_TYPEOF___INT64 20u ++#define LZO_TYPEOF___INT128 21u ++#define LZO_TYPEOF___INT256 22u ++#define LZO_TYPEOF___MODE_QI 33u ++#define LZO_TYPEOF___MODE_HI 34u ++#define LZO_TYPEOF___MODE_SI 35u ++#define LZO_TYPEOF___MODE_DI 36u ++#define LZO_TYPEOF___MODE_TI 37u ++#define LZO_TYPEOF_CHAR_P 129u + #if !defined(lzo_llong_t) + #if (LZO_SIZEOF_LONG_LONG+0 > 0) +-__lzo_gnuc_extension__ typedef long long lzo_llong_t__; +-__lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__; ++# if !(LZO_LANG_ASSEMBLER) ++ __lzo_gnuc_extension__ typedef long long lzo_llong_t__; ++ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__; ++# endif + # define lzo_llong_t lzo_llong_t__ + # define lzo_ullong_t lzo_ullong_t__ + #endif + #endif + #if !defined(lzo_int16e_t) +-#if (LZO_SIZEOF_LONG == 2) ++#if (LZO_CFG_PREFER_TYPEOF_ACC_INT16E_T == LZO_TYPEOF_SHORT) && (LZO_SIZEOF_SHORT != 2) ++# undef LZO_CFG_PREFER_TYPEOF_ACC_INT16E_T ++#endif ++#if (LZO_SIZEOF_LONG == 2) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT16E_T == LZO_TYPEOF_SHORT) + # define lzo_int16e_t long + # define lzo_uint16e_t unsigned long +-#elif (LZO_SIZEOF_INT == 2) ++# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF_LONG ++#elif (LZO_SIZEOF_INT == 2) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT16E_T == LZO_TYPEOF_SHORT) + # define lzo_int16e_t int + # define lzo_uint16e_t unsigned int ++# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF_INT + #elif (LZO_SIZEOF_SHORT == 2) + # define lzo_int16e_t short int + # define lzo_uint16e_t unsigned short int ++# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF_SHORT + #elif 1 && !(LZO_CFG_TYPE_NO_MODE_HI) && (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x025f00ul) || LZO_CC_LLVM) ++# if !(LZO_LANG_ASSEMBLER) + typedef int lzo_int16e_hi_t__ __attribute__((__mode__(__HI__))); + typedef unsigned int lzo_uint16e_hi_t__ __attribute__((__mode__(__HI__))); ++# endif + # define lzo_int16e_t lzo_int16e_hi_t__ + # define lzo_uint16e_t lzo_uint16e_hi_t__ ++# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF___MODE_HI + #elif (LZO_SIZEOF___INT16 == 2) + # define lzo_int16e_t __int16 + # define lzo_uint16e_t unsigned __int16 ++# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF___INT16 + #else + #endif + #endif +@@ -2679,33 +2894,47 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__; + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16e_t) == LZO_SIZEOF_LZO_INT16E_T) + #endif + #if !defined(lzo_int32e_t) +-#if (LZO_SIZEOF_LONG == 4) ++#if (LZO_CFG_PREFER_TYPEOF_ACC_INT32E_T == LZO_TYPEOF_INT) && (LZO_SIZEOF_INT != 4) ++# undef LZO_CFG_PREFER_TYPEOF_ACC_INT32E_T ++#endif ++#if (LZO_SIZEOF_LONG == 4) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT32E_T == LZO_TYPEOF_INT) + # define lzo_int32e_t long int + # define lzo_uint32e_t unsigned long int ++# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF_LONG + #elif (LZO_SIZEOF_INT == 4) + # define lzo_int32e_t int + # define lzo_uint32e_t unsigned int ++# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF_INT + #elif (LZO_SIZEOF_SHORT == 4) + # define lzo_int32e_t short int + # define lzo_uint32e_t unsigned short int ++# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF_SHORT + #elif (LZO_SIZEOF_LONG_LONG == 4) + # define lzo_int32e_t lzo_llong_t + # define lzo_uint32e_t lzo_ullong_t ++# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF_LONG_LONG + #elif 1 && !(LZO_CFG_TYPE_NO_MODE_SI) && (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x025f00ul) || LZO_CC_LLVM) && (__INT_MAX__+0 > 2147483647L) ++# if !(LZO_LANG_ASSEMBLER) + typedef int lzo_int32e_si_t__ __attribute__((__mode__(__SI__))); + typedef unsigned int lzo_uint32e_si_t__ __attribute__((__mode__(__SI__))); ++# endif + # define lzo_int32e_t lzo_int32e_si_t__ + # define lzo_uint32e_t lzo_uint32e_si_t__ ++# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF___MODE_SI + #elif 1 && !(LZO_CFG_TYPE_NO_MODE_SI) && (LZO_CC_GNUC >= 0x025f00ul) && defined(__AVR__) && (__LONG_MAX__+0 == 32767L) ++# if !(LZO_LANG_ASSEMBLER) + typedef int lzo_int32e_si_t__ __attribute__((__mode__(__SI__))); + typedef unsigned int lzo_uint32e_si_t__ __attribute__((__mode__(__SI__))); ++# endif + # define lzo_int32e_t lzo_int32e_si_t__ + # define lzo_uint32e_t lzo_uint32e_si_t__ + # define LZO_INT32_C(c) (c##LL) + # define LZO_UINT32_C(c) (c##ULL) ++# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF___MODE_SI + #elif (LZO_SIZEOF___INT32 == 4) + # define lzo_int32e_t __int32 + # define lzo_uint32e_t unsigned __int32 ++# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF___INT32 + #else + #endif + #endif +@@ -2716,21 +2945,28 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__; + #endif + #if !defined(lzo_int64e_t) + #if (LZO_SIZEOF___INT64 == 8) +-# if (LZO_CC_BORLANDC) && !(LZO_CFG_TYPE_PREFER___INT64) +-# define LZO_CFG_TYPE_PREFER___INT64 1 ++# if (LZO_CC_BORLANDC) && !defined(LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T) ++# define LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T LZO_TYPEOF___INT64 + # endif + #endif ++#if (LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF_LONG_LONG) && (LZO_SIZEOF_LONG_LONG != 8) ++# undef LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T ++#endif ++#if (LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF___INT64) && (LZO_SIZEOF___INT64 != 8) ++# undef LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T ++#endif + #if (LZO_SIZEOF_INT == 8) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG) + # define lzo_int64e_t int + # define lzo_uint64e_t unsigned int +-# define LZO_SIZEOF_LZO_INT64E_T LZO_SIZEOF_INT +-#elif (LZO_SIZEOF_LONG == 8) ++# define LZO_TYPEOF_LZO_INT64E_T LZO_TYPEOF_INT ++#elif (LZO_SIZEOF_LONG == 8) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF_LONG_LONG) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF___INT64) + # define lzo_int64e_t long int + # define lzo_uint64e_t unsigned long int +-# define LZO_SIZEOF_LZO_INT64E_T LZO_SIZEOF_LONG +-#elif (LZO_SIZEOF_LONG_LONG == 8) && !(LZO_CFG_TYPE_PREFER___INT64) ++# define LZO_TYPEOF_LZO_INT64E_T LZO_TYPEOF_LONG ++#elif (LZO_SIZEOF_LONG_LONG == 8) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF___INT64) + # define lzo_int64e_t lzo_llong_t + # define lzo_uint64e_t lzo_ullong_t ++# define LZO_TYPEOF_LZO_INT64E_T LZO_TYPEOF_LONG_LONG + # if (LZO_CC_BORLANDC) + # define LZO_INT64_C(c) ((c) + 0ll) + # define LZO_UINT64_C(c) ((c) + 0ull) +@@ -2741,10 +2977,10 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__; + # define LZO_INT64_C(c) (c##LL) + # define LZO_UINT64_C(c) (c##ULL) + # endif +-# define LZO_SIZEOF_LZO_INT64E_T LZO_SIZEOF_LONG_LONG + #elif (LZO_SIZEOF___INT64 == 8) + # define lzo_int64e_t __int64 + # define lzo_uint64e_t unsigned __int64 ++# define LZO_TYPEOF_LZO_INT64E_T LZO_TYPEOF___INT64 + # if (LZO_CC_BORLANDC) + # define LZO_INT64_C(c) ((c) + 0i64) + # define LZO_UINT64_C(c) ((c) + 0ui64) +@@ -2752,11 +2988,11 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__; + # define LZO_INT64_C(c) (c##i64) + # define LZO_UINT64_C(c) (c##ui64) + # endif +-# define LZO_SIZEOF_LZO_INT64E_T LZO_SIZEOF___INT64 + #else + #endif + #endif + #if defined(lzo_int64e_t) ++# define LZO_SIZEOF_LZO_INT64E_T 8 + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64e_t) == 8) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64e_t) == LZO_SIZEOF_LZO_INT64E_T) + #endif +@@ -2765,14 +3001,17 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__; + # define lzo_int32l_t lzo_int32e_t + # define lzo_uint32l_t lzo_uint32e_t + # define LZO_SIZEOF_LZO_INT32L_T LZO_SIZEOF_LZO_INT32E_T ++# define LZO_TYPEOF_LZO_INT32L_T LZO_TYPEOF_LZO_INT32E_T + #elif (LZO_SIZEOF_INT >= 4) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG) + # define lzo_int32l_t int + # define lzo_uint32l_t unsigned int + # define LZO_SIZEOF_LZO_INT32L_T LZO_SIZEOF_INT ++# define LZO_TYPEOF_LZO_INT32L_T LZO_SIZEOF_INT + #elif (LZO_SIZEOF_LONG >= 4) + # define lzo_int32l_t long int + # define lzo_uint32l_t unsigned long int + # define LZO_SIZEOF_LZO_INT32L_T LZO_SIZEOF_LONG ++# define LZO_TYPEOF_LZO_INT32L_T LZO_SIZEOF_LONG + #else + # error "lzo_int32l_t" + #endif +@@ -2786,6 +3025,7 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__; + # define lzo_int64l_t lzo_int64e_t + # define lzo_uint64l_t lzo_uint64e_t + # define LZO_SIZEOF_LZO_INT64L_T LZO_SIZEOF_LZO_INT64E_T ++# define LZO_TYPEOF_LZO_INT64L_T LZO_TYPEOF_LZO_INT64E_T + #else + #endif + #endif +@@ -2798,10 +3038,12 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__; + # define lzo_int32f_t lzo_int64l_t + # define lzo_uint32f_t lzo_uint64l_t + # define LZO_SIZEOF_LZO_INT32F_T LZO_SIZEOF_LZO_INT64L_T ++# define LZO_TYPEOF_LZO_INT32F_T LZO_TYPEOF_LZO_INT64L_T + #else + # define lzo_int32f_t lzo_int32l_t + # define lzo_uint32f_t lzo_uint32l_t + # define LZO_SIZEOF_LZO_INT32F_T LZO_SIZEOF_LZO_INT32L_T ++# define LZO_TYPEOF_LZO_INT32F_T LZO_TYPEOF_LZO_INT32L_T + #endif + #endif + #if 1 +@@ -2813,6 +3055,7 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__; + # define lzo_int64f_t lzo_int64l_t + # define lzo_uint64f_t lzo_uint64l_t + # define LZO_SIZEOF_LZO_INT64F_T LZO_SIZEOF_LZO_INT64L_T ++# define LZO_TYPEOF_LZO_INT64F_T LZO_TYPEOF_LZO_INT64L_T + #else + #endif + #endif +@@ -2823,33 +3066,43 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__; + #if !defined(lzo_intptr_t) + #if 1 && (LZO_OS_OS400 && (LZO_SIZEOF_VOID_P == 16)) + # define __LZO_INTPTR_T_IS_POINTER 1 +- typedef char* lzo_intptr_t; +- typedef char* lzo_uintptr_t; ++# if !(LZO_LANG_ASSEMBLER) ++ typedef char * lzo_intptr_t; ++ typedef char * lzo_uintptr_t; ++# endif + # define lzo_intptr_t lzo_intptr_t + # define lzo_uintptr_t lzo_uintptr_t + # define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_VOID_P ++# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_CHAR_P + #elif (LZO_CC_MSC && (_MSC_VER >= 1300) && (LZO_SIZEOF_VOID_P == 4) && (LZO_SIZEOF_INT == 4)) ++# if !(LZO_LANG_ASSEMBLER) + typedef __w64 int lzo_intptr_t; + typedef __w64 unsigned int lzo_uintptr_t; ++# endif + # define lzo_intptr_t lzo_intptr_t + # define lzo_uintptr_t lzo_uintptr_t + # define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_INT ++# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_INT + #elif (LZO_SIZEOF_SHORT == LZO_SIZEOF_VOID_P) && (LZO_SIZEOF_INT > LZO_SIZEOF_VOID_P) + # define lzo_intptr_t short + # define lzo_uintptr_t unsigned short + # define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_SHORT ++# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_SHORT + #elif (LZO_SIZEOF_INT >= LZO_SIZEOF_VOID_P) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG) + # define lzo_intptr_t int + # define lzo_uintptr_t unsigned int + # define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_INT ++# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_INT + #elif (LZO_SIZEOF_LONG >= LZO_SIZEOF_VOID_P) + # define lzo_intptr_t long + # define lzo_uintptr_t unsigned long + # define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_LONG ++# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_LONG + #elif (LZO_SIZEOF_LZO_INT64L_T >= LZO_SIZEOF_VOID_P) + # define lzo_intptr_t lzo_int64l_t + # define lzo_uintptr_t lzo_uint64l_t + # define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_LZO_INT64L_T ++# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_LZO_INT64L_T + #else + # error "lzo_intptr_t" + #endif +@@ -2863,34 +3116,43 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__; + #if (LZO_WORDSIZE == LZO_SIZEOF_LZO_INTPTR_T) && !(__LZO_INTPTR_T_IS_POINTER) + # define lzo_word_t lzo_uintptr_t + # define lzo_sword_t lzo_intptr_t +-# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LZO_INTPTR_T ++# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LZO_INTPTR_T ++# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_LZO_INTPTR_T + #elif (LZO_WORDSIZE == LZO_SIZEOF_LONG) + # define lzo_word_t unsigned long + # define lzo_sword_t long +-# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LONG ++# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LONG ++# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_LONG + #elif (LZO_WORDSIZE == LZO_SIZEOF_INT) + # define lzo_word_t unsigned int + # define lzo_sword_t int +-# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_INT ++# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_INT ++# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_INT + #elif (LZO_WORDSIZE == LZO_SIZEOF_SHORT) + # define lzo_word_t unsigned short + # define lzo_sword_t short +-# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_SHORT ++# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_SHORT ++# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_SHORT + #elif (LZO_WORDSIZE == 1) + # define lzo_word_t unsigned char + # define lzo_sword_t signed char +-# define LZO_SIZEOF_LZO_WORD_T 1 ++# define LZO_SIZEOF_LZO_WORD_T 1 ++# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_CHAR + #elif (LZO_WORDSIZE == LZO_SIZEOF_LZO_INT64L_T) + # define lzo_word_t lzo_uint64l_t + # define lzo_sword_t lzo_int64l_t +-# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LZO_INT64L_T ++# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LZO_INT64L_T ++# define LZO_TYPEOF_LZO_WORD_T LZO_SIZEOF_LZO_INT64L_T + #elif (LZO_ARCH_SPU) && (LZO_CC_GNUC) + #if 0 ++# if !(LZO_LANG_ASSEMBLER) + typedef unsigned lzo_word_t __attribute__((__mode__(__V16QI__))); + typedef int lzo_sword_t __attribute__((__mode__(__V16QI__))); ++# endif + # define lzo_word_t lzo_word_t + # define lzo_sword_t lzo_sword_t + # define LZO_SIZEOF_LZO_WORD_T 16 ++# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF___MODE_V16QI + #endif + #else + # error "lzo_word_t" +@@ -2905,6 +3167,7 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__; + #define lzo_int8_t signed char + #define lzo_uint8_t unsigned char + #define LZO_SIZEOF_LZO_INT8_T 1 ++#define LZO_TYPEOF_LZO_INT8_T LZO_TYPEOF_CHAR + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int8_t) == 1) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int8_t) == sizeof(lzo_uint8_t)) + #endif +@@ -2912,6 +3175,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int8_t) == sizeof(lzo_uint8_t)) + #define lzo_int16_t lzo_int16e_t + #define lzo_uint16_t lzo_uint16e_t + #define LZO_SIZEOF_LZO_INT16_T LZO_SIZEOF_LZO_INT16E_T ++#define LZO_TYPEOF_LZO_INT16_T LZO_TYPEOF_LZO_INT16E_T + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16_t) == 2) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16_t) == sizeof(lzo_uint16_t)) + #endif +@@ -2919,6 +3183,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16_t) == sizeof(lzo_uint16_t)) + #define lzo_int32_t lzo_int32e_t + #define lzo_uint32_t lzo_uint32e_t + #define LZO_SIZEOF_LZO_INT32_T LZO_SIZEOF_LZO_INT32E_T ++#define LZO_TYPEOF_LZO_INT32_T LZO_TYPEOF_LZO_INT32E_T + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32_t) == 4) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32_t) == sizeof(lzo_uint32_t)) + #endif +@@ -2926,6 +3191,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32_t) == sizeof(lzo_uint32_t)) + #define lzo_int64_t lzo_int64e_t + #define lzo_uint64_t lzo_uint64e_t + #define LZO_SIZEOF_LZO_INT64_T LZO_SIZEOF_LZO_INT64E_T ++#define LZO_TYPEOF_LZO_INT64_T LZO_TYPEOF_LZO_INT64E_T + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64_t) == 8) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64_t) == sizeof(lzo_uint64_t)) + #endif +@@ -2933,6 +3199,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64_t) == sizeof(lzo_uint64_t)) + #define lzo_int_least32_t lzo_int32l_t + #define lzo_uint_least32_t lzo_uint32l_t + #define LZO_SIZEOF_LZO_INT_LEAST32_T LZO_SIZEOF_LZO_INT32L_T ++#define LZO_TYPEOF_LZO_INT_LEAST32_T LZO_TYPEOF_LZO_INT32L_T + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least32_t) >= 4) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least32_t) == sizeof(lzo_uint_least32_t)) + #endif +@@ -2940,6 +3207,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least32_t) == sizeof(lzo_uint_leas + #define lzo_int_least64_t lzo_int64l_t + #define lzo_uint_least64_t lzo_uint64l_t + #define LZO_SIZEOF_LZO_INT_LEAST64_T LZO_SIZEOF_LZO_INT64L_T ++#define LZO_TYPEOF_LZO_INT_LEAST64_T LZO_TYPEOF_LZO_INT64L_T + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least64_t) >= 8) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least64_t) == sizeof(lzo_uint_least64_t)) + #endif +@@ -2947,6 +3215,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least64_t) == sizeof(lzo_uint_leas + #define lzo_int_fast32_t lzo_int32f_t + #define lzo_uint_fast32_t lzo_uint32f_t + #define LZO_SIZEOF_LZO_INT_FAST32_T LZO_SIZEOF_LZO_INT32F_T ++#define LZO_TYPEOF_LZO_INT_FAST32_T LZO_TYPEOF_LZO_INT32F_T + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast32_t) >= 4) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast32_t) == sizeof(lzo_uint_fast32_t)) + #endif +@@ -2954,6 +3223,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast32_t) == sizeof(lzo_uint_fast3 + #define lzo_int_fast64_t lzo_int64f_t + #define lzo_uint_fast64_t lzo_uint64f_t + #define LZO_SIZEOF_LZO_INT_FAST64_T LZO_SIZEOF_LZO_INT64F_T ++#define LZO_TYPEOF_LZO_INT_FAST64_T LZO_TYPEOF_LZO_INT64F_T + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast64_t) >= 8) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast64_t) == sizeof(lzo_uint_fast64_t)) + #endif +@@ -3020,7 +3290,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast64_t) == sizeof(lzo_uint_fast6 + #undef LZO_HAVE_CONFIG_H + #include "minilzo.h" + +-#if !defined(MINILZO_VERSION) || (MINILZO_VERSION != 0x2080) ++#if !defined(MINILZO_VERSION) || (MINILZO_VERSION != 0x20a0) + # error "version mismatch in miniLZO source files" + #endif + +@@ -3042,13 +3312,23 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast64_t) == sizeof(lzo_uint_fast6 + #if defined(__LZOCONF_H) || defined(__LZOCONF_H_INCLUDED) + # error "include this file first" + #endif +-#include "lzo/lzoconf.h" ++#if defined(LZO_CFG_BUILD_DLL) && (LZO_CFG_BUILD_DLL+0) && !defined(__LZO_EXPORT1) && !defined(__LZO_EXPORT2) && 0 ++#ifndef __LZODEFS_H_INCLUDED ++#if defined(LZO_HAVE_CONFIG_H) ++# include <config.h> ++#endif ++#include <limits.h> ++#include <stddef.h> ++#include <lzo/lzodefs.h> ++#endif ++#endif ++#include <lzo/lzoconf.h> + #if defined(LZO_CFG_EXTRA_CONFIG_HEADER2) + # include LZO_CFG_EXTRA_CONFIG_HEADER2 + #endif + #endif + +-#if (LZO_VERSION < 0x2080) || !defined(__LZOCONF_H_INCLUDED) ++#if !defined(__LZOCONF_H_INCLUDED) || (LZO_VERSION+0 != 0x20a0) + # error "version mismatch" + #endif + +@@ -3065,6 +3345,9 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast64_t) == sizeof(lzo_uint_fast6 + #if (LZO_CC_MSC && (_MSC_VER >= 1800)) + # pragma warning(disable: 4746) + #endif ++#if (LZO_CC_INTELC && (__INTEL_COMPILER >= 900)) ++# pragma warning(disable: 1684) ++#endif + + #if (LZO_CC_SUNPROC) + #if !defined(__cplusplus) +@@ -3074,6 +3357,32 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast64_t) == sizeof(lzo_uint_fast6 + #endif + #endif + ++#if !defined(__LZO_NOEXPORT1) ++# define __LZO_NOEXPORT1 /*empty*/ ++#endif ++#if !defined(__LZO_NOEXPORT2) ++# define __LZO_NOEXPORT2 /*empty*/ ++#endif ++ ++#if 1 ++# define LZO_PUBLIC_DECL(r) LZO_EXTERN(r) ++#endif ++#if 1 ++# define LZO_PUBLIC_IMPL(r) LZO_PUBLIC(r) ++#endif ++#if !defined(LZO_LOCAL_DECL) ++# define LZO_LOCAL_DECL(r) __LZO_EXTERN_C LZO_LOCAL_IMPL(r) ++#endif ++#if !defined(LZO_LOCAL_IMPL) ++# define LZO_LOCAL_IMPL(r) __LZO_NOEXPORT1 r __LZO_NOEXPORT2 __LZO_CDECL ++#endif ++#if 1 ++# define LZO_STATIC_DECL(r) LZO_PRIVATE(r) ++#endif ++#if 1 ++# define LZO_STATIC_IMPL(r) LZO_PRIVATE(r) ++#endif ++ + #if defined(__LZO_IN_MINILZO) || (LZO_CFG_FREESTANDING) + #elif 1 + # include <string.h> +@@ -3269,6 +3578,9 @@ __lzo_static_forceinline unsigned lzo_bitops_ctlz32_func(lzo_uint32_t v) + #elif (LZO_BITOPS_USE_GNUC_BITSCAN) && (LZO_SIZEOF_INT == 4) + unsigned r; r = (unsigned) __builtin_clz(v); return r; + #define lzo_bitops_ctlz32(v) ((unsigned) __builtin_clz(v)) ++#elif (LZO_BITOPS_USE_GNUC_BITSCAN) && (LZO_SIZEOF_LONG == 8) && (LZO_WORDSIZE >= 8) ++ unsigned r; r = (unsigned) __builtin_clzl(v); return r ^ 32; ++#define lzo_bitops_ctlz32(v) (((unsigned) __builtin_clzl(v)) ^ 32) + #else + LZO_UNUSED(v); return 0; + #endif +@@ -3338,25 +3650,20 @@ __lzo_static_forceinline unsigned lzo_bitops_cttz64_func(lzo_uint64_t v) + } + #endif + +-#if 1 && (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || (LZO_CC_GNUC >= 0x020700ul) || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) +-static void __attribute__((__unused__)) +-#else +-__lzo_static_forceinline void +-#endif +-lzo_bitops_unused_funcs(void) ++lzo_unused_funcs_impl(void, lzo_bitops_unused_funcs)(void) + { ++ LZO_UNUSED_FUNC(lzo_bitops_unused_funcs); + LZO_UNUSED_FUNC(lzo_bitops_ctlz32_func); + LZO_UNUSED_FUNC(lzo_bitops_cttz32_func); + #if defined(lzo_uint64_t) + LZO_UNUSED_FUNC(lzo_bitops_ctlz64_func); + LZO_UNUSED_FUNC(lzo_bitops_cttz64_func); + #endif +- LZO_UNUSED_FUNC(lzo_bitops_unused_funcs); + } + + #if defined(__lzo_alignof) && !(LZO_CFG_NO_UNALIGNED) +-#ifndef __lzo_memops_tcheck +-#define __lzo_memops_tcheck(t,a,b) ((void)0, sizeof(t) == (a) && __lzo_alignof(t) == (b)) ++#if !defined(lzo_memops_tcheck__) && 0 ++#define lzo_memops_tcheck__(t,a,b) ((void)0, sizeof(t) == (a) && __lzo_alignof(t) == (b)) + #endif + #endif + #ifndef lzo_memops_TU0p +@@ -3473,9 +3780,9 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(*(lzo_memops_TU1p)0)==1) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(*(lzo_memops_TU2p)0)==2) + #define LZO_MEMOPS_COPY2(dd,ss) \ + * (lzo_memops_TU2p) (lzo_memops_TU0p) (dd) = * (const lzo_memops_TU2p) (const lzo_memops_TU0p) (ss) +-#elif defined(__lzo_memops_tcheck) ++#elif defined(lzo_memops_tcheck__) + #define LZO_MEMOPS_COPY2(dd,ss) \ +- LZO_BLOCK_BEGIN if (__lzo_memops_tcheck(lzo_memops_TU2,2,1)) { \ ++ LZO_BLOCK_BEGIN if (lzo_memops_tcheck__(lzo_memops_TU2,2,1)) { \ + * (lzo_memops_TU2p) (lzo_memops_TU0p) (dd) = * (const lzo_memops_TU2p) (const lzo_memops_TU0p) (ss); \ + } else { LZO_MEMOPS_MOVE2(dd,ss); } LZO_BLOCK_END + #else +@@ -3485,9 +3792,9 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(*(lzo_memops_TU2p)0)==2) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(*(lzo_memops_TU4p)0)==4) + #define LZO_MEMOPS_COPY4(dd,ss) \ + * (lzo_memops_TU4p) (lzo_memops_TU0p) (dd) = * (const lzo_memops_TU4p) (const lzo_memops_TU0p) (ss) +-#elif defined(__lzo_memops_tcheck) ++#elif defined(lzo_memops_tcheck__) + #define LZO_MEMOPS_COPY4(dd,ss) \ +- LZO_BLOCK_BEGIN if (__lzo_memops_tcheck(lzo_memops_TU4,4,1)) { \ ++ LZO_BLOCK_BEGIN if (lzo_memops_tcheck__(lzo_memops_TU4,4,1)) { \ + * (lzo_memops_TU4p) (lzo_memops_TU0p) (dd) = * (const lzo_memops_TU4p) (const lzo_memops_TU0p) (ss); \ + } else { LZO_MEMOPS_MOVE4(dd,ss); } LZO_BLOCK_END + #else +@@ -3504,9 +3811,9 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(*(lzo_memops_TU8p)0)==8) + #elif (LZO_OPT_UNALIGNED32) + #define LZO_MEMOPS_COPY8(dd,ss) \ + LZO_BLOCK_BEGIN LZO_MEMOPS_COPY4(dd,ss); LZO_MEMOPS_COPY4((lzo_memops_TU1p)(lzo_memops_TU0p)(dd)+4,(const lzo_memops_TU1p)(const lzo_memops_TU0p)(ss)+4); LZO_BLOCK_END +-#elif defined(__lzo_memops_tcheck) ++#elif defined(lzo_memops_tcheck__) + #define LZO_MEMOPS_COPY8(dd,ss) \ +- LZO_BLOCK_BEGIN if (__lzo_memops_tcheck(lzo_memops_TU8,8,1)) { \ ++ LZO_BLOCK_BEGIN if (lzo_memops_tcheck__(lzo_memops_TU8,8,1)) { \ + * (lzo_memops_TU8p) (lzo_memops_TU0p) (dd) = * (const lzo_memops_TU8p) (const lzo_memops_TU0p) (ss); \ + } else { LZO_MEMOPS_MOVE8(dd,ss); } LZO_BLOCK_END + #else +@@ -3540,7 +3847,7 @@ __lzo_static_forceinline lzo_uint16_t lzo_memops_get_le16(const lzo_voidp ss) + return v; + } + #if (LZO_OPT_UNALIGNED16) && (LZO_ABI_LITTLE_ENDIAN) +-#define LZO_MEMOPS_GET_LE16(ss) * (const lzo_memops_TU2p) (const lzo_memops_TU0p) (ss) ++#define LZO_MEMOPS_GET_LE16(ss) (* (const lzo_memops_TU2p) (const lzo_memops_TU0p) (ss)) + #else + #define LZO_MEMOPS_GET_LE16(ss) lzo_memops_get_le16(ss) + #endif +@@ -3562,13 +3869,13 @@ __lzo_static_forceinline lzo_uint32_t lzo_memops_get_le32(const lzo_voidp ss) + return v; + } + #if (LZO_OPT_UNALIGNED32) && (LZO_ABI_LITTLE_ENDIAN) +-#define LZO_MEMOPS_GET_LE32(ss) * (const lzo_memops_TU4p) (const lzo_memops_TU0p) (ss) ++#define LZO_MEMOPS_GET_LE32(ss) (* (const lzo_memops_TU4p) (const lzo_memops_TU0p) (ss)) + #else + #define LZO_MEMOPS_GET_LE32(ss) lzo_memops_get_le32(ss) + #endif + + #if (LZO_OPT_UNALIGNED64) && (LZO_ABI_LITTLE_ENDIAN) +-#define LZO_MEMOPS_GET_LE64(ss) * (const lzo_memops_TU8p) (const lzo_memops_TU0p) (ss) ++#define LZO_MEMOPS_GET_LE64(ss) (* (const lzo_memops_TU8p) (const lzo_memops_TU0p) (ss)) + #endif + + __lzo_static_forceinline lzo_uint16_t lzo_memops_get_ne16(const lzo_voidp ss) +@@ -3578,7 +3885,8 @@ __lzo_static_forceinline lzo_uint16_t lzo_memops_get_ne16(const lzo_voidp ss) + return v; + } + #if (LZO_OPT_UNALIGNED16) +-#define LZO_MEMOPS_GET_NE16(ss) * (const lzo_memops_TU2p) (const lzo_memops_TU0p) (ss) ++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(*(lzo_memops_TU2p)0)==2) ++#define LZO_MEMOPS_GET_NE16(ss) (* (const lzo_memops_TU2p) (const lzo_memops_TU0p) (ss)) + #else + #define LZO_MEMOPS_GET_NE16(ss) lzo_memops_get_ne16(ss) + #endif +@@ -3590,13 +3898,15 @@ __lzo_static_forceinline lzo_uint32_t lzo_memops_get_ne32(const lzo_voidp ss) + return v; + } + #if (LZO_OPT_UNALIGNED32) +-#define LZO_MEMOPS_GET_NE32(ss) * (const lzo_memops_TU4p) (const lzo_memops_TU0p) (ss) ++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(*(lzo_memops_TU4p)0)==4) ++#define LZO_MEMOPS_GET_NE32(ss) (* (const lzo_memops_TU4p) (const lzo_memops_TU0p) (ss)) + #else + #define LZO_MEMOPS_GET_NE32(ss) lzo_memops_get_ne32(ss) + #endif + + #if (LZO_OPT_UNALIGNED64) +-#define LZO_MEMOPS_GET_NE64(ss) * (const lzo_memops_TU8p) (const lzo_memops_TU0p) (ss) ++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(*(lzo_memops_TU8p)0)==8) ++#define LZO_MEMOPS_GET_NE64(ss) (* (const lzo_memops_TU8p) (const lzo_memops_TU0p) (ss)) + #endif + + __lzo_static_forceinline void lzo_memops_put_le16(lzo_voidp dd, lzo_uint16_t vv) +@@ -3661,13 +3971,9 @@ __lzo_static_forceinline void lzo_memops_put_ne32(lzo_voidp dd, lzo_uint32_t vv) + #define LZO_MEMOPS_PUT_NE32(dd,vv) lzo_memops_put_ne32(dd,vv) + #endif + +-#if 1 && (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || (LZO_CC_GNUC >= 0x020700ul) || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) +-static void __attribute__((__unused__)) +-#else +-__lzo_static_forceinline void +-#endif +-lzo_memops_unused_funcs(void) ++lzo_unused_funcs_impl(void, lzo_memops_unused_funcs)(void) + { ++ LZO_UNUSED_FUNC(lzo_memops_unused_funcs); + LZO_UNUSED_FUNC(lzo_memops_get_le16); + LZO_UNUSED_FUNC(lzo_memops_get_le32); + LZO_UNUSED_FUNC(lzo_memops_get_ne16); +@@ -3676,7 +3982,6 @@ lzo_memops_unused_funcs(void) + LZO_UNUSED_FUNC(lzo_memops_put_le32); + LZO_UNUSED_FUNC(lzo_memops_put_ne16); + LZO_UNUSED_FUNC(lzo_memops_put_ne32); +- LZO_UNUSED_FUNC(lzo_memops_unused_funcs); + } + + #endif +@@ -3889,11 +4194,16 @@ __lzo_align_gap(const lzo_voidp ptr, lzo_uint size) + #error "__LZO_UINTPTR_T_IS_POINTER is unsupported" + #else + lzo_uintptr_t p, n; ++ if (size < 2) return 0; + p = __lzo_ptr_linear(ptr); ++#if 0 + n = (((p + size - 1) / size) * size) - p; ++#else ++ if ((size & (size - 1)) != 0) ++ return 0; ++ n = size; n = ((p + n - 1) & ~(n - 1)) - p; ++#endif + #endif +- +- assert(size > 0); + assert((long)n >= 0); + assert(n <= size); + return (unsigned)n; +@@ -3906,23 +4216,25 @@ __lzo_align_gap(const lzo_voidp ptr, lzo_uint size) + * keep this copyright string in the executable of your product. + */ + +-static const char __lzo_copyright[] = ++static const char lzo_copyright_[] = + #if !defined(__LZO_IN_MINLZO) + LZO_VERSION_STRING; + #else + "\r\n\n" + "LZO data compression library.\n" +- "$Copyright: LZO Copyright (C) 1996-2014 Markus Franz Xaver Johannes Oberhumer\n" ++ "$Copyright: LZO Copyright (C) 1996-2017 Markus Franz Xaver Johannes Oberhumer\n" + "<markus@oberhumer.com>\n" + "http://www.oberhumer.com $\n\n" + "$Id: LZO version: v" LZO_VERSION_STRING ", " LZO_VERSION_DATE " $\n" + "$Info: " LZO_INFO_STRING " $\n"; + #endif ++static const char lzo_version_string_[] = LZO_VERSION_STRING; ++static const char lzo_version_date_[] = LZO_VERSION_DATE; + + LZO_PUBLIC(const lzo_bytep) + lzo_copyright(void) + { +- return (const lzo_bytep) __lzo_copyright; ++ return (const lzo_bytep) lzo_copyright_; + } + + LZO_PUBLIC(unsigned) +@@ -3934,25 +4246,25 @@ lzo_version(void) + LZO_PUBLIC(const char *) + lzo_version_string(void) + { +- return LZO_VERSION_STRING; ++ return lzo_version_string_; + } + + LZO_PUBLIC(const char *) + lzo_version_date(void) + { +- return LZO_VERSION_DATE; ++ return lzo_version_date_; + } + + LZO_PUBLIC(const lzo_charp) + _lzo_version_string(void) + { +- return LZO_VERSION_STRING; ++ return lzo_version_string_; + } + + LZO_PUBLIC(const lzo_charp) + _lzo_version_date(void) + { +- return LZO_VERSION_DATE; ++ return lzo_version_date_; + } + + #define LZO_BASE 65521u +@@ -4324,7 +4636,7 @@ int __far __pascal LibMain ( int a, short b, short c, long d ) + #endif + + #if !defined(__LZO_IN_MINILZO) +-#include "lzo/lzo1x.h" ++#include <lzo/lzo1x.h> + #endif + + #ifndef LZO_EOF_CODE +@@ -4516,7 +4828,7 @@ extern "C" { + + #if !defined(DVAL_ASSERT) + #if defined(__LZO_HASH_INCREMENTAL) && !defined(NDEBUG) +-#if (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x020700ul) || LZO_CC_LLVM) ++#if 1 && (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || (LZO_CC_GNUC >= 0x020700ul) || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) + static void __attribute__((__unused__)) + #else + static void +diff --git a/grub-core/lib/minilzo/minilzo.h b/grub-core/lib/minilzo/minilzo.h +index 793745467..c1c229757 100644 +--- a/grub-core/lib/minilzo/minilzo.h ++++ b/grub-core/lib/minilzo/minilzo.h +@@ -2,7 +2,7 @@ + + This file is part of the LZO real-time data compression library. + +- Copyright (C) 1996-2014 Markus Franz Xaver Johannes Oberhumer ++ Copyright (C) 1996-2017 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + The LZO library is free software; you can redistribute it and/or +@@ -32,15 +32,25 @@ + */ + + +-#ifndef __MINILZO_H +-#define __MINILZO_H 1 ++#ifndef __MINILZO_H_INCLUDED ++#define __MINILZO_H_INCLUDED 1 + +-#define MINILZO_VERSION 0x2080 ++#define MINILZO_VERSION 0x20a0 /* 2.10 */ + +-#ifdef __LZOCONF_H ++#if defined(__LZOCONF_H_INCLUDED) + # error "you cannot use both LZO and miniLZO" + #endif + ++/* internal Autoconf configuration file - only used when building miniLZO */ ++#ifdef MINILZO_HAVE_CONFIG_H ++# include <config.h> ++#endif ++#include <limits.h> ++#include <stddef.h> ++ ++#ifndef __LZODEFS_H_INCLUDED ++#include "lzodefs.h" ++#endif + #undef LZO_HAVE_CONFIG_H + #include "lzoconf.h" + +@@ -92,3 +102,5 @@ lzo1x_decompress_safe ( const lzo_bytep src, lzo_uint src_len, + + #endif /* already included */ + ++ ++/* vim:set ts=4 sw=4 et: */ diff --git a/debian/patches/mkconfig-loopback.patch b/debian/patches/mkconfig-loopback.patch new file mode 100644 index 0000000..686117f --- /dev/null +++ b/debian/patches/mkconfig-loopback.patch @@ -0,0 +1,96 @@ +From 3f0c88e2ffa15cfb34641397cc9bdbe39085f1ba Mon Sep 17 00:00:00 2001 +From: Colin Watson <cjwatson@debian.org> +Date: Mon, 13 Jan 2014 12:13:00 +0000 +Subject: Handle filesystems loop-mounted on file images + +Improve prepare_grub_to_access_device to emit appropriate commands for +such filesystems, and ignore them in Linux grub.d scripts. + +This is needed for Ubuntu's Wubi installation method. + +This patch isn't inherently Debian/Ubuntu-specific. losetup and +/proc/mounts are Linux-specific, though, so we might need to refine this +before sending it upstream. The changes to the Linux grub.d scripts +might be better handled by integrating 10_lupin properly instead. + +Patch-Name: mkconfig-loopback.patch +--- + util/grub-mkconfig_lib.in | 24 ++++++++++++++++++++++++ + util/grub.d/10_linux.in | 5 +++++ + util/grub.d/20_linux_xen.in | 5 +++++ + 3 files changed, 34 insertions(+) + +diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in +index 17f9b3e58..e62cfc22b 100644 +--- a/util/grub-mkconfig_lib.in ++++ b/util/grub-mkconfig_lib.in +@@ -133,6 +133,22 @@ prepare_grub_to_access_device () + esac + done + ++ loop_file= ++ case $1 in ++ /dev/loop/*|/dev/loop[0-9]) ++ grub_loop_device="${1#/dev/}" ++ loop_file=`losetup "$1" | sed -e "s/^[^(]*(\([^)]\+\)).*/\1/"` ++ case $loop_file in ++ /dev/*) ;; ++ *) ++ loop_device="$1" ++ shift ++ set -- `"${grub_probe}" --target=device "${loop_file}"` "$@" ++ ;; ++ esac ++ ;; ++ esac ++ + # Abstraction modules aren't auto-loaded. + abstraction="`"${grub_probe}" --device $@ --target=abstraction`" + for module in ${abstraction} ; do +@@ -169,6 +185,14 @@ prepare_grub_to_access_device () + fi + fi + IFS="$old_ifs" ++ ++ if [ "x${loop_file}" != x ]; then ++ loop_mountpoint="$(awk '"'${loop_file}'" ~ "^"$2 && $2 != "/" { print $2 }' /proc/mounts | tail -n1)" ++ if [ "x${loop_mountpoint}" != x ]; then ++ echo "loopback ${grub_loop_device} ${loop_file#$loop_mountpoint}" ++ echo "set root=(${grub_loop_device})" ++ fi ++ fi + } + + grub_get_device_id () +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index 9446d6833..46696dd66 100644 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -40,6 +40,11 @@ fi + case ${GRUB_DEVICE} in + /dev/loop/*|/dev/loop[0-9]) + GRUB_DEVICE=`losetup ${GRUB_DEVICE} | sed -e "s/^[^(]*(\([^)]\+\)).*/\1/"` ++ # We can't cope with devices loop-mounted from files here. ++ case ${GRUB_DEVICE} in ++ /dev/*) ;; ++ *) exit 0 ;; ++ esac + ;; + esac + +diff --git a/util/grub.d/20_linux_xen.in b/util/grub.d/20_linux_xen.in +index 3b1f47049..7620a14fa 100644 +--- a/util/grub.d/20_linux_xen.in ++++ b/util/grub.d/20_linux_xen.in +@@ -40,6 +40,11 @@ fi + case ${GRUB_DEVICE} in + /dev/loop/*|/dev/loop[0-9]) + GRUB_DEVICE=`losetup ${GRUB_DEVICE} | sed -e "s/^[^(]*(\([^)]\+\)).*/\1/"` ++ # We can't cope with devices loop-mounted from files here. ++ case ${GRUB_DEVICE} in ++ /dev/*) ;; ++ *) exit 0 ;; ++ esac + ;; + esac + diff --git a/debian/patches/mkconfig-nonexistent-loopback.patch b/debian/patches/mkconfig-nonexistent-loopback.patch new file mode 100644 index 0000000..9c55c1d --- /dev/null +++ b/debian/patches/mkconfig-nonexistent-loopback.patch @@ -0,0 +1,55 @@ +From 989f83d664999deeb28d03a847e8f00a28639d7d Mon Sep 17 00:00:00 2001 +From: Colin Watson <cjwatson@ubuntu.com> +Date: Mon, 13 Jan 2014 12:13:08 +0000 +Subject: Avoid getting confused by inaccessible loop device backing paths + +Bug-Ubuntu: https://bugs.launchpad.net/bugs/938724 +Forwarded: no +Last-Update: 2021-09-24 + +Patch-Name: mkconfig-nonexistent-loopback.patch +--- + util/grub-mkconfig_lib.in | 2 +- + util/grub.d/30_os-prober.in | 9 +++++---- + 2 files changed, 6 insertions(+), 5 deletions(-) + +diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in +index e62cfc22b..b6a1d7dec 100644 +--- a/util/grub-mkconfig_lib.in ++++ b/util/grub-mkconfig_lib.in +@@ -143,7 +143,7 @@ prepare_grub_to_access_device () + *) + loop_device="$1" + shift +- set -- `"${grub_probe}" --target=device "${loop_file}"` "$@" ++ set -- `"${grub_probe}" --target=device "${loop_file}"` "$@" || return 0 + ;; + esac + ;; +diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in +index 37d5f05b5..e2ec80eb9 100644 +--- a/util/grub.d/30_os-prober.in ++++ b/util/grub.d/30_os-prober.in +@@ -222,6 +222,11 @@ EOF + LINITRD="${LINITRD#/boot}" + fi + ++ if [ -z "${prepare_boot_cache}" ]; then ++ prepare_boot_cache="$(prepare_grub_to_access_device ${LBOOT} | grub_add_tab)" ++ [ "${prepare_boot_cache}" ] || continue ++ fi ++ + onstr="$(gettext_printf "(on %s)" "${DEVICE}")" + recovery_params="$(echo "${LPARAMS}" | grep 'single\|recovery')" || true + counter=1 +@@ -233,10 +238,6 @@ EOF + fi + used_osprober_linux_ids="$used_osprober_linux_ids 'osprober-gnulinux-$LKERNEL-${recovery_params}-$counter-$boot_device_id'" + +- if [ -z "${prepare_boot_cache}" ]; then +- prepare_boot_cache="$(prepare_grub_to_access_device ${LBOOT} | grub_add_tab)" +- fi +- + # The GRUB_DISABLE_SUBMENU option used to be different than others since it was + # mentioned in the documentation that has to be set to 'y' instead of 'true' to + # enable it. This caused a lot of confusion to users that set the option to 'y', diff --git a/debian/patches/mkconfig-other-inits.patch b/debian/patches/mkconfig-other-inits.patch new file mode 100644 index 0000000..75bf4e4 --- /dev/null +++ b/debian/patches/mkconfig-other-inits.patch @@ -0,0 +1,90 @@ +From f8382052a32839fbc3715d1c5076f1b6bbcbcb63 Mon Sep 17 00:00:00 2001 +From: Colin Watson <cjwatson@debian.org> +Date: Sat, 3 Jan 2015 12:04:59 +0000 +Subject: Generate alternative init entries in advanced menu + +Add fallback boot entries for alternative installed init systems. Based +on patches from Michael Biebl and Didier Roche. + +Bug-Debian: https://bugs.debian.org/757298 +Bug-Debian: https://bugs.debian.org/773173 +Forwarded: no +Last-Update: 2017-06-23 + +Patch-Name: mkconfig-other-inits.patch +--- + util/grub.d/10_linux.in | 10 ++++++++++ + util/grub.d/20_linux_xen.in | 11 +++++++++++ + 2 files changed, 21 insertions(+) + +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index 635c609d6..4e09797f8 100644 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -32,6 +32,7 @@ export TEXTDOMAIN=@PACKAGE@ + export TEXTDOMAINDIR="@localedir@" + + CLASS="--class gnu-linux --class gnu --class os" ++SUPPORTED_INITS="sysvinit:/lib/sysvinit/init systemd:/lib/systemd/systemd upstart:/sbin/upstart" + + if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then + OS=GNU/Linux +@@ -127,6 +128,8 @@ linux_entry () + case $type in + recovery) + title="$(gettext_printf "%s, with Linux %s (%s)" "${os}" "${version}" "$(gettext "${GRUB_RECOVERY_TITLE}")")" ;; ++ init-*) ++ title="$(gettext_printf "%s, with Linux %s (%s)" "${os}" "${version}" "${type#init-}")" ;; + *) + title="$(gettext_printf "%s, with Linux %s" "${os}" "${version}")" ;; + esac +@@ -389,6 +392,13 @@ while [ "x$list" != "x" ] ; do + + linux_entry "${OS}" "${version}" advanced \ + "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" ++ for supported_init in ${SUPPORTED_INITS}; do ++ init_path="${supported_init#*:}" ++ if [ -x "${init_path}" ] && [ "$(readlink -f /sbin/init)" != "$(readlink -f "${init_path}")" ]; then ++ linux_entry "${OS}" "${version}" "init-${supported_init%%:*}" \ ++ "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT} init=${init_path}" ++ fi ++ done + if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then + linux_entry "${OS}" "${version}" recovery \ + "${GRUB_CMDLINE_LINUX_RECOVERY} ${GRUB_CMDLINE_LINUX}" +diff --git a/util/grub.d/20_linux_xen.in b/util/grub.d/20_linux_xen.in +index 64e26e4b4..d99751a94 100644 +--- a/util/grub.d/20_linux_xen.in ++++ b/util/grub.d/20_linux_xen.in +@@ -27,6 +27,7 @@ export TEXTDOMAIN=@PACKAGE@ + export TEXTDOMAINDIR="@localedir@" + + CLASS="--class gnu-linux --class gnu --class os --class xen" ++SUPPORTED_INITS="sysvinit:/lib/sysvinit/init systemd:/lib/systemd/systemd upstart:/sbin/upstart" + + if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then + OS=GNU/Linux +@@ -123,6 +124,8 @@ linux_entry_xsm () + if [ x$type != xsimple ] ; then + if [ x$type = xrecovery ] ; then + title="$(gettext_printf "%s, with Xen %s and Linux %s (%s)" "${os}" "${xen_version}" "${version}" "$(gettext "${GRUB_RECOVERY_TITLE}")")" ++ elif [ "${type#init-}" != "$type" ] ; then ++ title="$(gettext_printf "%s, with Xen %s and Linux %s (%s)" "${os}" "${xen_version}" "${version}" "${type#init-}")" + else + title="$(gettext_printf "%s, with Xen %s and Linux %s" "${os}" "${xen_version}" "${version}")" + fi +@@ -346,6 +349,14 @@ while [ "x${xen_list}" != "x" ] ; do + + linux_entry "${OS}" "${version}" "${xen_version}" advanced \ + "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" "${GRUB_CMDLINE_XEN} ${GRUB_CMDLINE_XEN_DEFAULT}" ++ for supported_init in ${SUPPORTED_INITS}; do ++ init_path="${supported_init#*:}" ++ if [ -x "${init_path}" ] && [ "$(readlink -f /sbin/init)" != "$(readlink -f "${init_path}")" ]; then ++ linux_entry "${OS}" "${version}" "${xen_version}" "init-${supported_init%%:*}" \ ++ "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT} init=${init_path}" "${GRUB_CMDLINE_XEN} ${GRUB_CMDLINE_XEN_DEFAULT}" ++ ++ fi ++ done + if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then + linux_entry "${OS}" "${version}" "${xen_version}" recovery \ + "single ${GRUB_CMDLINE_LINUX}" "${GRUB_CMDLINE_XEN}" diff --git a/debian/patches/mkconfig-recovery-title.patch b/debian/patches/mkconfig-recovery-title.patch new file mode 100644 index 0000000..74c8b9e --- /dev/null +++ b/debian/patches/mkconfig-recovery-title.patch @@ -0,0 +1,130 @@ +From fd81fffa2d498d66dce65b50da2532690c806ea4 Mon Sep 17 00:00:00 2001 +From: Colin Watson <cjwatson@ubuntu.com> +Date: Mon, 13 Jan 2014 12:13:33 +0000 +Subject: Add GRUB_RECOVERY_TITLE option + +This allows the controversial "recovery mode" text to be customised. + +Bug-Ubuntu: https://bugs.launchpad.net/bugs/1240360 +Forwarded: no +Last-Update: 2013-12-25 + +Patch-Name: mkconfig-recovery-title.patch +--- + docs/grub.texi | 5 +++++ + util/grub-mkconfig.in | 7 ++++++- + util/grub.d/10_hurd.in | 4 ++-- + util/grub.d/10_kfreebsd.in | 2 +- + util/grub.d/10_linux.in | 2 +- + util/grub.d/10_netbsd.in | 2 +- + util/grub.d/20_linux_xen.in | 2 +- + 7 files changed, 17 insertions(+), 7 deletions(-) + +diff --git a/docs/grub.texi b/docs/grub.texi +index 0b58dafb2..86e46f33b 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -1577,6 +1577,11 @@ a console is restricted or limited. + This option is only effective when GRUB was configured with the + @option{--enable-quick-boot} option. + ++@item GRUB_RECOVERY_TITLE ++This option sets the English text of the string that will be displayed in ++parentheses to indicate that a boot option is provided to help users recover ++a broken system. The default is "recovery mode". ++ + @end table + + The following options are still accepted for compatibility with existing +diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in +index fa9c53a92..0d39c8f05 100644 +--- a/util/grub-mkconfig.in ++++ b/util/grub-mkconfig.in +@@ -201,6 +201,10 @@ GRUB_ACTUAL_DEFAULT="$GRUB_DEFAULT" + + if [ "x${GRUB_ACTUAL_DEFAULT}" = "xsaved" ] ; then GRUB_ACTUAL_DEFAULT="`"${grub_editenv}" - list | sed -n '/^saved_entry=/ s,^saved_entry=,,p'`" ; fi + ++if [ "x${GRUB_RECOVERY_TITLE}" = "x" ]; then ++ GRUB_RECOVERY_TITLE="recovery mode" ++fi ++ + + # These are defined in this script, export them here so that user can + # override them. +@@ -257,7 +261,8 @@ export GRUB_DEFAULT \ + GRUB_BADRAM \ + GRUB_OS_PROBER_SKIP_LIST \ + GRUB_DISABLE_SUBMENU \ +- GRUB_RECORDFAIL_TIMEOUT ++ GRUB_RECORDFAIL_TIMEOUT \ ++ GRUB_RECOVERY_TITLE + + if test "x${grub_cfg}" != "x"; then + rm -f "${grub_cfg}.new" +diff --git a/util/grub.d/10_hurd.in b/util/grub.d/10_hurd.in +index 3663d360e..8f6041894 100644 +--- a/util/grub.d/10_hurd.in ++++ b/util/grub.d/10_hurd.in +@@ -88,8 +88,8 @@ hurd_entry () { + + if [ x$type != xsimple ] ; then + if [ x$type = xrecovery ] ; then +- title="$(gettext_printf "%s, with Hurd %s (recovery mode)" "${OS}" "${kernel_base}")" +- oldtitle="$OS using $kernel_base (recovery mode)" ++ title="$(gettext_printf "%s, with Hurd %s (%s)" "${OS}" "${kernel_base}" "$(gettext "${GRUB_RECOVERY_TITLE}")")" ++ oldtitle="$OS using $kernel_base ($GRUB_RECOVERY_TITLE)" + else + title="$(gettext_printf "%s, with Hurd %s" "${OS}" "${kernel_base}")" + oldtitle="$OS using $kernel_base" +diff --git a/util/grub.d/10_kfreebsd.in b/util/grub.d/10_kfreebsd.in +index 199b20e16..bbd63cf74 100644 +--- a/util/grub.d/10_kfreebsd.in ++++ b/util/grub.d/10_kfreebsd.in +@@ -76,7 +76,7 @@ kfreebsd_entry () + fi + if [ x$type != xsimple ] ; then + if [ x$type = xrecovery ] ; then +- title="$(gettext_printf "%s, with kFreeBSD %s (recovery mode)" "${os}" "${version}")" ++ title="$(gettext_printf "%s, with kFreeBSD %s (%s)" "${os}" "${version}" "$(gettext "${GRUB_RECOVERY_TITLE}")")" + else + title="$(gettext_printf "%s, with kFreeBSD %s" "${os}" "${version}")" + fi +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index 64204c216..f88a2de10 100644 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -126,7 +126,7 @@ linux_entry () + if [ x$type != xsimple ] ; then + case $type in + recovery) +- title="$(gettext_printf "%s, with Linux %s (recovery mode)" "${os}" "${version}")" ;; ++ title="$(gettext_printf "%s, with Linux %s (%s)" "${os}" "${version}" "$(gettext "${GRUB_RECOVERY_TITLE}")")" ;; + *) + title="$(gettext_printf "%s, with Linux %s" "${os}" "${version}")" ;; + esac +diff --git a/util/grub.d/10_netbsd.in b/util/grub.d/10_netbsd.in +index dc0cd1b17..336895012 100644 +--- a/util/grub.d/10_netbsd.in ++++ b/util/grub.d/10_netbsd.in +@@ -102,7 +102,7 @@ netbsd_entry () + + if [ x$type != xsimple ] ; then + if [ x$type = xrecovery ] ; then +- title="$(gettext_printf "%s, with kernel %s (via %s, recovery mode)" "${OS}" "$(echo ${kernel} | sed -e 's,^.*/,,')" "${loader}")" ++ title="$(gettext_printf "%s, with kernel %s (via %s, %s)" "${OS}" "$(echo ${kernel} | sed -e 's,^.*/,,')" "${loader}" "$(gettext "${GRUB_RECOVERY_TITLE}")")" + else + title="$(gettext_printf "%s, with kernel %s (via %s)" "${OS}" "$(echo ${kernel} | sed -e 's,^.*/,,')" "${loader}")" + fi +diff --git a/util/grub.d/20_linux_xen.in b/util/grub.d/20_linux_xen.in +index 7620a14fa..64e26e4b4 100644 +--- a/util/grub.d/20_linux_xen.in ++++ b/util/grub.d/20_linux_xen.in +@@ -122,7 +122,7 @@ linux_entry_xsm () + fi + if [ x$type != xsimple ] ; then + if [ x$type = xrecovery ] ; then +- title="$(gettext_printf "%s, with Xen %s and Linux %s (recovery mode)" "${os}" "${xen_version}" "${version}")" ++ title="$(gettext_printf "%s, with Xen %s and Linux %s (%s)" "${os}" "${xen_version}" "${version}" "$(gettext "${GRUB_RECOVERY_TITLE}")")" + else + title="$(gettext_printf "%s, with Xen %s and Linux %s" "${os}" "${xen_version}" "${version}")" + fi diff --git a/debian/patches/mkconfig-signed-kernel.patch b/debian/patches/mkconfig-signed-kernel.patch new file mode 100644 index 0000000..aa93fad --- /dev/null +++ b/debian/patches/mkconfig-signed-kernel.patch @@ -0,0 +1,48 @@ +From 9eefe03f4b52e65cb4f372e0ff12a2b68cada425 Mon Sep 17 00:00:00 2001 +From: Colin Watson <cjwatson@ubuntu.com> +Date: Mon, 13 Jan 2014 12:13:21 +0000 +Subject: Generate configuration for signed UEFI kernels if available + +Forwarded: no +Last-Update: 2013-12-25 + +Patch-Name: mkconfig-signed-kernel.patch +--- + util/grub.d/10_linux.in | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index 1603a75a7..1b8c6e146 100644 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -161,8 +161,16 @@ linux_entry () + message="$(gettext_printf "Loading Linux %s ..." ${version})" + sed "s/^/$submenu_indentation/" << EOF + echo '$(echo "$message" | grub_quote)' ++EOF ++ if test -d /sys/firmware/efi && test -e "${linux}.efi.signed"; then ++ sed "s/^/$submenu_indentation/" << EOF ++ linux ${rel_dirname}/${basename}.efi.signed root=${linux_root_device_thisversion} ro ${args} ++EOF ++ else ++ sed "s/^/$submenu_indentation/" << EOF + linux ${rel_dirname}/${basename} root=${linux_root_device_thisversion} ro ${args} + EOF ++ fi + if test -n "${initrd}" ; then + # TRANSLATORS: ramdisk isn't identifier. Should be translated. + message="$(gettext_printf "Loading initial ramdisk ...")" +@@ -214,6 +222,13 @@ submenu_indentation="" + is_top_level=true + while [ "x$list" != "x" ] ; do + linux=`version_find_latest $list` ++ case $linux in ++ *.efi.signed) ++ # We handle these in linux_entry. ++ list=`echo $list | tr ' ' '\n' | grep -vx $linux | tr '\n' ' '` ++ continue ++ ;; ++ esac + gettext_printf "Found linux image: %s\n" "$linux" >&2 + basename=`basename $linux` + dirname=`dirname $linux` diff --git a/debian/patches/mkconfig-ubuntu-distributor.patch b/debian/patches/mkconfig-ubuntu-distributor.patch new file mode 100644 index 0000000..8ec05e0 --- /dev/null +++ b/debian/patches/mkconfig-ubuntu-distributor.patch @@ -0,0 +1,37 @@ +From 84938bc37ee1cfabf84915ad4b6c8904b4770ef6 Mon Sep 17 00:00:00 2001 +From: Mario Limonciello <Mario_Limonciello@dell.com> +Date: Mon, 13 Jan 2014 12:13:14 +0000 +Subject: Remove GNU/Linux from default distributor string for Ubuntu + +Ubuntu is called "Ubuntu", not "Ubuntu GNU/Linux". + +Author: Colin Watson <cjwatson@debian.org> +Author: Harald Sitter <apachelogger@kubuntu.org> +Forwarded: not-needed +Last-Update: 2013-12-25 + +Patch-Name: mkconfig-ubuntu-distributor.patch +--- + util/grub.d/10_linux.in | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index f215e3213..1603a75a7 100644 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -32,7 +32,14 @@ CLASS="--class gnu-linux --class gnu --class os" + if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then + OS=GNU/Linux + else +- OS="${GRUB_DISTRIBUTOR} GNU/Linux" ++ case ${GRUB_DISTRIBUTOR} in ++ Ubuntu|Kubuntu) ++ OS="${GRUB_DISTRIBUTOR}" ++ ;; ++ *) ++ OS="${GRUB_DISTRIBUTOR} GNU/Linux" ++ ;; ++ esac + CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1|LC_ALL=C sed 's,[^[:alnum:]_],_,g') ${CLASS}" + fi + diff --git a/debian/patches/mkconfig-ubuntu-recovery.patch b/debian/patches/mkconfig-ubuntu-recovery.patch new file mode 100644 index 0000000..1fa5bde --- /dev/null +++ b/debian/patches/mkconfig-ubuntu-recovery.patch @@ -0,0 +1,107 @@ +From 13c9a7101d2611bbc02b464ef4e32b02cfc7860b Mon Sep 17 00:00:00 2001 +From: Colin Watson <cjwatson@ubuntu.com> +Date: Mon, 13 Jan 2014 12:13:06 +0000 +Subject: "single" -> "recovery" when friendly-recovery is installed +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If configured with --enable-ubuntu-recovery, also set nomodeset for +recovery mode, and disable 'set gfxpayload=keep' even if the system +normally supports it. See +https://launchpad.net/ubuntu/+spec/desktop-o-xorg-tools-and-processes. + +Author: Stéphane Graber <stgraber@ubuntu.com> +Forwarded: no +Last-Update: 2013-12-25 + +Patch-Name: mkconfig-ubuntu-recovery.patch +--- + configure.ac | 11 +++++++++++ + util/grub.d/10_linux.in | 16 ++++++++++++++-- + util/grub.d/30_os-prober.in | 2 +- + 3 files changed, 26 insertions(+), 3 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 7517fc49d..74778a6f8 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1904,6 +1904,17 @@ fi + AC_SUBST([LIBZFS]) + AC_SUBST([LIBNVPAIR]) + ++AC_ARG_ENABLE([ubuntu-recovery], ++ [AS_HELP_STRING([--enable-ubuntu-recovery], ++ [adjust boot options for the Ubuntu recovery mode (default=no)])], ++ [], [enable_ubuntu_recovery=no]) ++if test x"$enable_ubuntu_recovery" = xyes ; then ++ UBUNTU_RECOVERY=1 ++else ++ UBUNTU_RECOVERY=0 ++fi ++AC_SUBST([UBUNTU_RECOVERY]) ++ + LIBS="" + + AC_SUBST([FONT_SOURCE]) +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index 46696dd66..f215e3213 100644 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -20,6 +20,7 @@ set -e + prefix="@prefix@" + exec_prefix="@exec_prefix@" + datarootdir="@datarootdir@" ++ubuntu_recovery="@UBUNTU_RECOVERY@" + + . "$pkgdatadir/grub-mkconfig_lib" + +@@ -84,6 +85,15 @@ esac + + title_correction_code= + ++if [ -x /lib/recovery-mode/recovery-menu ]; then ++ GRUB_CMDLINE_LINUX_RECOVERY=recovery ++else ++ GRUB_CMDLINE_LINUX_RECOVERY=single ++fi ++if [ "$ubuntu_recovery" = 1 ]; then ++ GRUB_CMDLINE_LINUX_RECOVERY="$GRUB_CMDLINE_LINUX_RECOVERY nomodeset" ++fi ++ + linux_entry () + { + os="$1" +@@ -123,7 +133,9 @@ linux_entry () + if [ "x$GRUB_GFXPAYLOAD_LINUX" != xtext ]; then + echo " load_video" | sed "s/^/$submenu_indentation/" + fi +- echo " set gfxpayload=$GRUB_GFXPAYLOAD_LINUX" | sed "s/^/$submenu_indentation/" ++ if [ "$ubuntu_recovery" = 0 ] || [ x$type != xrecovery ]; then ++ echo " set gfxpayload=$GRUB_GFXPAYLOAD_LINUX" | sed "s/^/$submenu_indentation/" ++ fi + fi + + echo " insmod gzio" | sed "s/^/$submenu_indentation/" +@@ -288,7 +300,7 @@ while [ "x$list" != "x" ] ; do + "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" + if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then + linux_entry "${OS}" "${version}" recovery \ +- "single ${GRUB_CMDLINE_LINUX}" ++ "${GRUB_CMDLINE_LINUX_RECOVERY} ${GRUB_CMDLINE_LINUX}" + fi + + list=`echo $list | tr ' ' '\n' | fgrep -vx "$linux" | tr '\n' ' '` +diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in +index 5984e92d2..37d5f05b5 100644 +--- a/util/grub.d/30_os-prober.in ++++ b/util/grub.d/30_os-prober.in +@@ -223,7 +223,7 @@ EOF + fi + + onstr="$(gettext_printf "(on %s)" "${DEVICE}")" +- recovery_params="$(echo "${LPARAMS}" | grep single)" || true ++ recovery_params="$(echo "${LPARAMS}" | grep 'single\|recovery')" || true + counter=1 + while echo "$used_osprober_linux_ids" | grep 'osprober-gnulinux-$LKERNEL-${recovery_params}-$counter-$boot_device_id' > /dev/null; do + counter=$((counter+1)); diff --git a/debian/patches/mkimage-fix-section-sizes.patch b/debian/patches/mkimage-fix-section-sizes.patch new file mode 100644 index 0000000..107bd0e --- /dev/null +++ b/debian/patches/mkimage-fix-section-sizes.patch @@ -0,0 +1,109 @@ +From e5be30174c7ed596ca2fd28d636a4fbc26a0199a Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas <javierm@redhat.com> +Date: Fri, 16 Apr 2021 21:37:23 +0200 +Subject: util/mkimage: Some fixes to PE binaries section size calculation + +Commit f60ba9e5945 (util/mkimage: Refactor section setup to use a helper) +added a helper function to setup PE sections, but it caused regressions +in some arches where the natural alignment lead to wrong section sizes. + +This patch fixes a few things that were caused the section sizes to be +calculated wrongly. These fixes are: + + * Only align the virtual memory addresses but not the raw data offsets. + * Use aligned sizes for virtual memory sizes but not for raw data sizes. + * Always align the sizes to set the virtual memory sizes. + +These seems to not cause problems for x64 and aa64 EFI platforms but was +a problem for ia64. Because the size of the ".data" and "mods" sections +were wrong and didn't have the correct content. Which lead to GRUB not +being able to load any built-in module. + +Reported-by: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> +Signed-off-by: Javier Martinez Canillas <javierm@redhat.com> + +Bug-Debian: https://bugs.debian.org/987103 + +Patch-Name: mkimage-fix-section-sizes.patch +--- + util/mkimage.c | 21 ++++++++++++--------- + 1 file changed, 12 insertions(+), 9 deletions(-) + +diff --git a/util/mkimage.c b/util/mkimage.c +index a26cf76f7..b84311f1f 100644 +--- a/util/mkimage.c ++++ b/util/mkimage.c +@@ -841,7 +841,7 @@ init_pe_section(const struct grub_install_image_target_desc *image_target, + + section->raw_data_offset = grub_host_to_target32 (*rda); + section->raw_data_size = grub_host_to_target32 (rsz); +- (*rda) = ALIGN_UP (*rda + rsz, GRUB_PE32_FILE_ALIGNMENT); ++ (*rda) = *rda + rsz; + + section->characteristics = grub_host_to_target32 (characteristics); + +@@ -1309,7 +1309,7 @@ grub_install_generate_image (const char *dir, const char *prefix, + char *pe_img, *pe_sbat, *header; + struct grub_pe32_section_table *section; + size_t n_sections = 4; +- size_t scn_size; ++ size_t scn_size, raw_size; + grub_uint32_t vma, raw_data; + size_t pe_size, header_size; + struct grub_pe32_coff_header *c; +@@ -1410,7 +1410,8 @@ grub_install_generate_image (const char *dir, const char *prefix, + GRUB_PE32_SCN_MEM_EXECUTE | + GRUB_PE32_SCN_MEM_READ); + +- scn_size = ALIGN_UP (layout.kernel_size - layout.exec_size, GRUB_PE32_FILE_ALIGNMENT); ++ raw_size = layout.kernel_size - layout.exec_size; ++ scn_size = ALIGN_UP (raw_size, GRUB_PE32_FILE_ALIGNMENT); + /* ALIGN_UP (sbat_size, GRUB_PE32_FILE_ALIGNMENT) is done earlier. */ + PE_OHDR (o32, o64, data_size) = grub_host_to_target32 (scn_size + sbat_size + + ALIGN_UP (total_module_size, +@@ -1418,15 +1419,16 @@ grub_install_generate_image (const char *dir, const char *prefix, + + section = init_pe_section (image_target, section, ".data", + &vma, scn_size, image_target->section_align, +- &raw_data, scn_size, ++ &raw_data, raw_size, + GRUB_PE32_SCN_CNT_INITIALIZED_DATA | + GRUB_PE32_SCN_MEM_READ | + GRUB_PE32_SCN_MEM_WRITE); + +- scn_size = pe_size - layout.reloc_size - sbat_size - raw_data; ++ raw_size = pe_size - layout.reloc_size - sbat_size - raw_data; ++ scn_size = ALIGN_UP (raw_size, GRUB_PE32_FILE_ALIGNMENT); + section = init_pe_section (image_target, section, "mods", + &vma, scn_size, image_target->section_align, +- &raw_data, scn_size, ++ &raw_data, raw_size, + GRUB_PE32_SCN_CNT_INITIALIZED_DATA | + GRUB_PE32_SCN_MEM_READ | + GRUB_PE32_SCN_MEM_WRITE); +@@ -1436,21 +1438,22 @@ grub_install_generate_image (const char *dir, const char *prefix, + pe_sbat = pe_img + raw_data; + grub_util_load_image (sbat_path, pe_sbat); + ++ scn_size = ALIGN_UP (sbat_size, GRUB_PE32_FILE_ALIGNMENT); + section = init_pe_section (image_target, section, ".sbat", +- &vma, sbat_size, ++ &vma, scn_size, + image_target->section_align, + &raw_data, sbat_size, + GRUB_PE32_SCN_CNT_INITIALIZED_DATA | + GRUB_PE32_SCN_MEM_READ); + } + +- scn_size = layout.reloc_size; ++ scn_size = ALIGN_UP (layout.reloc_size, GRUB_PE32_FILE_ALIGNMENT); + PE_OHDR (o32, o64, base_relocation_table.rva) = grub_host_to_target32 (vma); + PE_OHDR (o32, o64, base_relocation_table.size) = grub_host_to_target32 (scn_size); + memcpy (pe_img + raw_data, layout.reloc_section, scn_size); + init_pe_section (image_target, section, ".reloc", + &vma, scn_size, image_target->section_align, +- &raw_data, scn_size, ++ &raw_data, layout.reloc_size, + GRUB_PE32_SCN_CNT_INITIALIZED_DATA | + GRUB_PE32_SCN_MEM_DISCARDABLE | + GRUB_PE32_SCN_MEM_READ); diff --git a/debian/patches/mkrescue-efi-modules.patch b/debian/patches/mkrescue-efi-modules.patch new file mode 100644 index 0000000..8b6df4f --- /dev/null +++ b/debian/patches/mkrescue-efi-modules.patch @@ -0,0 +1,35 @@ +From 41f0edb8bebe40b7d9302418100034dead84dfe9 Mon Sep 17 00:00:00 2001 +From: Mario Limonciello <Mario_Limonciello@dell.com> +Date: Mon, 13 Jan 2014 12:12:59 +0000 +Subject: Build vfat into EFI boot images + +Author: Colin Watson <cjwatson@ubuntu.com> +Bug-Ubuntu: https://bugs.launchpad.net/bugs/677758 +Forwarded: http://lists.gnu.org/archive/html/grub-devel/2011-01/msg00028.html +Last-Update: 2016-09-18 + +Patch-Name: mkrescue-efi-modules.patch +--- + util/grub-mkrescue.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/util/grub-mkrescue.c b/util/grub-mkrescue.c +index fb4dcc6d5..fcb35726c 100644 +--- a/util/grub-mkrescue.c ++++ b/util/grub-mkrescue.c +@@ -753,6 +753,7 @@ main (int argc, char *argv[]) + + grub_install_push_module ("part_gpt"); + grub_install_push_module ("part_msdos"); ++ grub_install_push_module ("fat"); + + imgname = grub_util_path_concat (2, efidir_efi_boot, "bootia64.efi"); + make_image_fwdisk_abs (GRUB_INSTALL_PLATFORM_IA64_EFI, "ia64-efi", imgname); +@@ -830,6 +831,7 @@ main (int argc, char *argv[]) + free (efidir); + grub_install_pop_module (); + grub_install_pop_module (); ++ grub_install_pop_module (); + } + + grub_install_push_module ("part_apple"); diff --git a/debian/patches/net-read-bracketed-ipv6-addr.patch b/debian/patches/net-read-bracketed-ipv6-addr.patch new file mode 100644 index 0000000..93ee7d7 --- /dev/null +++ b/debian/patches/net-read-bracketed-ipv6-addr.patch @@ -0,0 +1,255 @@ +From c7e2338904e5e1e2546f1097cad1a020615463cf Mon Sep 17 00:00:00 2001 +From: Aaron Miller <aaronmiller@fb.com> +Date: Thu, 27 Oct 2016 17:39:49 -0400 +Subject: net: read bracketed ipv6 addrs and port numbers + +Allow specifying port numbers for http and tftp paths, and allow ipv6 addresses +to be recognized with brackets around them, which is required to specify a port +number + +Last-Update: 2021-09-24 + +Patch-Name: net-read-bracketed-ipv6-addr.patch +--- + grub-core/net/http.c | 21 ++++++++-- + grub-core/net/net.c | 93 +++++++++++++++++++++++++++++++++++++++++--- + grub-core/net/tftp.c | 6 ++- + include/grub/net.h | 1 + + 4 files changed, 110 insertions(+), 11 deletions(-) + +diff --git a/grub-core/net/http.c b/grub-core/net/http.c +index b616cf40b..3fe155f1b 100644 +--- a/grub-core/net/http.c ++++ b/grub-core/net/http.c +@@ -312,12 +312,14 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial) + int i; + struct grub_net_buff *nb; + grub_err_t err; ++ char* server = file->device->net->server; ++ int port = file->device->net->port; + + nb = grub_netbuff_alloc (GRUB_NET_TCP_RESERVE_SIZE + + sizeof ("GET ") - 1 + + grub_strlen (data->filename) + + sizeof (" HTTP/1.1\r\nHost: ") - 1 +- + grub_strlen (file->device->net->server) ++ + grub_strlen (server) + sizeof (":XXXXXXXXXX") + + sizeof ("\r\nUser-Agent: " PACKAGE_STRING + "\r\n") - 1 + + sizeof ("Range: bytes=XXXXXXXXXXXXXXXXXXXX" +@@ -356,7 +358,7 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial) + sizeof (" HTTP/1.1\r\nHost: ") - 1); + + ptr = nb->tail; +- err = grub_netbuff_put (nb, grub_strlen (file->device->net->server)); ++ err = grub_netbuff_put (nb, grub_strlen (server)); + if (err) + { + grub_netbuff_free (nb); +@@ -365,6 +367,15 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial) + grub_memcpy (ptr, file->device->net->server, + grub_strlen (file->device->net->server)); + ++ if (port) ++ { ++ ptr = nb->tail; ++ grub_snprintf ((char *) ptr, ++ sizeof (":XXXXXXXXXX"), ++ ":%d", ++ port); ++ } ++ + ptr = nb->tail; + err = grub_netbuff_put (nb, + sizeof ("\r\nUser-Agent: " PACKAGE_STRING "\r\n") +@@ -390,8 +401,10 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial) + grub_netbuff_put (nb, 2); + grub_memcpy (ptr, "\r\n", 2); + +- data->sock = grub_net_tcp_open (file->device->net->server, +- HTTP_PORT, http_receive, ++ grub_dprintf ("http", "opening path %s on host %s TCP port %d\n", ++ data->filename, server, port ? port : HTTP_PORT); ++ data->sock = grub_net_tcp_open (server, ++ port ? port : HTTP_PORT, http_receive, + http_err, NULL, + file); + if (!data->sock) +diff --git a/grub-core/net/net.c b/grub-core/net/net.c +index 4d3eb5c1a..15a2f29a9 100644 +--- a/grub-core/net/net.c ++++ b/grub-core/net/net.c +@@ -442,6 +442,12 @@ parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest) + grub_uint16_t newip[8]; + const char *ptr = val; + int word, quaddot = -1; ++ int bracketed = 0; ++ ++ if (ptr[0] == '[') { ++ bracketed = 1; ++ ptr++; ++ } + + if (ptr[0] == ':' && ptr[1] != ':') + return 0; +@@ -480,6 +486,9 @@ parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest) + grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0])); + } + grub_memcpy (ip, newip, 16); ++ if (bracketed && *ptr == ']') { ++ ptr++; ++ } + if (rest) + *rest = ptr; + return 1; +@@ -1265,8 +1274,10 @@ grub_net_open_real (const char *name) + { + grub_net_app_level_t proto; + const char *protname, *server; ++ char *host; + grub_size_t protnamelen; + int try; ++ int port = 0; + + if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0) + { +@@ -1304,6 +1315,72 @@ grub_net_open_real (const char *name) + return NULL; + } + ++ char* port_start; ++ /* ipv6 or port specified? */ ++ if ((port_start = grub_strchr (server, ':'))) ++ { ++ char* ipv6_begin; ++ if((ipv6_begin = grub_strchr (server, '['))) ++ { ++ char* ipv6_end = grub_strchr (server, ']'); ++ if(!ipv6_end) ++ { ++ grub_error (GRUB_ERR_NET_BAD_ADDRESS, ++ N_("mismatched [ in address")); ++ return NULL; ++ } ++ /* port number after bracketed ipv6 addr */ ++ if(ipv6_end[1] == ':') ++ { ++ port = grub_strtoul (ipv6_end + 2, NULL, 10); ++ if(port > 65535) ++ { ++ grub_error (GRUB_ERR_NET_BAD_ADDRESS, ++ N_("bad port number")); ++ return NULL; ++ } ++ } ++ host = grub_strndup (ipv6_begin, (ipv6_end - ipv6_begin) + 1); ++ } ++ else ++ { ++ if (grub_strchr (port_start + 1, ':')) ++ { ++ int iplen = grub_strlen (server); ++ /* bracket bare ipv6 addrs */ ++ host = grub_malloc (iplen + 3); ++ if(!host) ++ { ++ return NULL; ++ } ++ host[0] = '['; ++ grub_memcpy (host + 1, server, iplen); ++ host[iplen + 1] = ']'; ++ host[iplen + 2] = '\0'; ++ } ++ else ++ { ++ /* hostname:port or ipv4:port */ ++ port = grub_strtol (port_start + 1, NULL, 10); ++ if(port > 65535) ++ { ++ grub_error (GRUB_ERR_NET_BAD_ADDRESS, ++ N_("bad port number")); ++ return NULL; ++ } ++ host = grub_strndup (server, port_start - server); ++ } ++ } ++ } ++ else ++ { ++ host = grub_strdup (server); ++ } ++ if (!host) ++ { ++ return NULL; ++ } ++ + for (try = 0; try < 2; try++) + { + FOR_NET_APP_LEVEL (proto) +@@ -1313,15 +1390,19 @@ grub_net_open_real (const char *name) + { + grub_net_t ret = grub_zalloc (sizeof (*ret)); + if (!ret) +- return NULL; +- ret->protocol = proto; +- ret->server = grub_strdup (server); +- if (!ret->server) ++ grub_free (host); ++ if (host) + { +- grub_free (ret); +- return NULL; ++ ret->server = grub_strdup (host); ++ if (!ret->server) ++ { ++ grub_free (ret); ++ return NULL; ++ } + } + ret->fs = &grub_net_fs; ++ ret->protocol = proto; ++ ret->port = port; + return ret; + } + } +diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c +index 7f44b30f5..f3e787938 100644 +--- a/grub-core/net/tftp.c ++++ b/grub-core/net/tftp.c +@@ -295,6 +295,7 @@ tftp_open (struct grub_file *file, const char *filename) + grub_err_t err; + grub_uint8_t *nbd; + grub_net_network_level_address_t addr; ++ int port = file->device->net->port; + + data = grub_zalloc (sizeof (*data)); + if (!data) +@@ -361,12 +362,15 @@ tftp_open (struct grub_file *file, const char *filename) + err = grub_net_resolve_address (file->device->net->server, &addr); + if (err) + { ++ grub_dprintf ("tftp", "file_size is %llu, block_size is %llu\n", ++ (unsigned long long)data->file_size, ++ (unsigned long long)data->block_size); + grub_free (data); + return err; + } + + data->sock = grub_net_udp_open (addr, +- TFTP_SERVER_PORT, tftp_receive, ++ port ? port : TFTP_SERVER_PORT, tftp_receive, + file); + if (!data->sock) + { +diff --git a/include/grub/net.h b/include/grub/net.h +index 7ae4b6bd8..69bfe0947 100644 +--- a/include/grub/net.h ++++ b/include/grub/net.h +@@ -270,6 +270,7 @@ typedef struct grub_net + { + char *server; + char *name; ++ int port; + grub_net_app_level_t protocol; + grub_net_packets_t packs; + grub_off_t offset; diff --git a/debian/patches/ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-parsing-a-volume-label.patch b/debian/patches/ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-parsing-a-volume-label.patch new file mode 100644 index 0000000..24601f7 --- /dev/null +++ b/debian/patches/ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-parsing-a-volume-label.patch @@ -0,0 +1,57 @@ +From: Maxim Suhanov <dfirblog@gmail.com> +Date: Mon, 28 Aug 2023 16:38:19 +0300 +Subject: fs/ntfs: Fix an OOB read when parsing a volume label + +This fix introduces checks to ensure that an NTFS volume label is always +read from the corresponding file record segment. + +The current NTFS code allows the volume label string to be read from an +arbitrary, attacker-chosen memory location. However, the bytes read are +always treated as UTF-16LE. So, the final string displayed is mostly +unreadable and it can't be easily converted back to raw bytes. + +The lack of this check is a minor issue, likely not causing a significant +data leak. + +Reported-by: Maxim Suhanov <dfirblog@gmail.com> +Signed-off-by: Maxim Suhanov <dfirblog@gmail.com> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/fs/ntfs.c | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c +index bb70c89..ff5e374 100644 +--- a/grub-core/fs/ntfs.c ++++ b/grub-core/fs/ntfs.c +@@ -1213,13 +1213,29 @@ grub_ntfs_label (grub_device_t device, char **label) + + init_attr (&mft->attr, mft); + pa = find_attr (&mft->attr, GRUB_NTFS_AT_VOLUME_NAME); ++ ++ if (pa >= mft->buf + (mft->data->mft_size << GRUB_NTFS_BLK_SHR)) ++ { ++ grub_error (GRUB_ERR_BAD_FS, "can\'t parse volume label"); ++ goto fail; ++ } ++ ++ if (mft->buf + (mft->data->mft_size << GRUB_NTFS_BLK_SHR) - pa < 0x16) ++ { ++ grub_error (GRUB_ERR_BAD_FS, "can\'t parse volume label"); ++ goto fail; ++ } ++ + if ((pa) && (pa[8] == 0) && (u32at (pa, 0x10))) + { + int len; + + len = u32at (pa, 0x10) / 2; + pa += u16at (pa, 0x14); +- *label = get_utf8 (pa, len); ++ if (mft->buf + (mft->data->mft_size << GRUB_NTFS_BLK_SHR) - pa >= 2 * len) ++ *label = get_utf8 (pa, len); ++ else ++ grub_error (GRUB_ERR_BAD_FS, "can\'t parse volume label"); + } + + fail: diff --git a/debian/patches/ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-parsing-bitmaps-for-index-at.patch b/debian/patches/ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-parsing-bitmaps-for-index-at.patch new file mode 100644 index 0000000..29b9dd5 --- /dev/null +++ b/debian/patches/ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-parsing-bitmaps-for-index-at.patch @@ -0,0 +1,46 @@ +From: Maxim Suhanov <dfirblog@gmail.com> +Date: Mon, 28 Aug 2023 16:33:44 +0300 +Subject: fs/ntfs: Fix an OOB read when parsing bitmaps for index attributes + +This fix introduces checks to ensure that bitmaps for directory indices +are never read beyond their actual sizes. + +The lack of this check is a minor issue, likely not exploitable in any way. + +Reported-by: Maxim Suhanov <dfirblog@gmail.com> +Signed-off-by: Maxim Suhanov <dfirblog@gmail.com> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/fs/ntfs.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c +index 2d78b96..bb70c89 100644 +--- a/grub-core/fs/ntfs.c ++++ b/grub-core/fs/ntfs.c +@@ -843,6 +843,25 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir, + + if (is_resident) + { ++ if (bitmap_len > (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR)) ++ { ++ grub_error (GRUB_ERR_BAD_FS, "resident bitmap too large"); ++ goto done; ++ } ++ ++ if (cur_pos >= at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR)) ++ { ++ grub_error (GRUB_ERR_BAD_FS, "resident bitmap out of range"); ++ goto done; ++ } ++ ++ if (u16at (cur_pos, 0x14) + u32at (cur_pos, 0x10) > ++ (grub_addr_t) at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR) - (grub_addr_t) cur_pos) ++ { ++ grub_error (GRUB_ERR_BAD_FS, "resident bitmap out of range"); ++ goto done; ++ } ++ + grub_memcpy (bmp, cur_pos + u16at (cur_pos, 0x14), + bitmap_len); + } diff --git a/debian/patches/ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-parsing-directory-entries-fr.patch b/debian/patches/ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-parsing-directory-entries-fr.patch new file mode 100644 index 0000000..bbc90c3 --- /dev/null +++ b/debian/patches/ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-parsing-directory-entries-fr.patch @@ -0,0 +1,69 @@ +From: Maxim Suhanov <dfirblog@gmail.com> +Date: Mon, 28 Aug 2023 16:33:17 +0300 +Subject: fs/ntfs: Fix an OOB read when parsing directory entries from + resident and non-resident index attributes + +This fix introduces checks to ensure that index entries are never read +beyond the corresponding directory index. + +The lack of this check is a minor issue, likely not exploitable in any way. + +Reported-by: Maxim Suhanov <dfirblog@gmail.com> +Signed-off-by: Maxim Suhanov <dfirblog@gmail.com> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/fs/ntfs.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c +index a68e173..2d78b96 100644 +--- a/grub-core/fs/ntfs.c ++++ b/grub-core/fs/ntfs.c +@@ -599,7 +599,7 @@ get_utf8 (grub_uint8_t *in, grub_size_t len) + } + + static int +-list_file (struct grub_ntfs_file *diro, grub_uint8_t *pos, ++list_file (struct grub_ntfs_file *diro, grub_uint8_t *pos, grub_uint8_t *end_pos, + grub_fshelp_iterate_dir_hook_t hook, void *hook_data) + { + grub_uint8_t *np; +@@ -610,6 +610,9 @@ list_file (struct grub_ntfs_file *diro, grub_uint8_t *pos, + grub_uint8_t namespace; + char *ustr; + ++ if ((pos >= end_pos) || (end_pos - pos < 0x52)) ++ break; ++ + if (pos[0xC] & 2) /* end signature */ + break; + +@@ -617,6 +620,9 @@ list_file (struct grub_ntfs_file *diro, grub_uint8_t *pos, + ns = *(np++); + namespace = *(np++); + ++ if (2 * ns > end_pos - pos - 0x52) ++ break; ++ + /* + * Ignore files in DOS namespace, as they will reappear as Win32 + * names. +@@ -806,7 +812,9 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir, + } + + cur_pos += 0x10; /* Skip index root */ +- ret = list_file (mft, cur_pos + u16at (cur_pos, 0), hook, hook_data); ++ ret = list_file (mft, cur_pos + u16at (cur_pos, 0), ++ at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR), ++ hook, hook_data); + if (ret) + goto done; + +@@ -893,6 +901,7 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir, + (const grub_uint8_t *) "INDX"))) + goto done; + ret = list_file (mft, &indx[0x18 + u16at (indx, 0x18)], ++ indx + (mft->data->idx_size << GRUB_NTFS_BLK_SHR), + hook, hook_data); + if (ret) + goto done; diff --git a/debian/patches/ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-reading-data-from-the-reside.patch b/debian/patches/ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-reading-data-from-the-reside.patch new file mode 100644 index 0000000..d762c06 --- /dev/null +++ b/debian/patches/ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-reading-data-from-the-reside.patch @@ -0,0 +1,54 @@ +From: Maxim Suhanov <dfirblog@gmail.com> +Date: Mon, 28 Aug 2023 16:32:33 +0300 +Subject: fs/ntfs: Fix an OOB read when reading data from the resident $DATA + attribute + +When reading a file containing resident data, i.e., the file data is stored in +the $DATA attribute within the NTFS file record, not in external clusters, +there are no checks that this resident data actually fits the corresponding +file record segment. + +When parsing a specially-crafted file system image, the current NTFS code will +read the file data from an arbitrary, attacker-chosen memory offset and of +arbitrary, attacker-chosen length. + +This allows an attacker to display arbitrary chunks of memory, which could +contain sensitive information like password hashes or even plain-text, +obfuscated passwords from BS EFI variables. + +This fix implements a check to ensure that resident data is read from the +corresponding file record segment only. + +Fixes: CVE-2023-4693 + +Reported-by: Maxim Suhanov <dfirblog@gmail.com> +Signed-off-by: Maxim Suhanov <dfirblog@gmail.com> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/fs/ntfs.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c +index c3c4db1..a68e173 100644 +--- a/grub-core/fs/ntfs.c ++++ b/grub-core/fs/ntfs.c +@@ -401,7 +401,18 @@ read_data (struct grub_ntfs_attr *at, grub_uint8_t *pa, grub_uint8_t *dest, + { + if (ofs + len > u32at (pa, 0x10)) + return grub_error (GRUB_ERR_BAD_FS, "read out of range"); +- grub_memcpy (dest, pa + u32at (pa, 0x14) + ofs, len); ++ ++ if (u32at (pa, 0x10) > (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR)) ++ return grub_error (GRUB_ERR_BAD_FS, "resident attribute too large"); ++ ++ if (pa >= at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR)) ++ return grub_error (GRUB_ERR_BAD_FS, "resident attribute out of range"); ++ ++ if (u16at (pa, 0x14) + u32at (pa, 0x10) > ++ (grub_addr_t) at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR) - (grub_addr_t) pa) ++ return grub_error (GRUB_ERR_BAD_FS, "resident attribute out of range"); ++ ++ grub_memcpy (dest, pa + u16at (pa, 0x14) + ofs, len); + return 0; + } + diff --git a/debian/patches/ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-write-when-parsing-the-ATTRIBUTE_LIST-.patch b/debian/patches/ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-write-when-parsing-the-ATTRIBUTE_LIST-.patch new file mode 100644 index 0000000..06279b8 --- /dev/null +++ b/debian/patches/ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-write-when-parsing-the-ATTRIBUTE_LIST-.patch @@ -0,0 +1,89 @@ +From: Maxim Suhanov <dfirblog@gmail.com> +Date: Mon, 28 Aug 2023 16:31:57 +0300 +Subject: fs/ntfs: Fix an OOB write when parsing the $ATTRIBUTE_LIST attribute + for the $MFT file + +When parsing an extremely fragmented $MFT file, i.e., the file described +using the $ATTRIBUTE_LIST attribute, current NTFS code will reuse a buffer +containing bytes read from the underlying drive to store sector numbers, +which are consumed later to read data from these sectors into another buffer. + +These sectors numbers, two 32-bit integers, are always stored at predefined +offsets, 0x10 and 0x14, relative to first byte of the selected entry within +the $ATTRIBUTE_LIST attribute. Usually, this won't cause any problem. + +However, when parsing a specially-crafted file system image, this may cause +the NTFS code to write these integers beyond the buffer boundary, likely +causing the GRUB memory allocator to misbehave or fail. These integers contain +values which are controlled by on-disk structures of the NTFS file system. + +Such modification and resulting misbehavior may touch a memory range not +assigned to the GRUB and owned by firmware or another EFI application/driver. + +This fix introduces checks to ensure that these sector numbers are never +written beyond the boundary. + +Fixes: CVE-2023-4692 + +Reported-by: Maxim Suhanov <dfirblog@gmail.com> +Signed-off-by: Maxim Suhanov <dfirblog@gmail.com> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/fs/ntfs.c | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c +index bbdbe24..c3c4db1 100644 +--- a/grub-core/fs/ntfs.c ++++ b/grub-core/fs/ntfs.c +@@ -184,7 +184,7 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) + } + if (at->attr_end) + { +- grub_uint8_t *pa; ++ grub_uint8_t *pa, *pa_end; + + at->emft_buf = grub_malloc (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR); + if (at->emft_buf == NULL) +@@ -209,11 +209,13 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) + } + at->attr_nxt = at->edat_buf; + at->attr_end = at->edat_buf + u32at (pa, 0x30); ++ pa_end = at->edat_buf + n; + } + else + { + at->attr_nxt = at->attr_end + u16at (pa, 0x14); + at->attr_end = at->attr_end + u32at (pa, 4); ++ pa_end = at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR); + } + at->flags |= GRUB_NTFS_AF_ALST; + while (at->attr_nxt < at->attr_end) +@@ -230,6 +232,13 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) + at->flags |= GRUB_NTFS_AF_GPOS; + at->attr_cur = at->attr_nxt; + pa = at->attr_cur; ++ ++ if ((pa >= pa_end) || (pa_end - pa < 0x18)) ++ { ++ grub_error (GRUB_ERR_BAD_FS, "can\'t parse attribute list"); ++ return NULL; ++ } ++ + grub_set_unaligned32 ((char *) pa + 0x10, + grub_cpu_to_le32 (at->mft->data->mft_start)); + grub_set_unaligned32 ((char *) pa + 0x14, +@@ -240,6 +249,13 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) + { + if (*pa != attr) + break; ++ ++ if ((pa >= pa_end) || (pa_end - pa < 0x18)) ++ { ++ grub_error (GRUB_ERR_BAD_FS, "can\'t parse attribute list"); ++ return NULL; ++ } ++ + if (read_attr + (at, pa + 0x10, + u32at (pa, 0x10) * (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR), diff --git a/debian/patches/ntfs-cve-fixes/fs-ntfs-Make-code-more-readable.patch b/debian/patches/ntfs-cve-fixes/fs-ntfs-Make-code-more-readable.patch new file mode 100644 index 0000000..bc3bfd7 --- /dev/null +++ b/debian/patches/ntfs-cve-fixes/fs-ntfs-Make-code-more-readable.patch @@ -0,0 +1,155 @@ +From: Maxim Suhanov <dfirblog@gmail.com> +Date: Mon, 28 Aug 2023 16:40:07 +0300 +Subject: fs/ntfs: Make code more readable + +Move some calls used to access NTFS attribute header fields into +functions with human-readable names. + +Suggested-by: Daniel Kiper <daniel.kiper@oracle.com> +Signed-off-by: Maxim Suhanov <dfirblog@gmail.com> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> +--- + grub-core/fs/ntfs.c | 48 +++++++++++++++++++++++++++++++++--------------- + 1 file changed, 33 insertions(+), 15 deletions(-) + +diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c +index ff5e374..de435aa 100644 +--- a/grub-core/fs/ntfs.c ++++ b/grub-core/fs/ntfs.c +@@ -52,6 +52,24 @@ u64at (void *ptr, grub_size_t ofs) + return grub_le_to_cpu64 (grub_get_unaligned64 ((char *) ptr + ofs)); + } + ++static grub_uint16_t ++first_attr_off (void *mft_buf_ptr) ++{ ++ return u16at (mft_buf_ptr, 0x14); ++} ++ ++static grub_uint16_t ++res_attr_data_off (void *res_attr_ptr) ++{ ++ return u16at (res_attr_ptr, 0x14); ++} ++ ++static grub_uint32_t ++res_attr_data_len (void *res_attr_ptr) ++{ ++ return u32at (res_attr_ptr, 0x10); ++} ++ + grub_ntfscomp_func_t grub_ntfscomp_func; + + static grub_err_t +@@ -106,7 +124,7 @@ init_attr (struct grub_ntfs_attr *at, struct grub_ntfs_file *mft) + { + at->mft = mft; + at->flags = (mft == &mft->data->mmft) ? GRUB_NTFS_AF_MMFT : 0; +- at->attr_nxt = mft->buf + u16at (mft->buf, 0x14); ++ at->attr_nxt = mft->buf + first_attr_off (mft->buf); + at->attr_end = at->emft_buf = at->edat_buf = at->sbuf = NULL; + } + +@@ -154,7 +172,7 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) + return NULL; + } + +- new_pos = &at->emft_buf[u16at (at->emft_buf, 0x14)]; ++ new_pos = &at->emft_buf[first_attr_off (at->emft_buf)]; + while (*new_pos != 0xFF) + { + if ((*new_pos == *at->attr_cur) +@@ -213,7 +231,7 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) + } + else + { +- at->attr_nxt = at->attr_end + u16at (pa, 0x14); ++ at->attr_nxt = at->attr_end + res_attr_data_off (pa); + at->attr_end = at->attr_end + u32at (pa, 4); + pa_end = at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR); + } +@@ -399,20 +417,20 @@ read_data (struct grub_ntfs_attr *at, grub_uint8_t *pa, grub_uint8_t *dest, + + if (pa[8] == 0) + { +- if (ofs + len > u32at (pa, 0x10)) ++ if (ofs + len > res_attr_data_len (pa)) + return grub_error (GRUB_ERR_BAD_FS, "read out of range"); + +- if (u32at (pa, 0x10) > (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR)) ++ if (res_attr_data_len (pa) > (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR)) + return grub_error (GRUB_ERR_BAD_FS, "resident attribute too large"); + + if (pa >= at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR)) + return grub_error (GRUB_ERR_BAD_FS, "resident attribute out of range"); + +- if (u16at (pa, 0x14) + u32at (pa, 0x10) > ++ if (res_attr_data_off (pa) + res_attr_data_len (pa) > + (grub_addr_t) at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR) - (grub_addr_t) pa) + return grub_error (GRUB_ERR_BAD_FS, "resident attribute out of range"); + +- grub_memcpy (dest, pa + u16at (pa, 0x14) + ofs, len); ++ grub_memcpy (dest, pa + res_attr_data_off (pa) + ofs, len); + return 0; + } + +@@ -556,7 +574,7 @@ init_file (struct grub_ntfs_file *mft, grub_uint64_t mftno) + (unsigned long long) mftno); + + if (!pa[8]) +- mft->size = u32at (pa, 0x10); ++ mft->size = res_attr_data_len (pa); + else + mft->size = u64at (pa, 0x30); + +@@ -805,7 +823,7 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir, + (u32at (cur_pos, 0x18) != 0x490024) || + (u32at (cur_pos, 0x1C) != 0x300033)) + continue; +- cur_pos += u16at (cur_pos, 0x14); ++ cur_pos += res_attr_data_off (cur_pos); + if (*cur_pos != 0x30) /* Not filename index */ + continue; + break; +@@ -834,7 +852,7 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir, + { + int is_resident = (cur_pos[8] == 0); + +- bitmap_len = ((is_resident) ? u32at (cur_pos, 0x10) : ++ bitmap_len = ((is_resident) ? res_attr_data_len (cur_pos) : + u32at (cur_pos, 0x28)); + + bmp = grub_malloc (bitmap_len); +@@ -855,14 +873,14 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir, + goto done; + } + +- if (u16at (cur_pos, 0x14) + u32at (cur_pos, 0x10) > ++ if (res_attr_data_off (cur_pos) + res_attr_data_len (cur_pos) > + (grub_addr_t) at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR) - (grub_addr_t) cur_pos) + { + grub_error (GRUB_ERR_BAD_FS, "resident bitmap out of range"); + goto done; + } + +- grub_memcpy (bmp, cur_pos + u16at (cur_pos, 0x14), ++ grub_memcpy (bmp, cur_pos + res_attr_data_off (cur_pos), + bitmap_len); + } + else +@@ -1226,12 +1244,12 @@ grub_ntfs_label (grub_device_t device, char **label) + goto fail; + } + +- if ((pa) && (pa[8] == 0) && (u32at (pa, 0x10))) ++ if ((pa) && (pa[8] == 0) && (res_attr_data_len (pa))) + { + int len; + +- len = u32at (pa, 0x10) / 2; +- pa += u16at (pa, 0x14); ++ len = res_attr_data_len (pa) / 2; ++ pa += res_attr_data_off (pa); + if (mft->buf + (mft->data->mft_size << GRUB_NTFS_BLK_SHR) - pa >= 2 * len) + *label = get_utf8 (pa, len); + else diff --git a/debian/patches/olpc-prefix-hack.patch b/debian/patches/olpc-prefix-hack.patch new file mode 100644 index 0000000..6ba9b1e --- /dev/null +++ b/debian/patches/olpc-prefix-hack.patch @@ -0,0 +1,51 @@ +From 39e079ec50c46fa2fc2f43a1a2e01172ef7dd7c6 Mon Sep 17 00:00:00 2001 +From: Colin Watson <cjwatson@debian.org> +Date: Mon, 13 Jan 2014 12:12:50 +0000 +Subject: Hack prefix for OLPC + +This sucks, but it's better than what OFW was giving us. + +Patch-Name: olpc-prefix-hack.patch +--- + grub-core/kern/ieee1275/init.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index d483e35ee..8b089b48d 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -76,6 +76,7 @@ grub_exit (void) + grub_ieee1275_exit (); + } + ++#ifndef __i386__ + /* Translate an OF filesystem path (separated by backslashes), into a GRUB + path (separated by forward slashes). */ + static void +@@ -90,9 +91,18 @@ grub_translate_ieee1275_path (char *filepath) + backslash = grub_strchr (filepath, '\\'); + } + } ++#endif + + void (*grub_ieee1275_net_config) (const char *dev, char **device, char **path, + char *bootpath); ++#ifdef __i386__ ++void ++grub_machine_get_bootlocation (char **device __attribute__ ((unused)), ++ char **path __attribute__ ((unused))) ++{ ++ grub_env_set ("prefix", "(sd,1)/"); ++} ++#else + void + grub_machine_get_bootlocation (char **device, char **path) + { +@@ -146,6 +156,7 @@ grub_machine_get_bootlocation (char **device, char **path) + } + grub_free (bootpath); + } ++#endif + + /* Claim some available memory in the first /memory node. */ + #ifdef __sparc__ diff --git a/debian/patches/pc-verifiers-module.patch b/debian/patches/pc-verifiers-module.patch new file mode 100644 index 0000000..a3c1303 --- /dev/null +++ b/debian/patches/pc-verifiers-module.patch @@ -0,0 +1,167 @@ +From 4a6abe501f39c4c8afe4ed7405ff99aff8559a13 Mon Sep 17 00:00:00 2001 +From: Michael Chang <mchang@suse.com> +Date: Thu, 18 Mar 2021 19:30:26 +0800 +Subject: i386-pc: build verifiers API as module + +Given no core functions on i386-pc would require verifiers to work and +the only consumer of the verifier API is the pgp module, it looks good +to me that we can move the verifiers out of the kernel image and let +moddep.lst to auto-load it when pgp is loaded on i386-pc platform. + +This helps to reduce the size of core image and thus can relax the +tension of exploding on some i386-pc system with very short MBR gap +size. See also a very comprehensive summary from Colin [1] about the +details. + +[1] https://lists.gnu.org/archive/html/grub-devel/2021-03/msg00240.html + +V2: +Drop COND_NOT_i386_pc and use !COND_i386_pc. +Add comment in kern/verifiers.c to help understanding what's going on +without digging into the commit history. + +Reported-by: Colin Watson <cjwatson@debian.org> +Reviewed-by: Colin Watson <cjwatson@debian.org> +Signed-off-by: Michael Chang <mchang@suse.com> + +Origin: other, https://lists.gnu.org/archive/html/grub-devel/2021-03/msg00251.html +Bug-Debian: https://bugs.debian.org/984488 +Bug-Debian: https://bugs.debian.org/985374 +Last-Update: 2021-09-24 + +Patch-Name: pc-verifiers-module.patch +--- + grub-core/Makefile.am | 2 ++ + grub-core/Makefile.core.def | 8 +++++++- + grub-core/kern/main.c | 4 ++++ + grub-core/kern/verifiers.c | 17 +++++++++++++++++ + include/grub/verify.h | 9 +++++++++ + 5 files changed, 39 insertions(+), 1 deletion(-) + +diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am +index ee88e44e9..b6872d20f 100644 +--- a/grub-core/Makefile.am ++++ b/grub-core/Makefile.am +@@ -93,7 +93,9 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/partition.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/stack_protector.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/term.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/time.h ++if !COND_i386_pc + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/verify.h ++endif + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/mm_private.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/net.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/memory.h +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 2ff266806..da3269899 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -141,7 +141,7 @@ kernel = { + common = kern/rescue_parser.c; + common = kern/rescue_reader.c; + common = kern/term.c; +- common = kern/verifiers.c; ++ nopc = kern/verifiers.c; + + noemu = kern/compiler-rt.c; + noemu = kern/mm.c; +@@ -946,6 +946,12 @@ module = { + cppflags = '-I$(srcdir)/lib/posix_wrap'; + }; + ++module = { ++ name = verifiers; ++ common = kern/verifiers.c; ++ enable = i386_pc; ++}; ++ + module = { + name = hdparm; + common = commands/hdparm.c; +diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c +index 2879d644a..c6fb66853 100644 +--- a/grub-core/kern/main.c ++++ b/grub-core/kern/main.c +@@ -29,7 +29,9 @@ + #include <grub/command.h> + #include <grub/reader.h> + #include <grub/parser.h> ++#ifndef GRUB_MACHINE_PCBIOS + #include <grub/verify.h> ++#endif + + #ifdef GRUB_MACHINE_PCBIOS + #include <grub/machine/memory.h> +@@ -285,8 +287,10 @@ grub_main (void) + grub_setcolorstate (GRUB_TERM_COLOR_STANDARD); + #endif + ++#ifndef GRUB_MACHINE_PCBIOS + /* Init verifiers API. */ + grub_verifiers_init (); ++#endif + + grub_load_config (); + +diff --git a/grub-core/kern/verifiers.c b/grub-core/kern/verifiers.c +index 75d7994cf..1245d0d9e 100644 +--- a/grub-core/kern/verifiers.c ++++ b/grub-core/kern/verifiers.c +@@ -221,8 +221,25 @@ grub_verify_string (char *str, enum grub_verify_string_type type) + return GRUB_ERR_NONE; + } + ++/* ++ * It is intended to build verifiers as module on i386-pc platform to minimize ++ * the impact of growing core image size could blow up the 63 sectors limit of ++ * some MBR gap one day. It is also adequate to do so, given no core function ++ * on i386-pc would require the verifiers API to work. ++ */ ++#ifdef GRUB_MACHINE_PCBIOS ++GRUB_MOD_INIT(verifiers) ++#else + void + grub_verifiers_init (void) ++#endif + { + grub_file_filter_register (GRUB_FILE_FILTER_VERIFY, grub_verifiers_open); + } ++ ++#ifdef GRUB_MACHINE_PCBIOS ++GRUB_MOD_FINI(verifiers) ++{ ++ grub_file_filter_unregister (GRUB_FILE_FILTER_VERIFY); ++} ++#endif +diff --git a/include/grub/verify.h b/include/grub/verify.h +index cd129c398..6fde244fc 100644 +--- a/include/grub/verify.h ++++ b/include/grub/verify.h +@@ -64,10 +64,14 @@ struct grub_file_verifier + grub_err_t (*verify_string) (char *str, enum grub_verify_string_type type); + }; + ++#ifdef GRUB_MACHINE_PCBIOS ++extern struct grub_file_verifier *grub_file_verifiers; ++#else + extern struct grub_file_verifier *EXPORT_VAR (grub_file_verifiers); + + extern void + grub_verifiers_init (void); ++#endif + + static inline void + grub_verifier_register (struct grub_file_verifier *ver) +@@ -81,7 +85,12 @@ grub_verifier_unregister (struct grub_file_verifier *ver) + grub_list_remove (GRUB_AS_LIST (ver)); + } + ++#ifdef GRUB_MACHINE_PCBIOS ++grub_err_t ++grub_verify_string (char *str, enum grub_verify_string_type type); ++#else + extern grub_err_t + EXPORT_FUNC (grub_verify_string) (char *str, enum grub_verify_string_type type); ++#endif + + #endif /* ! GRUB_VERIFY_HEADER */ diff --git a/debian/patches/ppc64el-disable-vsx.patch b/debian/patches/ppc64el-disable-vsx.patch new file mode 100644 index 0000000..bd29ae8 --- /dev/null +++ b/debian/patches/ppc64el-disable-vsx.patch @@ -0,0 +1,52 @@ +From c1c72eb757d40208128fb1da02199b0210a206ab Mon Sep 17 00:00:00 2001 +From: Paulo Flabiano Smorigo <pfsmorigo@linux.vnet.ibm.com> +Date: Thu, 25 Sep 2014 19:33:39 -0300 +Subject: Disable VSX instruction + +VSX bit is enabled by default for Power7 and Power8 CPU models, +so we need to disable them in order to avoid instruction exceptions. +Kernel will activate it when necessary. + +* grub-core/kern/powerpc/ieee1275/startup.S: Disable VSX. + +Also-By: Adhemerval Zanella <azanella@linux.vnet.ibm.com> +Also-By: Colin Watson <cjwatson@debian.org> + +Origin: other, https://lists.gnu.org/archive/html/grub-devel/2014-09/msg00078.html +Last-Update: 2015-01-27 + +Patch-Name: ppc64el-disable-vsx.patch +--- + grub-core/kern/powerpc/ieee1275/startup.S | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/grub-core/kern/powerpc/ieee1275/startup.S b/grub-core/kern/powerpc/ieee1275/startup.S +index 21c884b43..de9a9601a 100644 +--- a/grub-core/kern/powerpc/ieee1275/startup.S ++++ b/grub-core/kern/powerpc/ieee1275/startup.S +@@ -20,6 +20,8 @@ + #include <grub/symbol.h> + #include <grub/offsets.h> + ++#define MSR_VSX 0x80 ++ + .extern __bss_start + .extern _end + +@@ -28,6 +30,16 @@ + .globl start, _start + start: + _start: ++ _start: ++ ++ /* Disable VSX instruction */ ++ mfmsr 0 ++ oris 0,0,MSR_VSX ++ /* The "VSX Available" bit is in the lower half of the MSR, so we ++ don't need mtmsrd, which in any case won't work in 32-bit mode. */ ++ mtmsr 0 ++ isync ++ + li 2, 0 + li 13, 0 + diff --git a/debian/patches/probe-fusionio.patch b/debian/patches/probe-fusionio.patch new file mode 100644 index 0000000..d0d5efa --- /dev/null +++ b/debian/patches/probe-fusionio.patch @@ -0,0 +1,76 @@ +From 611974f8c3231d87ca572feda72eb6d1a5a6b309 Mon Sep 17 00:00:00 2001 +From: Colin Watson <cjwatson@ubuntu.com> +Date: Mon, 13 Jan 2014 12:13:31 +0000 +Subject: Probe FusionIO devices + +Bug-Ubuntu: https://bugs.launchpad.net/bugs/1237519 +Forwarded: no +Last-Update: 2016-09-18 + +Patch-Name: probe-fusionio.patch +--- + grub-core/osdep/linux/getroot.c | 13 +++++++++++++ + util/deviceiter.c | 19 +++++++++++++++++++ + 2 files changed, 32 insertions(+) + +diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c +index 001b818fe..c506f4cb5 100644 +--- a/grub-core/osdep/linux/getroot.c ++++ b/grub-core/osdep/linux/getroot.c +@@ -963,6 +963,19 @@ grub_util_part_to_disk (const char *os_dev, struct stat *st, + *pp = '\0'; + return path; + } ++ ++ /* If this is a FusionIO disk. */ ++ if ((strncmp ("fio", p, 3) == 0) && p[3] >= 'a' && p[3] <= 'z') ++ { ++ char *pp = p + 3; ++ while (*pp >= 'a' && *pp <= 'z') ++ pp++; ++ if (*pp) ++ *is_part = 1; ++ /* /dev/fio[a-z]+[0-9]* */ ++ *pp = '\0'; ++ return path; ++ } + } + + return path; +diff --git a/util/deviceiter.c b/util/deviceiter.c +index b5b9ac6ab..3a8f2770e 100644 +--- a/util/deviceiter.c ++++ b/util/deviceiter.c +@@ -384,6 +384,12 @@ get_nvme_disk_name (char *name, int controller, int namespace) + { + sprintf (name, "/dev/nvme%dn%d", controller, namespace); + } ++ ++static void ++get_fio_disk_name (char *name, int unit) ++{ ++ sprintf (name, "/dev/fio%c", unit + 'a'); ++} + #endif + + static struct seen_device +@@ -929,6 +935,19 @@ grub_util_iterate_devices (int (*hook) (const char *, int, void *), void *hook_d + } + } + ++ /* FusionIO. */ ++ for (i = 0; i < 26; i++) ++ { ++ char name[16]; ++ ++ get_fio_disk_name (name, i); ++ if (check_device_readable_unique (name)) ++ { ++ if (hook (name, 0, hook_data)) ++ goto out; ++ } ++ } ++ + # ifdef HAVE_DEVICE_MAPPER + # define dmraid_check(cond, ...) \ + if (! (cond)) \ diff --git a/debian/patches/quick-boot-lvm.patch b/debian/patches/quick-boot-lvm.patch new file mode 100644 index 0000000..6f3ac2d --- /dev/null +++ b/debian/patches/quick-boot-lvm.patch @@ -0,0 +1,77 @@ +From 4f5e080c61055b04db3cdf8067cf180f193cf89f Mon Sep 17 00:00:00 2001 +From: Steve Langasek <steve.langasek@ubuntu.com> +Date: Tue, 30 Oct 2018 15:04:16 -0700 +Subject: If we don't have writable grubenv and we're on EFI, always show the + menu + +If we don't have writable grubenv, recordfail doesn't work, which means our +quickboot behavior - with a timeout of 0 - leaves the user without a +reliable way to access the boot menu if they're on UEFI, because unlike +BIOS, UEFI does not support checking the state of modifier keys (i.e. +holding down shift at boot is not detectable). + +Handle this corner case by always using a non-zero timeout on EFI when +save_env doesn't work. + +Reuse GRUB_RECORDFAIL_TIMEOUT to avoid introducing another variable. + +Signed-off-by: Steve Langasek <steve.langasek@canonical.com> + +Bug-Ubuntu: https://bugs.launchpad.net/bugs/1800722 +Last-Update: 2019-06-24 + +Patch-Name: quick-boot-lvm.patch +--- + util/grub.d/00_header.in | 18 +++++++++++++++--- + 1 file changed, 15 insertions(+), 3 deletions(-) + +diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in +index 674a76140..b7135b655 100644 +--- a/util/grub.d/00_header.in ++++ b/util/grub.d/00_header.in +@@ -115,7 +115,7 @@ EOF + cat <<EOF + # GRUB lacks write support for $abstraction, so recordfail support is disabled. + EOF +- return ++ return 1 + ;; + esac + done +@@ -126,7 +126,7 @@ EOF + cat <<EOF + # GRUB lacks write support for $FS, so recordfail support is disabled. + EOF +- return ++ return 1 + ;; + esac + +@@ -135,7 +135,9 @@ EOF + EOF + } + +- check_writable ++ if ! check_writable; then ++ recordfail_broken=1 ++ fi + + cat <<EOF + } +@@ -379,6 +381,16 @@ EOF + fi + fi + EOF ++if [ "$recordfail_broken" = 1 ]; then ++ cat << EOF ++if [ \$grub_platform = efi ]; then ++ set timeout=${GRUB_RECORDFAIL_TIMEOUT:-30} ++ if [ x\$feature_timeout_style = xy ] ; then ++ set timeout_style=menu ++ fi ++fi ++EOF ++fi + } + + if [ "x$GRUB_BUTTON_CMOS_ADDRESS" != "x" ]; then diff --git a/debian/patches/quick-boot.patch b/debian/patches/quick-boot.patch new file mode 100644 index 0000000..73860af --- /dev/null +++ b/debian/patches/quick-boot.patch @@ -0,0 +1,358 @@ +From e760841d961fc46c5f7a82830d2e0eb6d4b53e8d Mon Sep 17 00:00:00 2001 +From: Colin Watson <cjwatson@ubuntu.com> +Date: Mon, 13 Jan 2014 12:13:28 +0000 +Subject: Add configure option to bypass boot menu if possible + +If other operating systems are installed, then automatically unhide the +menu. Otherwise, if GRUB_HIDDEN_TIMEOUT is 0, then use keystatus if +available to check whether Shift is pressed. If it is, show the menu, +otherwise boot immediately. If keystatus is not available, then fall +back to a short delay interruptible with Escape. + +This may or may not remain Ubuntu-specific, although it's not obviously +wanted upstream. It implements a requirement of +https://wiki.ubuntu.com/DesktopExperienceTeam/KarmicBootExperienceDesignSpec#Bootloader. + +If the previous boot failed (defined as failing to get to the end of one +of the normal runlevels), then show the boot menu regardless. + +Author: Richard Laager <rlaager@wiktel.com> +Author: Robie Basak <robie.basak@ubuntu.com> +Forwarded: no +Last-Update: 2015-09-04 + +Patch-Name: quick-boot.patch +--- + configure.ac | 11 ++++++ + docs/grub.texi | 14 +++++++ + grub-core/normal/menu.c | 24 ++++++++++++ + util/grub-mkconfig.in | 3 +- + util/grub.d/00_header.in | 77 +++++++++++++++++++++++++++++++------ + util/grub.d/10_linux.in | 4 ++ + util/grub.d/30_os-prober.in | 21 ++++++++++ + 7 files changed, 141 insertions(+), 13 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 256fc44ef..c42e4c784 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1926,6 +1926,17 @@ else + fi + AC_SUBST([QUIET_BOOT]) + ++AC_ARG_ENABLE([quick-boot], ++ [AS_HELP_STRING([--enable-quick-boot], ++ [bypass boot menu if possible (default=no)])], ++ [], [enable_quick_boot=no]) ++if test x"$enable_quick_boot" = xyes ; then ++ QUICK_BOOT=1 ++else ++ QUICK_BOOT=0 ++fi ++AC_SUBST([QUICK_BOOT]) ++ + LIBS="" + + AC_SUBST([FONT_SOURCE]) +diff --git a/docs/grub.texi b/docs/grub.texi +index f8b4b3b21..0b58dafb2 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -1563,6 +1563,20 @@ This option may be set to a list of GRUB module names separated by spaces. + Each module will be loaded as early as possible, at the start of + @file{grub.cfg}. + ++@item GRUB_RECORDFAIL_TIMEOUT ++If this option is set, it overrides the default recordfail setting. A ++setting of -1 causes GRUB to wait for user input indefinitely. However, a ++false positive in the recordfail mechanism may occur if power is lost during ++boot before boot success is recorded in userspace. The default setting is ++30, which causes GRUB to wait for user input for thirty seconds before ++continuing. This default allows interactive users the opportunity to switch ++to a different, working kernel, while avoiding a false positive causing the ++boot to block indefinitely on headless and appliance systems where access to ++a console is restricted or limited. ++ ++This option is only effective when GRUB was configured with the ++@option{--enable-quick-boot} option. ++ + @end table + + The following options are still accepted for compatibility with existing +diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c +index e9d8444b5..0440340b8 100644 +--- a/grub-core/normal/menu.c ++++ b/grub-core/normal/menu.c +@@ -603,6 +603,30 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot) + static struct grub_term_coordinate *pos; + int entry = -1; + ++ if (timeout == 0) ++ { ++ /* If modifier key statuses can't be detected without a delay, ++ then a hidden timeout of zero cannot be interrupted in any way, ++ which is not very helpful. Bump it to three seconds in this ++ case to give the user a fighting chance. */ ++ grub_term_input_t term; ++ int nterms = 0; ++ int mods_detectable = 1; ++ ++ FOR_ACTIVE_TERM_INPUTS(term) ++ { ++ if (!term->getkeystatus) ++ { ++ mods_detectable = 0; ++ break; ++ } ++ else ++ nterms++; ++ } ++ if (!mods_detectable || !nterms) ++ timeout = 3; ++ } ++ + if (timeout_style == TIMEOUT_STYLE_COUNTDOWN && timeout) + { + pos = grub_term_save_pos (); +diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in +index 0265a5a66..fa9c53a92 100644 +--- a/util/grub-mkconfig.in ++++ b/util/grub-mkconfig.in +@@ -256,7 +256,8 @@ export GRUB_DEFAULT \ + GRUB_ENABLE_CRYPTODISK \ + GRUB_BADRAM \ + GRUB_OS_PROBER_SKIP_LIST \ +- GRUB_DISABLE_SUBMENU ++ GRUB_DISABLE_SUBMENU \ ++ GRUB_RECORDFAIL_TIMEOUT + + if test "x${grub_cfg}" != "x"; then + rm -f "${grub_cfg}.new" +diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in +index 93a90233e..674a76140 100644 +--- a/util/grub.d/00_header.in ++++ b/util/grub.d/00_header.in +@@ -21,6 +21,8 @@ prefix="@prefix@" + exec_prefix="@exec_prefix@" + datarootdir="@datarootdir@" + grub_lang=`echo $LANG | cut -d . -f 1` ++grubdir="`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'`" ++quick_boot="@QUICK_BOOT@" + + export TEXTDOMAIN=@PACKAGE@ + export TEXTDOMAINDIR="@localedir@" +@@ -44,6 +46,7 @@ if [ "x${GRUB_TIMEOUT_BUTTON}" = "x" ] ; then GRUB_TIMEOUT_BUTTON="$GRUB_TIMEOUT + + cat << EOF + if [ -s \$prefix/grubenv ]; then ++ set have_grubenv=true + load_env + fi + EOF +@@ -96,7 +99,50 @@ function savedefault { + save_env saved_entry + fi + } ++EOF ++ ++if [ "$quick_boot" = 1 ]; then ++ cat <<EOF ++function recordfail { ++ set recordfail=1 ++EOF ++ ++ check_writable () { ++ abstractions="$(grub-probe --target=abstraction "${grubdir}")" ++ for abstraction in $abstractions; do ++ case "$abstraction" in ++ diskfilter | lvm) ++ cat <<EOF ++ # GRUB lacks write support for $abstraction, so recordfail support is disabled. ++EOF ++ return ++ ;; ++ esac ++ done ++ ++ FS="$(grub-probe --target=fs "${grubdir}")" ++ case "$FS" in ++ btrfs | cpiofs | newc | odc | romfs | squash4 | tarfs | zfs) ++ cat <<EOF ++ # GRUB lacks write support for $FS, so recordfail support is disabled. ++EOF ++ return ++ ;; ++ esac ++ ++ cat <<EOF ++ if [ -n "\${have_grubenv}" ]; then if [ -z "\${boot_once}" ]; then save_env recordfail; fi; fi ++EOF ++ } ++ ++ check_writable + ++ cat <<EOF ++} ++EOF ++fi ++ ++cat <<EOF + function load_video { + EOF + if [ -n "${GRUB_VIDEO_BACKEND}" ]; then +@@ -282,10 +328,16 @@ fi + + make_timeout () + { ++ cat << EOF ++if [ "\${recordfail}" = 1 ] ; then ++ set timeout=${GRUB_RECORDFAIL_TIMEOUT:-30} ++else ++EOF + if [ "x${3}" != "x" ] ; then + timeout="${2}" + style="${3}" +- elif [ "x${1}" != "x" ] && [ "x${1}" != "x0" ] ; then ++ elif [ "x${1}" != "x" ] && \ ++ ([ "$quick_boot" = 1 ] || [ "x${1}" != "x0" ]) ; then + # Handle the deprecated GRUB_HIDDEN_TIMEOUT scheme. + timeout="${1}" + if [ "x${2}" != "x0" ] ; then +@@ -304,26 +356,27 @@ make_timeout () + style="menu" + fi + cat << EOF +-if [ x\$feature_timeout_style = xy ] ; then +- set timeout_style=${style} +- set timeout=${timeout} ++ if [ x\$feature_timeout_style = xy ] ; then ++ set timeout_style=${style} ++ set timeout=${timeout} + EOF + if [ "x${style}" = "xmenu" ] ; then + cat << EOF +-# Fallback normal timeout code in case the timeout_style feature is +-# unavailable. +-else +- set timeout=${timeout} ++ # Fallback normal timeout code in case the timeout_style feature is ++ # unavailable. ++ else ++ set timeout=${timeout} + EOF + else + cat << EOF +-# Fallback hidden-timeout code in case the timeout_style feature is +-# unavailable. +-elif sleep${verbose} --interruptible ${timeout} ; then +- set timeout=0 ++ # Fallback hidden-timeout code in case the timeout_style feature is ++ # unavailable. ++ elif sleep${verbose} --interruptible ${timeout} ; then ++ set timeout=0 + EOF + fi + cat << EOF ++ fi + fi + EOF + } +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index 869a7eec5..80315a31b 100644 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -22,6 +22,7 @@ exec_prefix="@exec_prefix@" + datarootdir="@datarootdir@" + ubuntu_recovery="@UBUNTU_RECOVERY@" + quiet_boot="@QUIET_BOOT@" ++quick_boot="@QUICK_BOOT@" + + . "$pkgdatadir/grub-mkconfig_lib" + +@@ -129,6 +130,9 @@ linux_entry () + else + echo "menuentry '$(echo "$os" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-simple-$boot_device_id' {" | sed "s/^/$submenu_indentation/" + fi ++ if [ "$quick_boot" = 1 ]; then ++ echo " recordfail" | sed "s/^/$submenu_indentation/" ++ fi + if [ x$type != xrecovery ] ; then + save_default_entry | grub_add_tab + fi +diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in +index 98aee403e..225a3baf7 100644 +--- a/util/grub.d/30_os-prober.in ++++ b/util/grub.d/30_os-prober.in +@@ -20,12 +20,26 @@ set -e + prefix="@prefix@" + exec_prefix="@exec_prefix@" + datarootdir="@datarootdir@" ++quick_boot="@QUICK_BOOT@" + + export TEXTDOMAIN=@PACKAGE@ + export TEXTDOMAINDIR="@localedir@" + + . "$pkgdatadir/grub-mkconfig_lib" + ++found_other_os= ++ ++adjust_timeout () { ++ if [ "$quick_boot" = 1 ] && [ "x${found_other_os}" != "x" ]; then ++ cat << EOF ++set timeout_style=menu ++if [ "\${timeout}" = 0 ]; then ++ set timeout=10 ++fi ++EOF ++ fi ++} ++ + if [ "x${GRUB_DISABLE_OS_PROBER}" = "xtrue" ]; then + grub_warn "$(gettext_printf "os-prober will not be executed to detect other bootable partitions.\nSystems on them will not be added to the GRUB boot configuration.\nCheck GRUB_DISABLE_OS_PROBER documentation entry.")" + exit 0 +@@ -45,6 +59,7 @@ if [ -z "${OSPROBED}" ] ; then + fi + + osx_entry() { ++ found_other_os=1 + if [ x$2 = x32 ]; then + # TRANSLATORS: it refers to kernel architecture (32-bit) + bitstr="$(gettext "(32-bit)")" +@@ -168,6 +183,7 @@ for OS in ${OSPROBED} ; do + ;; + esac + ++ found_other_os=1 + onstr="$(gettext_printf "(on %s)" "${DEVICE}")" + cat << EOF + menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' $CLASS --class os \$menuentry_id_option 'osprober-chain-$(grub_get_device_id "${DEVICE}")' { +@@ -198,6 +214,7 @@ EOF + ;; + efi) + ++ found_other_os=1 + EFIPATH=${DEVICE#*@} + DEVICE=${DEVICE%@*} + onstr="$(gettext_printf "(on %s)" "${DEVICE}")" +@@ -246,6 +263,7 @@ EOF + [ "${prepare_boot_cache}" ] || continue + fi + ++ found_other_os=1 + onstr="$(gettext_printf "(on %s)" "${DEVICE}")" + recovery_params="$(echo "${LPARAMS}" | grep 'single\|recovery')" || true + counter=1 +@@ -322,6 +340,7 @@ EOF + fi + ;; + hurd) ++ found_other_os=1 + onstr="$(gettext_printf "(on %s)" "${DEVICE}")" + cat << EOF + menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' --class hurd --class gnu --class os \$menuentry_id_option 'osprober-gnuhurd-/boot/gnumach.gz-false-$(grub_get_device_id "${DEVICE}")' { +@@ -364,3 +383,5 @@ EOF + ;; + esac + done ++ ++adjust_timeout diff --git a/debian/patches/reenable_os-prober.patch b/debian/patches/reenable_os-prober.patch new file mode 100644 index 0000000..04ed937 --- /dev/null +++ b/debian/patches/reenable_os-prober.patch @@ -0,0 +1,15 @@ +diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in +index f8cbb8d7a..a6d1e2d22 100644 +--- a/util/grub-mkconfig.in ++++ b/util/grub-mkconfig.in +@@ -140,8 +140,8 @@ GRUB_DEVICE_PARTUUID="`${grub_probe} --device ${GRUB_DEVICE} --target=partuuid 2 + GRUB_DEVICE_BOOT="`${grub_probe} --target=device /boot`" + GRUB_DEVICE_BOOT_UUID="`${grub_probe} --device ${GRUB_DEVICE_BOOT} --target=fs_uuid 2> /dev/null`" || true + +-# Disable os-prober by default due to security reasons. +-GRUB_DISABLE_OS_PROBER="true" ++# Enable os-prober by default for stable updates, let's not break expectations ++GRUB_DISABLE_OS_PROBER="false" + + # Filesystem for the device containing our userland. Used for stuff like + # choosing Hurd filesystem module. diff --git a/debian/patches/restore-mkdevicemap.patch b/debian/patches/restore-mkdevicemap.patch new file mode 100644 index 0000000..3822430 --- /dev/null +++ b/debian/patches/restore-mkdevicemap.patch @@ -0,0 +1,1326 @@ +From a7b960126fbc0d4541babe5553546e5f9530ac48 Mon Sep 17 00:00:00 2001 +From: Colin Watson <cjwatson@debian.org> +Date: Mon, 13 Jan 2014 12:13:01 +0000 +Subject: Restore grub-mkdevicemap + +This is kind of a mess, requiring lots of OS-specific code to iterate +over all possible devices. However, we use it in a number of scripts to +discover devices and reimplementing those in terms of something else +would be very complicated. + +Author: Dimitri John Ledkov <dimitri.ledkov@canonical.com> +Forwarded: no +Last-Update: 2021-09-24 + +Patch-Name: restore-mkdevicemap.patch +--- + Makefile.util.def | 17 + + docs/man/grub-mkdevicemap.h2m | 4 + + include/grub/util/deviceiter.h | 14 + + util/deviceiter.c | 1027 ++++++++++++++++++++++++++++++++ + util/devicemap.c | 13 + + util/grub-mkdevicemap.c | 181 ++++++ + 6 files changed, 1256 insertions(+) + create mode 100644 docs/man/grub-mkdevicemap.h2m + create mode 100644 include/grub/util/deviceiter.h + create mode 100644 util/deviceiter.c + create mode 100644 util/devicemap.c + create mode 100644 util/grub-mkdevicemap.c + +diff --git a/Makefile.util.def b/Makefile.util.def +index f8b356cc1..27f948291 100644 +--- a/Makefile.util.def ++++ b/Makefile.util.def +@@ -336,6 +336,23 @@ program = { + condition = COND_GRUB_MKFONT; + }; + ++program = { ++ name = grub-mkdevicemap; ++ installdir = sbin; ++ mansection = 8; ++ ++ common = util/grub-mkdevicemap.c; ++ common = util/deviceiter.c; ++ common = util/devicemap.c; ++ common = grub-core/osdep/init.c; ++ ++ ldadd = libgrubmods.a; ++ ldadd = libgrubgcry.a; ++ ldadd = libgrubkern.a; ++ ldadd = grub-core/lib/gnulib/libgnu.a; ++ ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; ++}; ++ + program = { + name = grub-probe; + installdir = sbin; +diff --git a/docs/man/grub-mkdevicemap.h2m b/docs/man/grub-mkdevicemap.h2m +new file mode 100644 +index 000000000..96cd6ee72 +--- /dev/null ++++ b/docs/man/grub-mkdevicemap.h2m +@@ -0,0 +1,4 @@ ++[NAME] ++grub-mkdevicemap \- make a device map file automatically ++[SEE ALSO] ++.BR grub-probe (8) +diff --git a/include/grub/util/deviceiter.h b/include/grub/util/deviceiter.h +new file mode 100644 +index 000000000..85374978c +--- /dev/null ++++ b/include/grub/util/deviceiter.h +@@ -0,0 +1,14 @@ ++#ifndef GRUB_DEVICEITER_MACHINE_UTIL_HEADER ++#define GRUB_DEVICEITER_MACHINE_UTIL_HEADER 1 ++ ++#include <config.h> ++ ++typedef int (*grub_util_iterate_devices_hook_t) (const char *name, ++ int is_floppy, void *data); ++ ++void grub_util_iterate_devices (grub_util_iterate_devices_hook_t hook, ++ void *hook_data, int floppy_disks); ++void grub_util_emit_devicemap_entry (FILE *fp, char *name, int is_floppy, ++ int *num_fd, int *num_hd); ++ ++#endif /* ! GRUB_DEVICEITER_MACHINE_UTIL_HEADER */ +diff --git a/util/deviceiter.c b/util/deviceiter.c +new file mode 100644 +index 000000000..b5b9ac6ab +--- /dev/null ++++ b/util/deviceiter.c +@@ -0,0 +1,1027 @@ ++/* deviceiter.c - iterate over system devices */ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008,2011 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++#include <config.h> ++ ++#include <stdio.h> ++#include <unistd.h> ++#include <string.h> ++#include <stdlib.h> ++#include <sys/types.h> ++#include <sys/stat.h> ++#include <errno.h> ++#include <fcntl.h> ++#include <limits.h> ++#include <dirent.h> ++ ++#include <grub/util/misc.h> ++#include <grub/util/deviceiter.h> ++#include <grub/list.h> ++#include <grub/misc.h> ++#include <grub/emu/misc.h> ++#include <grub/safemath.h> ++ ++#ifdef __linux__ ++# if !defined(__GLIBC__) || \ ++ ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))) ++/* Maybe libc doesn't have large file support. */ ++# include <linux/unistd.h> /* _llseek */ ++# endif /* (GLIBC < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR < 1)) */ ++# include <sys/ioctl.h> /* ioctl */ ++# ifndef HDIO_GETGEO ++# define HDIO_GETGEO 0x0301 /* get device geometry */ ++/* If HDIO_GETGEO is not defined, it is unlikely that hd_geometry is ++ defined. */ ++struct hd_geometry ++{ ++ unsigned char heads; ++ unsigned char sectors; ++ unsigned short cylinders; ++ unsigned long start; ++}; ++# endif /* ! HDIO_GETGEO */ ++# ifndef FLOPPY_MAJOR ++# define FLOPPY_MAJOR 2 /* the major number for floppy */ ++# endif /* ! FLOPPY_MAJOR */ ++# ifndef MAJOR ++# define MAJOR(dev) \ ++ ({ \ ++ unsigned long long __dev = (dev); \ ++ (unsigned) ((__dev >> 8) & 0xfff) \ ++ | ((unsigned int) (__dev >> 32) & ~0xfff); \ ++ }) ++# endif /* ! MAJOR */ ++# ifndef MINOR ++# define MINOR(dev) \ ++ ({ \ ++ unsigned long long __dev = (dev); \ ++ (unsigned) (__dev & 0xff) | ((unsigned int) (__dev >> 12) & ~0xff); \ ++ }) ++# endif /* ! MINOR */ ++# ifndef CDROM_GET_CAPABILITY ++# define CDROM_GET_CAPABILITY 0x5331 /* get capabilities */ ++# endif /* ! CDROM_GET_CAPABILITY */ ++# ifndef BLKGETSIZE ++# define BLKGETSIZE _IO(0x12,96) /* return device size */ ++# endif /* ! BLKGETSIZE */ ++ ++#ifdef HAVE_DEVICE_MAPPER ++# include <libdevmapper.h> ++# pragma GCC diagnostic ignored "-Wcast-align" ++#endif ++#endif /* __linux__ */ ++ ++/* Use __FreeBSD_kernel__ instead of __FreeBSD__ for compatibility with ++ kFreeBSD-based non-FreeBSD systems (e.g. GNU/kFreeBSD) */ ++#if defined(__FreeBSD__) && ! defined(__FreeBSD_kernel__) ++# define __FreeBSD_kernel__ ++#endif ++#ifdef __FreeBSD_kernel__ ++ /* Obtain version of kFreeBSD headers */ ++# include <osreldate.h> ++# ifndef __FreeBSD_kernel_version ++# define __FreeBSD_kernel_version __FreeBSD_version ++# endif ++ ++ /* Runtime detection of kernel */ ++# include <sys/utsname.h> ++static int ++get_kfreebsd_version (void) ++{ ++ struct utsname uts; ++ int major; ++ int minor; ++ int v[2]; ++ ++ uname (&uts); ++ sscanf (uts.release, "%d.%d", &major, &minor); ++ ++ if (major >= 9) ++ major = 9; ++ if (major >= 5) ++ { ++ v[0] = minor/10; v[1] = minor%10; ++ } ++ else ++ { ++ v[0] = minor%10; v[1] = minor/10; ++ } ++ return major*100000+v[0]*10000+v[1]*1000; ++} ++#endif /* __FreeBSD_kernel__ */ ++ ++#if defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) ++# include <sys/ioctl.h> /* ioctl */ ++# include <sys/disklabel.h> ++# include <sys/cdio.h> /* CDIOCCLRDEBUG */ ++# if defined(__FreeBSD_kernel__) ++# include <sys/param.h> ++# if __FreeBSD_kernel_version >= 500040 ++# include <sys/disk.h> ++# endif ++# endif /* __FreeBSD_kernel__ */ ++#endif /* __FreeBSD_kernel__ || __NetBSD__ || __OpenBSD__ */ ++ ++#ifdef HAVE_OPENDISK ++# include <util.h> ++#endif /* HAVE_OPENDISK */ ++ ++#ifdef __linux__ ++/* Check if we have devfs support. */ ++static int ++have_devfs (void) ++{ ++ struct stat st; ++ return stat ("/dev/.devfsd", &st) == 0; ++} ++#endif /* __linux__ */ ++ ++/* These three functions are quite different among OSes. */ ++static void ++get_floppy_disk_name (char *name, int unit) ++{ ++#if defined(__linux__) ++ /* GNU/Linux */ ++ if (have_devfs ()) ++ sprintf (name, "/dev/floppy/%d", unit); ++ else ++ sprintf (name, "/dev/fd%d", unit); ++#elif defined(__GNU__) ++ /* GNU/Hurd */ ++ sprintf (name, "/dev/fd%d", unit); ++#elif defined(__FreeBSD_kernel__) ++ /* kFreeBSD */ ++ if (get_kfreebsd_version () >= 400000) ++ sprintf (name, "/dev/fd%d", unit); ++ else ++ sprintf (name, "/dev/rfd%d", unit); ++#elif defined(__NetBSD__) ++ /* NetBSD */ ++ /* opendisk() doesn't work for floppies. */ ++ sprintf (name, "/dev/rfd%da", unit); ++#elif defined(__OpenBSD__) ++ /* OpenBSD */ ++ sprintf (name, "/dev/rfd%dc", unit); ++#elif defined(__QNXNTO__) ++ /* QNX RTP */ ++ sprintf (name, "/dev/fd%d", unit); ++#elif defined(__CYGWIN__) ++ /* Cygwin */ ++ sprintf (name, "/dev/fd%d", unit); ++#elif defined(__MINGW32__) ++ (void) unit; ++ *name = 0; ++#else ++# warning "BIOS floppy drives cannot be guessed in your operating system." ++ /* Set NAME to a bogus string. */ ++ *name = 0; ++#endif ++} ++ ++static void ++get_ide_disk_name (char *name, int unit) ++{ ++#if defined(__linux__) ++ /* GNU/Linux */ ++ sprintf (name, "/dev/hd%c", unit + 'a'); ++#elif defined(__GNU__) ++ /* GNU/Hurd */ ++ sprintf (name, "/dev/hd%d", unit); ++#elif defined(__FreeBSD_kernel__) ++ /* kFreeBSD */ ++ if (get_kfreebsd_version () >= 400000) ++ sprintf (name, "/dev/ad%d", unit); ++ else ++ sprintf (name, "/dev/rwd%d", unit); ++#elif defined(__NetBSD__) && defined(HAVE_OPENDISK) ++ /* NetBSD */ ++ char shortname[16]; ++ int fd; ++ ++ sprintf (shortname, "wd%d", unit); ++ fd = opendisk (shortname, O_RDONLY, name, ++ 16, /* length of NAME */ ++ 0 /* char device */ ++ ); ++ close (fd); ++#elif defined(__OpenBSD__) ++ /* OpenBSD */ ++ sprintf (name, "/dev/rwd%dc", unit); ++#elif defined(__QNXNTO__) ++ /* QNX RTP */ ++ /* Actually, QNX RTP doesn't distinguish IDE from SCSI, so this could ++ contain SCSI disks. */ ++ sprintf (name, "/dev/hd%d", unit); ++#elif defined(__CYGWIN__) ++ /* Cygwin emulates all disks as /dev/sdX. */ ++ (void) unit; ++ *name = 0; ++#elif defined(__MINGW32__) ++ sprintf (name, "//./PHYSICALDRIVE%d", unit); ++#else ++# warning "BIOS IDE drives cannot be guessed in your operating system." ++ /* Set NAME to a bogus string. */ ++ *name = 0; ++#endif ++} ++ ++static void ++get_scsi_disk_name (char *name, int unit) ++{ ++#if defined(__linux__) ++ /* GNU/Linux */ ++ sprintf (name, "/dev/sd%c", unit + 'a'); ++#elif defined(__GNU__) ++ /* GNU/Hurd */ ++ sprintf (name, "/dev/sd%d", unit); ++#elif defined(__FreeBSD_kernel__) ++ /* kFreeBSD */ ++ if (get_kfreebsd_version () >= 400000) ++ sprintf (name, "/dev/da%d", unit); ++ else ++ sprintf (name, "/dev/rda%d", unit); ++#elif defined(__NetBSD__) && defined(HAVE_OPENDISK) ++ /* NetBSD */ ++ char shortname[16]; ++ int fd; ++ ++ sprintf (shortname, "sd%d", unit); ++ fd = opendisk (shortname, O_RDONLY, name, ++ 16, /* length of NAME */ ++ 0 /* char device */ ++ ); ++ close (fd); ++#elif defined(__OpenBSD__) ++ /* OpenBSD */ ++ sprintf (name, "/dev/rsd%dc", unit); ++#elif defined(__QNXNTO__) ++ /* QNX RTP */ ++ /* QNX RTP doesn't distinguish SCSI from IDE, so it is better to ++ disable the detection of SCSI disks here. */ ++ *name = 0; ++#elif defined(__CYGWIN__) ++ /* Cygwin emulates all disks as /dev/sdX. */ ++ sprintf (name, "/dev/sd%c", unit + 'a'); ++#elif defined(__MINGW32__) ++ (void) unit; ++ *name = 0; ++#else ++# warning "BIOS SCSI drives cannot be guessed in your operating system." ++ /* Set NAME to a bogus string. */ ++ *name = 0; ++#endif ++} ++ ++#ifdef __FreeBSD_kernel__ ++static void ++get_ada_disk_name (char *name, int unit) ++{ ++ sprintf (name, "/dev/ada%d", unit); ++} ++ ++static void ++get_ataraid_disk_name (char *name, int unit) ++{ ++ sprintf (name, "/dev/ar%d", unit); ++} ++ ++static void ++get_mfi_disk_name (char *name, int unit) ++{ ++ sprintf (name, "/dev/mfid%d", unit); ++} ++ ++static void ++get_virtio_disk_name (char *name, int unit) ++{ ++ sprintf (name, "/dev/vtbd%d", unit); ++} ++ ++static void ++get_xvd_disk_name (char *name, int unit) ++{ ++ sprintf (name, "/dev/xbd%d", unit); ++} ++#endif ++ ++#ifdef __linux__ ++static void ++get_virtio_disk_name (char *name, int unit) ++{ ++#ifdef __sparc__ ++ sprintf (name, "/dev/vdisk%c", unit + 'a'); ++#else ++ sprintf (name, "/dev/vd%c", unit + 'a'); ++#endif ++} ++ ++static void ++get_dac960_disk_name (char *name, int controller, int drive) ++{ ++ sprintf (name, "/dev/rd/c%dd%d", controller, drive); ++} ++ ++static void ++get_acceleraid_disk_name (char *name, int controller, int drive) ++{ ++ sprintf (name, "/dev/rs/c%dd%d", controller, drive); ++} ++ ++static void ++get_ataraid_disk_name (char *name, int unit) ++{ ++ sprintf (name, "/dev/ataraid/d%c", unit + '0'); ++} ++ ++static void ++get_i2o_disk_name (char *name, char unit) ++{ ++ sprintf (name, "/dev/i2o/hd%c", unit); ++} ++ ++static void ++get_cciss_disk_name (char *name, int controller, int drive) ++{ ++ sprintf (name, "/dev/cciss/c%dd%d", controller, drive); ++} ++ ++static void ++get_ida_disk_name (char *name, int controller, int drive) ++{ ++ sprintf (name, "/dev/ida/c%dd%d", controller, drive); ++} ++ ++static void ++get_mmc_disk_name (char *name, int unit) ++{ ++ sprintf (name, "/dev/mmcblk%d", unit); ++} ++ ++static void ++get_xvd_disk_name (char *name, int unit) ++{ ++ sprintf (name, "/dev/xvd%c", unit + 'a'); ++} ++ ++static void ++get_nvme_disk_name (char *name, int controller, int namespace) ++{ ++ sprintf (name, "/dev/nvme%dn%d", controller, namespace); ++} ++#endif ++ ++static struct seen_device ++{ ++ struct seen_device *next; ++ struct seen_device **prev; ++ const char *name; ++} *seen; ++ ++/* Check if DEVICE can be read. Skip any DEVICE that we have already seen. ++ If an error occurs, return zero, otherwise return non-zero. */ ++static int ++check_device_readable_unique (const char *device) ++{ ++ char *real_device; ++ char buf[512]; ++ FILE *fp; ++ struct seen_device *seen_elt; ++ ++ /* If DEVICE is empty, just return error. */ ++ if (*device == 0) ++ return 0; ++ ++ /* Have we seen this device already? */ ++ real_device = canonicalize_file_name (device); ++ if (! real_device) ++ return 0; ++ if (grub_named_list_find (GRUB_AS_NAMED_LIST (seen), real_device)) ++ { ++ grub_dprintf ("deviceiter", "Already seen %s (%s)\n", ++ device, real_device); ++ goto fail; ++ } ++ ++ fp = fopen (device, "r"); ++ if (! fp) ++ { ++ switch (errno) ++ { ++#ifdef ENOMEDIUM ++ case ENOMEDIUM: ++# if 0 ++ /* At the moment, this finds only CDROMs, which can't be ++ read anyway, so leave it out. Code should be ++ reactivated if `removable disks' and CDROMs are ++ supported. */ ++ /* Accept it, it may be inserted. */ ++ return 1; ++# endif ++ break; ++#endif /* ENOMEDIUM */ ++ default: ++ /* Break case and leave. */ ++ break; ++ } ++ /* Error opening the device. */ ++ goto fail; ++ } ++ ++ /* Make sure CD-ROMs don't get assigned a BIOS disk number ++ before SCSI disks! */ ++#ifdef __linux__ ++# ifdef CDROM_GET_CAPABILITY ++ if (ioctl (fileno (fp), CDROM_GET_CAPABILITY, 0) >= 0) ++ goto fail; ++# else /* ! CDROM_GET_CAPABILITY */ ++ /* Check if DEVICE is a CD-ROM drive by the HDIO_GETGEO ioctl. */ ++ { ++ struct hd_geometry hdg; ++ struct stat st; ++ ++ if (fstat (fileno (fp), &st)) ++ goto fail; ++ ++ /* If it is a block device and isn't a floppy, check if HDIO_GETGEO ++ succeeds. */ ++ if (S_ISBLK (st.st_mode) ++ && MAJOR (st.st_rdev) != FLOPPY_MAJOR ++ && ioctl (fileno (fp), HDIO_GETGEO, &hdg)) ++ goto fail; ++ } ++# endif /* ! CDROM_GET_CAPABILITY */ ++#endif /* __linux__ */ ++ ++#if defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) ++# ifdef CDIOCCLRDEBUG ++ if (ioctl (fileno (fp), CDIOCCLRDEBUG, 0) >= 0) ++ goto fail; ++# endif /* CDIOCCLRDEBUG */ ++#endif /* __FreeBSD_kernel__ || __NetBSD__ || __OpenBSD__ */ ++ ++ /* Attempt to read the first sector. */ ++ if (fread (buf, 1, 512, fp) != 512) ++ { ++ fclose (fp); ++ goto fail; ++ } ++ ++ /* Remember that we've seen this device. */ ++ seen_elt = xmalloc (sizeof (*seen_elt)); ++ seen_elt->name = real_device; /* steal memory */ ++ grub_list_push (GRUB_AS_LIST_P (&seen), GRUB_AS_LIST (seen_elt)); ++ ++ fclose (fp); ++ return 1; ++ ++fail: ++ free (real_device); ++ return 0; ++} ++ ++static void ++clear_seen_devices (void) ++{ ++ while (seen) ++ { ++ struct seen_device *seen_elt = seen; ++ seen = seen->next; ++ free (seen_elt); ++ } ++ seen = NULL; ++} ++ ++#ifdef __linux__ ++struct device ++{ ++ char *stable; ++ char *kernel; ++}; ++ ++/* Sort by the kernel name for preference since that most closely matches ++ older device.map files, but sort by stable by-id names as a fallback. ++ This is because /dev/disk/by-id/ usually has a few alternative ++ identifications of devices (e.g. ATA vs. SATA). ++ check_device_readable_unique will ensure that we only get one for any ++ given disk, but sort the list so that the choice of which one we get is ++ stable. */ ++static int ++compare_devices (const void *a, const void *b) ++{ ++ const struct device *left = (const struct device *) a; ++ const struct device *right = (const struct device *) b; ++ ++ if (left->kernel && right->kernel) ++ { ++ int ret = strcmp (left->kernel, right->kernel); ++ if (ret) ++ return ret; ++ } ++ ++ return strcmp (left->stable, right->stable); ++} ++#endif /* __linux__ */ ++ ++void ++grub_util_iterate_devices (int (*hook) (const char *, int, void *), void *hook_data, ++ int floppy_disks) ++{ ++ int i; ++ ++ clear_seen_devices (); ++ ++ /* Floppies. */ ++ for (i = 0; i < floppy_disks; i++) ++ { ++ char name[32]; ++ struct stat st; ++ ++ get_floppy_disk_name (name, i); ++ if (stat (name, &st) < 0) ++ break; ++ /* In floppies, write the map, whether check_device_readable_unique ++ succeeds or not, because the user just may not insert floppies. */ ++ if (hook (name, 1, hook_data)) ++ goto out; ++ } ++ ++#ifdef __linux__ ++ { ++ DIR *dir = opendir ("/dev/disk/by-id"); ++ ++ if (dir) ++ { ++ struct dirent *entry; ++ struct device *devs; ++ size_t devs_len = 0, devs_max = 1024, dev; ++ ++ devs = xcalloc (devs_max, sizeof (*devs)); ++ ++ /* Dump all the directory entries into names, resizing if ++ necessary. */ ++ for (entry = readdir (dir); entry; entry = readdir (dir)) ++ { ++ /* Skip current and parent directory entries. */ ++ if (strcmp (entry->d_name, ".") == 0 || ++ strcmp (entry->d_name, "..") == 0) ++ continue; ++ /* Skip partition entries. */ ++ if (strstr (entry->d_name, "-part")) ++ continue; ++ /* Skip device-mapper entries; we'll handle the ones we want ++ later. */ ++ if (strncmp (entry->d_name, "dm-", sizeof ("dm-") - 1) == 0) ++ continue; ++ /* Skip RAID entries; they are handled by upper layers. */ ++ if (strncmp (entry->d_name, "md-", sizeof ("md-") - 1) == 0) ++ continue; ++ if (devs_len >= devs_max) ++ { ++ size_t sz; ++ ++ devs_max *= 2; ++ sz = devs_max; ++ if (grub_mul (sz, sizeof (*devs), &sz)) ++ grub_util_error ("%s", _("overflow is detected")); ++ devs = xrealloc (devs, sz); ++ } ++ devs[devs_len].stable = ++ xasprintf ("/dev/disk/by-id/%s", entry->d_name); ++ devs[devs_len].kernel = ++ canonicalize_file_name (devs[devs_len].stable); ++ devs_len++; ++ } ++ ++ qsort (devs, devs_len, sizeof (*devs), &compare_devices); ++ ++ closedir (dir); ++ ++ /* Now add all the devices in sorted order. */ ++ for (dev = 0; dev < devs_len; ++dev) ++ { ++ if (check_device_readable_unique (devs[dev].stable)) ++ { ++ if (hook (devs[dev].stable, 0, hook_data)) ++ goto out; ++ } ++ free (devs[dev].stable); ++ free (devs[dev].kernel); ++ } ++ free (devs); ++ } ++ } ++ ++ if (have_devfs ()) ++ { ++ i = 0; ++ while (1) ++ { ++ char discn[32]; ++ char name[PATH_MAX]; ++ struct stat st; ++ ++ /* Linux creates symlinks "/dev/discs/discN" for convenience. ++ The way to number disks is the same as GRUB's. */ ++ sprintf (discn, "/dev/discs/disc%d", i++); ++ if (stat (discn, &st) < 0) ++ break; ++ ++ if (realpath (discn, name)) ++ { ++ strcat (name, "/disc"); ++ if (hook (name, 0, hook_data)) ++ goto out; ++ } ++ } ++ goto out; ++ } ++#endif /* __linux__ */ ++ ++ /* IDE disks. */ ++ for (i = 0; i < 96; i++) ++ { ++ char name[16]; ++ ++ get_ide_disk_name (name, i); ++ if (check_device_readable_unique (name)) ++ { ++ if (hook (name, 0, hook_data)) ++ goto out; ++ } ++ } ++ ++#ifdef __FreeBSD_kernel__ ++ /* IDE disks using ATA Direct Access driver. */ ++ if (get_kfreebsd_version () >= 800000) ++ for (i = 0; i < 96; i++) ++ { ++ char name[16]; ++ ++ get_ada_disk_name (name, i); ++ if (check_device_readable_unique (name)) ++ { ++ if (hook (name, 0, hook_data)) ++ goto out; ++ } ++ } ++ ++ /* ATARAID disks. */ ++ for (i = 0; i < 8; i++) ++ { ++ char name[20]; ++ ++ get_ataraid_disk_name (name, i); ++ if (check_device_readable_unique (name)) ++ { ++ if (hook (name, 0, hook_data)) ++ goto out; ++ } ++ } ++ ++ /* LSI MegaRAID SAS. */ ++ for (i = 0; i < 32; i++) ++ { ++ char name[20]; ++ ++ get_mfi_disk_name (name, i); ++ if (check_device_readable_unique (name)) ++ { ++ if (hook (name, 0, hook_data)) ++ goto out; ++ } ++ } ++ ++ /* Virtio disks. */ ++ for (i = 0; i < 96; i++) ++ { ++ char name[16]; ++ ++ get_virtio_disk_name (name, i); ++ if (check_device_readable_unique (name)) ++ { ++ if (hook (name, 0, hook_data)) ++ goto out; ++ } ++ } ++ ++ /* Xen virtual block devices. */ ++ for (i = 0; i < 96; i++) ++ { ++ char name[16]; ++ ++ get_xvd_disk_name (name, i); ++ if (check_device_readable_unique (name)) ++ { ++ if (hook (name, 0, hook_data)) ++ goto out; ++ } ++ } ++#endif ++ ++#ifdef __linux__ ++ /* Virtio disks. */ ++ for (i = 0; i < 26; i++) ++ { ++ char name[16]; ++ ++ get_virtio_disk_name (name, i); ++ if (check_device_readable_unique (name)) ++ { ++ if (hook (name, 0, hook_data)) ++ goto out; ++ } ++ } ++ ++ /* ATARAID disks. */ ++ for (i = 0; i < 8; i++) ++ { ++ char name[20]; ++ ++ get_ataraid_disk_name (name, i); ++ if (check_device_readable_unique (name)) ++ { ++ if (hook (name, 0, hook_data)) ++ goto out; ++ } ++ } ++ ++ /* Xen virtual block devices. */ ++ for (i = 0; i < 26; i++) ++ { ++ char name[16]; ++ ++ get_xvd_disk_name (name, i); ++ if (check_device_readable_unique (name)) ++ { ++ if (hook (name, 0, hook_data)) ++ goto out; ++ } ++ } ++#endif /* __linux__ */ ++ ++ /* The rest is SCSI disks. */ ++ for (i = 0; i < 48; i++) ++ { ++ char name[16]; ++ ++ get_scsi_disk_name (name, i); ++ if (check_device_readable_unique (name)) ++ { ++ if (hook (name, 0, hook_data)) ++ goto out; ++ } ++ } ++ ++#ifdef __linux__ ++ /* This is for DAC960 - we have ++ /dev/rd/c<controller>d<logical drive>p<partition>. ++ ++ DAC960 driver currently supports up to 8 controllers, 32 logical ++ drives, and 7 partitions. */ ++ { ++ int controller, drive; ++ ++ for (controller = 0; controller < 8; controller++) ++ { ++ for (drive = 0; drive < 15; drive++) ++ { ++ char name[24]; ++ ++ get_dac960_disk_name (name, controller, drive); ++ if (check_device_readable_unique (name)) ++ { ++ if (hook (name, 0, hook_data)) ++ goto out; ++ } ++ } ++ } ++ } ++ ++ /* This is for Mylex Acceleraid - we have ++ /dev/rd/c<controller>d<logical drive>p<partition>. */ ++ { ++ int controller, drive; ++ ++ for (controller = 0; controller < 8; controller++) ++ { ++ for (drive = 0; drive < 15; drive++) ++ { ++ char name[24]; ++ ++ get_acceleraid_disk_name (name, controller, drive); ++ if (check_device_readable_unique (name)) ++ { ++ if (hook (name, 0, hook_data)) ++ goto out; ++ } ++ } ++ } ++ } ++ ++ /* This is for CCISS - we have ++ /dev/cciss/c<controller>d<logical drive>p<partition>. */ ++ { ++ int controller, drive; ++ ++ for (controller = 0; controller < 3; controller++) ++ { ++ for (drive = 0; drive < 16; drive++) ++ { ++ char name[24]; ++ ++ get_cciss_disk_name (name, controller, drive); ++ if (check_device_readable_unique (name)) ++ { ++ if (hook (name, 0, hook_data)) ++ goto out; ++ } ++ } ++ } ++ } ++ ++ /* This is for Compaq Intelligent Drive Array - we have ++ /dev/ida/c<controller>d<logical drive>p<partition>. */ ++ { ++ int controller, drive; ++ ++ for (controller = 0; controller < 3; controller++) ++ { ++ for (drive = 0; drive < 16; drive++) ++ { ++ char name[24]; ++ ++ get_ida_disk_name (name, controller, drive); ++ if (check_device_readable_unique (name)) ++ { ++ if (hook (name, 0, hook_data)) ++ goto out; ++ } ++ } ++ } ++ } ++ ++ /* This is for I2O - we have /dev/i2o/hd<logical drive><partition> */ ++ { ++ char unit; ++ ++ for (unit = 'a'; unit < 'f'; unit++) ++ { ++ char name[24]; ++ ++ get_i2o_disk_name (name, unit); ++ if (check_device_readable_unique (name)) ++ { ++ if (hook (name, 0, hook_data)) ++ goto out; ++ } ++ } ++ } ++ ++ /* MultiMediaCard (MMC). */ ++ for (i = 0; i < 10; i++) ++ { ++ char name[16]; ++ ++ get_mmc_disk_name (name, i); ++ if (check_device_readable_unique (name)) ++ { ++ if (hook (name, 0, hook_data)) ++ goto out; ++ } ++ } ++ ++ /* This is for standard NVMe controllers ++ /dev/nvme<controller>n<namespace>p<partition>. No idea about ++ actual limits of how many controllers a system can have and/or ++ how many namespace that would be, 10 for now. */ ++ { ++ int controller, namespace; ++ ++ for (controller = 0; controller < 10; controller++) ++ { ++ for (namespace = 0; namespace < 10; namespace++) ++ { ++ char name[16]; ++ ++ get_nvme_disk_name (name, controller, namespace); ++ if (check_device_readable_unique (name)) ++ { ++ if (hook (name, 0, hook_data)) ++ goto out; ++ } ++ } ++ } ++ } ++ ++# ifdef HAVE_DEVICE_MAPPER ++# define dmraid_check(cond, ...) \ ++ if (! (cond)) \ ++ { \ ++ grub_dprintf ("deviceiter", __VA_ARGS__); \ ++ goto dmraid_end; \ ++ } ++ ++ /* DM-RAID. */ ++ if (grub_device_mapper_supported ()) ++ { ++ struct dm_tree *tree = NULL; ++ struct dm_task *task = NULL; ++ struct dm_names *names = NULL; ++ unsigned int next = 0; ++ void *top_handle, *second_handle; ++ struct dm_tree_node *root, *top, *second; ++ ++ /* Build DM tree for all devices. */ ++ tree = dm_tree_create (); ++ dmraid_check (tree, "dm_tree_create failed\n"); ++ task = dm_task_create (DM_DEVICE_LIST); ++ dmraid_check (task, "dm_task_create failed\n"); ++ dmraid_check (dm_task_run (task), "dm_task_run failed\n"); ++ names = dm_task_get_names (task); ++ dmraid_check (names, "dm_task_get_names failed\n"); ++ dmraid_check (names->dev, "No DM devices found\n"); ++ do ++ { ++ names = (struct dm_names *) ((char *) names + next); ++ dmraid_check (dm_tree_add_dev (tree, MAJOR (names->dev), ++ MINOR (names->dev)), ++ "dm_tree_add_dev (%s) failed\n", names->name); ++ next = names->next; ++ } ++ while (next); ++ ++ /* Walk the second-level children of the inverted tree; that is, devices ++ which are directly composed of non-DM devices such as hard disks. ++ This class includes all DM-RAID disks and excludes all DM-RAID ++ partitions. */ ++ root = dm_tree_find_node (tree, 0, 0); ++ top_handle = NULL; ++ top = dm_tree_next_child (&top_handle, root, 1); ++ while (top) ++ { ++ second_handle = NULL; ++ second = dm_tree_next_child (&second_handle, top, 1); ++ while (second) ++ { ++ const char *node_name, *node_uuid; ++ char *name; ++ ++ node_name = dm_tree_node_get_name (second); ++ dmraid_check (node_name, "dm_tree_node_get_name failed\n"); ++ node_uuid = dm_tree_node_get_uuid (second); ++ dmraid_check (node_uuid, "dm_tree_node_get_uuid failed\n"); ++ if (strstr (node_uuid, "DMRAID-") == 0) ++ { ++ grub_dprintf ("deviceiter", "%s is not DM-RAID\n", node_name); ++ goto dmraid_next_child; ++ } ++ ++ name = xasprintf ("/dev/mapper/%s", node_name); ++ if (check_device_readable_unique (name)) ++ { ++ if (hook (name, 0, hook_data)) ++ { ++ free (name); ++ if (task) ++ dm_task_destroy (task); ++ if (tree) ++ dm_tree_free (tree); ++ goto out; ++ } ++ } ++ free (name); ++ ++dmraid_next_child: ++ second = dm_tree_next_child (&second_handle, top, 1); ++ } ++ top = dm_tree_next_child (&top_handle, root, 1); ++ } ++ ++dmraid_end: ++ if (task) ++ dm_task_destroy (task); ++ if (tree) ++ dm_tree_free (tree); ++ } ++# endif /* HAVE_DEVICE_MAPPER */ ++#endif /* __linux__ */ ++ ++out: ++ clear_seen_devices (); ++} +diff --git a/util/devicemap.c b/util/devicemap.c +new file mode 100644 +index 000000000..c61864420 +--- /dev/null ++++ b/util/devicemap.c +@@ -0,0 +1,13 @@ ++#include <stdio.h> ++ ++#include <grub/util/deviceiter.h> ++ ++void ++grub_util_emit_devicemap_entry (FILE *fp, char *name, int is_floppy, ++ int *num_fd, int *num_hd) ++{ ++ if (is_floppy) ++ fprintf (fp, "(fd%d)\t%s\n", (*num_fd)++, name); ++ else ++ fprintf (fp, "(hd%d)\t%s\n", (*num_hd)++, name); ++} +diff --git a/util/grub-mkdevicemap.c b/util/grub-mkdevicemap.c +new file mode 100644 +index 000000000..c4bbdbf69 +--- /dev/null ++++ b/util/grub-mkdevicemap.c +@@ -0,0 +1,181 @@ ++/* grub-mkdevicemap.c - make a device map file automatically */ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008,2009,2010 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++#include <config.h> ++ ++#include <stdio.h> ++#include <unistd.h> ++#include <string.h> ++#include <stdlib.h> ++#include <sys/types.h> ++#include <sys/stat.h> ++#include <errno.h> ++#include <fcntl.h> ++#include <limits.h> ++ ++#include <grub/emu/misc.h> ++#include <grub/emu/hostdisk.h> ++#include <grub/util/misc.h> ++#include <grub/util/deviceiter.h> ++#include <grub/env.h> ++#include <grub/i18n.h> ++ ++#define _GNU_SOURCE 1 ++#include <getopt.h> ++ ++#include "progname.h" ++ ++/* Context for make_device_map. */ ++struct make_device_map_ctx ++{ ++ FILE *fp; ++ int num_fd; ++ int num_hd; ++}; ++ ++/* Helper for make_device_map. */ ++static int ++process_device (const char *name, int is_floppy, void *data) ++{ ++ struct make_device_map_ctx *ctx = data; ++ ++ grub_util_emit_devicemap_entry (ctx->fp, (char *) name, ++ is_floppy, &ctx->num_fd, &ctx->num_hd); ++ return 0; ++} ++ ++static void ++make_device_map (const char *device_map, int floppy_disks) ++{ ++ struct make_device_map_ctx ctx = { ++ .num_fd = 0, ++ .num_hd = 0 ++ }; ++ ++ if (strcmp (device_map, "-") == 0) ++ ctx.fp = stdout; ++ else ++ ctx.fp = fopen (device_map, "w"); ++ ++ if (! ctx.fp) ++ grub_util_error (_("cannot open %s"), device_map); ++ ++ grub_util_iterate_devices (process_device, &ctx, floppy_disks); ++ ++ if (ctx.fp != stdout) ++ fclose (ctx.fp); ++} ++ ++static struct option options[] = ++ { ++ {"device-map", required_argument, 0, 'm'}, ++ {"probe-second-floppy", no_argument, 0, 's'}, ++ {"no-floppy", no_argument, 0, 'n'}, ++ {"help", no_argument, 0, 'h'}, ++ {"version", no_argument, 0, 'V'}, ++ {"verbose", no_argument, 0, 'v'}, ++ {0, 0, 0, 0} ++ }; ++ ++static void ++usage (int status) ++{ ++ if (status) ++ fprintf (stderr, ++ _("Try `%s --help' for more information.\n"), program_name); ++ else ++ printf (_("\ ++Usage: %s [OPTION]...\n\ ++\n\ ++Generate a device map file automatically.\n\ ++\n\ ++ -n, --no-floppy do not probe any floppy drive\n\ ++ -s, --probe-second-floppy probe the second floppy drive\n\ ++ -m, --device-map=FILE use FILE as the device map [default=%s]\n\ ++ -h, --help display this message and exit\n\ ++ -V, --version print version information and exit\n\ ++ -v, --verbose print verbose messages\n\ ++\n\ ++Report bugs to <%s>.\n\ ++"), program_name, ++ DEFAULT_DEVICE_MAP, PACKAGE_BUGREPORT); ++ ++ exit (status); ++} ++ ++int ++main (int argc, char *argv[]) ++{ ++ char *dev_map = 0; ++ int floppy_disks = 1; ++ ++ grub_util_host_init (&argc, &argv); ++ ++ /* Check for options. */ ++ while (1) ++ { ++ int c = getopt_long (argc, argv, "snm:r:hVv", options, 0); ++ ++ if (c == -1) ++ break; ++ else ++ switch (c) ++ { ++ case 'm': ++ if (dev_map) ++ free (dev_map); ++ ++ dev_map = xstrdup (optarg); ++ break; ++ ++ case 'n': ++ floppy_disks = 0; ++ break; ++ ++ case 's': ++ floppy_disks = 2; ++ break; ++ ++ case 'h': ++ usage (0); ++ break; ++ ++ case 'V': ++ printf ("%s (%s) %s\n", program_name, PACKAGE_NAME, PACKAGE_VERSION); ++ return 0; ++ ++ case 'v': ++ verbosity++; ++ break; ++ ++ default: ++ usage (1); ++ break; ++ } ++ } ++ ++ if (verbosity > 1) ++ grub_env_set ("debug", "all"); ++ ++ make_device_map (dev_map ? : DEFAULT_DEVICE_MAP, floppy_disks); ++ ++ free (dev_map); ++ ++ return 0; ++} diff --git a/debian/patches/series b/debian/patches/series new file mode 100644 index 0000000..6a6fc3d --- /dev/null +++ b/debian/patches/series @@ -0,0 +1,115 @@ +olpc-prefix-hack.patch +core-in-fs.patch +dpkg-version-comparison.patch +grub-legacy-0-based-partitions.patch +disable-floppies.patch +grub.cfg-400.patch +gfxpayload-keep-default.patch +install-stage2-confusion.patch +mkrescue-efi-modules.patch +mkconfig-loopback.patch +restore-mkdevicemap.patch +gettext-quiet.patch +install-efi-fallback.patch +mkconfig-ubuntu-recovery.patch +install-locale-langpack.patch +mkconfig-nonexistent-loopback.patch +default-grub-d.patch +blacklist-1440x900x32.patch +mkconfig-ubuntu-distributor.patch +linuxefi.patch +mkconfig-signed-kernel.patch +install-signed.patch +wubi-no-windows.patch +maybe-quiet.patch +install-efi-adjust-distributor.patch +quick-boot.patch +quick-boot-lvm.patch +gfxpayload-dynamic.patch +vt-handoff.patch +probe-fusionio.patch +ignore-grub_func_test-failures.patch +mkconfig-recovery-title.patch +install-powerpc-machtypes.patch +ieee1275-clear-reset.patch +ppc64el-disable-vsx.patch +grub-install-pvxen-paths.patch +insmod-xzio-and-lzopio-on-xen.patch +grub-install-extra-removable.patch +mkconfig-other-inits.patch +zpool-full-device-name.patch +net-read-bracketed-ipv6-addr.patch +bootp-new-net_bootp6-command.patch +efinet-uefi-ipv6-pxe-support.patch +bootp-process-dhcpack-http-boot.patch +efinet-set-network-from-uefi-devpath.patch +efinet-set-dns-from-uefi-proto.patch +fix-lockdown.patch +skip-grub_cmd_set_date.patch +bash-completion-drop-have-checks.patch +at_keyboard-module-init.patch +uefi-secure-boot-cryptomount.patch +efi-variable-storage-minimise-writes.patch +grub-install-removable-shim.patch +dejavu-font-path.patch +xen-no-xsm-policy-in-non-xsm-options.patch +pc-verifiers-module.patch +debug_verifiers.patch +mkimage-fix-section-sizes.patch +tpm-unknown-error-non-fatal.patch +xfs-fix-v4-superblock.patch +tests-ahci-update-qemu-device-name.patch +minilzo-2.10.patch +0063-loader-efi-chainloader-Simplify-the-loader-state.patch +0064-commands-boot-Add-API-to-pass-context-to-loader.patch +0065-loader-efi-chainloader-Use-grub_loader_set_ex.patch +0066-kern-efi-sb-Reject-non-kernel-files-in-the-shim_lock.patch +0067-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch +0068-video-readers-png-Abort-sooner-if-a-read-operation-f.patch +0069-video-readers-png-Refuse-to-handle-multiple-image-he.patch +0070-video-readers-png-Drop-greyscale-support-to-fix-heap.patch +0071-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch +0072-video-readers-png-Sanity-check-some-huffman-codes.patch +0073-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch +0074-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch +0075-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch +0076-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch +0077-normal-charset-Fix-array-out-of-bounds-formatting-un.patch +0078-net-netbuff-Block-overly-large-netbuff-allocs.patch +0079-net-ip-Do-IP-fragment-maths-safely.patch +0080-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch +0081-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch +0082-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch +0083-net-tftp-Avoid-a-trivial-UAF.patch +0084-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch +0085-net-http-Fix-OOB-write-for-split-http-headers.patch +0086-net-http-Error-out-on-headers-with-LF-without-CR.patch +0087-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch +0088-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch +0089-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch +0090-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch +0091-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch +0092-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch +reenable_os-prober.patch +cve_2022_2601/0001-video-readers-Add-artificial-limit-to-image-dimensio.patch +cve_2022_2601/0002-font-Reject-glyphs-exceeds-font-max_glyph_width-or-f.patch +cve_2022_2601/0003-font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch +cve_2022_2601/0004-font-Fix-several-integer-overflows-in-grub_font_cons.patch +cve_2022_2601/0005-font-Remove-grub_font_dup_glyph.patch +cve_2022_2601/0006-font-Fix-integer-overflow-in-ensure_comb_space.patch +cve_2022_2601/0007-font-Fix-integer-overflow-in-BMP-index.patch +cve_2022_2601/0008-font-Fix-integer-underflow-in-binary-search-of-char-.patch +cve_2022_2601/0009-kern-efi-sb-Enforce-verification-of-font-files.patch +cve_2022_2601/0010-fbutil-Fix-integer-overflow.patch +cve_2022_2601/0011-font-Fix-an-integer-underflow-in-blit_comb.patch +cve_2022_2601/0012-font-Harden-grub_font_blit_glyph-and-grub_font_blit_.patch +cve_2022_2601/0013-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch +cve_2022_2601/0014-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch +font-Try-opening-fonts-from-the-bundled-memdisk.patch +kern-file-Fix-error-handling-in-grub_file_open.patch +ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-write-when-parsing-the-ATTRIBUTE_LIST-.patch +ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-reading-data-from-the-reside.patch +ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-parsing-directory-entries-fr.patch +ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-parsing-bitmaps-for-index-at.patch +ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-parsing-a-volume-label.patch +ntfs-cve-fixes/fs-ntfs-Make-code-more-readable.patch diff --git a/debian/patches/skip-grub_cmd_set_date.patch b/debian/patches/skip-grub_cmd_set_date.patch new file mode 100644 index 0000000..830b887 --- /dev/null +++ b/debian/patches/skip-grub_cmd_set_date.patch @@ -0,0 +1,27 @@ +From dc8f60ab6ca24cb871fe17955385138d43712727 Mon Sep 17 00:00:00 2001 +From: Colin Watson <cjwatson@debian.org> +Date: Sun, 28 Oct 2018 19:45:56 +0000 +Subject: Skip flaky grub_cmd_set_date test + +Bug-Debian: https://bugs.debian.org/906470 +Last-Update: 2018-10-28 + +Patch-Name: skip-grub_cmd_set_date.patch +--- + tests/grub_cmd_set_date.in | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/tests/grub_cmd_set_date.in b/tests/grub_cmd_set_date.in +index aac120a6c..1bb5be4ca 100644 +--- a/tests/grub_cmd_set_date.in ++++ b/tests/grub_cmd_set_date.in +@@ -1,6 +1,9 @@ + #! @BUILD_SHEBANG@ + set -e + ++echo "Skipping flaky test." ++exit 77 ++ + . "@builddir@/grub-core/modinfo.sh" + + case "${grub_modinfo_target_cpu}-${grub_modinfo_platform}" in diff --git a/debian/patches/tests-ahci-update-qemu-device-name.patch b/debian/patches/tests-ahci-update-qemu-device-name.patch new file mode 100644 index 0000000..f10fc08 --- /dev/null +++ b/debian/patches/tests-ahci-update-qemu-device-name.patch @@ -0,0 +1,34 @@ +From 1a1c93cd19a9ec67d6237d5a537976ff9297ab78 Mon Sep 17 00:00:00 2001 +From: Marius Bakke <marius@gnu.org> +Date: Sun, 13 Jun 2021 15:11:51 +0200 +Subject: tests/ahci: Change "ide-drive" deprecated QEMU device name to + "ide-hd" + +The "ide-drive" device was removed in QEMU 6.0. The "ide-hd" has been +available for more than 10 years now in QEMU. Thus there shouldn't be +any need for backwards compatible names. + +Signed-off-by: Marius Bakke <marius@gnu.org> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> + +Origin: upstream, https://git.savannah.gnu.org/cgit/grub.git/commit/?id=aaea244a6ddd1e35aed60a5c7a08ddc41f51805b +Last-Update: 2021-09-24 + +Patch-Name: tests-ahci-update-qemu-device-name.patch +--- + tests/ahci_test.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tests/ahci_test.in b/tests/ahci_test.in +index 7df560462..d844fe680 100644 +--- a/tests/ahci_test.in ++++ b/tests/ahci_test.in +@@ -41,7 +41,7 @@ echo "hello" > "$outfile" + + tar cf "$imgfile" "$outfile" + +-if [ "$(echo "nativedisk; source '(ahci0)/$outfile';" | "${grubshell}" --qemu-opts="-drive id=disk,file=$imgfile,if=none -device ahci,id=ahci -device ide-drive,drive=disk,bus=ahci.0 " | tail -n 1)" != "Hello World" ]; then ++if [ "$(echo "nativedisk; source '(ahci0)/$outfile';" | "${grubshell}" --qemu-opts="-drive id=disk,file=$imgfile,if=none -device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 " | tail -n 1)" != "Hello World" ]; then + rm "$imgfile" + rm "$outfile" + exit 1 diff --git a/debian/patches/tpm-unknown-error-non-fatal.patch b/debian/patches/tpm-unknown-error-non-fatal.patch new file mode 100644 index 0000000..5f3c3ee --- /dev/null +++ b/debian/patches/tpm-unknown-error-non-fatal.patch @@ -0,0 +1,31 @@ +From ba3a0d4b6c0b56f6d7935911b53a02a7d0504da5 Mon Sep 17 00:00:00 2001 +From: Mathieu Trudel-Lapierre <mathieu.trudel-lapierre@canonical.com> +Date: Sat, 10 Jul 2021 22:32:00 +0100 +Subject: tpm: Pass unknown error as non-fatal, but debug print the error we + got + +Signed-off-by: Mathieu Trudel-Lapierre <mathieu.trudel-lapierre@canonical.com> + +Bug-Debian: https://bugs.debian.org/940911 +Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/grub2/+bug/1848892 +Last-Update: 2021-09-24 + +Patch-Name: tpm-unknown-error-non-fatal.patch +--- + grub-core/commands/efi/tpm.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/grub-core/commands/efi/tpm.c b/grub-core/commands/efi/tpm.c +index a97d85368..e73bd5561 100644 +--- a/grub-core/commands/efi/tpm.c ++++ b/grub-core/commands/efi/tpm.c +@@ -145,7 +145,8 @@ grub_efi_log_event_status (grub_efi_status_t status) + case GRUB_EFI_NOT_FOUND: + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("TPM unavailable")); + default: +- return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("Unknown TPM error")); ++ grub_dprintf ("tpm", "Unknown TPM error: %" PRIdGRUB_SSIZE, status); ++ return 0; + } + } + diff --git a/debian/patches/uefi-secure-boot-cryptomount.patch b/debian/patches/uefi-secure-boot-cryptomount.patch new file mode 100644 index 0000000..cbef39c --- /dev/null +++ b/debian/patches/uefi-secure-boot-cryptomount.patch @@ -0,0 +1,48 @@ +From 7fd79864c87c57d586989d12c3d4a7e432b3d73a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Herv=C3=A9=20Werner?= <dud225@hotmail.com> +Date: Mon, 28 Jan 2019 17:24:23 +0100 +Subject: Fix setup on Secure Boot systems where cryptodisk is in use + +On full-encrypted systems, including /boot, the current code omits +cryptodisk commands needed to open the drives if Secure Boot is enabled. +This prevents grub2 from reading any further configuration residing on +the encrypted disk. +This patch fixes this issue by adding the needed "cryptomount" commands in +the load.cfg file that is then copied in the EFI partition. + +Bug-Debian: https://bugs.debian.org/917117 +Last-Update: 2019-02-10 + +Patch-Name: uefi-secure-boot-cryptomount.patch +--- + util/grub-install.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/util/grub-install.c b/util/grub-install.c +index b51fe4710..58f1453ba 100644 +--- a/util/grub-install.c ++++ b/util/grub-install.c +@@ -1531,6 +1531,23 @@ main (int argc, char *argv[]) + || uefi_secure_boot) + { + char *uuid = NULL; ++ ++ if (uefi_secure_boot && config.is_cryptodisk_enabled) ++ { ++ if (grub_dev->disk) ++ probe_cryptodisk_uuid (grub_dev->disk); ++ ++ for (curdrive = grub_drives + 1; *curdrive; curdrive++) ++ { ++ grub_device_t dev = grub_device_open (*curdrive); ++ if (!dev) ++ continue; ++ if (dev->disk) ++ probe_cryptodisk_uuid (dev->disk); ++ grub_device_close (dev); ++ } ++ } ++ + /* generic method (used on coreboot and ata mod). */ + if (!force_file_id + && grub_fs->fs_uuid && grub_fs->fs_uuid (grub_dev, &uuid)) diff --git a/debian/patches/vt-handoff.patch b/debian/patches/vt-handoff.patch new file mode 100644 index 0000000..153c58d --- /dev/null +++ b/debian/patches/vt-handoff.patch @@ -0,0 +1,101 @@ +From 4336395ce7d82827b466a0088e1b08d42ef24ae8 Mon Sep 17 00:00:00 2001 +From: Colin Watson <cjwatson@ubuntu.com> +Date: Mon, 13 Jan 2014 12:13:30 +0000 +Subject: Add configure option to use vt.handoff=7 + +This is used for non-recovery Linux entries only; it enables +flicker-free booting if gfxpayload=keep is in use and a suitable kernel +is present. + +Author: Andy Whitcroft <apw@canonical.com> +Forwarded: not-needed +Last-Update: 2013-12-25 + +Patch-Name: vt-handoff.patch +--- + configure.ac | 11 +++++++++++ + util/grub.d/10_linux.in | 28 +++++++++++++++++++++++++++- + 2 files changed, 38 insertions(+), 1 deletion(-) + +diff --git a/configure.ac b/configure.ac +index 947fd529f..e11df6bc5 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1948,6 +1948,17 @@ else + fi + AC_SUBST([GFXPAYLOAD_DYNAMIC]) + ++AC_ARG_ENABLE([vt-handoff], ++ [AS_HELP_STRING([--enable-vt-handoff], ++ [use Linux vt.handoff option for flicker-free booting (default=no)])], ++ [], [enable_vt_handoff=no]) ++if test x"$enable_vt_handoff" = xyes ; then ++ VT_HANDOFF=1 ++else ++ VT_HANDOFF=0 ++fi ++AC_SUBST([VT_HANDOFF]) ++ + LIBS="" + + AC_SUBST([FONT_SOURCE]) +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index d46d7852b..64204c216 100644 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -24,6 +24,7 @@ ubuntu_recovery="@UBUNTU_RECOVERY@" + quiet_boot="@QUIET_BOOT@" + quick_boot="@QUICK_BOOT@" + gfxpayload_dynamic="@GFXPAYLOAD_DYNAMIC@" ++vt_handoff="@VT_HANDOFF@" + + . "$pkgdatadir/grub-mkconfig_lib" + +@@ -104,6 +105,14 @@ if [ "$ubuntu_recovery" = 1 ]; then + GRUB_CMDLINE_LINUX_RECOVERY="$GRUB_CMDLINE_LINUX_RECOVERY nomodeset" + fi + ++if [ "$vt_handoff" = 1 ]; then ++ for word in $GRUB_CMDLINE_LINUX_DEFAULT; do ++ if [ "$word" = splash ]; then ++ GRUB_CMDLINE_LINUX_DEFAULT="$GRUB_CMDLINE_LINUX_DEFAULT \$vt_handoff" ++ fi ++ done ++fi ++ + linux_entry () + { + os="$1" +@@ -149,7 +158,7 @@ linux_entry () + fi + if ([ "$ubuntu_recovery" = 0 ] || [ x$type != xrecovery ]) && \ + ([ "x$GRUB_GFXPAYLOAD_LINUX" != x ] || [ "$gfxpayload_dynamic" = 1 ]); then +- echo " set gfxpayload=\$linux_gfx_mode" | sed "s/^/$submenu_indentation/" ++ echo " gfxmode \$linux_gfx_mode" | sed "s/^/$submenu_indentation/" + fi + + echo " insmod gzio" | sed "s/^/$submenu_indentation/" +@@ -228,6 +237,23 @@ prepare_root_cache= + boot_device_id= + title_correction_code= + ++cat << 'EOF' ++function gfxmode { ++ set gfxpayload="${1}" ++EOF ++if [ "$vt_handoff" = 1 ]; then ++ cat << 'EOF' ++ if [ "${1}" = "keep" ]; then ++ set vt_handoff=vt.handoff=7 ++ else ++ set vt_handoff= ++ fi ++EOF ++fi ++cat << EOF ++} ++EOF ++ + # Use ELILO's generic "efifb" when it's known to be available. + # FIXME: We need an interface to select vesafb in case efifb can't be used. + if [ "x$GRUB_GFXPAYLOAD_LINUX" != x ] || [ "$gfxpayload_dynamic" = 0 ]; then diff --git a/debian/patches/wubi-no-windows.patch b/debian/patches/wubi-no-windows.patch new file mode 100644 index 0000000..407d391 --- /dev/null +++ b/debian/patches/wubi-no-windows.patch @@ -0,0 +1,57 @@ +From f36695098443076b8eb12399c286136ac8ed50d3 Mon Sep 17 00:00:00 2001 +From: Colin Watson <cjwatson@ubuntu.com> +Date: Mon, 13 Jan 2014 12:13:24 +0000 +Subject: Skip Windows os-prober entries on Wubi systems + +Since we're already being booted from the Windows boot loader, including +entries that take us back to it mostly just causes confusion, and stops +us from being able to hide the menu if there are no other OSes +installed. + +https://blueprints.launchpad.net/ubuntu/+spec/foundations-o-wubi + +Forwarded: not-needed +Last-Update: 2013-11-26 + +Patch-Name: wubi-no-windows.patch +--- + util/grub.d/30_os-prober.in | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in +index e2ec80eb9..98aee403e 100644 +--- a/util/grub.d/30_os-prober.in ++++ b/util/grub.d/30_os-prober.in +@@ -113,6 +113,8 @@ EOF + + used_osprober_linux_ids= + ++wubi= ++ + for OS in ${OSPROBED} ; do + DEVICE="`echo ${OS} | cut -d ':' -f 1`" + LONGNAME="`echo ${OS} | cut -d ':' -f 2 | tr '^' ' '`" +@@ -149,6 +151,23 @@ for OS in ${OSPROBED} ; do + case ${BOOT} in + chain) + ++ case ${LONGNAME} in ++ Windows*) ++ if [ -z "$wubi" ]; then ++ if [ -x /usr/share/lupin-support/grub-mkimage ] && \ ++ /usr/share/lupin-support/grub-mkimage --test; then ++ wubi=yes ++ else ++ wubi=no ++ fi ++ fi ++ if [ "$wubi" = yes ]; then ++ echo "Skipping ${LONGNAME} on Wubi system" >&2 ++ continue ++ fi ++ ;; ++ esac ++ + onstr="$(gettext_printf "(on %s)" "${DEVICE}")" + cat << EOF + menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' $CLASS --class os \$menuentry_id_option 'osprober-chain-$(grub_get_device_id "${DEVICE}")' { diff --git a/debian/patches/xen-no-xsm-policy-in-non-xsm-options.patch b/debian/patches/xen-no-xsm-policy-in-non-xsm-options.patch new file mode 100644 index 0000000..315bdab --- /dev/null +++ b/debian/patches/xen-no-xsm-policy-in-non-xsm-options.patch @@ -0,0 +1,35 @@ +From 4d208a51f41c6df932805dfd681ad64a02c2c728 Mon Sep 17 00:00:00 2001 +From: Ian Jackson <ian.jackson@eu.citrix.com> +Date: Wed, 27 May 2020 17:00:45 +0100 +Subject: 20_linux_xen: Do not load XSM policy in non-XSM options + +For complicated reasons, even if you have XSM/FLASK disabled (as is +the default) the Xen build system still builds a policy file and puts +it in /boot. + +Even so, we shouldn't be loading this in the usual non-"XSM enabled" +entries. It doesn't do any particular harm but it is quite confusing. + +Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com> + +Bug-Debian: https://bugs.debian.org/961673 +Last-Update: 2020-05-29 + +Patch-Name: xen-no-xsm-policy-in-non-xsm-options.patch +--- + util/grub.d/20_linux_xen.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/util/grub.d/20_linux_xen.in b/util/grub.d/20_linux_xen.in +index d99751a94..a12780ebe 100644 +--- a/util/grub.d/20_linux_xen.in ++++ b/util/grub.d/20_linux_xen.in +@@ -173,7 +173,7 @@ EOF + ${module_loader} --nounzip $(echo $initrd_path) + EOF + fi +- if test -n "${xenpolicy}" ; then ++ if ${xsm} && test -n "${xenpolicy}" ; then + message="$(gettext_printf "Loading XSM policy ...")" + sed "s/^/$submenu_indentation/" << EOF + echo '$(echo "$message" | grub_quote)' diff --git a/debian/patches/xfs-fix-v4-superblock.patch b/debian/patches/xfs-fix-v4-superblock.patch new file mode 100644 index 0000000..7bafc46 --- /dev/null +++ b/debian/patches/xfs-fix-v4-superblock.patch @@ -0,0 +1,122 @@ +From bf29fbd997292bbf6be2eec03594ec82f0899f57 Mon Sep 17 00:00:00 2001 +From: Erwan Velu <erwanaliasr1@gmail.com> +Date: Wed, 25 Aug 2021 15:31:52 +0200 +Subject: fs/xfs: Fix unreadable filesystem with v4 superblock + +The commit 8b1e5d193 (fs/xfs: Add bigtime incompat feature support) +introduced the bigtime support by adding some features in v3 inodes. +This change extended grub_xfs_inode struct by 76 bytes but also changed +the computation of XFS_V2_INODE_SIZE and XFS_V3_INODE_SIZE. Prior this +commit, XFS_V2_INODE_SIZE was 100 bytes. After the commit it's 84 bytes +XFS_V2_INODE_SIZE becomes 16 bytes too small. + +As a result, the data structures aren't properly aligned and the GRUB +generates "attempt to read or write outside of partition" errors when +trying to read the XFS filesystem: + + GNU GRUB version 2.11 + .... + grub> set debug=efi,gpt,xfs + grub> insmod part_gpt + grub> ls (hd0,gpt1)/ + partmap/gpt.c:93: Read a valid GPT header + partmap/gpt.c:115: GPT entry 0: start=4096, length=1953125 + fs/xfs.c:931: Reading sb + fs/xfs.c:270: Validating superblock + fs/xfs.c:295: XFS v4 superblock detected + fs/xfs.c:962: Reading root ino 128 + fs/xfs.c:515: Reading inode (128) - 64, 0 + fs/xfs.c:515: Reading inode (739521961424144223) - 344365866970255880, 3840 + error: attempt to read or write outside of partition. + +This commit change the XFS_V2_INODE_SIZE computation by subtracting 76 +bytes instead of 92 bytes from the actual size of grub_xfs_inode struct. +This 76 bytes value comes from added members: + 20 grub_uint8_t unused5 + 1 grub_uint64_t flags2 + 48 grub_uint8_t unused6 + +This patch explicitly splits the v2 and v3 parts of the structure. +The unused4 is still ending of the v2 structures and the v3 starts +at unused5. Thanks to this we will avoid future corruptions of v2 +or v3 inodes. + +The XFS_V2_INODE_SIZE is returning to its expected size and the +filesystem is back to a readable state: + + GNU GRUB version 2.11 + .... + grub> set debug=efi,gpt,xfs + grub> insmod part_gpt + grub> ls (hd0,gpt1)/ + partmap/gpt.c:93: Read a valid GPT header + partmap/gpt.c:115: GPT entry 0: start=4096, length=1953125 + fs/xfs.c:931: Reading sb + fs/xfs.c:270: Validating superblock + fs/xfs.c:295: XFS v4 superblock detected + fs/xfs.c:962: Reading root ino 128 + fs/xfs.c:515: Reading inode (128) - 64, 0 + fs/xfs.c:515: Reading inode (128) - 64, 0 + fs/xfs.c:931: Reading sb + fs/xfs.c:270: Validating superblock + fs/xfs.c:295: XFS v4 superblock detected + fs/xfs.c:962: Reading root ino 128 + fs/xfs.c:515: Reading inode (128) - 64, 0 + fs/xfs.c:515: Reading inode (128) - 64, 0 + fs/xfs.c:515: Reading inode (128) - 64, 0 + fs/xfs.c:515: Reading inode (131) - 64, 768 + efi/ fs/xfs.c:515: Reading inode (3145856) - 1464904, 0 + grub2/ fs/xfs.c:515: Reading inode (132) - 64, 1024 + grub/ fs/xfs.c:515: Reading inode (139) - 64, 2816 + grub> + +Fixes: 8b1e5d193 (fs/xfs: Add bigtime incompat feature support) + +Signed-off-by: Erwan Velu <e.velu@criteo.com> +Tested-by: Carlos Maiolino <cmaiolino@redhat.com> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> + +Origin: upstream, https://git.savannah.gnu.org/cgit/grub.git/commit/?id=a4b495520e4dc41a896a8b916a64eda9970c50ea +Last-Update: 2021-09-24 + +Patch-Name: xfs-fix-v4-superblock.patch +--- + grub-core/fs/xfs.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c +index 0f524c3a8..e3816d1ec 100644 +--- a/grub-core/fs/xfs.c ++++ b/grub-core/fs/xfs.c +@@ -192,6 +192,11 @@ struct grub_xfs_time_legacy + grub_uint32_t nanosec; + } GRUB_PACKED; + ++/* ++ * The struct grub_xfs_inode layout was taken from the ++ * struct xfs_dinode_core which is described here: ++ * https://mirrors.edge.kernel.org/pub/linux/utils/fs/xfs/docs/xfs_filesystem_structure.pdf ++ */ + struct grub_xfs_inode + { + grub_uint8_t magic[2]; +@@ -208,14 +213,15 @@ struct grub_xfs_inode + grub_uint32_t nextents; + grub_uint16_t unused3; + grub_uint8_t fork_offset; +- grub_uint8_t unused4[37]; ++ grub_uint8_t unused4[17]; /* Last member of inode v2. */ ++ grub_uint8_t unused5[20]; /* First member of inode v3. */ + grub_uint64_t flags2; +- grub_uint8_t unused5[48]; ++ grub_uint8_t unused6[48]; /* Last member of inode v3. */ + } GRUB_PACKED; + + #define XFS_V3_INODE_SIZE sizeof(struct grub_xfs_inode) +-/* Size of struct grub_xfs_inode until fork_offset (included). */ +-#define XFS_V2_INODE_SIZE (XFS_V3_INODE_SIZE - 92) ++/* Size of struct grub_xfs_inode v2, up to unused4 member included. */ ++#define XFS_V2_INODE_SIZE (XFS_V3_INODE_SIZE - 76) + + struct grub_xfs_dirblock_tail + { diff --git a/debian/patches/zpool-full-device-name.patch b/debian/patches/zpool-full-device-name.patch new file mode 100644 index 0000000..4f6ce65 --- /dev/null +++ b/debian/patches/zpool-full-device-name.patch @@ -0,0 +1,33 @@ +From be244ee23f3b12266a5671486af814c57c616a6c Mon Sep 17 00:00:00 2001 +From: Chad MILLER <chad.miller@canonical.com> +Date: Thu, 27 Oct 2016 17:15:07 -0400 +Subject: Tell zpool to emit full device names + +zfs-initramfs currently provides extraneous, undesired symlinks to +devices directly underneath /dev/ to satisfy zpool's historical output +of unqualified device names. By including this environment variable to +signal our intent to zpool, zfs-linux packages can drop the symlink +behavior when updating to its upstream or backported output behavior. + +Bug: https://savannah.gnu.org/bugs/?43653 +Bug-Debian: https://bugs.debian.org/824974 +Bug-Ubuntu: https://bugs.launchpad.net/bugs/1527727 +Last-Update: 2016-11-01 + +Patch-Name: zpool-full-device-name.patch +--- + grub-core/osdep/unix/getroot.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/grub-core/osdep/unix/getroot.c b/grub-core/osdep/unix/getroot.c +index 46d7116c6..da102918d 100644 +--- a/grub-core/osdep/unix/getroot.c ++++ b/grub-core/osdep/unix/getroot.c +@@ -243,6 +243,7 @@ grub_util_find_root_devices_from_poolname (char *poolname) + argv[2] = poolname; + argv[3] = NULL; + ++ setenv ("ZPOOL_VDEV_NAME_PATH", "YES", 1); + pid = grub_util_exec_pipe (argv, &fd); + if (!pid) + return NULL; |