From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Nicolas Frayer Date: Thu, 16 May 2024 10:58:32 +0200 Subject: [PATCH] cmd/search: Rework of CVE-2023-4001 fix The initial fix implemented a new flag that forces the grub cfg stub to be located on the same disk as grub. This created several issues such as RAID machines not being able to boot as their partition names under grub were different from the partition where grub is located. It also simply means that any machines with the /boot partition located on a disk other than the one containing grub won't boot. This commit denies booting if the grub cfg stub is located on a USB drive with a duplicated UUID (UUID being the same as the partition containing the actual grub cfg stub) Signed-off-by: Nicolas Frayer --- grub-core/commands/search.c | 136 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 127 insertions(+), 9 deletions(-) diff --git a/grub-core/commands/search.c b/grub-core/commands/search.c index 819231751c38..1e61a5cf940f 100644 --- a/grub-core/commands/search.c +++ b/grub-core/commands/search.c @@ -30,6 +30,8 @@ #include #include #include +#include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -54,6 +56,100 @@ struct search_ctx int is_cache; }; +static int +is_device_usb (const char *name) +{ + int ret = 0; + + grub_device_t dev = grub_device_open(name); + + if (dev) + { + struct grub_efidisk_data + { + grub_efi_handle_t handle; + grub_efi_device_path_t *device_path; + grub_efi_device_path_t *last_device_path; + grub_efi_block_io_t *block_io; + struct grub_efidisk_data *next; + }; + + if (dev->disk && dev->disk->data) + { + struct grub_efidisk_data *dp = dev->disk->data; + + if ( GRUB_EFI_DEVICE_PATH_TYPE (dp->last_device_path) == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE && + GRUB_EFI_DEVICE_PATH_SUBTYPE (dp->last_device_path) == GRUB_EFI_USB_DEVICE_PATH_SUBTYPE) + { + ret = 1; + } + } + grub_device_close(dev); + } + + return ret; +} + +static int +get_device_uuid(const char *name, char** quid) +{ + int ret = 0; + + grub_device_t dev_part = grub_device_open(name); + + if (dev_part) + { + grub_fs_t fs; + + fs = grub_fs_probe (dev_part); + +#ifdef DO_SEARCH_FS_UUID +#define read_fn fs_uuid +#else +#define read_fn fs_label +#endif + if (fs && fs->read_fn) + { + fs->read_fn (dev_part, quid); + + if (grub_errno == GRUB_ERR_NONE && *quid) + { + ret = 1; + } + + } + grub_device_close (dev_part); + } + + return ret; +} +struct uuid_context { + char* name; + char* uuid; +}; + +static int +check_for_duplicate (const char *name, void *data) +{ + int ret = 0; + struct uuid_context * uuid_ctx = (struct uuid_context *)data; + char *quid = 0; + + get_device_uuid(name, &quid); + + if (quid == NULL) + return 0; + + if (!grub_strcasecmp(quid, uuid_ctx->uuid) && grub_strcasecmp(name, uuid_ctx->name)) + { + ret = 1; + } + + grub_free(quid); + + return ret; +} + /* Helper for FUNC_NAME. */ static int iterate_device (const char *name, void *data) @@ -104,15 +200,37 @@ iterate_device (const char *name, void *data) grub_str_sep (root_dev, root_disk, ',', rem_1); grub_str_sep (name, name_disk, ',', rem_2); if (root_disk != NULL && *root_disk != '\0' && - name_disk != NULL && *name_disk != '\0') - if (grub_strcmp(root_disk, name_disk) != 0) - { - grub_free (root_disk); - grub_free (name_disk); - grub_free (rem_1); - grub_free (rem_2); - return 0; - } + name_disk != NULL && *name_disk != '\0') + { + grub_device_t dev, dev_part; + + if (is_device_usb(name) && !is_device_usb(root_dev)) + { + char *quid_name = NULL; + int longlist = 0; + struct uuid_context uuid_ctx; + int ret = 0; + + get_device_uuid(name, &quid_name); + if (!grub_strcmp(quid_name, ctx->key)) + { + uuid_ctx.name = name; + uuid_ctx.uuid = quid_name; + + ret = grub_device_iterate (check_for_duplicate, &uuid_ctx); + + if (ret) + { + grub_printf("Duplicated media UUID found, rebooting ...\n"); + grub_sleep(10); + grub_reboot(); + } + } + + if (quid_name) grub_free (quid_name); + + } + } } grub_free (root_disk); grub_free (name_disk);