[SPECIFICATION RFC v3] The firmware and bootloader log specification
pends on the producer, - msg: the log message, NUL terminated string. In bf_log_msg, the producers are free to use or ignore any of the level, facility, and type fields. If level or facility are ignored, they should be set to 0. If type is ignored, it should be set to an empty NUL terminated string. Since it doesn't seem possible to have each boot component using the same log format, we added a log_format and log_phys_addr fields to give flexibility in how logs are stored. An example of a different log format that can be used is the cbmem_console log format used by coreboot: cbmem_console: +---+ u32| size | u32| cursor| u8[m] | body | +---+ There is still the outstanding issue of how the logs will be sent to the OS. If UEFI is used, we can use config tables. If ACPI or Device Tree is used, we can use bf_log_header.next_bflh_addr to present the logs. If none of these platforms are used, it becomes a lot trickier to solve this issue. Any suggestions are much appreciated and will be taken into consideration. I will be presenting this work at the LPC System Boot and Security Micro-conference on the 22nd of September at 7:50 AM PDT (14:50 UTC). Come and join if you want to discuss the design. The schedule for the System Boot and Security Micro-conference can be found here [3]. Thanks! Alec Brown [1] https://lists.gnu.org/archive/html/grub-devel/2020-11/msg00100.html [2] https://lists.gnu.org/archive/html/grub-devel/2020-12/msg00021.html [3] https://linuxplumbersconf.org/event/11/sessions/116/#20210922 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
Re: [SPECIFICATION RFC v3] The firmware and bootloader log specification
On Sun, Sep 19, 2021 at 12:53:35AM +0200, Heinrich Schuchardt wrote: > > > Am 18. September 2021 18:04:13 MESZ schrieb Alec Brown > : > >Hi everyone, > > > >I've been working on improving the specification for the firmware and > >bootloader > >log that Daniel Kiper has proposed and take into account most of the > >suggestions > >that were made in these threads [1], [2]. > > > >The goal is to allow various boot components to pass logs to the running OS > >and > >then to the user space for processing and analysis. These logs should be > >generic > >enough so that it can work in multiple environments and be human readable. > > Hello Alec, > > in your mail it remains unclear which information you want to put into the > log and why it is needed. I would prefer the motivation and content to be > clarified before defining any interface structures. > > We already the EFI_TCG2_PROTOCOL and RFC 5424 (The syslog protocol). Why do > we need to start from scratch? > > Best regards > > Heinrich Hi Heinrich, The motivation behind developing these logs was to allow TrenchBoot to be able to view how the platform was setup during boot. We intend for our specification to target the Bootloader and Firmware and collect logs from them, but not TPM event logs, which is what the EFI_TCG2_PROTOCOL collects. We plan on using our specification for the GRUB Bootloader since it will be more efficient and flexible to use than the syslog protocol. However, if other boot components want to use a different logging format, our bf_log_header allows them to do so. Alec Brown > > > > >It has yet to be decided where to put the final version of this > >specification. > >It should be merged into an existing specification, e.g. UEFI, ACPI, > >Multiboot2, > >or be standalone, such as a part of OASIS Standards. > > > >Below is how the layout of these logs would store their data. > > > >bf_log_header: > > +---+ > >u32| version | > >u32| size | > >u8[64] | producer | > >u8[64] | log_format| > >u64| flags | > >u64| next_bflh_addr| > >u64| log_addr | > >u32| log_size | > > +---+ > > > >bf_log_buffer: > > +---+ > >u32| version | > >u32| size | > >u8[64] | producer | > >u32| next_msg_off | > >bf_log_msg[l] | msgs | > > +---+ > > > >bf_log_msg: > > +---+ > >u32| size | > >u64| ts_nsec | > >u32| level | > >u32| facility | > >u32| msg_off | > >u8[n] | type | > >u8[m] | msg | > > +---+ > > > >Where l is the number of msgs, n is the size of type, and m is the size of > >the > >msg. > > > >The bf_log_header structure forms a linked list. Each bf_log_header element > >in > >the linked list points to the individual log buffer and the next > >bf_log_header > >element in the linked list. The first element in the linked list points to > >the > >last boot component in the boot chain. The last element points to the > >starting > >boot component in the boot chain. The log buffers which contain the log > >messages are produced by the various boot components, typically from the > >firmware to the bootloader. The log message is stored in a log format that is > >compatible with the boot component that produced it. > > > >The fields in bf_log_header structure: > > - version: the firmware and bootloader log header version number, 1 for > > now, > > - size: the size of the bf_log_header to allow for backward compatibility > > if > >other fields are added, > > - producer: the producer/firmware/bootloader/... entity, NUL terminated > >string, e.g. GRUB, Coreboot; the length allows for ASCII UUID storage, > > - log_format: the format used to record the log messages, NUL terminated > >string, e.g. bf_log_msg, cbmem_cons, etc.; various producers may generate > >logs in various formats if needed, > > - flags: bit field used to store information about the log state, if bit 0 > > has > &
Re: [External] : Re: [SPECIFICATION RFC v3] The firmware and bootloader log specification
On Tue, Sep 21, 2021 at 03:40:20PM +, Peter Stuge wrote: > Alec Brown wrote: > > Below is how the layout of these logs would store their data. > > > > bf_log_header: > >+---+ > > u32| version | > > u32| size | > > u8[64] | producer | > > u8[64] | log_format| > > u64| flags | > > u64| next_bflh_addr| > > u64| log_addr | > > u32| log_size | > >+---+ > > I suggest to include a .magic at least in bf_log_header and an > .xor_checksum or .crc32 only in bf_log_header. > > .magic doubles as endianess indicator when the structures are > stored on movable media. (Pick an asymmetric magic bit pattern!) This is something we will need to think about. > > I suggest renaming .next_bflh_addr to .next_log_header and .log_addr > to .log_buffer_addr. > > I suggest to remove .size and .log_size: > > The rationale for .size is "to allow for backward compatibility" but > that seems redundant thanks to .version. > > .log_size can be calculated from the subordinate data and is thus > mostly an unneccessary source of potential inconsistency. Looking back, I agree with removing .size since .version accomplishes the same task. I'm not so sure on removing .log_size as it can be very convenient, and .log_size won't need to be calculated every time someone wants to know the size of the logs generated from the boot component. > > > > bf_log_buffer: > >+---+ > > u32| version | > > u32| size | > > u8[64] | producer | > > u32| next_msg_off | > > bf_log_msg[l] | msgs | > >+---+ > > I suggest replacing .size and .next_msg_off with .messages containing l: > > .size can then be calculated from .messages; again, reliably avoiding > inconsistency between .size and .next_msg_off. > > Allocated size doesn't seem useful if writers must anyway maintain state > containing the starting address. If writers must be allowed to be completely > stateless then maybe at least rename .size to .allocated_size and see below > for discovery. > > Having .messages also eliminates the need for an end-of-messages marker > when the allocated space is not yet filled. > After some thinking, it makes sense to replace the meaning of .size with the meaning of .next_msg_off and removing .next_msg_off from the structure. This wouldn't be useful to store for the readers of the log. > > > bf_log_msg: > >+---+ > > u32| size | > > u64| ts_nsec | > > u32| level | > > u32| facility | > > u32| msg_off | > > u8[n] | type | > > u8[m] | msg | > >+---+ > > It seems inconsistent that log_header.size and log_msg.size cover only > the respective struct itself while log_buffer.size also covers all > subordinate messages. Skipping all .size in this version fixes that. > > And log_msg.size is not very useful since both .type and .msg have variable > length; it's not possible to access .msg without scanning .type. Please at > a minimum add .type_size but better yet replace .size with .type_size and > .msg_size. > You bring up some good points about the names for the fields and that they need to be more consistent. By removing .size in bf_log_header, this should make it more consistent. > > > There is still the outstanding issue of how the logs will be sent to the > > OS. If > > UEFI is used, we can use config tables. If ACPI or Device Tree is used, we > > can > > use bf_log_header.next_bflh_addr to present the logs. If none of these > > platforms > > are used, it becomes a lot trickier to solve this issue. > > > > Any suggestions are much appreciated and will be taken into consideration. > > Having bf_log_header.magic and some bf_log_header.$checksum, a strict rule > for bf_log_header start address granularity and a strict maximum offset > for the first header from top and/or bottom of memory allows to quickly > discover a log in memory without explicit handover. > This is something we'll have to think about some more. We aren't convinced about using .magic for log discovery and are looking for a more explicit way of doin
Re: [External] : Re: [SPECIFICATION RFC v3] The firmware and bootloader log specification
On Tue, Sep 21, 2021 at 03:07:25PM -0700, Julius Werner wrote: > > Since it doesn't seem possible to have each boot component using the same > > log > > format, we added a log_format and log_phys_addr fields to give flexibility > > in > > how logs are stored. An example of a different log format that can be used > > is > > the cbmem_console log format used by coreboot: > > I am not exactly sure how you expect this interoperability you seem to > be suggesting here to work. Are you saying that your bf_log_header can > sometimes point to the bf_log_buffer structure you define, and > sometimes to a coreboot CBMEM console buffer? But that's a completely > different format that requires a different reader implementation, how > is that supposed to work? If this proposal is just "we define a > wrapper structure that points to everyone's custom firmware log > implementation", then I don't really see the point (the only benefit > still left then might be discovery of the log buffer, but that's the > part you leave open in your design while all those other > implementations already have working discovery mechanisms of their own > anyway). > Depending on the preferred logging format by the boot component, bf_log_header can point to our bf_log_buffer, a Coreboot CBMEM console buffer, or some other preferred logging format. We are looking at ways to pass all logs through one mechanism to make it simpler to discover all logs along the boot chain. From our understanding, the CBMEM console is passed to the OS via a CBMEM table stored in lower memory in a forwarding entry and is discovered by a user space tool looking through /dev/mem. Is this correct? We aren't entirely sure how other implementations of log buffers accomplish this, but we think that an explicit mechanism can be beneficial. This is something we'll need to expand upon in the specification. > For the other structures you have defined, the same feedback that I > think was already mentioned on the last iteration of this thread still > applies: it seems incredibly bloated for a simple firmware logging > mechanism. You have a whooping 24+n bytes of overhead *per line* which > probably comes out to somewhere between 30-50% of total space wasted > on overhead for the average log buffer. I guess there are just > fundamentally different opinions on how featureful a firmware log > mechanism needs to be so we're probably not gonna find a format that > makes everyone happy here, but at least for the coreboot project I see > little reason for us to implement something like this when we already > have a well-working existing solution with tooling and wideranged > support. Since, the logging format we are proposing won't be the best for each boot component environment, we are giving the option for boot components to use other logging formats that best suits their environment. ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 1/2] commands/probe: Fix resource leaks
Commit 1fc860bb76bb (commands/probe: Fix a resource leak when probing disks), missed other cases where grub_device_close() should be called before a return statement is called. Also found that grub_disk_close() wasn't being called when an error is being returned. To avoid conflict with grub_errno, grub_error_push() should be called before either grub_device_close() or grub_disk_close() is called and grub_error_pop() should be called before grub_errno is returned. Fixes: 1fc860bb76bb (commands/probe: Fix a resource leak when probing disks) Fixes: CID 292443 Signed-off-by: Alec Brown --- grub-core/commands/probe.c | 57 -- 1 file changed, 43 insertions(+), 14 deletions(-) diff --git a/grub-core/commands/probe.c b/grub-core/commands/probe.c index e53b61178..9a80ea54f 100644 --- a/grub-core/commands/probe.c +++ b/grub-core/commands/probe.c @@ -122,7 +122,13 @@ grub_cmd_probe (grub_extcmd_context_t ctxt, int argc, char **args) grub_gpt_part_guid_t *guid; if (grub_disk_read(disk, p->offset, p->index, sizeof(entry), &entry)) - return grub_errno; + { + grub_error_push (); + grub_disk_close (disk); + grub_device_close (dev); + grub_error_pop (); + return grub_errno; + } guid = &entry.guid; grub_snprintf (val, sizeof(val), "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", @@ -153,7 +159,12 @@ grub_cmd_probe (grub_extcmd_context_t ctxt, int argc, char **args) } fs = grub_fs_probe (dev); if (! fs) -return grub_errno; +{ + grub_error_push (); + grub_device_close (dev); + grub_error_pop (); + return grub_errno; +} if (state[3].set) { if (state[0].set) @@ -167,14 +178,23 @@ grub_cmd_probe (grub_extcmd_context_t ctxt, int argc, char **args) { char *uuid; if (! fs->fs_uuid) - return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - N_("%s does not support UUIDs"), fs->name); + { + grub_device_close (dev); + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, +N_("%s does not support UUIDs"), fs->name); + } err = fs->fs_uuid (dev, &uuid); if (err) - return err; + { + grub_device_close (dev); + return err; + } if (! uuid) - return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - N_("%s does not support UUIDs"), fs->name); + { + grub_device_close (dev); + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, +N_("%s does not support UUIDs"), fs->name); + } if (state[0].set) grub_env_set (state[0].arg, uuid); @@ -188,16 +208,25 @@ grub_cmd_probe (grub_extcmd_context_t ctxt, int argc, char **args) { char *label; if (! fs->fs_label) - return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - N_("filesystem `%s' does not support labels"), - fs->name); + { + grub_device_close (dev); + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, +N_("filesystem `%s' does not support labels"), +fs->name); + } err = fs->fs_label (dev, &label); if (err) - return err; + { + grub_device_close (dev); + return err; + } if (! label) - return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - N_("filesystem `%s' does not support labels"), - fs->name); + { + grub_device_close (dev); + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, +N_("filesystem `%s' does not support labels"), +fs->name); + } if (state[0].set) grub_env_set (state[0].arg, label); -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 0/2] Fix some Coverity resource leak bugs
There were a couple of commits which made fixes to a few Coverity bugs addressing resource leaks, but missed some cases where a variable was not being freed before a return statement was called. The Coverity Bugs being addressed are: CID 292443 CID 73804 Alec Brown (2): commands/probe: Fix resource leaks disk/ldm: Fix resource leak grub-core/commands/probe.c | 57 +++-- grub-core/disk/ldm.c | 1 + 2 files changed, 44 insertions(+), 14 deletions(-) ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 2/2] disk/ldm: Fix resource leak
Commit 23e39f50ca7a (disk/ldm: Make sure comp data is freed before exiting from make_vg()) fixed several spots in make_vg() where comp data was leaking memory when an error was being handled but missed one. To avoid leaking memory, comp should be freed when an error is being handled after comp has been successfully allocated memory in the for loop. Fixes: 23e39f50ca7a (disk/ldm: Make sure comp data is freed before exiting from make_vg()) Fixes: CID 73804 Signed-off-by: Alec Brown --- grub-core/disk/ldm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/grub-core/disk/ldm.c b/grub-core/disk/ldm.c index 4577a51dc..337abf704 100644 --- a/grub-core/disk/ldm.c +++ b/grub-core/disk/ldm.c @@ -487,6 +487,7 @@ make_vg (grub_disk_t disk, ptr = vblk[i].dynamic; if (ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic)) { + grub_free (comp); goto fail2; } comp->internal_id = grub_malloc ((grub_size_t) ptr[0] + 2); -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH] affs: Fix resource leaks
In commit 178ac5107389 (affs: Fix memory leaks), fixes were made to grub_affs_iterate_dir() to prevent memory leaks from occuring after it returns without freeing node. However, there were still some instances where node was causing a memory leak when the function returns after calling grub_affs_create_node(). In this function, new memory is allocated to node but doesn't get freed until the hook() function is called near the end. Before hook() is called, node should be freed in grub_affs_create_node() before returning out of it. Fixes: 178ac5107389 (affs: Fix memory leaks) Fixes: CID 73759 Signed-off-by: Alec Brown --- grub-core/fs/affs.c | 15 --- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/grub-core/fs/affs.c b/grub-core/fs/affs.c index cafcd0fba..7b9e62064 100644 --- a/grub-core/fs/affs.c +++ b/grub-core/fs/affs.c @@ -370,17 +370,26 @@ grub_affs_create_node (grub_fshelp_node_t dir, GRUB_DISK_SECTOR_SIZE - GRUB_AFFS_FILE_LOCATION, sizeof ((*node)->di), (char *) &(*node)->di); if (err) - return 1; + { + grub_free (*node); + return 1; + } continue; } default: - return 0; + { + grub_free (*node); + return 0; + } } break; } if (nest == 8) -return 0; +{ + grub_free (*node); + return 0; +} type |= GRUB_FSHELP_CASE_INSENSITIVE; -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 1/4] util/grub-module-verifierXX.c: Add function to calculate section headers
Added the function get_shdr() which returns the section header at a given index parameter passed into this function. This helps traverse the section header table and reduces repeated calls to lengthy equations used to obtain section headers. Note that it may look as though the argument *arch isn't being used, it's actually required in order to use the macros grub_target_to_host*(x) which are unwinded to grub_target_to_host*_real(arch, (x)) based on defines earlier in the file. Signed-off-by: Alec Brown --- util/grub-module-verifierXX.c | 25 +++-- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/util/grub-module-verifierXX.c b/util/grub-module-verifierXX.c index ceb24309a..92f9ae2a4 100644 --- a/util/grub-module-verifierXX.c +++ b/util/grub-module-verifierXX.c @@ -131,6 +131,12 @@ grub_target_to_host_real (const struct grub_module_verifier_arch *arch, grub_uin return grub_target_to_host32_real (arch, in); } +static Elf_Shdr * +get_shdr (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, Elf_Word index) +{ + return (Elf_Shdr *) ((char *) e + grub_target_to_host (e->e_shoff) + + index * grub_target_to_host16 (e->e_shentsize)); +} static Elf_Shdr * find_section (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, const char *name) @@ -139,12 +145,12 @@ find_section (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, const c const char *str; unsigned i; - s = (Elf_Shdr *) ((char *) e + grub_target_to_host (e->e_shoff) + grub_target_to_host16 (e->e_shstrndx) * grub_target_to_host16 (e->e_shentsize)); + s = get_shdr (arch, e, grub_target_to_host16 (e->e_shstrndx)); str = (char *) e + grub_target_to_host (s->sh_offset); - for (i = 0, s = (Elf_Shdr *) ((char *) e + grub_target_to_host (e->e_shoff)); + for (i = 0, s = get_shdr (arch, e, 0); i < grub_target_to_host16 (e->e_shnum); - i++, s = (Elf_Shdr *) ((char *) s + grub_target_to_host16 (e->e_shentsize))) + i++, s = get_shdr (arch, e, i)) if (strcmp (str + grub_target_to_host32 (s->sh_name), name) == 0) return s; return NULL; @@ -166,13 +172,12 @@ static Elf_Sym * get_symtab (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, Elf_Word *size, Elf_Word *entsize) { unsigned i; - Elf_Shdr *s, *sections; + Elf_Shdr *s; Elf_Sym *sym; - sections = (Elf_Shdr *) ((char *) e + grub_target_to_host (e->e_shoff)); - for (i = 0, s = sections; + for (i = 0, s = get_shdr (arch, e, 0); i < grub_target_to_host16 (e->e_shnum); - i++, s = (Elf_Shdr *) ((char *) s + grub_target_to_host16 (e->e_shentsize))) + i++, s = get_shdr (arch, e, i)) if (grub_target_to_host32 (s->sh_type) == SHT_SYMTAB) break; @@ -364,9 +369,9 @@ check_relocations (const char * const modname, Elf_Shdr *s; unsigned i; - for (i = 0, s = (Elf_Shdr *) ((char *) e + grub_target_to_host (e->e_shoff)); + for (i = 0, s = get_shdr (arch, e, 0); i < grub_target_to_host16 (e->e_shnum); - i++, s = (Elf_Shdr *) ((char *) s + grub_target_to_host16 (e->e_shentsize))) + i++, s = get_shdr (arch, e, i)) if (grub_target_to_host32 (s->sh_type) == SHT_REL || grub_target_to_host32 (s->sh_type) == SHT_RELA) { Elf_Shdr *ts; @@ -379,7 +384,7 @@ check_relocations (const char * const modname, /* Find the target segment. */ if (grub_target_to_host32 (s->sh_info) >= grub_target_to_host16 (e->e_shnum)) grub_util_error ("%s: orphaned reloc section", modname); - ts = (Elf_Shdr *) ((char *) e + grub_target_to_host (e->e_shoff) + grub_target_to_host32 (s->sh_info) * grub_target_to_host16 (e->e_shentsize)); + ts = get_shdr (arch, e, grub_target_to_host32 (s->sh_info)); section_check_relocations (modname, arch, e, s, grub_target_to_host (ts->sh_size)); } -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 3/4] util/grub-module-verifierXX.c: Validate elf section header table index for section name string table
In grub-module-verifierXX.c, the function find_section() uses the value from grub_target_to_host16 (e->e_shstrndx) to obtain the section header table index of the section name string table, but it wasn't being checked if the value was there. According to the elf(5) manual page, "If the index of section name string table section is larger than or equal to SHN_LORESERVE (0xff00), this member holds SHN_XINDEX (0x) and the real index of the section name string table section is held in the sh_link member of the initial entry in section header table. Otherwise, the sh_link member of the initial entry in section header table contains the value zero." Since this check wasn't being made, the function get_shstrndx() is being added to make this check and use e_shstrndx if it doesn't have SHN_XINDEX as a value, else use sh_link. We also need to make sure e_shstrndx isn't greater than or equal to SHN_LORESERVE and sh_link isn't less than SHN_LORESERVE. Note that it may look as though the argument *arch isn't being used, it's actually required in order to use the macros grub_target_to_host*(x) which are unwinded to grub_target_to_host*_real(arch, (x)) based on defines earlier in the file. Signed-off-by: Alec Brown --- util/grub-module-verifierXX.c | 25 - 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/util/grub-module-verifierXX.c b/util/grub-module-verifierXX.c index 61b82141f..3a5265aff 100644 --- a/util/grub-module-verifierXX.c +++ b/util/grub-module-verifierXX.c @@ -161,6 +161,29 @@ get_shnum (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e) return shnum; } +static Elf_Word +get_shstrndx (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e) +{ + Elf_Shdr *s; + Elf_Word shstrndx; + + shstrndx = grub_target_to_host16 (e->e_shstrndx); + if (shstrndx == SHN_XINDEX) +{ + s = get_shdr (arch, e, 0); + shstrndx = grub_target_to_host (s->sh_link); + if (shstrndx < SHN_LORESERVE) + grub_util_error ("Invalid section header table index in sh_link: %d", shstrndx); +} + else +{ + if (shstrndx >= SHN_LORESERVE) + grub_util_error ("Invalid section header table index in e_shstrndx: %d", shstrndx); +} + + return shstrndx; +} + static Elf_Shdr * find_section (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, const char *name) { @@ -168,7 +191,7 @@ find_section (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, const c const char *str; unsigned i; - s = get_shdr (arch, e, grub_target_to_host16 (e->e_shstrndx)); + s = get_shdr (arch, e, get_shstrndx (arch, e)); str = (char *) e + grub_target_to_host (s->sh_offset); for (i = 0, s = get_shdr (arch, e, 0); -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 0/4] Clean up code and fix coverity bugs in util/grub-module-verifierXX.c
Coverity identified several untrusted loop bounds in util/grub-module-verifierXX.c. This patch series addresses these bugs, cleans up lengthy equations, and makes checks to values based on the elf manual page. The Coverity Bugs being addressed are: CID 314021 CID 314027 CID 314033 Alec Brown (4): util/grub-module-verifierXX.c: Add function to calculate section headers util/grub-module-verifierXX.c: Validate number of elf section header table entries util/grub-module-verifierXX.c: Validate elf section header table index for section name string table util/grub-module-verifierXX.c: Add module_size parameter to functions for sanity checking util/grub-module-verifierXX.c | 124 +--- 1 file changed, 93 insertions(+), 31 deletions(-) ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 4/4] util/grub-module-verifierXX.c: Add module_size parameter to functions for sanity checking
In grub-module-verifierXX.c, the function grub_module_verifyXX() performs an initial check that the ELF section headers are within the module's size but doesn't check if the sections being accessed have contents that are within the module's size. In particular, we need to check that sh_offset and sh_size are less than the module's size. However, for some section header types we don't need to make these checks. For the type SHT_NULL, the section header is marked as inactive and the rest of the members within the section header have undefined values, so we don't need to check for sh_offset or sh_size. In the case of the type SHT_NOBITS, sh_offset has a conceptual offset which may be beyond the module size. Also, this type's sh_size may have a non-zero size, but a section of this type will take up no space in the module. This can all be checked in the function get_shdr(), but in order to do so, the parameter module_size must be added to functions so that the value of the module size can be used in get_shdr() from grub_module_verifyXX(). Signed-off-by: Alec Brown --- util/grub-module-verifierXX.c | 69 --- 1 file changed, 40 insertions(+), 29 deletions(-) diff --git a/util/grub-module-verifierXX.c b/util/grub-module-verifierXX.c index 3a5265aff..ac7b6fa78 100644 --- a/util/grub-module-verifierXX.c +++ b/util/grub-module-verifierXX.c @@ -132,10 +132,21 @@ grub_target_to_host_real (const struct grub_module_verifier_arch *arch, grub_uin } static Elf_Shdr * -get_shdr (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, Elf_Word index) +get_shdr (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, Elf_Word index, size_t module_size) { - return (Elf_Shdr *) ((char *) e + grub_target_to_host (e->e_shoff) + - index * grub_target_to_host16 (e->e_shentsize)); + Elf_Shdr *s; + + s = (Elf_Shdr *) ((char *) e + grub_target_to_host (e->e_shoff) + + index * grub_target_to_host16 (e->e_shentsize)); + /* Check that the header being accessed isn't outside the module size */ + if (grub_target_to_host32 (s->sh_type) != SHT_NULL && grub_target_to_host32 (s->sh_type) != SHT_NOBITS) +{ + if (grub_target_to_host (s->sh_offset) > module_size) + grub_util_error ("Section %d starts after the end of the module", index); + if (grub_target_to_host (s->sh_offset) + grub_target_to_host (s->sh_size) > module_size) + grub_util_error ("Section %d ends after the end of the module", index); +} + return s; } static Elf_Word @@ -147,7 +158,7 @@ get_shnum (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e) shnum = grub_target_to_host16 (e->e_shnum); if (shnum == SHN_UNDEF) { - s = get_shdr (arch, e, 0); + s = get_shdr (arch, e, 0, 0); shnum = grub_target_to_host (s->sh_size); if (shnum < SHN_LORESERVE) grub_util_error ("Invalid number of section header table entries in sh_size: %d", shnum); @@ -162,7 +173,7 @@ get_shnum (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e) } static Elf_Word -get_shstrndx (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e) +get_shstrndx (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, size_t module_size) { Elf_Shdr *s; Elf_Word shstrndx; @@ -170,7 +181,7 @@ get_shstrndx (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e) shstrndx = grub_target_to_host16 (e->e_shstrndx); if (shstrndx == SHN_XINDEX) { - s = get_shdr (arch, e, 0); + s = get_shdr (arch, e, 0, 0); shstrndx = grub_target_to_host (s->sh_link); if (shstrndx < SHN_LORESERVE) grub_util_error ("Invalid section header table index in sh_link: %d", shstrndx); @@ -185,18 +196,18 @@ get_shstrndx (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e) } static Elf_Shdr * -find_section (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, const char *name) +find_section (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, const char *name, size_t module_size) { Elf_Shdr *s; const char *str; unsigned i; - s = get_shdr (arch, e, get_shstrndx (arch, e)); + s = get_shdr (arch, e, get_shstrndx (arch, e, module_size), module_size); str = (char *) e + grub_target_to_host (s->sh_offset); - for (i = 0, s = get_shdr (arch, e, 0); + for (i = 0, s = get_shdr (arch, e, 0, 0); i < get_shnum (arch, e); - i++, s = get_shdr (arch, e, i)) + i++, s = get_shdr (arch, e, i, module_size)) if (strcmp (str + grub_target_to_host32 (s->sh_name), name) == 0) return s; return NULL; @@ -204,9 +215,9 @@ find_section (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, const c static void check_license (const char * const filename, - const struct grub_modul
[PATCH 2/4] util/grub-module-verifierXX.c: Validate number of elf section header table entries
In grub-module-verifierXX.c, grub_target_to_host16 (e->e_shnum) is used to obtain the number of section header table entries, but it wasn't being checked if the value was there. According to the elf(5) manual page, "If the number of entries in the section header table is larger than or equal to SHN_LORESERVE (0xff00), e_shnum holds the value zero and the real number of entries in the section header table is held in the sh_size member of the intial entry in section header table. Otherwise, the sh_size member of the initial entry in the section header table holds the value zero." Since this check wasn't being made, the function get_shnum() is being added to make this check and use whichever member doesn't have a value of zero. If both are zero, then we must return an error. We also need to make sure that e_shnum doesn't have a value greater than or equal to SHN_LORESERVE and sh_size isn't less than SHN_LORESERVE. Note that it may look as though the argument *arch isn't being used, it's actually required in order to use the macros grub_target_to_host*(x) which are unwinded to grub_target_to_host*_real(arch, (x)) based on defines earlier in the file. Fixes: CID 314021 Fixes: CID 314027 Fixes: CID 314033 Signed-off-by: Alec Brown --- util/grub-module-verifierXX.c | 35 +-- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/util/grub-module-verifierXX.c b/util/grub-module-verifierXX.c index 92f9ae2a4..61b82141f 100644 --- a/util/grub-module-verifierXX.c +++ b/util/grub-module-verifierXX.c @@ -138,6 +138,29 @@ get_shdr (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, Elf_Word in index * grub_target_to_host16 (e->e_shentsize)); } +static Elf_Word +get_shnum (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e) +{ + Elf_Shdr *s; + Elf_Word shnum; + + shnum = grub_target_to_host16 (e->e_shnum); + if (shnum == SHN_UNDEF) +{ + s = get_shdr (arch, e, 0); + shnum = grub_target_to_host (s->sh_size); + if (shnum < SHN_LORESERVE) + grub_util_error ("Invalid number of section header table entries in sh_size: %d", shnum); +} + else +{ + if (shnum >= SHN_LORESERVE) + grub_util_error ("Invalid number of section header table entries in e_shnum: %d", shnum); +} + + return shnum; +} + static Elf_Shdr * find_section (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, const char *name) { @@ -149,7 +172,7 @@ find_section (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, const c str = (char *) e + grub_target_to_host (s->sh_offset); for (i = 0, s = get_shdr (arch, e, 0); - i < grub_target_to_host16 (e->e_shnum); + i < get_shnum (arch, e); i++, s = get_shdr (arch, e, i)) if (strcmp (str + grub_target_to_host32 (s->sh_name), name) == 0) return s; @@ -176,12 +199,12 @@ get_symtab (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, Elf_Word Elf_Sym *sym; for (i = 0, s = get_shdr (arch, e, 0); - i < grub_target_to_host16 (e->e_shnum); + i < get_shnum (arch, e); i++, s = get_shdr (arch, e, i)) if (grub_target_to_host32 (s->sh_type) == SHT_SYMTAB) break; - if (i == grub_target_to_host16 (e->e_shnum)) + if (i == get_shnum (arch, e)) return NULL; sym = (Elf_Sym *) ((char *) e + grub_target_to_host (s->sh_offset)); @@ -370,7 +393,7 @@ check_relocations (const char * const modname, unsigned i; for (i = 0, s = get_shdr (arch, e, 0); - i < grub_target_to_host16 (e->e_shnum); + i < get_shnum (arch, e); i++, s = get_shdr (arch, e, i)) if (grub_target_to_host32 (s->sh_type) == SHT_REL || grub_target_to_host32 (s->sh_type) == SHT_RELA) { @@ -382,7 +405,7 @@ check_relocations (const char * const modname, grub_util_error ("%s: unsupported SHT_RELA", modname); /* Find the target segment. */ - if (grub_target_to_host32 (s->sh_info) >= grub_target_to_host16 (e->e_shnum)) + if (grub_target_to_host32 (s->sh_info) >= get_shnum (arch, e)) grub_util_error ("%s: orphaned reloc section", modname); ts = get_shdr (arch, e, grub_target_to_host32 (s->sh_info)); @@ -423,7 +446,7 @@ SUFFIX(grub_module_verify) (const char * const filename, /* Make sure that every section is within the core. */ if (size < grub_target_to_host (e->e_shoff) - + (grub_uint32_t) grub_target_to_host16 (e->e_shentsize) * grub_target_to_host16(e->e_shnum)) + + (grub_uint32_t) grub_target_to_host16 (e->e_shentsize) * get_shnum (arch, e)) { grub_util_error ("%s: ELF sections outside core", filename); } -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 0/7] Fix coverity uninitialized scalar variable bugs in grub-core
Coverity identified multiple uninitialized scalar variable bugs in multiple components of the grub-core. These patches address these issues. The Coverity bugs being addressed are: CID 375026 CID 375028 CID 375030 CID 375031 CID 375033 CID 375035 CID 375036 Alec Brown (7): grub-core/loader/i386/bsd.c: Fix uninitialized scalar variable grub-core/loader/i386/pc/linux.c: Fix uninitialized scalar variable grub-core/net/arp.c: Fix uninitialized scalar variable grub-core/loader/i386/xnu.c: Fix uninitialized scalar variable grub-core/net/net.c: Fix uninitialized scalar variable grub-core/loader/i386/xnu.c: Fix uninitialized scalar variable grub-core/net/bootp.c: Fix uninitialized scalar variable grub-core/loader/i386/bsd.c | 2 +- grub-core/loader/i386/pc/linux.c | 2 +- grub-core/loader/i386/xnu.c | 4 ++-- grub-core/net/arp.c | 3 ++- grub-core/net/bootp.c| 2 +- grub-core/net/net.c | 2 +- 6 files changed, 8 insertions(+), 7 deletions(-) ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 3/7] grub-core/net/arp.c: Fix uninitialized scalar variable
In the function grub_net_arp_receive(), grub_net_network_level_address_t sender_addr and target_addr are being called but aren't being initialized. To prevent contents of these structures from being filled with junk data from the stack, we can initialize them to 0 by setting sender_addr and target_addr to {}. Fixes: CID 375030 Signed-off-by: Alec Brown --- grub-core/net/arp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/grub-core/net/arp.c b/grub-core/net/arp.c index 54306e3b1..2b3765932 100644 --- a/grub-core/net/arp.c +++ b/grub-core/net/arp.c @@ -115,7 +115,8 @@ grub_net_arp_receive (struct grub_net_buff *nb, struct grub_net_card *card, grub_uint16_t *vlantag) { struct arppkt *arp_packet = (struct arppkt *) nb->data; - grub_net_network_level_address_t sender_addr, target_addr; + grub_net_network_level_address_t sender_addr = {}; + grub_net_network_level_address_t target_addr = {}; grub_net_link_level_address_t sender_mac_addr; struct grub_net_network_level_interface *inf; -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 1/7] grub-core/loader/i386/bsd.c: Fix uninitialized scalar variable
In the function grub_netbsd_setup_video(), struct grub_netbsd_btinfo_framebuf params is called but isn't being initialized. To prevent contents of this structure from being filled with junk data from the stack, we can initialize it to 0 by setting params to {}. Fixes: CID 375026 Signed-off-by: Alec Brown --- grub-core/loader/i386/bsd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grub-core/loader/i386/bsd.c b/grub-core/loader/i386/bsd.c index 5f3290ce1..b99344556 100644 --- a/grub-core/loader/i386/bsd.c +++ b/grub-core/loader/i386/bsd.c @@ -929,7 +929,7 @@ grub_netbsd_setup_video (void) struct grub_video_mode_info mode_info; void *framebuffer; const char *modevar; - struct grub_netbsd_btinfo_framebuf params; + struct grub_netbsd_btinfo_framebuf params = {}; grub_err_t err; grub_video_driver_id_t driv_id; -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 5/7] grub-core/net/net.c: Fix uninitialized scalar variable
In the function grub_net_ipv6_get_link_local(), grub_net_network_level_address_t addr is called but isn't being initialized. To prevent contents of this structure from being filled with junk data from the stack, we can initialize it to 0 by setting addr to {}; Fixes: CID 375033 Signed-off-by: Alec Brown --- grub-core/net/net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grub-core/net/net.c b/grub-core/net/net.c index 4d3eb5c1a..4e93365a7 100644 --- a/grub-core/net/net.c +++ b/grub-core/net/net.c @@ -287,7 +287,7 @@ grub_net_ipv6_get_link_local (struct grub_net_card *card, struct grub_net_network_level_interface *inf; char *name; char *ptr; - grub_net_network_level_address_t addr; + grub_net_network_level_address_t addr = {}; addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; addr.ipv6[0] = grub_cpu_to_be64_compile_time (0xfe80ULL << 48); -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 4/7] grub-core/loader/i386/xnu.c: Fix uninitialized scalar variable
In the function grub_xnu_boot_resume(), struct grub_relocator32_state state is called but isn't being initialized. To prevent contents of this structure from being filled with junk data from the stack, we can initialize it to 0 by setting state to {}. Fixes: CID 375031 Signed-off-by: Alec Brown --- grub-core/loader/i386/xnu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grub-core/loader/i386/xnu.c b/grub-core/loader/i386/xnu.c index a70093607..caab5cfa6 100644 --- a/grub-core/loader/i386/xnu.c +++ b/grub-core/loader/i386/xnu.c @@ -805,7 +805,7 @@ grub_cpu_xnu_fill_devicetree (grub_uint64_t *fsbfreq_out) grub_err_t grub_xnu_boot_resume (void) { - struct grub_relocator32_state state; + struct grub_relocator32_state state = {}; state.esp = grub_xnu_stack; state.ebp = grub_xnu_stack; -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 2/7] grub-core/loader/i386/pc/linux.c: Fix uninitialized scalar variable
In the function grub_linux16_boot(), struct grub_relocator16_state state is called but isn't being initialized. To prevent contents of this structure from being filled with junk data from the stack, we can initialize it to 0 by setting state to {}; Fixes: CID 375028 Signed-off-by: Alec Brown --- grub-core/loader/i386/pc/linux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grub-core/loader/i386/pc/linux.c b/grub-core/loader/i386/pc/linux.c index 2a2995201..808818d5f 100644 --- a/grub-core/loader/i386/pc/linux.c +++ b/grub-core/loader/i386/pc/linux.c @@ -55,7 +55,7 @@ static grub_err_t grub_linux16_boot (void) { grub_uint16_t segment; - struct grub_relocator16_state state; + struct grub_relocator16_state state = {}; segment = grub_linux_real_target >> 4; state.gs = state.fs = state.es = state.ds = state.ss = segment; -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 6/7] grub-core/loader/i386/xnu.c: Fix uninitialized scalar variable
In the function grub_xnu_boot(), struct grub_relocator32_state state is called but isn't being initialized. To prevent contents of this structure from being filled with junk data from the stack, we can initialize it to 0 by setting state to {}. Fixes: CID 375035 Signed-off-by: Alec Brown --- grub-core/loader/i386/xnu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grub-core/loader/i386/xnu.c b/grub-core/loader/i386/xnu.c index caab5cfa6..c956942a2 100644 --- a/grub-core/loader/i386/xnu.c +++ b/grub-core/loader/i386/xnu.c @@ -960,7 +960,7 @@ grub_xnu_boot (void) grub_addr_t devtree_target; grub_size_t devtreelen; int i; - struct grub_relocator32_state state; + struct grub_relocator32_state state = {}; grub_uint64_t fsbfreq = 1; int v2 = (grub_xnu_darwin_version >= 11); grub_uint32_t efi_system_table = 0; -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 7/7] grub-core/net/bootp.c: Fix uninitialized scalar variable
In the function grub_net_configure_by_dhcp_ack(), grub_net_network_level_address_t addr is called but isn't being initialized. To prevent contents of this structure from being filled with junk data from the stack, we can initialize it to 0 by setting addr to {}. Fixes: CID 375036 Signed-off-by: Alec Brown --- grub-core/net/bootp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c index 6fb562702..708d601df 100644 --- a/grub-core/net/bootp.c +++ b/grub-core/net/bootp.c @@ -232,7 +232,7 @@ grub_net_configure_by_dhcp_ack (const char *name, grub_size_t size, int is_def, char **device, char **path) { - grub_net_network_level_address_t addr; + grub_net_network_level_address_t addr = {}; grub_net_link_level_address_t hwaddr; struct grub_net_network_level_interface *inter; int mask = -1; -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v2 0/7] Fix coverity uninitialized scalar variable bugs in grub-core
v2: Set structs with multiple uninitialized members to {0} and set single uninitialized members to 0. Coverity identified multiple uninitialized scalar variable bugs in multiple components of the grub-core. These patches address these issues. The Coverity bugs being addressed are: CID 375026 CID 375028 CID 375030 CID 375031 CID 375033 CID 375035 CID 375036 Alec Brown (7): grub-core/loader/i386/bsd.c: Fix uninitialized scalar variable grub-core/loader/i386/pc/linux.c: Fix uninitialized scalar variable grub-core/net/arp.c: Fix uninitialized scalar variable grub-core/loader/i386/xnu.c: Fix uninitialized scalar variable grub-core/net/net.c: Fix uninitialized scalar variable grub-core/loader/i386/xnu.c: Fix uninitialized scalar variable grub-core/net/bootp.c: Fix uninitialized scalar variable grub-core/loader/i386/bsd.c | 2 +- grub-core/loader/i386/pc/linux.c | 2 +- grub-core/loader/i386/xnu.c | 4 ++-- grub-core/net/arp.c | 2 ++ grub-core/net/bootp.c| 1 + grub-core/net/net.c | 1 + 6 files changed, 8 insertions(+), 4 deletions(-) ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v2 3/7] grub-core/net/arp.c: Fix uninitialized scalar variable
In the function grub_net_arp_receive(), grub_net_network_level_address_t sender_addr and target_addr are being called but aren't being initialized. In both of these structs, each member is being set to a value except for grub_dns_option_t option. This results in this member being filled with junk data from the stack. To prevent this, we can set the option member in both structs to 0. Fixes: CID 375030 Signed-off-by: Alec Brown --- grub-core/net/arp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/grub-core/net/arp.c b/grub-core/net/arp.c index 54306e3b1..1d367436c 100644 --- a/grub-core/net/arp.c +++ b/grub-core/net/arp.c @@ -128,6 +128,8 @@ grub_net_arp_receive (struct grub_net_buff *nb, struct grub_net_card *card, target_addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; sender_addr.ipv4 = arp_packet->sender_ip; target_addr.ipv4 = arp_packet->recv_ip; + sender_addr.option = 0; + target_addr.option = 0; if (arp_packet->sender_ip == pending_req) have_pending = 1; -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v2 4/7] grub-core/loader/i386/xnu.c: Fix uninitialized scalar variable
In the function grub_xnu_boot_resume(), struct grub_relocator32_state state is called but isn't being initialized. This results in the members grub_uint32_t ebx, grub_uint32_t ecx, grub_uint32_t edx, grub_uint32_t esi, and grub_uint32_t edi being filled with junk data from the stack since none of them are being set to any values. We can prevent this by setting state to {0}. Fixes: CID 375031 Signed-off-by: Alec Brown --- grub-core/loader/i386/xnu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grub-core/loader/i386/xnu.c b/grub-core/loader/i386/xnu.c index a70093607..2bc118fc0 100644 --- a/grub-core/loader/i386/xnu.c +++ b/grub-core/loader/i386/xnu.c @@ -805,7 +805,7 @@ grub_cpu_xnu_fill_devicetree (grub_uint64_t *fsbfreq_out) grub_err_t grub_xnu_boot_resume (void) { - struct grub_relocator32_state state; + struct grub_relocator32_state state = {0}; state.esp = grub_xnu_stack; state.ebp = grub_xnu_stack; -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v2 5/7] grub-core/net/net.c: Fix uninitialized scalar variable
In the function grub_net_ipv6_get_link_local(), grub_net_network_level_address_t addr is called but isn't being initialized. This results in the member grub_dns_option_t option being filled with junk data from the stack. We can prevent this by setting the option member in addr to 0. Fixes: CID 375033 Signed-off-by: Alec Brown --- grub-core/net/net.c | 1 + 1 file changed, 1 insertion(+) diff --git a/grub-core/net/net.c b/grub-core/net/net.c index 4d3eb5c1a..b6eb1f951 100644 --- a/grub-core/net/net.c +++ b/grub-core/net/net.c @@ -292,6 +292,7 @@ grub_net_ipv6_get_link_local (struct grub_net_card *card, addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; addr.ipv6[0] = grub_cpu_to_be64_compile_time (0xfe80ULL << 48); addr.ipv6[1] = grub_net_ipv6_get_id (hwaddr); + addr.option = 0; FOR_NET_NETWORK_LEVEL_INTERFACES (inf) { -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v2 7/7] grub-core/net/bootp.c: Fix uninitialized scalar variable
In the function grub_net_configure_by_dhcp_ack(), grub_net_network_level_address_t addr is called but isn't being initialized. This results in the member grub_dns_option_t option being filled with junk data from the stack. To prevent this, we can set the option member in addr to 0. Fixes: CID 375036 Signed-off-by: Alec Brown --- grub-core/net/bootp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c index 6fb562702..8dbd1b232 100644 --- a/grub-core/net/bootp.c +++ b/grub-core/net/bootp.c @@ -244,6 +244,7 @@ grub_net_configure_by_dhcp_ack (const char *name, addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; addr.ipv4 = bp->your_ip; + addr.option = 0; if (device) *device = 0; -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v2 1/7] grub-core/loader/i386/bsd.c: Fix uninitialized scalar variable
In the function grub_netbsd_setup_video(), struct grub_netbsd_btinfo_framebuf params is called but isn't being initialized. The member grub_uint8_t reserved[16] isn't set to any values and is instead filled with junk data from the stack. We can prevent this by setting params to {0}. Fixes: CID 375026 Signed-off-by: Alec Brown --- grub-core/loader/i386/bsd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grub-core/loader/i386/bsd.c b/grub-core/loader/i386/bsd.c index 5f3290ce1..de63ca8dc 100644 --- a/grub-core/loader/i386/bsd.c +++ b/grub-core/loader/i386/bsd.c @@ -929,7 +929,7 @@ grub_netbsd_setup_video (void) struct grub_video_mode_info mode_info; void *framebuffer; const char *modevar; - struct grub_netbsd_btinfo_framebuf params; + struct grub_netbsd_btinfo_framebuf params = {0}; grub_err_t err; grub_video_driver_id_t driv_id; -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v2 2/7] grub-core/loader/i386/pc/linux.c: Fix uninitialized scalar variable
In the function grub_linux16_boot(), struct grub_relocator16_state state is called but isn't being initialized. This results in the members grub_uint32_t ebx, grub_uint32_t edx, grub_uint32_t esi, and grub_uint32_t ebp being filled with junk data from the stack since none of them are being set to any values. We can prevent this by setting state to {0}. Fixes: CID 375028 Signed-off-by: Alec Brown --- grub-core/loader/i386/pc/linux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grub-core/loader/i386/pc/linux.c b/grub-core/loader/i386/pc/linux.c index 2a2995201..bf4dc0488 100644 --- a/grub-core/loader/i386/pc/linux.c +++ b/grub-core/loader/i386/pc/linux.c @@ -55,7 +55,7 @@ static grub_err_t grub_linux16_boot (void) { grub_uint16_t segment; - struct grub_relocator16_state state; + struct grub_relocator16_state state = {0}; segment = grub_linux_real_target >> 4; state.gs = state.fs = state.es = state.ds = state.ss = segment; -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v2 6/7] grub-core/loader/i386/xnu.c: Fix uninitialized scalar variable
In the function grub_xnu_boot(), struct grub_relocator32_state state is called but isn't being initialized. This results in the members grub_uint32_t ebx, grub_uint32_t ecx, grub_uint32_t edx, grub_uint32_t edi, and grub_uint32_t esi being filled with junk data from the stack since none of them are being set to any values. We can prevent this by setting state to {0}. Fixes: CID 375035 Signed-off-by: Alec Brown --- grub-core/loader/i386/xnu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grub-core/loader/i386/xnu.c b/grub-core/loader/i386/xnu.c index 2bc118fc0..c0fb76df4 100644 --- a/grub-core/loader/i386/xnu.c +++ b/grub-core/loader/i386/xnu.c @@ -960,7 +960,7 @@ grub_xnu_boot (void) grub_addr_t devtree_target; grub_size_t devtreelen; int i; - struct grub_relocator32_state state; + struct grub_relocator32_state state = {0}; grub_uint64_t fsbfreq = 1; int v2 = (grub_xnu_darwin_version >= 11); grub_uint32_t efi_system_table = 0; -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v3 0/5] Fix coverity bugs and add checks for elf values in grub-core
v3: Added check for e_shoff, made starting words lowercase in error messages, and added comment to why return pointers are set to 0. Coverity identified several untrusted loop bounds and untrusted allocation size bugs in grub-core/loader/i386/bsdXX.c and grub-core/loader/multiboot_elfXX.c. Upon review of these bugs, I found that specific checks weren't being made to various elf header values based on the elf manual page. This patch series addresses the coverity bugs, as well as adds functions to check for the correct elf header values. The Coverity bugs being addressed are: CID 314018 CID 314030 CID 314031 CID 314039 Alec Brown (5): grub-core/loader/i386/bsdXX.c: Avoid downcasting (char *) to (Elf_Shdr *) elf: Validate number of elf section header table entries elf: Validate elf section header table index for section name string table elf: Validate number of elf program header table entries util/grub-module-verifierXX.c: Add e_shoff check in get_shdr() grub-core/kern/elf.c | 15 +++ grub-core/kern/elfXX.c | 101 + grub-core/loader/i386/bsdXX.c | 137 + grub-core/loader/multiboot_elfxx.c | 76 +++- include/grub/elf.h | 18 ++ util/grub-module-verifierXX.c | 3 +++ 6 files changed, 273 insertions(+), 77 deletions(-) ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v3 4/5] elf: Validate number of elf program header table entries
In bsdXX.c and multiboot_elfXX.c, e_phnum is used to obtain the number of program header table entries, but it wasn't being checked if the value was there. According to the elf(5) manual page, "If the number of entries in the program header table is larger than or equal to PN_XNUM (0x), this member holds PN_XNUM (0x) and the real number of entries in the program header table is held in the sh_info member of the initial entry in section header table. Otherwise, the sh_info member of the initial entry contains the value zero." Since this check wasn't being made, grub_elfXX_get_phnum() is being added to elfXX.c to make this check and use e_phnum if it doesn't have PN_XNUM as a value, else use sh_info. We also need to make sure e_phnum isn't greater than PN_XNUM and sh_info isn't less than PN_XNUM. Note that even though elf.c and elfXX.c are located in grub-core/kern, they are compiled as modules and don't need the EXPORT_FUNC macro to define the functions in elf.h. Signed-off-by: Alec Brown --- grub-core/kern/elf.c | 3 +++ grub-core/kern/elfXX.c | 34 ++ grub-core/loader/i386/bsdXX.c | 11 +++--- grub-core/loader/multiboot_elfxx.c | 19 +++-- include/grub/elf.h | 5 + 5 files changed, 63 insertions(+), 9 deletions(-) diff --git a/grub-core/kern/elf.c b/grub-core/kern/elf.c index 19440a318..ff5655206 100644 --- a/grub-core/kern/elf.c +++ b/grub-core/kern/elf.c @@ -176,6 +176,7 @@ grub_elf_open (const char *name, enum grub_file_type type) #define grub_elfXX_check_endianess_and_bswap_ehdr grub_elf32_check_endianess_and_bswap_ehdr #define grub_elfXX_get_shnum grub_elf32_get_shnum #define grub_elfXX_get_shstrndx grub_elf32_get_shstrndx +#define grub_elfXX_get_phnum grub_elf32_get_phnum #include "elfXX.c" @@ -198,6 +199,7 @@ grub_elf_open (const char *name, enum grub_file_type type) #undef grub_elfXX_check_endianess_and_bswap_ehdr #undef grub_elfXX_get_shnum #undef grub_elfXX_get_shstrndx +#undef grub_elfXX_get_phnum /* 64-bit */ @@ -220,5 +222,6 @@ grub_elf_open (const char *name, enum grub_file_type type) #define grub_elfXX_check_endianess_and_bswap_ehdr grub_elf64_check_endianess_and_bswap_ehdr #define grub_elfXX_get_shnum grub_elf64_get_shnum #define grub_elfXX_get_shstrndx grub_elf64_get_shstrndx +#define grub_elfXX_get_phnum grub_elf64_get_phnum #include "elfXX.c" diff --git a/grub-core/kern/elfXX.c b/grub-core/kern/elfXX.c index d09b37213..a917e7cce 100644 --- a/grub-core/kern/elfXX.c +++ b/grub-core/kern/elfXX.c @@ -272,3 +272,37 @@ grub_elfXX_get_shstrndx (ElfXX_Ehdr *e, grub_uint32_t *shstrndx) } return GRUB_ERR_NONE; } + +grub_err_t +grub_elfXX_get_phnum (ElfXX_Ehdr *e, grub_uint32_t *phnum) +{ + ElfXX_Shdr *s; + + if (phnum == NULL) +return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("NULL pointer passed for phnum")); + + /* Set *phnum to 0 so that phnum doesn't return junk on error */ + *phnum = 0; + + if (e == NULL) +return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("NULL pointer passed for elf header")); + + *phnum = e->e_phnum; + if (*phnum == PN_XNUM) +{ + if (e->e_shoff == 0) + return grub_error (GRUB_ERR_BAD_NUMBER, N_("invalid section header table offset in e_shoff")); + + s = (ElfXX_Shdr *) ((grub_uint8_t *) e + e->e_shoff); + *phnum = s->sh_info; + if (*phnum < PN_XNUM) + return grub_error (GRUB_ERR_BAD_NUMBER, N_("invalid number of program header table entries in sh_info: %d"), *phnum); +} + else +{ + if (*phnum >= PN_XNUM) + return grub_error (GRUB_ERR_BAD_NUMBER, N_("invalid number of program header table entries in e_phnum: %d"), *phnum); +} + + return GRUB_ERR_NONE; +} diff --git a/grub-core/loader/i386/bsdXX.c b/grub-core/loader/i386/bsdXX.c index 7d9b65d1a..eb1164dd7 100644 --- a/grub-core/loader/i386/bsdXX.c +++ b/grub-core/loader/i386/bsdXX.c @@ -185,6 +185,7 @@ SUFFIX (grub_freebsd_load_elfmodule) (struct grub_relocator *relocator, Elf_Shdr *s; Elf_Shdr *shdr = NULL; Elf_Word shnum; + grub_uint32_t phnum; grub_addr_t curload, module; grub_err_t err; grub_size_t chunk_size = 0; @@ -200,6 +201,10 @@ SUFFIX (grub_freebsd_load_elfmodule) (struct grub_relocator *relocator, if (err != GRUB_ERR_NONE) goto out; + err = grub_elf_get_phnum (&e, &phnum); + if (err != GRUB_ERR_NONE) +goto out; + for (s = shdr; s < (Elf_Shdr *) ((grub_uint8_t *) shdr + shnum * e.e_shentsize); s = (Elf_Shdr *) ((grub_uint8_t *) s + e.e_shentsize)) { @@ -214,7 +219,7 @@ SUFFIX (grub_freebsd_load_elfmodule) (struct grub_relocator *relocator, if (chunk_size < sizeof (e)) chunk_size = sizeof (e); - chunk_size += (grub_uint32_t) e.e_phnum * e.e_phentsize; + chunk_size += (grub_size_t) p
[PATCH v3 2/5] elf: Validate number of elf section header table entries
In bsdXX.c and multiboot_elfXX.c, e_shnum is used to obtain the number of section header table entries, but it wasn't being checked if the value was there. According to the elf(5) manual page, "If the number of entries in the section header table is larger than or equal to SHN_LORESERVE (0xff00), e_shnum holds the value zero and the real number of entries in the section header table is held in the sh_size member of the intial entry in section header table. Otherwise, the sh_size member of the initial entry in the section header table holds the value zero." Since this check wasn't being made, grub_elfXX_get_shnum() is being added to elfXX.c to make this check and use whichever member doesn't have a value of zero. If both are zero, then we must return an error. We also need to make sure that e_shnum doesn't have a value greater than or equal to SHN_LORESERVE and sh_size isn't less than SHN_LORESERVE. Note that even though elf.c and elfXX.c are located in grub-core/kern, they are compiled as modules and don't need the EXPORT_FUNC macro to define the functions in elf.h. Signed-off-by: Alec Brown --- grub-core/kern/elf.c | 9 grub-core/kern/elfXX.c | 34 + grub-core/loader/i386/bsdXX.c | 82 ++ grub-core/loader/multiboot_elfxx.c | 49 +++--- include/grub/elf.h | 9 5 files changed, 142 insertions(+), 41 deletions(-) diff --git a/grub-core/kern/elf.c b/grub-core/kern/elf.c index 9d7149b38..5be770583 100644 --- a/grub-core/kern/elf.c +++ b/grub-core/kern/elf.c @@ -167,11 +167,14 @@ grub_elf_open (const char *name, enum grub_file_type type) #define grub_elfXX_load_phdrs grub_elf32_load_phdrs #define ElfXX_Phdr Elf32_Phdr #define ElfXX_Ehdr Elf32_Ehdr +#define ElfXX_Shdr Elf32_Shdr +#define ElfXX_Word Elf32_Word #define grub_uintXX_t grub_uint32_t #define grub_swap_bytes_addrXX grub_swap_bytes32 #define grub_swap_bytes_offXX grub_swap_bytes32 #define grub_swap_bytes_XwordXX grub_swap_bytes32 #define grub_elfXX_check_endianess_and_bswap_ehdr grub_elf32_check_endianess_and_bswap_ehdr +#define grub_elfXX_get_shnum grub_elf32_get_shnum #include "elfXX.c" @@ -185,11 +188,14 @@ grub_elf_open (const char *name, enum grub_file_type type) #undef grub_elfXX_load_phdrs #undef ElfXX_Phdr #undef ElfXX_Ehdr +#undef ElfXX_Shdr +#undef ElfXX_Word #undef grub_uintXX_t #undef grub_swap_bytes_addrXX #undef grub_swap_bytes_offXX #undef grub_swap_bytes_XwordXX #undef grub_elfXX_check_endianess_and_bswap_ehdr +#undef grub_elfXX_get_shnum /* 64-bit */ @@ -203,10 +209,13 @@ grub_elf_open (const char *name, enum grub_file_type type) #define grub_elfXX_load_phdrs grub_elf64_load_phdrs #define ElfXX_Phdr Elf64_Phdr #define ElfXX_Ehdr Elf64_Ehdr +#define ElfXX_Shdr Elf64_Shdr +#define ElfXX_Word Elf64_Word #define grub_uintXX_t grub_uint64_t #define grub_swap_bytes_addrXX grub_swap_bytes64 #define grub_swap_bytes_offXX grub_swap_bytes64 #define grub_swap_bytes_XwordXX grub_swap_bytes64 #define grub_elfXX_check_endianess_and_bswap_ehdr grub_elf64_check_endianess_and_bswap_ehdr +#define grub_elfXX_get_shnum grub_elf64_get_shnum #include "elfXX.c" diff --git a/grub-core/kern/elfXX.c b/grub-core/kern/elfXX.c index 1859d1880..ed2dc7075 100644 --- a/grub-core/kern/elfXX.c +++ b/grub-core/kern/elfXX.c @@ -205,3 +205,37 @@ grub_elfXX_check_endianess_and_bswap_ehdr (grub_elf_t elf) return 0; } + +grub_err_t +grub_elfXX_get_shnum (ElfXX_Ehdr *e, ElfXX_Word *shnum) +{ + ElfXX_Shdr *s; + + if (shnum == NULL) +return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("NULL pointer passed for shnum")); + + /* Set *shnum to 0 so that shnum doesn't return junk on error */ + *shnum = 0; + + if (e == NULL) +return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("NULL pointer passed for elf header")); + + *shnum = e->e_shnum; + if (*shnum == SHN_UNDEF) +{ + if (e->e_shoff == 0) + return grub_error (GRUB_ERR_BAD_NUMBER, N_("invalid section header table offset in e_shoff")); + + s = (ElfXX_Shdr *) ((grub_uint8_t *) e + e->e_shoff); + *shnum = s->sh_size; + if (*shnum < SHN_LORESERVE) + return grub_error (GRUB_ERR_BAD_NUMBER, N_("invalid number of section header table entries in sh_size: %d"), *shnum); +} + else +{ + if (*shnum >= SHN_LORESERVE) + return grub_error (GRUB_ERR_BAD_NUMBER, N_("invalid number of section header table entries in e_shnum: %d"), *shnum); +} + + return GRUB_ERR_NONE; +} diff --git a/grub-core/loader/i386/bsdXX.c b/grub-core/loader/i386/bsdXX.c index 6946cecbb..7d9b65d1a 100644 --- a/grub-core/loader/i386/bsdXX.c +++ b/grub-core/loader/i386/bsdXX.c @@ -26,7 +26,10 @@ load (grub_file_t file, const char *filename, void *where, grub_off_t off, grub_ static inline grub_err_t read_headers (gru
[PATCH v3 1/5] grub-core/loader/i386/bsdXX.c: Avoid downcasting (char *) to (Elf_Shdr *)
In bsdXX.c, a couple of untrusted loop bound and untrusted allocation size bugs were flagged by Coverity in the functions grub_openbsd_find_ramdisk() and grub_freebsd_load_elfmodule(). These bugs were flagged by coverity because the variable shdr was downcasting from a char pointer to an Elf_Shdr pointer whenever it was used to set the base value in for loops. To avoid this, we need to set shdr as an Elf_Shdr pointer where it is initialized. In the function read_headers(), the function is reading elf section header data from a file and passing it to the variable shdr as data for a char pointer. If we switch the type of shdr to an Elf_Shdr pointer in read_headers() as well as other functions, then we won't need to downcast to an Elf_Shdr pointer and won't have to worry about tainted data later in the code. Fixes: CID 314018 Fixes: CID 314030 Fixes: CID 314031 Fixes: CID 314039 Signed-off-by: Alec Brown --- grub-core/loader/i386/bsdXX.c | 66 +++ 1 file changed, 28 insertions(+), 38 deletions(-) diff --git a/grub-core/loader/i386/bsdXX.c b/grub-core/loader/i386/bsdXX.c index e4f4aa365..6946cecbb 100644 --- a/grub-core/loader/i386/bsdXX.c +++ b/grub-core/loader/i386/bsdXX.c @@ -24,7 +24,7 @@ load (grub_file_t file, const char *filename, void *where, grub_off_t off, grub_ } static inline grub_err_t -read_headers (grub_file_t file, const char *filename, Elf_Ehdr *e, char **shdr) +read_headers (grub_file_t file, const char *filename, Elf_Ehdr *e, Elf_Shdr **shdr) { if (grub_file_seek (file, 0) == (grub_off_t) -1) return grub_errno; @@ -78,7 +78,7 @@ SUFFIX (grub_freebsd_load_elfmodule_obj) (struct grub_relocator *relocator, { Elf_Ehdr e; Elf_Shdr *s; - char *shdr = 0; + Elf_Shdr *shdr = NULL; grub_addr_t curload, module; grub_err_t err; grub_size_t chunk_size = 0; @@ -90,9 +90,8 @@ SUFFIX (grub_freebsd_load_elfmodule_obj) (struct grub_relocator *relocator, if (err) goto out; - for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) ((char *) shdr - + e.e_shnum * e.e_shentsize); - s = (Elf_Shdr *) ((char *) s + e.e_shentsize)) + for (s = shdr; s < (Elf_Shdr *) ((grub_uint8_t *) shdr + e.e_shnum * e.e_shentsize); + s = (Elf_Shdr *) ((grub_uint8_t *) s + e.e_shentsize)) { if (s->sh_size == 0) continue; @@ -113,9 +112,8 @@ SUFFIX (grub_freebsd_load_elfmodule_obj) (struct grub_relocator *relocator, chunk_src = get_virtual_current_address (ch); } - for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) ((char *) shdr - + e.e_shnum * e.e_shentsize); - s = (Elf_Shdr *) ((char *) s + e.e_shentsize)) + for (s = shdr; s < (Elf_Shdr *) ((grub_uint8_t *) shdr + e.e_shnum * e.e_shentsize); + s = (Elf_Shdr *) ((grub_uint8_t *) s + e.e_shentsize)) { if (s->sh_size == 0) continue; @@ -173,7 +171,7 @@ SUFFIX (grub_freebsd_load_elfmodule) (struct grub_relocator *relocator, { Elf_Ehdr e; Elf_Shdr *s; - char *shdr = 0; + Elf_Shdr *shdr = NULL; grub_addr_t curload, module; grub_err_t err; grub_size_t chunk_size = 0; @@ -185,9 +183,8 @@ SUFFIX (grub_freebsd_load_elfmodule) (struct grub_relocator *relocator, if (err) goto out; - for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) ((char *) shdr - + e.e_shnum * e.e_shentsize); - s = (Elf_Shdr *) ((char *) s + e.e_shentsize)) + for (s = shdr; s < (Elf_Shdr *) ((grub_uint8_t *) shdr + e.e_shnum * e.e_shentsize); + s = (Elf_Shdr *) ((grub_uint8_t *) s + e.e_shentsize)) { if (s->sh_size == 0) continue; @@ -214,9 +211,8 @@ SUFFIX (grub_freebsd_load_elfmodule) (struct grub_relocator *relocator, chunk_src = get_virtual_current_address (ch); } - for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) ((char *) shdr - + e.e_shnum * e.e_shentsize); - s = (Elf_Shdr *) ((char *) s + e.e_shentsize)) + for (s = shdr; s < (Elf_Shdr *) ((grub_uint8_t *) shdr + e.e_shnum * e.e_shentsize); + s = (Elf_Shdr *) ((grub_uint8_t *) s + e.e_shentsize)) { if (s->sh_size == 0) continue; @@ -285,7 +281,7 @@ SUFFIX (grub_freebsd_load_elf_meta) (struct grub_relocator *relocator, grub_err_t err; Elf_Ehdr e; Elf_Shdr *s; - char *shdr = 0; + Elf_Shdr *shdr = NULL; unsigned symoff, stroff, symsize, strsize; grub_freebsd_addr_t symstart, symend, symentsize, dynamic; Elf_Sym *sym; @@ -306,13 +302,11 @@ SUFFIX (grub_freebsd_load_elf_meta) (struct grub_relocator *relocator, if (err) goto out; - for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) (shdr - + e.e_shnum * e.e_shentsize); - s = (Elf_Shdr *) ((char *) s + e.e_shentsize)) + for (s = shdr; s < (Elf_Shdr *) ((grub_uint
[PATCH v3 5/5] util/grub-module-verifierXX.c: Add e_shoff check in get_shdr()
In util/grub-module-verifierXX.c, the function get_shdr() is used to obtain the section header at a given index but isn't checking that there is an offset for the section header table. To validate that there is, we can check that e_shoff isn't 0. Signed-off-by: Alec Brown --- util/grub-module-verifierXX.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/util/grub-module-verifierXX.c b/util/grub-module-verifierXX.c index 4e6cf133f..cf3ff0dfa 100644 --- a/util/grub-module-verifierXX.c +++ b/util/grub-module-verifierXX.c @@ -134,6 +134,9 @@ grub_target_to_host_real (const struct grub_module_verifier_arch *arch, grub_uin static Elf_Shdr * get_shdr (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, Elf_Word index) { + if (grub_target_to_host (e->e_shoff) == 0) +grub_util_error ("Invalid section header offset"); + return (Elf_Shdr *) ((char *) e + grub_target_to_host (e->e_shoff) + index * grub_target_to_host16 (e->e_shentsize)); } -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v3 3/5] elf: Validate elf section header table index for section name string table
In multiboot_elfXX.c, e_shstrndx is used to obtain the section header table index of the section name string table, but it wasn't being checked if the value was there. According to the elf(5) manual page, "If the index of section name string table section is larger than or equal to SHN_LORESERVE (0xff00), this member holds SHN_XINDEX (0x) and the real index of the section name string table section is held in the sh_link member of the initial entry in section header table. Otherwise, the sh_link member of the initial entry in section header table contains the value zero." Since this check wasn't being made, grub_elfXX_get_shstrndx() is being added to elfXX.c to make this check and use e_shstrndx if it doesn't have SHN_XINDEX as a value, else use sh_link. We also need to make sure e_shstrndx isn't greater than or equal to SHN_LORESERVE and sh_link isn't less than SHN_LORESERVE. Note that even though elf.c and elfXX.c are located in grub-core/kern, they are compiled as modules and don't need the EXPORT_FUNC macro to define the functions in elf.h. Signed-off-by: Alec Brown --- grub-core/kern/elf.c | 3 +++ grub-core/kern/elfXX.c | 33 ++ grub-core/loader/multiboot_elfxx.c | 10 - include/grub/elf.h | 4 4 files changed, 49 insertions(+), 1 deletion(-) diff --git a/grub-core/kern/elf.c b/grub-core/kern/elf.c index 5be770583..19440a318 100644 --- a/grub-core/kern/elf.c +++ b/grub-core/kern/elf.c @@ -175,6 +175,7 @@ grub_elf_open (const char *name, enum grub_file_type type) #define grub_swap_bytes_XwordXX grub_swap_bytes32 #define grub_elfXX_check_endianess_and_bswap_ehdr grub_elf32_check_endianess_and_bswap_ehdr #define grub_elfXX_get_shnum grub_elf32_get_shnum +#define grub_elfXX_get_shstrndx grub_elf32_get_shstrndx #include "elfXX.c" @@ -196,6 +197,7 @@ grub_elf_open (const char *name, enum grub_file_type type) #undef grub_swap_bytes_XwordXX #undef grub_elfXX_check_endianess_and_bswap_ehdr #undef grub_elfXX_get_shnum +#undef grub_elfXX_get_shstrndx /* 64-bit */ @@ -217,5 +219,6 @@ grub_elf_open (const char *name, enum grub_file_type type) #define grub_swap_bytes_XwordXX grub_swap_bytes64 #define grub_elfXX_check_endianess_and_bswap_ehdr grub_elf64_check_endianess_and_bswap_ehdr #define grub_elfXX_get_shnum grub_elf64_get_shnum +#define grub_elfXX_get_shstrndx grub_elf64_get_shstrndx #include "elfXX.c" diff --git a/grub-core/kern/elfXX.c b/grub-core/kern/elfXX.c index ed2dc7075..d09b37213 100644 --- a/grub-core/kern/elfXX.c +++ b/grub-core/kern/elfXX.c @@ -239,3 +239,36 @@ grub_elfXX_get_shnum (ElfXX_Ehdr *e, ElfXX_Word *shnum) return GRUB_ERR_NONE; } + +grub_err_t +grub_elfXX_get_shstrndx (ElfXX_Ehdr *e, grub_uint32_t *shstrndx) +{ + ElfXX_Shdr *s; + + if (shstrndx == NULL) +return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("NULL pointer passed for shstrndx")); + + /* Set *shstrndx to 0 so that shstrndx doesn't return junk on error */ + *shstrndx = 0; + + if (e == NULL) +return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("NULL pointer passed for elf header")); + + *shstrndx = e->e_shstrndx; + if (*shstrndx == SHN_XINDEX) +{ + if (e->e_shoff == 0) + return grub_error (GRUB_ERR_BAD_NUMBER, N_("invalid section header table offset in e_shoff")); + + s = (ElfXX_Shdr *) ((grub_uint8_t *) e + e->e_shoff); + *shstrndx = s->sh_link; + if (*shstrndx < SHN_LORESERVE) + return grub_error (GRUB_ERR_BAD_NUMBER, N_("invalid section header table index in sh_link: %d"), *shstrndx); +} + else +{ + if (*shstrndx >= SHN_LORESERVE) + return grub_error (GRUB_ERR_BAD_NUMBER, N_("invalid section header table index in e_shstrndx: %d"), *shstrndx); +} + return GRUB_ERR_NONE; +} diff --git a/grub-core/loader/multiboot_elfxx.c b/grub-core/loader/multiboot_elfxx.c index 1fe9be91b..54aaa24aa 100644 --- a/grub-core/loader/multiboot_elfxx.c +++ b/grub-core/loader/multiboot_elfxx.c @@ -25,6 +25,7 @@ # define Elf_Shdr Elf32_Shdr # define Elf_Word Elf32_Word # define grub_elf_get_shnumgrub_elf32_get_shnum +# define grub_elf_get_shstrndx grub_elf32_get_shstrndx #elif defined(MULTIBOOT_LOAD_ELF64) # define XX64 # define E_MACHINE MULTIBOOT_ELF64_MACHINE @@ -34,6 +35,7 @@ # define Elf_Shdr Elf64_Shdr # define Elf_Word Elf64_Word # define grub_elf_get_shnumgrub_elf64_get_shnum +# define grub_elf_get_shstrndx grub_elf64_get_shstrndx #else #error "I'm confused" #endif @@ -62,6 +64,7 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld) grub_err_t err; grub_relocator_chunk_t ch; grub_uint32_t load_offset = 0, load_size; + grub_uint32_t shstrndx; Elf_Word shnum; unsigned int i; void
[PATCH 0/6] Fix coverity bugs and add checks for elf values in grub-core
Coverity identified several untrusted loop bounds and untrusted allocation size bugs in grub-core/loader/i386/bsdXX.c and grub-core/loader/multiboot_elfXX.c. Upon review of these bugs, I found that specific checks weren't being made to various elf header values based on the elf manual page. The first four patches in this patch series address the coverity bugs, as well as adds functions to check for the correct elf header values. The last two patches adds fixes to previous work done in util/grub-module-verifierXX.c that also relates to making checks of elf header values. The Coverity bugs being addressed are: CID 314018 CID 314030 CID 314031 CID 314039 Alec Brown (6): grub-core/loader/i386/bsdXX.c: Avoid downcasting (char *) to (Elf_Shdr *) elf: Validate number of elf section header table entries elf: Validate elf section header table index for section name string table elf: Validate number of elf program header table entries util/grub-module-verifierXX.c: Add e_shoff check in get_shdr() util/grub-module-verifierXX.c: Changed get_shnum() return type grub-core/kern/elf.c | 18 ++ grub-core/kern/elfXX.c | 101 + grub-core/loader/i386/bsdXX.c | 142 +- grub-core/loader/multiboot_elfxx.c | 79 ++- include/grub/elf.h | 23 +++ util/grub-module-verifierXX.c | 13 + 6 files changed, 290 insertions(+), 86 deletions(-) ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 5/6] util/grub-module-verifierXX.c: Add e_shoff check in get_shdr()
In util/grub-module-verifierXX.c, the function get_shdr() is used to obtain the section header at a given index but isn't checking that there is an offset for the section header table. To validate that there is, we can check that e_shoff isn't 0. Signed-off-by: Alec Brown --- util/grub-module-verifierXX.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/util/grub-module-verifierXX.c b/util/grub-module-verifierXX.c index 4e6cf133f..cf3ff0dfa 100644 --- a/util/grub-module-verifierXX.c +++ b/util/grub-module-verifierXX.c @@ -134,6 +134,9 @@ grub_target_to_host_real (const struct grub_module_verifier_arch *arch, grub_uin static Elf_Shdr * get_shdr (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, Elf_Word index) { + if (grub_target_to_host (e->e_shoff) == 0) +grub_util_error ("Invalid section header offset"); + return (Elf_Shdr *) ((char *) e + grub_target_to_host (e->e_shoff) + index * grub_target_to_host16 (e->e_shentsize)); } -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 6/6] util/grub-module-verifierXX.c: Changed get_shnum() return type
In util/grub-module-verifierXX.c, the function get_shnum() returns the variable shnum, which is of the type Elf_Word. In the function, shnum can be obtained by the e_shnum member of an Elf_Ehdr or the sh_size member of an Elf_Shdr. The sh_size member can either be grub_uint32_t or grub_uint64_t, depending on the architecture, but Elf_Word is only grub_uint32_t. To account for when sh_size is grub_uint64_t, we can set shnum to have type Elf_Shnum and have get_shnum() return an Elf_Shnum. Signed-off-by: Alec Brown --- util/grub-module-verifierXX.c | 10 ++ 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/util/grub-module-verifierXX.c b/util/grub-module-verifierXX.c index cf3ff0dfa..8e0cd91d9 100644 --- a/util/grub-module-verifierXX.c +++ b/util/grub-module-verifierXX.c @@ -18,6 +18,7 @@ # define Elf_RelElf32_Rel # define Elf_Word Elf32_Word # define Elf_Half Elf32_Half +# define Elf_Shnum Elf32_Shnum # define Elf_SectionElf32_Section # define ELF_R_SYM(val)ELF32_R_SYM(val) # define ELF_R_TYPE(val) ELF32_R_TYPE(val) @@ -36,6 +37,7 @@ # define Elf_RelElf64_Rel # define Elf_Word Elf64_Word # define Elf_Half Elf64_Half +# define Elf_Shnum Elf64_Shnum # define Elf_SectionElf64_Section # define ELF_R_SYM(val)ELF64_R_SYM(val) # define ELF_R_TYPE(val) ELF64_R_TYPE(val) @@ -141,11 +143,11 @@ get_shdr (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, Elf_Word in index * grub_target_to_host16 (e->e_shentsize)); } -static Elf_Word +static Elf_Shnum get_shnum (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e) { Elf_Shdr *s; - Elf_Word shnum; + Elf_Shnum shnum; shnum = grub_target_to_host16 (e->e_shnum); if (shnum == SHN_UNDEF) @@ -153,12 +155,12 @@ get_shnum (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e) s = get_shdr (arch, e, 0); shnum = grub_target_to_host (s->sh_size); if (shnum < SHN_LORESERVE) - grub_util_error ("Invalid number of section header table entries in sh_size: %d", shnum); + grub_util_error ("Invalid number of section header table entries in sh_size: %" PRIuGRUB_UINT64_T, (grub_uint64_t) shnum); } else { if (shnum >= SHN_LORESERVE) - grub_util_error ("Invalid number of section header table entries in e_shnum: %d", shnum); + grub_util_error ("Invalid number of section header table entries in e_shnum: %" PRIuGRUB_UINT64_T, (grub_uint64_t) shnum); } return shnum; -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 4/6] elf: Validate number of elf program header table entries
In bsdXX.c and multiboot_elfXX.c, e_phnum is used to obtain the number of program header table entries, but it wasn't being checked if the value was there. According to the elf(5) manual page, "If the number of entries in the program header table is larger than or equal to PN_XNUM (0x), this member holds PN_XNUM (0x) and the real number of entries in the program header table is held in the sh_info member of the initial entry in section header table. Otherwise, the sh_info member of the initial entry contains the value zero." Since this check wasn't being made, grub_elfXX_get_phnum() is being added to elfXX.c to make this check and use e_phnum if it doesn't have PN_XNUM as a value, else use sh_info. We also need to make sure e_phnum isn't greater than PN_XNUM and sh_info isn't less than PN_XNUM. Note that even though elf.c and elfXX.c are located in grub-core/kern, they are compiled as modules and don't need the EXPORT_FUNC macro to define the functions in elf.h. Also, changed casts of phnum to match variables being set as well as dropped casts when unnecessary. Signed-off-by: Alec Brown --- grub-core/kern/elf.c | 3 +++ grub-core/kern/elfXX.c | 34 ++ grub-core/loader/i386/bsdXX.c | 11 +++--- grub-core/loader/multiboot_elfxx.c | 19 +++-- include/grub/elf.h | 5 + 5 files changed, 63 insertions(+), 9 deletions(-) diff --git a/grub-core/kern/elf.c b/grub-core/kern/elf.c index c676db694..077a8500c 100644 --- a/grub-core/kern/elf.c +++ b/grub-core/kern/elf.c @@ -177,6 +177,7 @@ grub_elf_open (const char *name, enum grub_file_type type) #define grub_elfXX_check_endianess_and_bswap_ehdr grub_elf32_check_endianess_and_bswap_ehdr #define grub_elfXX_get_shnum grub_elf32_get_shnum #define grub_elfXX_get_shstrndx grub_elf32_get_shstrndx +#define grub_elfXX_get_phnum grub_elf32_get_phnum #include "elfXX.c" @@ -200,6 +201,7 @@ grub_elf_open (const char *name, enum grub_file_type type) #undef grub_elfXX_check_endianess_and_bswap_ehdr #undef grub_elfXX_get_shnum #undef grub_elfXX_get_shstrndx +#undef grub_elfXX_get_phnum /* 64-bit */ @@ -223,5 +225,6 @@ grub_elf_open (const char *name, enum grub_file_type type) #define grub_elfXX_check_endianess_and_bswap_ehdr grub_elf64_check_endianess_and_bswap_ehdr #define grub_elfXX_get_shnum grub_elf64_get_shnum #define grub_elfXX_get_shstrndx grub_elf64_get_shstrndx +#define grub_elfXX_get_phnum grub_elf64_get_phnum #include "elfXX.c" diff --git a/grub-core/kern/elfXX.c b/grub-core/kern/elfXX.c index 4e3254fa5..aabf4b9d7 100644 --- a/grub-core/kern/elfXX.c +++ b/grub-core/kern/elfXX.c @@ -272,3 +272,37 @@ grub_elfXX_get_shstrndx (ElfXX_Ehdr *e, ElfXX_Word *shstrndx) } return GRUB_ERR_NONE; } + +grub_err_t +grub_elfXX_get_phnum (ElfXX_Ehdr *e, ElfXX_Word *phnum) +{ + ElfXX_Shdr *s; + + if (phnum == NULL) +return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("NULL pointer passed for phnum")); + + /* Set *phnum to 0 so that phnum doesn't return junk on error */ + *phnum = 0; + + if (e == NULL) +return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("NULL pointer passed for elf header")); + + *phnum = e->e_phnum; + if (*phnum == PN_XNUM) +{ + if (e->e_shoff == 0) + return grub_error (GRUB_ERR_BAD_NUMBER, N_("invalid section header table offset in e_shoff")); + + s = (ElfXX_Shdr *) ((grub_uint8_t *) e + e->e_shoff); + *phnum = s->sh_info; + if (*phnum < PN_XNUM) + return grub_error (GRUB_ERR_BAD_NUMBER, N_("invalid number of program header table entries in sh_info: %d"), *phnum); +} + else +{ + if (*phnum >= PN_XNUM) + return grub_error (GRUB_ERR_BAD_NUMBER, N_("invalid number of program header table entries in e_phnum: %d"), *phnum); +} + + return GRUB_ERR_NONE; +} diff --git a/grub-core/loader/i386/bsdXX.c b/grub-core/loader/i386/bsdXX.c index 6e5eb3643..2cc1daa49 100644 --- a/grub-core/loader/i386/bsdXX.c +++ b/grub-core/loader/i386/bsdXX.c @@ -183,6 +183,7 @@ SUFFIX (grub_freebsd_load_elfmodule) (struct grub_relocator *relocator, Elf_Ehdr e; Elf_Shdr *s, *shdr = NULL; Elf_Shnum shnum; + Elf_Word phnum; grub_addr_t curload, module; grub_err_t err; grub_size_t chunk_size = 0; @@ -198,6 +199,10 @@ SUFFIX (grub_freebsd_load_elfmodule) (struct grub_relocator *relocator, if (err != GRUB_ERR_NONE) goto out; + err = grub_elf_get_phnum (&e, &phnum); + if (err != GRUB_ERR_NONE) +goto out; + for (s = shdr; s < (Elf_Shdr *) ((grub_uint8_t *) shdr + shnum * e.e_shentsize); s = (Elf_Shdr *) ((grub_uint8_t *) s + e.e_shentsize)) { @@ -212,7 +217,7 @@ SUFFIX (grub_freebsd_load_elfmodule) (struct grub_relocator *relocator, if (chunk_size < sizeof (e)) chunk_size = sizeof (e); -
[PATCH 1/6] grub-core/loader/i386/bsdXX.c: Avoid downcasting (char *) to (Elf_Shdr *)
In bsdXX.c, a couple of untrusted loop bound and untrusted allocation size bugs were flagged by Coverity in the functions grub_openbsd_find_ramdisk() and grub_freebsd_load_elfmodule(). These bugs were flagged by coverity because the variable shdr was downcasting from a char pointer to an Elf_Shdr pointer whenever it was used to set the base value in for loops. To avoid this, we need to set shdr as an Elf_Shdr pointer where it is initialized. In the function read_headers(), the function is reading elf section header data from a file and passing it to the variable shdr as data for a char pointer. If we switch the type of shdr to an Elf_Shdr pointer in read_headers() as well as other functions, then we won't need to downcast to an Elf_Shdr pointer. By doing this, the issue becomes masked from Coverity's view. In the following patches, we check limits to ensure the data isn't tainted. Also, switched use of (char *) to (grub_uint8_t *) to give a better indication of pointer arithmetic and not suggest use of a C string. Fixes: CID 314018 Fixes: CID 314030 Fixes: CID 314031 Fixes: CID 314039 Signed-off-by: Alec Brown --- grub-core/loader/i386/bsdXX.c | 71 ++- 1 file changed, 28 insertions(+), 43 deletions(-) diff --git a/grub-core/loader/i386/bsdXX.c b/grub-core/loader/i386/bsdXX.c index e4f4aa365..e6edc6fb6 100644 --- a/grub-core/loader/i386/bsdXX.c +++ b/grub-core/loader/i386/bsdXX.c @@ -24,7 +24,7 @@ load (grub_file_t file, const char *filename, void *where, grub_off_t off, grub_ } static inline grub_err_t -read_headers (grub_file_t file, const char *filename, Elf_Ehdr *e, char **shdr) +read_headers (grub_file_t file, const char *filename, Elf_Ehdr *e, Elf_Shdr **shdr) { if (grub_file_seek (file, 0) == (grub_off_t) -1) return grub_errno; @@ -77,8 +77,7 @@ SUFFIX (grub_freebsd_load_elfmodule_obj) (struct grub_relocator *relocator, char *argv[], grub_addr_t *kern_end) { Elf_Ehdr e; - Elf_Shdr *s; - char *shdr = 0; + Elf_Shdr *s, *shdr = NULL; grub_addr_t curload, module; grub_err_t err; grub_size_t chunk_size = 0; @@ -90,9 +89,8 @@ SUFFIX (grub_freebsd_load_elfmodule_obj) (struct grub_relocator *relocator, if (err) goto out; - for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) ((char *) shdr - + e.e_shnum * e.e_shentsize); - s = (Elf_Shdr *) ((char *) s + e.e_shentsize)) + for (s = shdr; s < (Elf_Shdr *) ((grub_uint8_t *) shdr + e.e_shnum * e.e_shentsize); + s = (Elf_Shdr *) ((grub_uint8_t *) s + e.e_shentsize)) { if (s->sh_size == 0) continue; @@ -113,9 +111,8 @@ SUFFIX (grub_freebsd_load_elfmodule_obj) (struct grub_relocator *relocator, chunk_src = get_virtual_current_address (ch); } - for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) ((char *) shdr - + e.e_shnum * e.e_shentsize); - s = (Elf_Shdr *) ((char *) s + e.e_shentsize)) + for (s = shdr; s < (Elf_Shdr *) ((grub_uint8_t *) shdr + e.e_shnum * e.e_shentsize); + s = (Elf_Shdr *) ((grub_uint8_t *) s + e.e_shentsize)) { if (s->sh_size == 0) continue; @@ -172,8 +169,7 @@ SUFFIX (grub_freebsd_load_elfmodule) (struct grub_relocator *relocator, grub_addr_t *kern_end) { Elf_Ehdr e; - Elf_Shdr *s; - char *shdr = 0; + Elf_Shdr *s, *shdr = NULL; grub_addr_t curload, module; grub_err_t err; grub_size_t chunk_size = 0; @@ -185,9 +181,8 @@ SUFFIX (grub_freebsd_load_elfmodule) (struct grub_relocator *relocator, if (err) goto out; - for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) ((char *) shdr - + e.e_shnum * e.e_shentsize); - s = (Elf_Shdr *) ((char *) s + e.e_shentsize)) + for (s = shdr; s < (Elf_Shdr *) ((grub_uint8_t *) shdr + e.e_shnum * e.e_shentsize); + s = (Elf_Shdr *) ((grub_uint8_t *) s + e.e_shentsize)) { if (s->sh_size == 0) continue; @@ -214,9 +209,8 @@ SUFFIX (grub_freebsd_load_elfmodule) (struct grub_relocator *relocator, chunk_src = get_virtual_current_address (ch); } - for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) ((char *) shdr - + e.e_shnum * e.e_shentsize); - s = (Elf_Shdr *) ((char *) s + e.e_shentsize)) + for (s = shdr; s < (Elf_Shdr *) ((grub_uint8_t *) shdr + e.e_shnum * e.e_shentsize); + s = (Elf_Shdr *) ((grub_uint8_t *) s + e.e_shentsize)) { if (s->sh_size == 0) continue; @@ -284,8 +278,7 @@ SUFFIX (grub_freebsd_load_elf_meta) (struct grub_relocator *relocator, { grub_err_t err; Elf_Ehdr e; - Elf_Shdr *s; - char *shdr = 0; + Elf_Shdr *s, *shdr = NULL; unsigned symoff, stroff, symsize, strsize; grub_freebsd_addr_t symstart, symend, symentsize, dyn
[PATCH 2/6] elf: Validate number of elf section header table entries
In bsdXX.c and multiboot_elfXX.c, e_shnum is used to obtain the number of section header table entries, but it wasn't being checked if the value was there. According to the elf(5) manual page, "If the number of entries in the section header table is larger than or equal to SHN_LORESERVE (0xff00), e_shnum holds the value zero and the real number of entries in the section header table is held in the sh_size member of the intial entry in section header table. Otherwise, the sh_size member of the initial entry in the section header table holds the value zero." Since this check wasn't being made, grub_elfXX_get_shnum() is being added to elfXX.c to make this check and use whichever member doesn't have a value of zero. If both are zero, then we must return an error. We also need to make sure that e_shnum doesn't have a value greater than or equal to SHN_LORESERVE and sh_size isn't less than SHN_LORESERVE. In order to get this function to work, the type ElfXX_Shnum is being added where Elf32_Shnum defines Elf32_Word and Elf64_Shnum defines Elf64_Xword. This new type is needed because if shnum obtains a value from sh_size, sh_size could be of type El32_Word for Elf32_Shdr structures or Elf64_Xword for Elf64_Shdr structures. Note that even though elf.c and elfXX.c are located in grub-core/kern, they are compiled as modules and don't need the EXPORT_FUNC macro to define the functions in elf.h. Also, changed casts of shnum to match variables being set as well as dropped casts when unnecessary and fixed spacing errors in bsdXX.c. Signed-off-by: Alec Brown --- grub-core/kern/elf.c | 12 + grub-core/kern/elfXX.c | 34 + grub-core/loader/i386/bsdXX.c | 82 ++ grub-core/loader/multiboot_elfxx.c | 49 +++--- include/grub/elf.h | 14 + 5 files changed, 150 insertions(+), 41 deletions(-) diff --git a/grub-core/kern/elf.c b/grub-core/kern/elf.c index 9d7149b38..66b69293e 100644 --- a/grub-core/kern/elf.c +++ b/grub-core/kern/elf.c @@ -167,11 +167,15 @@ grub_elf_open (const char *name, enum grub_file_type type) #define grub_elfXX_load_phdrs grub_elf32_load_phdrs #define ElfXX_Phdr Elf32_Phdr #define ElfXX_Ehdr Elf32_Ehdr +#define ElfXX_Shdr Elf32_Shdr +#define ElfXX_Word Elf32_Word +#define ElfXX_Shnum Elf32_Shnum #define grub_uintXX_t grub_uint32_t #define grub_swap_bytes_addrXX grub_swap_bytes32 #define grub_swap_bytes_offXX grub_swap_bytes32 #define grub_swap_bytes_XwordXX grub_swap_bytes32 #define grub_elfXX_check_endianess_and_bswap_ehdr grub_elf32_check_endianess_and_bswap_ehdr +#define grub_elfXX_get_shnum grub_elf32_get_shnum #include "elfXX.c" @@ -185,11 +189,15 @@ grub_elf_open (const char *name, enum grub_file_type type) #undef grub_elfXX_load_phdrs #undef ElfXX_Phdr #undef ElfXX_Ehdr +#undef ElfXX_Shdr +#undef ElfXX_Word +#undef ElfXX_Shnum #undef grub_uintXX_t #undef grub_swap_bytes_addrXX #undef grub_swap_bytes_offXX #undef grub_swap_bytes_XwordXX #undef grub_elfXX_check_endianess_and_bswap_ehdr +#undef grub_elfXX_get_shnum /* 64-bit */ @@ -203,10 +211,14 @@ grub_elf_open (const char *name, enum grub_file_type type) #define grub_elfXX_load_phdrs grub_elf64_load_phdrs #define ElfXX_Phdr Elf64_Phdr #define ElfXX_Ehdr Elf64_Ehdr +#define ElfXX_Shdr Elf64_Shdr +#define ElfXX_Word Elf64_Word +#define ElfXX_Shnum Elf64_Shnum #define grub_uintXX_t grub_uint64_t #define grub_swap_bytes_addrXX grub_swap_bytes64 #define grub_swap_bytes_offXX grub_swap_bytes64 #define grub_swap_bytes_XwordXX grub_swap_bytes64 #define grub_elfXX_check_endianess_and_bswap_ehdr grub_elf64_check_endianess_and_bswap_ehdr +#define grub_elfXX_get_shnum grub_elf64_get_shnum #include "elfXX.c" diff --git a/grub-core/kern/elfXX.c b/grub-core/kern/elfXX.c index 1859d1880..48b7745a5 100644 --- a/grub-core/kern/elfXX.c +++ b/grub-core/kern/elfXX.c @@ -205,3 +205,37 @@ grub_elfXX_check_endianess_and_bswap_ehdr (grub_elf_t elf) return 0; } + +grub_err_t +grub_elfXX_get_shnum (ElfXX_Ehdr *e, ElfXX_Shnum *shnum) +{ + ElfXX_Shdr *s; + + if (shnum == NULL) +return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("NULL pointer passed for shnum")); + + /* Set *shnum to 0 so that shnum doesn't return junk on error */ + *shnum = 0; + + if (e == NULL) +return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("NULL pointer passed for elf header")); + + *shnum = e->e_shnum; + if (*shnum == SHN_UNDEF) +{ + if (e->e_shoff == 0) + return grub_error (GRUB_ERR_BAD_NUMBER, N_("invalid section header table offset in e_shoff")); + + s = (ElfXX_Shdr *) ((grub_uint8_t *) e + e->e_shoff); + *shnum = s->sh_size; + if (*shnum < SHN_LORESERVE) + return grub_error (GRUB_ERR_BAD_NUMBER, N_("invalid number of section header table entries in sh_size: %" PRIuGRUB
[PATCH 3/6] elf: Validate elf section header table index for section name string table
In multiboot_elfXX.c, e_shstrndx is used to obtain the section header table index of the section name string table, but it wasn't being checked if the value was there. According to the elf(5) manual page, "If the index of section name string table section is larger than or equal to SHN_LORESERVE (0xff00), this member holds SHN_XINDEX (0x) and the real index of the section name string table section is held in the sh_link member of the initial entry in section header table. Otherwise, the sh_link member of the initial entry in section header table contains the value zero." Since this check wasn't being made, grub_elfXX_get_shstrndx() is being added to elfXX.c to make this check and use e_shstrndx if it doesn't have SHN_XINDEX as a value, else use sh_link. We also need to make sure e_shstrndx isn't greater than or equal to SHN_LORESERVE and sh_link isn't less than SHN_LORESERVE. Note that even though elf.c and elfXX.c are located in grub-core/kern, they are compiled as modules and don't need the EXPORT_FUNC macro to define the functions in elf.h. Signed-off-by: Alec Brown --- grub-core/kern/elf.c | 3 +++ grub-core/kern/elfXX.c | 33 ++ grub-core/loader/multiboot_elfxx.c | 13 +++- include/grub/elf.h | 4 4 files changed, 52 insertions(+), 1 deletion(-) diff --git a/grub-core/kern/elf.c b/grub-core/kern/elf.c index 66b69293e..c676db694 100644 --- a/grub-core/kern/elf.c +++ b/grub-core/kern/elf.c @@ -176,6 +176,7 @@ grub_elf_open (const char *name, enum grub_file_type type) #define grub_swap_bytes_XwordXX grub_swap_bytes32 #define grub_elfXX_check_endianess_and_bswap_ehdr grub_elf32_check_endianess_and_bswap_ehdr #define grub_elfXX_get_shnum grub_elf32_get_shnum +#define grub_elfXX_get_shstrndx grub_elf32_get_shstrndx #include "elfXX.c" @@ -198,6 +199,7 @@ grub_elf_open (const char *name, enum grub_file_type type) #undef grub_swap_bytes_XwordXX #undef grub_elfXX_check_endianess_and_bswap_ehdr #undef grub_elfXX_get_shnum +#undef grub_elfXX_get_shstrndx /* 64-bit */ @@ -220,5 +222,6 @@ grub_elf_open (const char *name, enum grub_file_type type) #define grub_swap_bytes_XwordXX grub_swap_bytes64 #define grub_elfXX_check_endianess_and_bswap_ehdr grub_elf64_check_endianess_and_bswap_ehdr #define grub_elfXX_get_shnum grub_elf64_get_shnum +#define grub_elfXX_get_shstrndx grub_elf64_get_shstrndx #include "elfXX.c" diff --git a/grub-core/kern/elfXX.c b/grub-core/kern/elfXX.c index 48b7745a5..4e3254fa5 100644 --- a/grub-core/kern/elfXX.c +++ b/grub-core/kern/elfXX.c @@ -239,3 +239,36 @@ grub_elfXX_get_shnum (ElfXX_Ehdr *e, ElfXX_Shnum *shnum) return GRUB_ERR_NONE; } + +grub_err_t +grub_elfXX_get_shstrndx (ElfXX_Ehdr *e, ElfXX_Word *shstrndx) +{ + ElfXX_Shdr *s; + + if (shstrndx == NULL) +return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("NULL pointer passed for shstrndx")); + + /* Set *shstrndx to 0 so that shstrndx doesn't return junk on error */ + *shstrndx = 0; + + if (e == NULL) +return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("NULL pointer passed for elf header")); + + *shstrndx = e->e_shstrndx; + if (*shstrndx == SHN_XINDEX) +{ + if (e->e_shoff == 0) + return grub_error (GRUB_ERR_BAD_NUMBER, N_("invalid section header table offset in e_shoff")); + + s = (ElfXX_Shdr *) ((grub_uint8_t *) e + e->e_shoff); + *shstrndx = s->sh_link; + if (*shstrndx < SHN_LORESERVE) + return grub_error (GRUB_ERR_BAD_NUMBER, N_("invalid section header table index in sh_link: %d"), *shstrndx); +} + else +{ + if (*shstrndx >= SHN_LORESERVE) + return grub_error (GRUB_ERR_BAD_NUMBER, N_("invalid section header table index in e_shstrndx: %d"), *shstrndx); +} + return GRUB_ERR_NONE; +} diff --git a/grub-core/loader/multiboot_elfxx.c b/grub-core/loader/multiboot_elfxx.c index 0d6b6612f..8e0384505 100644 --- a/grub-core/loader/multiboot_elfxx.c +++ b/grub-core/loader/multiboot_elfxx.c @@ -23,8 +23,10 @@ # define Elf_Ehdr Elf32_Ehdr # define Elf_Phdr Elf32_Phdr # define Elf_Shdr Elf32_Shdr +# define Elf_Word Elf32_Word # define Elf_Shnum Elf32_Shnum # define grub_elf_get_shnumgrub_elf32_get_shnum +# define grub_elf_get_shstrndx grub_elf32_get_shstrndx #elif defined(MULTIBOOT_LOAD_ELF64) # define XX64 # define E_MACHINE MULTIBOOT_ELF64_MACHINE @@ -32,8 +34,10 @@ # define Elf_Ehdr Elf64_Ehdr # define Elf_Phdr Elf64_Phdr # define Elf_Shdr Elf64_Shdr +# define Elf_Word Elf64_Word # define Elf_Shnum Elf64_Shnum # define grub_elf_get_shnumgrub_elf64_get_shnum +# define grub_elf_get_shstrndx grub_elf64_get_shstrndx #else #error "I'
Re: [PATCH] Initialize local relocator subchunk struct to all zeros
On Thu, Jul 14, 2022 at 03:38:04PM +0100, Darren Kenny wrote: > Hi Ross, > > This looks good to me. > > On Thursday, 2022-07-14 at 09:41:28 -04, Ross Philipson wrote: > > The way the code is written the tofree variable would never be > > passed to the free_subchunk() function uninitialized. Coverity > > cannot determine this and flags the situation as "Using uninitialized > > value...". The fix is just to initialize the local struct. > > > > Fixes: CID 314016 > > > > Signed-off-by: Ross Philipson > > Reviewed-by: Darren Kenny I ran this through a private Coverity scan which marked the bug as eliminated and didn't have any issues running it on a VM. Tested-by: Alec Brown Alec Brown > > Thanks, > > Darren. > > > --- > > grub-core/lib/relocator.c | 2 +- > > 1 file changed, 1 insertion(+), 1 deletion(-) > > > > diff --git a/grub-core/lib/relocator.c b/grub-core/lib/relocator.c > > index 68ef128..bfcc70d 100644 > > --- a/grub-core/lib/relocator.c > > +++ b/grub-core/lib/relocator.c > > @@ -989,7 +989,7 @@ malloc_in_range (struct grub_relocator *rel, > > if (j != 0 && events[j - 1].pos != events[j].pos) > > { > > grub_addr_t alloc_start, alloc_end; > > - struct grub_relocator_subchunk tofree; > > + struct grub_relocator_subchunk tofree = {0}; > > struct grub_relocator_subchunk *curschu = &tofree; > > if (!oom) > > curschu = &res->subchunks[cural]; > > -- > > 1.8.3.1 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v2 1/5] elf: Validate number of elf section header table entries
In bsdXX.c and multiboot_elfxx.c, e_shnum is used to obtain the number of section header table entries, but it wasn't being checked if the value was there. According to the elf(5) manual page, "If the number of entries in the section header table is larger than or equal to SHN_LORESERVE (0xff00), e_shnum holds the value zero and the real number of entries in the section header table is held in the sh_size member of the intial entry in section header table. Otherwise, the sh_size member of the initial entry in the section header table holds the value zero." Since this check wasn't being made, grub_elfXX_get_shnum() is being added to elfXX.c to make this check and use whichever member doesn't have a value of zero. If both are zero, then we must return an error. We also need to make sure that e_shnum doesn't have a value greater than or equal to SHN_LORESERVE and sh_size isn't less than SHN_LORESERVE. In order to get this function to work, the type ElfXX_Shnum is being added where Elf32_Shnum defines Elf32_Word and Elf64_Shnum defines Elf64_Xword. This new type is needed because if shnum obtains a value from sh_size, sh_size could be of type El32_Word for Elf32_Shdr structures or Elf64_Xword for Elf64_Shdr structures. Note that even though elf.c and elfXX.c are located in grub-core/kern, they are compiled as modules and don't need the EXPORT_FUNC macro to define the functions in elf.h. For a few smaller changes, changed casts of shnum to match variables being set as well as dropped casts when unnecessary and fixed spacing errors in bsdXX.c. Also, shnum is an unsigned integer and is compared to int i in multiboot_elfxx.c, it should be unsigned to match shnum. Signed-off-by: Alec Brown --- grub-core/kern/elf.c | 12 + grub-core/kern/elfXX.c | 34 + grub-core/loader/i386/bsdXX.c | 82 ++ grub-core/loader/multiboot_elfxx.c | 49 +++--- include/grub/elf.h | 14 + 5 files changed, 150 insertions(+), 41 deletions(-) diff --git a/grub-core/kern/elf.c b/grub-core/kern/elf.c index 9d7149b38..66b69293e 100644 --- a/grub-core/kern/elf.c +++ b/grub-core/kern/elf.c @@ -167,11 +167,15 @@ grub_elf_open (const char *name, enum grub_file_type type) #define grub_elfXX_load_phdrs grub_elf32_load_phdrs #define ElfXX_Phdr Elf32_Phdr #define ElfXX_Ehdr Elf32_Ehdr +#define ElfXX_Shdr Elf32_Shdr +#define ElfXX_Word Elf32_Word +#define ElfXX_Shnum Elf32_Shnum #define grub_uintXX_t grub_uint32_t #define grub_swap_bytes_addrXX grub_swap_bytes32 #define grub_swap_bytes_offXX grub_swap_bytes32 #define grub_swap_bytes_XwordXX grub_swap_bytes32 #define grub_elfXX_check_endianess_and_bswap_ehdr grub_elf32_check_endianess_and_bswap_ehdr +#define grub_elfXX_get_shnum grub_elf32_get_shnum #include "elfXX.c" @@ -185,11 +189,15 @@ grub_elf_open (const char *name, enum grub_file_type type) #undef grub_elfXX_load_phdrs #undef ElfXX_Phdr #undef ElfXX_Ehdr +#undef ElfXX_Shdr +#undef ElfXX_Word +#undef ElfXX_Shnum #undef grub_uintXX_t #undef grub_swap_bytes_addrXX #undef grub_swap_bytes_offXX #undef grub_swap_bytes_XwordXX #undef grub_elfXX_check_endianess_and_bswap_ehdr +#undef grub_elfXX_get_shnum /* 64-bit */ @@ -203,10 +211,14 @@ grub_elf_open (const char *name, enum grub_file_type type) #define grub_elfXX_load_phdrs grub_elf64_load_phdrs #define ElfXX_Phdr Elf64_Phdr #define ElfXX_Ehdr Elf64_Ehdr +#define ElfXX_Shdr Elf64_Shdr +#define ElfXX_Word Elf64_Word +#define ElfXX_Shnum Elf64_Shnum #define grub_uintXX_t grub_uint64_t #define grub_swap_bytes_addrXX grub_swap_bytes64 #define grub_swap_bytes_offXX grub_swap_bytes64 #define grub_swap_bytes_XwordXX grub_swap_bytes64 #define grub_elfXX_check_endianess_and_bswap_ehdr grub_elf64_check_endianess_and_bswap_ehdr +#define grub_elfXX_get_shnum grub_elf64_get_shnum #include "elfXX.c" diff --git a/grub-core/kern/elfXX.c b/grub-core/kern/elfXX.c index 1859d1880..48b7745a5 100644 --- a/grub-core/kern/elfXX.c +++ b/grub-core/kern/elfXX.c @@ -205,3 +205,37 @@ grub_elfXX_check_endianess_and_bswap_ehdr (grub_elf_t elf) return 0; } + +grub_err_t +grub_elfXX_get_shnum (ElfXX_Ehdr *e, ElfXX_Shnum *shnum) +{ + ElfXX_Shdr *s; + + if (shnum == NULL) +return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("NULL pointer passed for shnum")); + + /* Set *shnum to 0 so that shnum doesn't return junk on error */ + *shnum = 0; + + if (e == NULL) +return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("NULL pointer passed for elf header")); + + *shnum = e->e_shnum; + if (*shnum == SHN_UNDEF) +{ + if (e->e_shoff == 0) + return grub_error (GRUB_ERR_BAD_NUMBER, N_("invalid section header table offset in e_shoff")); + + s = (ElfXX_Shdr *) ((grub_uint8_t *) e + e->e_shoff); + *shnum = s->sh_size; + if (*shnum < SHN_LORESERVE)
[PATCH v2 3/5] elf: Validate number of elf program header table entries
In bsdXX.c and multiboot_elfxx.c, e_phnum is used to obtain the number of program header table entries, but it wasn't being checked if the value was there. According to the elf(5) manual page, "If the number of entries in the program header table is larger than or equal to PN_XNUM (0x), this member holds PN_XNUM (0x) and the real number of entries in the program header table is held in the sh_info member of the initial entry in section header table. Otherwise, the sh_info member of the initial entry contains the value zero." Since this check wasn't being made, grub_elfXX_get_phnum() is being added to elfXX.c to make this check and use e_phnum if it doesn't have PN_XNUM as a value, else use sh_info. We also need to make sure e_phnum isn't greater than PN_XNUM and sh_info isn't less than PN_XNUM. Note that even though elf.c and elfXX.c are located in grub-core/kern, they are compiled as modules and don't need the EXPORT_FUNC macro to define the functions in elf.h. Also, changed casts of phnum to match variables being set as well as dropped casts when unnecessary. Signed-off-by: Alec Brown --- grub-core/kern/elf.c | 3 +++ grub-core/kern/elfXX.c | 34 ++ grub-core/loader/i386/bsdXX.c | 11 +++--- grub-core/loader/multiboot_elfxx.c | 19 +++-- include/grub/elf.h | 5 + 5 files changed, 63 insertions(+), 9 deletions(-) diff --git a/grub-core/kern/elf.c b/grub-core/kern/elf.c index c676db694..077a8500c 100644 --- a/grub-core/kern/elf.c +++ b/grub-core/kern/elf.c @@ -177,6 +177,7 @@ grub_elf_open (const char *name, enum grub_file_type type) #define grub_elfXX_check_endianess_and_bswap_ehdr grub_elf32_check_endianess_and_bswap_ehdr #define grub_elfXX_get_shnum grub_elf32_get_shnum #define grub_elfXX_get_shstrndx grub_elf32_get_shstrndx +#define grub_elfXX_get_phnum grub_elf32_get_phnum #include "elfXX.c" @@ -200,6 +201,7 @@ grub_elf_open (const char *name, enum grub_file_type type) #undef grub_elfXX_check_endianess_and_bswap_ehdr #undef grub_elfXX_get_shnum #undef grub_elfXX_get_shstrndx +#undef grub_elfXX_get_phnum /* 64-bit */ @@ -223,5 +225,6 @@ grub_elf_open (const char *name, enum grub_file_type type) #define grub_elfXX_check_endianess_and_bswap_ehdr grub_elf64_check_endianess_and_bswap_ehdr #define grub_elfXX_get_shnum grub_elf64_get_shnum #define grub_elfXX_get_shstrndx grub_elf64_get_shstrndx +#define grub_elfXX_get_phnum grub_elf64_get_phnum #include "elfXX.c" diff --git a/grub-core/kern/elfXX.c b/grub-core/kern/elfXX.c index 4e3254fa5..aabf4b9d7 100644 --- a/grub-core/kern/elfXX.c +++ b/grub-core/kern/elfXX.c @@ -272,3 +272,37 @@ grub_elfXX_get_shstrndx (ElfXX_Ehdr *e, ElfXX_Word *shstrndx) } return GRUB_ERR_NONE; } + +grub_err_t +grub_elfXX_get_phnum (ElfXX_Ehdr *e, ElfXX_Word *phnum) +{ + ElfXX_Shdr *s; + + if (phnum == NULL) +return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("NULL pointer passed for phnum")); + + /* Set *phnum to 0 so that phnum doesn't return junk on error */ + *phnum = 0; + + if (e == NULL) +return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("NULL pointer passed for elf header")); + + *phnum = e->e_phnum; + if (*phnum == PN_XNUM) +{ + if (e->e_shoff == 0) + return grub_error (GRUB_ERR_BAD_NUMBER, N_("invalid section header table offset in e_shoff")); + + s = (ElfXX_Shdr *) ((grub_uint8_t *) e + e->e_shoff); + *phnum = s->sh_info; + if (*phnum < PN_XNUM) + return grub_error (GRUB_ERR_BAD_NUMBER, N_("invalid number of program header table entries in sh_info: %d"), *phnum); +} + else +{ + if (*phnum >= PN_XNUM) + return grub_error (GRUB_ERR_BAD_NUMBER, N_("invalid number of program header table entries in e_phnum: %d"), *phnum); +} + + return GRUB_ERR_NONE; +} diff --git a/grub-core/loader/i386/bsdXX.c b/grub-core/loader/i386/bsdXX.c index 2d91fd44d..dffa79d56 100644 --- a/grub-core/loader/i386/bsdXX.c +++ b/grub-core/loader/i386/bsdXX.c @@ -183,6 +183,7 @@ SUFFIX (grub_freebsd_load_elfmodule) (struct grub_relocator *relocator, Elf_Ehdr e; Elf_Shdr *s, *shdr = NULL; Elf_Shnum shnum; + Elf_Word phnum; grub_addr_t curload, module; grub_err_t err; grub_size_t chunk_size = 0; @@ -198,6 +199,10 @@ SUFFIX (grub_freebsd_load_elfmodule) (struct grub_relocator *relocator, if (err != GRUB_ERR_NONE) goto out; + err = grub_elf_get_phnum (&e, &phnum); + if (err != GRUB_ERR_NONE) +goto out; + for (s = shdr; s < (Elf_Shdr *) ((grub_uint8_t *) shdr + shnum * e.e_shentsize); s = (Elf_Shdr *) ((grub_uint8_t *) s + e.e_shentsize)) { @@ -212,7 +217,7 @@ SUFFIX (grub_freebsd_load_elfmodule) (struct grub_relocator *relocator, if (chunk_size < sizeof (e)) chunk_size = sizeof (e); -
[PATCH v2 4/5] util/grub-module-verifierXX.c: Changed get_shnum() return type
In util/grub-module-verifierXX.c, the function get_shnum() returns the variable shnum, which is of the type Elf_Word. In the function, shnum can be obtained by the e_shnum member of an Elf_Ehdr or the sh_size member of an Elf_Shdr. The sh_size member can either be grub_uint32_t or grub_uint64_t, depending on the architecture, but Elf_Word is only grub_uint32_t. To account for when sh_size is grub_uint64_t, we can set shnum to have type Elf_Shnum and have get_shnum() return an Elf_Shnum. Signed-off-by: Alec Brown --- util/grub-module-verifierXX.c | 10 ++ 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/util/grub-module-verifierXX.c b/util/grub-module-verifierXX.c index cf3ff0dfa..8e0cd91d9 100644 --- a/util/grub-module-verifierXX.c +++ b/util/grub-module-verifierXX.c @@ -18,6 +18,7 @@ # define Elf_RelElf32_Rel # define Elf_Word Elf32_Word # define Elf_Half Elf32_Half +# define Elf_Shnum Elf32_Shnum # define Elf_SectionElf32_Section # define ELF_R_SYM(val)ELF32_R_SYM(val) # define ELF_R_TYPE(val) ELF32_R_TYPE(val) @@ -36,6 +37,7 @@ # define Elf_RelElf64_Rel # define Elf_Word Elf64_Word # define Elf_Half Elf64_Half +# define Elf_Shnum Elf64_Shnum # define Elf_SectionElf64_Section # define ELF_R_SYM(val)ELF64_R_SYM(val) # define ELF_R_TYPE(val) ELF64_R_TYPE(val) @@ -141,11 +143,11 @@ get_shdr (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, Elf_Word in index * grub_target_to_host16 (e->e_shentsize)); } -static Elf_Word +static Elf_Shnum get_shnum (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e) { Elf_Shdr *s; - Elf_Word shnum; + Elf_Shnum shnum; shnum = grub_target_to_host16 (e->e_shnum); if (shnum == SHN_UNDEF) @@ -153,12 +155,12 @@ get_shnum (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e) s = get_shdr (arch, e, 0); shnum = grub_target_to_host (s->sh_size); if (shnum < SHN_LORESERVE) - grub_util_error ("Invalid number of section header table entries in sh_size: %d", shnum); + grub_util_error ("Invalid number of section header table entries in sh_size: %" PRIuGRUB_UINT64_T, (grub_uint64_t) shnum); } else { if (shnum >= SHN_LORESERVE) - grub_util_error ("Invalid number of section header table entries in e_shnum: %d", shnum); + grub_util_error ("Invalid number of section header table entries in e_shnum: %" PRIuGRUB_UINT64_T, (grub_uint64_t) shnum); } return shnum; -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v2 0/5] Fix coverity bugs and add checks for elf values in grub-core
Updates from v1: - A few patches didn't work on 32-bit platforms. Fixed this by renaming function definitions in multiboot_elfxx.c. The patches that did work were merged with the master branch. - Added a patch to make error conditionals consistent in comparing to GRUB_ERR_NONE. Coverity identified several untrusted loop bounds and untrusted allocation size bugs in grub-core/loader/i386/bsdXX.c and grub-core/loader/multiboot_elfXX.c. Upon review of these bugs, I found that specific checks weren't being made to various elf header values based on the elf manual page. The first version of the patch series contained the patches fixing the Coverity bugs, but those have been merged with the master branch. The remaining patches add functions to check for the correct elf header values, update previous work done in util/grub-module-verifierXX.c that checks elf header values, and update error conditionals of the affected files. Also, I was able to verify that these patches work by using Multiboot and Multiboot2 to boot a Xen image. Alec Brown (5): elf: Validate number of elf section header table entries elf: Validate elf section header table index for section name string table elf: Validate number of elf program header table entries util/grub-module-verifierXX.c: Changed get_shnum() return type loader: Update error conditionals to use enums grub-core/kern/elf.c | 18 ++ grub-core/kern/elfXX.c | 101 + grub-core/loader/i386/bsdXX.c | 131 +++ grub-core/loader/multiboot_elfxx.c | 85 + include/grub/elf.h | 23 +++ util/grub-module-verifierXX.c | 10 ++ 6 files changed, 292 insertions(+), 76 deletions(-) Interdiff against v1: diff --git a/grub-core/loader/i386/bsdXX.c b/grub-core/loader/i386/bsdXX.c index 2cc1daa49..09d909f1b 100644 --- a/grub-core/loader/i386/bsdXX.c +++ b/grub-core/loader/i386/bsdXX.c @@ -52,7 +52,7 @@ read_headers (grub_file_t file, const char *filename, Elf_Ehdr *e, Elf_Shdr **sh return grub_error (GRUB_ERR_BAD_OS, N_("invalid arch-dependent ELF magic")); err = grub_elf_get_shnum (e, &shnum); - if (err) + if (err != GRUB_ERR_NONE) return err; *shdr = grub_calloc (shnum, e->e_shentsize); @@ -94,7 +94,7 @@ SUFFIX (grub_freebsd_load_elfmodule_obj) (struct grub_relocator *relocator, curload = module = ALIGN_PAGE (*kern_end); err = read_headers (file, argv[0], &e, &shdr); - if (err) + if (err != GRUB_ERR_NONE) goto out; err = grub_elf_get_shnum (&e, &shnum); @@ -118,7 +118,7 @@ SUFFIX (grub_freebsd_load_elfmodule_obj) (struct grub_relocator *relocator, grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_addr (relocator, &ch, module, chunk_size); -if (err) +if (err != GRUB_ERR_NONE) goto out; chunk_src = get_virtual_current_address (ch); } @@ -143,7 +143,7 @@ SUFFIX (grub_freebsd_load_elfmodule_obj) (struct grub_relocator *relocator, case SHT_PROGBITS: err = load (file, argv[0], (grub_uint8_t *) chunk_src + curload - *kern_end, s->sh_offset, s->sh_size); - if (err) + if (err != GRUB_ERR_NONE) goto out; break; case SHT_NOBITS: @@ -159,11 +159,11 @@ SUFFIX (grub_freebsd_load_elfmodule_obj) (struct grub_relocator *relocator, err = grub_freebsd_add_meta_module (argv[0], FREEBSD_MODTYPE_ELF_MODULE_OBJ, argc - 1, argv + 1, module, curload - module); - if (! err) + if (err == GRUB_ERR_NONE) err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA | FREEBSD_MODINFOMD_ELFHDR, &e, sizeof (e)); - if (! err) + if (err == GRUB_ERR_NONE) err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA | FREEBSD_MODINFOMD_SHDR, shdr, shnum * e.e_shentsize); @@ -192,7 +192,7 @@ SUFFIX (grub_freebsd_load_elfmodule) (struct grub_relocator *relocator, curload = module = ALIGN_PAGE (*kern_end); err = read_headers (file, argv[0], &e, &shdr); - if (err) + if (err != GRUB_ERR_NONE) goto out; err = grub_elf_get_shnum (&e, &shnum); @@ -225,7 +225,7 @@ SUFFIX (grub_freebsd_load_elfmodule) (struct grub_relocator *relocator, err = grub_relocator_alloc_chunk_addr (relocator, &ch, module, chunk_size);
[PATCH v2 2/5] elf: Validate elf section header table index for section name string table
In multiboot_elfxx.c, e_shstrndx is used to obtain the section header table index of the section name string table, but it wasn't being checked if the value was there. According to the elf(5) manual page, "If the index of section name string table section is larger than or equal to SHN_LORESERVE (0xff00), this member holds SHN_XINDEX (0x) and the real index of the section name string table section is held in the sh_link member of the initial entry in section header table. Otherwise, the sh_link member of the initial entry in section header table contains the value zero." Since this check wasn't being made, grub_elfXX_get_shstrndx() is being added to elfXX.c to make this check and use e_shstrndx if it doesn't have SHN_XINDEX as a value, else use sh_link. We also need to make sure e_shstrndx isn't greater than or equal to SHN_LORESERVE and sh_link isn't less than SHN_LORESERVE. Note that even though elf.c and elfXX.c are located in grub-core/kern, they are compiled as modules and don't need the EXPORT_FUNC macro to define the functions in elf.h. Signed-off-by: Alec Brown --- grub-core/kern/elf.c | 3 +++ grub-core/kern/elfXX.c | 33 ++ grub-core/loader/multiboot_elfxx.c | 13 +++- include/grub/elf.h | 4 4 files changed, 52 insertions(+), 1 deletion(-) diff --git a/grub-core/kern/elf.c b/grub-core/kern/elf.c index 66b69293e..c676db694 100644 --- a/grub-core/kern/elf.c +++ b/grub-core/kern/elf.c @@ -176,6 +176,7 @@ grub_elf_open (const char *name, enum grub_file_type type) #define grub_swap_bytes_XwordXX grub_swap_bytes32 #define grub_elfXX_check_endianess_and_bswap_ehdr grub_elf32_check_endianess_and_bswap_ehdr #define grub_elfXX_get_shnum grub_elf32_get_shnum +#define grub_elfXX_get_shstrndx grub_elf32_get_shstrndx #include "elfXX.c" @@ -198,6 +199,7 @@ grub_elf_open (const char *name, enum grub_file_type type) #undef grub_swap_bytes_XwordXX #undef grub_elfXX_check_endianess_and_bswap_ehdr #undef grub_elfXX_get_shnum +#undef grub_elfXX_get_shstrndx /* 64-bit */ @@ -220,5 +222,6 @@ grub_elf_open (const char *name, enum grub_file_type type) #define grub_swap_bytes_XwordXX grub_swap_bytes64 #define grub_elfXX_check_endianess_and_bswap_ehdr grub_elf64_check_endianess_and_bswap_ehdr #define grub_elfXX_get_shnum grub_elf64_get_shnum +#define grub_elfXX_get_shstrndx grub_elf64_get_shstrndx #include "elfXX.c" diff --git a/grub-core/kern/elfXX.c b/grub-core/kern/elfXX.c index 48b7745a5..4e3254fa5 100644 --- a/grub-core/kern/elfXX.c +++ b/grub-core/kern/elfXX.c @@ -239,3 +239,36 @@ grub_elfXX_get_shnum (ElfXX_Ehdr *e, ElfXX_Shnum *shnum) return GRUB_ERR_NONE; } + +grub_err_t +grub_elfXX_get_shstrndx (ElfXX_Ehdr *e, ElfXX_Word *shstrndx) +{ + ElfXX_Shdr *s; + + if (shstrndx == NULL) +return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("NULL pointer passed for shstrndx")); + + /* Set *shstrndx to 0 so that shstrndx doesn't return junk on error */ + *shstrndx = 0; + + if (e == NULL) +return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("NULL pointer passed for elf header")); + + *shstrndx = e->e_shstrndx; + if (*shstrndx == SHN_XINDEX) +{ + if (e->e_shoff == 0) + return grub_error (GRUB_ERR_BAD_NUMBER, N_("invalid section header table offset in e_shoff")); + + s = (ElfXX_Shdr *) ((grub_uint8_t *) e + e->e_shoff); + *shstrndx = s->sh_link; + if (*shstrndx < SHN_LORESERVE) + return grub_error (GRUB_ERR_BAD_NUMBER, N_("invalid section header table index in sh_link: %d"), *shstrndx); +} + else +{ + if (*shstrndx >= SHN_LORESERVE) + return grub_error (GRUB_ERR_BAD_NUMBER, N_("invalid section header table index in e_shstrndx: %d"), *shstrndx); +} + return GRUB_ERR_NONE; +} diff --git a/grub-core/loader/multiboot_elfxx.c b/grub-core/loader/multiboot_elfxx.c index ed5a4ae9d..ec4ba3b8d 100644 --- a/grub-core/loader/multiboot_elfxx.c +++ b/grub-core/loader/multiboot_elfxx.c @@ -23,8 +23,10 @@ # define Elf_Ehdr Elf32_Ehdr # define Elf_Phdr Elf32_Phdr # define Elf_Shdr Elf32_Shdr +# define Elf_Word Elf32_Word # define Elf_Shnum Elf32_Shnum # define grub_multiboot_elf_get_shnum grub_elf32_get_shnum +# define grub_multiboot_elf_get_shstrndx grub_elf32_get_shstrndx #elif defined(MULTIBOOT_LOAD_ELF64) # define XX64 # define E_MACHINE MULTIBOOT_ELF64_MACHINE @@ -32,8 +34,10 @@ # define Elf_Ehdr Elf64_Ehdr # define Elf_Phdr Elf64_Phdr # define Elf_Shdr Elf64_Shdr +# define Elf_Word Elf64_Word # define Elf_Shnum Elf64_Shnum # define grub_multiboot_elf_get_shnum grub_elf64_get_shnum +# define grub_multiboot_elf_
[PATCH v2 5/5] loader: Update error conditionals to use enums
In grub-core/loader/i386/bsdXX.c and grub-core/loader/multiboot_elfxx.c, error conditionals are simplified to statements such as "if (err)". Even though the assumption that non-zero values give errors is correct, it would be clearer and more consistent to compare these conditionals to GRUB_ERR_NONE. Signed-off-by: Alec Brown --- grub-core/loader/i386/bsdXX.c | 38 +++--- grub-core/loader/multiboot_elfxx.c | 6 ++--- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/grub-core/loader/i386/bsdXX.c b/grub-core/loader/i386/bsdXX.c index dffa79d56..09d909f1b 100644 --- a/grub-core/loader/i386/bsdXX.c +++ b/grub-core/loader/i386/bsdXX.c @@ -94,7 +94,7 @@ SUFFIX (grub_freebsd_load_elfmodule_obj) (struct grub_relocator *relocator, curload = module = ALIGN_PAGE (*kern_end); err = read_headers (file, argv[0], &e, &shdr); - if (err) + if (err != GRUB_ERR_NONE) goto out; err = grub_elf_get_shnum (&e, &shnum); @@ -118,7 +118,7 @@ SUFFIX (grub_freebsd_load_elfmodule_obj) (struct grub_relocator *relocator, grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_addr (relocator, &ch, module, chunk_size); -if (err) +if (err != GRUB_ERR_NONE) goto out; chunk_src = get_virtual_current_address (ch); } @@ -143,7 +143,7 @@ SUFFIX (grub_freebsd_load_elfmodule_obj) (struct grub_relocator *relocator, case SHT_PROGBITS: err = load (file, argv[0], (grub_uint8_t *) chunk_src + curload - *kern_end, s->sh_offset, s->sh_size); - if (err) + if (err != GRUB_ERR_NONE) goto out; break; case SHT_NOBITS: @@ -159,11 +159,11 @@ SUFFIX (grub_freebsd_load_elfmodule_obj) (struct grub_relocator *relocator, err = grub_freebsd_add_meta_module (argv[0], FREEBSD_MODTYPE_ELF_MODULE_OBJ, argc - 1, argv + 1, module, curload - module); - if (! err) + if (err == GRUB_ERR_NONE) err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA | FREEBSD_MODINFOMD_ELFHDR, &e, sizeof (e)); - if (! err) + if (err == GRUB_ERR_NONE) err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA | FREEBSD_MODINFOMD_SHDR, shdr, shnum * e.e_shentsize); @@ -192,7 +192,7 @@ SUFFIX (grub_freebsd_load_elfmodule) (struct grub_relocator *relocator, curload = module = ALIGN_PAGE (*kern_end); err = read_headers (file, argv[0], &e, &shdr); - if (err) + if (err != GRUB_ERR_NONE) goto out; err = grub_elf_get_shnum (&e, &shnum); @@ -225,7 +225,7 @@ SUFFIX (grub_freebsd_load_elfmodule) (struct grub_relocator *relocator, err = grub_relocator_alloc_chunk_addr (relocator, &ch, module, chunk_size); -if (err) +if (err != GRUB_ERR_NONE) goto out; chunk_src = get_virtual_current_address (ch); @@ -252,7 +252,7 @@ SUFFIX (grub_freebsd_load_elfmodule) (struct grub_relocator *relocator, (grub_uint8_t *) chunk_src + module + s->sh_addr - *kern_end, s->sh_offset, s->sh_size); - if (err) + if (err != GRUB_ERR_NONE) goto out; break; case SHT_NOBITS: @@ -285,7 +285,7 @@ SUFFIX (grub_freebsd_load_elfmodule) (struct grub_relocator *relocator, curload - module); out: grub_free (shdr); - if (err) + if (err != GRUB_ERR_NONE) return err; return SUFFIX (grub_freebsd_load_elf_meta) (relocator, file, argv[0], kern_end); } @@ -313,7 +313,7 @@ SUFFIX (grub_freebsd_load_elf_meta) (struct grub_relocator *relocator, grub_size_t chunk_size; err = read_headers (file, filename, &e, &shdr); - if (err) + if (err != GRUB_ERR_NONE) goto out; err = grub_elf_get_shnum (&e, &shnum); @@ -323,7 +323,7 @@ SUFFIX (grub_freebsd_load_elf_meta) (struct grub_relocator *relocator, err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA | FREEBSD_MODINFOMD_ELFHDR, &e, sizeof (e)); - if (err) + if (err != GRUB_ERR_NONE) goto out; for (s = shdr; s < (Elf_Shdr *) ((grub_uint8_t *) shdr + shnum * e.e_shentsize); @@ -351,7 +351,7 @@ SUFFIX (grub_freebsd_load_elf_meta) (struct grub_relocator *relocator, grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_addr (relocator, &ch, symtarget, chunk_size); -if (err) +if (err != GRUB_ERR_NONE) goto out; sym_chunk = get_virtual_current_address (ch); } @@ -414,14 +414,14 @@ SUFFIX (grub_freebsd_load_elf_meta) (struct grub_relocator *relocator, err = grub_b
[PATCH] grub-core/disk/cryptodisk.c: Fix unintentional integer overflow
In the function grub_cryptodisk_endecrypt(), a for loop is incrementing the variable i by (1U << log_sector_size). The variable i is of type grub_size_t which is a 64-bit unsigned integer on x86_64 architecture. On the other hand, 1U is a 32-bit unsigned integer. By performing a left shift between these two values of different types, there may be potential for an integer overflow. To avoid this, we replace 1U with (grub_size_t) 1. Fixes: CID 307788 Signed-off-by: Alec Brown --- grub-core/disk/cryptodisk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c index 9f5dc7acb..cdcb882ca 100644 --- a/grub-core/disk/cryptodisk.c +++ b/grub-core/disk/cryptodisk.c @@ -239,7 +239,7 @@ grub_cryptodisk_endecrypt (struct grub_cryptodisk *dev, return (do_encrypt ? grub_crypto_ecb_encrypt (dev->cipher, data, data, len) : grub_crypto_ecb_decrypt (dev->cipher, data, data, len)); - for (i = 0; i < len; i += (1U << log_sector_size)) + for (i = 0; i < len; i += ((grub_size_t) 1 << log_sector_size)) { grub_size_t sz = ((dev->cipher->cipher->blocksize + sizeof (grub_uint32_t) - 1) -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v2] grub-core/disk/cryptodisk.c: Fix unintentional integer overflow
In the function grub_cryptodisk_endecrypt(), a for loop is incrementing the variable i by (1U << log_sector_size). The variable i is of type grub_size_t which is a 64-bit unsigned integer on x86_64 architecture. On the other hand, 1U is a 32-bit unsigned integer. By performing a left shift on a 32-bit value and assigning it to a 64-bit variable, the 64-bit variable may have incorrect values in the high 32-bits if the shift has an overflow. To avoid this, we replace 1U with (grub_size_t) 1. Fixes: CID 307788 Signed-off-by: Alec Brown --- There was a mistake in v1 of the commit message describing the issue in the code. This version fixes the commit message so that it's accurate. grub-core/disk/cryptodisk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c index 9f5dc7acb..cdcb882ca 100644 --- a/grub-core/disk/cryptodisk.c +++ b/grub-core/disk/cryptodisk.c @@ -239,7 +239,7 @@ grub_cryptodisk_endecrypt (struct grub_cryptodisk *dev, return (do_encrypt ? grub_crypto_ecb_encrypt (dev->cipher, data, data, len) : grub_crypto_ecb_decrypt (dev->cipher, data, data, len)); - for (i = 0; i < len; i += (1U << log_sector_size)) + for (i = 0; i < len; i += ((grub_size_t) 1 << log_sector_size)) { grub_size_t sz = ((dev->cipher->cipher->blocksize + sizeof (grub_uint32_t) - 1) -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 2/2] video/readers/jpeg: Check next_marker is within file size
In grub-core/video/readers/jpeg.c, the function grub_jpeg_decode_huff_table() has the variable next_marker which reads data from grub_jpeg_get_word() and then uses it as an upper limit in a while loop. However, the function isn't checking that next_marker is within the file size, so this check is being added to the function. Signed-off-by: Alec Brown --- grub-core/video/readers/jpeg.c | 6 ++ 1 file changed, 6 insertions(+) diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c index 0eeea0e63..c0f95fbf9 100644 --- a/grub-core/video/readers/jpeg.c +++ b/grub-core/video/readers/jpeg.c @@ -199,6 +199,12 @@ grub_jpeg_decode_huff_table (struct grub_jpeg_data *data) next_marker = data->file->offset; next_marker += grub_jpeg_get_word (data); + if (next_marker > data->file->size) +{ + /* Should never be set beyond the size of the file. */ + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid next reference"); +} + while (data->file->offset + sizeof (count) + 1 <= next_marker) { id = grub_jpeg_get_byte (data); -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 0/2] Fix Coverity untrusted loop bound bugs in jpeg.c
In grub-core/video/readers/jpeg.c, Coverity identified an untrusted loop bound bug. After resolving this bug, a private Coverity scan identified another untrusted loop bound bug in a different function. Since this bug only shows up after resolving the first bug, there isn't a CID for the second bug. The Coverity bugs being addressed are: CID 292450 Alec Brown (2): video/readers: Add artificial limit to image dimensions video/readers/jpeg: Check next_marker is within file size docs/grub.texi | 3 ++- grub-core/video/readers/jpeg.c | 12 +++- grub-core/video/readers/png.c | 6 +- grub-core/video/readers/tga.c | 7 +++ include/grub/bitmap.h | 2 ++ 5 files changed, 27 insertions(+), 3 deletions(-) ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 1/2] 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 bitmap.h, which has a value of 16384, to act as an artifical 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 --- 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 9835c878a..d448ca969 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -1507,7 +1507,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 e31602f76..0eeea0e63 100644 --- a/grub-core/video/readers/jpeg.c +++ b/grub-core/video/readers/jpeg.c @@ -301,7 +301,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 54dfedf43..d658cbb0e 100644 --- a/grub-core/video/readers/png.c +++ b/grub-core/video/readers/png.c @@ -252,7 +252,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..f2f563d06 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 #include +#define IMAGE_HW_MAX_PX16384 + struct grub_video_bitmap { /* Bitmap format description. */ -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
Re: [External] : Re: [PATCH 2/2] video/readers/jpeg: Check next_marker is within file size
On Sat, Oct 22, 2022 at 12:52:02AM +1100, Daniel Axtens wrote: > Alec Brown writes: > > > In grub-core/video/readers/jpeg.c, the function > > grub_jpeg_decode_huff_table() > > has the variable next_marker which reads data from grub_jpeg_get_word() and > > then uses it as an upper limit in a while loop. However, the function isn't > > checking that next_marker is within the file size, so this check is being > > added > > to the function. > > > > Signed-off-by: Alec Brown > > --- > > grub-core/video/readers/jpeg.c | 6 ++ > > 1 file changed, 6 insertions(+) > > > > diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c > > index 0eeea0e63..c0f95fbf9 100644 > > --- a/grub-core/video/readers/jpeg.c > > +++ b/grub-core/video/readers/jpeg.c > > @@ -199,6 +199,12 @@ grub_jpeg_decode_huff_table (struct grub_jpeg_data > > *data) > >next_marker = data->file->offset; > >next_marker += grub_jpeg_get_word (data); > > > > + if (next_marker > data->file->size) > > +{ > > + /* Should never be set beyond the size of the file. */ > > + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid next > > reference"); > > +} > > + > > This is a good idea. I briefly wondered why this didn't lead to issues > detected in fuzzing. It'll be because the code reads byte by byte until > we get an EOF and then the loop will bail. Your change is still good, I > just wanted to double check that you hadn't accidentally found and fixed > a more serious bug. > I took a look at the code again and realized I made a mistake. There is already a fix for this issue. Turns out the branch I was using to develop my code was outdated and this patch is redundant. My bad. Alec Brown > The fuller context: > > while (data->file->offset + sizeof (count) + 1 <= next_marker) > { > id = grub_jpeg_get_byte (data); > if (grub_errno != GRUB_ERR_NONE) > return grub_errno; > > > >while (data->file->offset + sizeof (count) + 1 <= next_marker) > > { > >id = grub_jpeg_get_byte (data); > > -- > > 2.27.0 > > > > > > ___ > > Grub-devel mailing list > > Grub-devel@gnu.org > > https://urldefense.com/v3/__https://lists.gnu.org/mailman/listinfo/grub-devel__;!!ACWV5N9M2RV99hQ!IlmVbvmGcbJZqlfowZKaM9HBO2MzpJDPrCjfmlLWmsN8tlaAmt5iNq5JZTiU3rQor7YXKdCwTYpAAQ$ > > ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v2] 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 bitmap.h, which has a value of 16384, to act as an artifical 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 --- In v1, the patch set was developed on outdated code and there was already a fix for the second patch. So in this version, the second patch has been dropped. The only thing that has changed in this patch is line numbers. 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..f2f563d06 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 #include +#define IMAGE_HW_MAX_PX16384 + struct grub_video_bitmap { /* Bitmap format description. */ -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH] net/bootp: Fix unchecked return value
In the function send_dhcp_packet(), added an error check for the return value of grub_netbuff_push(). Fixes: CID 404614 Signed-off-by: Alec Brown --- grub-core/net/bootp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c index 7d31dba97..abe45ef7b 100644 --- a/grub-core/net/bootp.c +++ b/grub-core/net/bootp.c @@ -583,7 +583,9 @@ send_dhcp_packet (struct grub_net_network_level_interface *iface) grub_memcpy (&pack->mac_addr, &iface->hwaddress.mac, 6); - grub_netbuff_push (nb, sizeof (*udph)); + err = grub_netbuff_push (nb, sizeof (*udph)); + if (err) +goto out; udph = (struct udphdr *) nb->data; udph->src = grub_cpu_to_be16_compile_time (68); -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH] util/grub-module-verifierXX.c: Add module_size parameter to functions for sanity checking
In grub-module-verifierXX.c, the function grub_module_verifyXX() performs an initial check that the ELF section headers are within the module's size, but doesn't check if the sections being accessed have contents that are within the module's size. In particular, we need to check that sh_offset and sh_size are less than the module's size. However, for some section header types we don't need to make these checks. For the type SHT_NULL, the section header is marked as inactive and the rest of the members within the section header have undefined values, so we don't need to check for sh_offset or sh_size. In the case of the type SHT_NOBITS, sh_offset has a conceptual offset which may be beyond the module size. Also, this type's sh_size may have a non-zero size, but a section of this type will take up no space in the module. This can all be checked in the function get_shdr(), but in order to do so, the parameter module_size must be added to functions so that the value of the module size can be used in get_shdr() from grub_module_verifyXX(). Also, had to rework some for loops to ensure the index passed to get_shdr() is within bounds. Signed-off-by: Alec Brown --- util/grub-module-verifierXX.c | 111 -- 1 file changed, 64 insertions(+), 47 deletions(-) diff --git a/util/grub-module-verifierXX.c b/util/grub-module-verifierXX.c index d5907f268..b3f77ea0e 100644 --- a/util/grub-module-verifierXX.c +++ b/util/grub-module-verifierXX.c @@ -143,13 +143,24 @@ grub_target_to_host_real (const struct grub_module_verifier_arch *arch, grub_uin } static Elf_Shdr * -get_shdr (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, Elf_Word index) +get_shdr (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, Elf_Word index, size_t module_size) { + Elf_Shdr *s; + if (grub_target_to_host (e->e_shoff) == 0) grub_util_error ("Invalid section header offset"); - return (Elf_Shdr *) ((char *) e + grub_target_to_host (e->e_shoff) + - index * grub_target_to_host16 (e->e_shentsize)); + s = (Elf_Shdr *) ((char *) e + grub_target_to_host (e->e_shoff) + + index * grub_target_to_host16 (e->e_shentsize)); + /* Check that the header being accessed isn't outside the module size */ + if (grub_target_to_host32 (s->sh_type) != SHT_NULL && grub_target_to_host32 (s->sh_type) != SHT_NOBITS) +{ + if (grub_target_to_host (s->sh_offset) > module_size) + grub_util_error ("Section %d starts after the end of the module", index); + if (grub_target_to_host (s->sh_offset) + grub_target_to_host (s->sh_size) > module_size) + grub_util_error ("Section %d ends after the end of the module", index); +} + return s; } static Elf_Shnum @@ -161,7 +172,7 @@ get_shnum (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e) shnum = grub_target_to_host16 (e->e_shnum); if (shnum == SHN_UNDEF) { - s = get_shdr (arch, e, 0); + s = get_shdr (arch, e, 0, 0); shnum = grub_target_to_host (s->sh_size); if (shnum < SHN_LORESERVE) grub_util_error ("Invalid number of section header table entries in sh_size: %" PRIuGRUB_UINT64_T, (grub_uint64_t) shnum); @@ -176,7 +187,7 @@ get_shnum (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e) } static Elf_Word -get_shstrndx (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e) +get_shstrndx (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, size_t module_size) { Elf_Shdr *s; Elf_Word shstrndx; @@ -184,7 +195,7 @@ get_shstrndx (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e) shstrndx = grub_target_to_host16 (e->e_shstrndx); if (shstrndx == SHN_XINDEX) { - s = get_shdr (arch, e, 0); + s = get_shdr (arch, e, 0, 0); shstrndx = grub_target_to_host (s->sh_link); if (shstrndx < SHN_LORESERVE) grub_util_error ("Invalid section header table index in sh_link: %d", shstrndx); @@ -199,28 +210,30 @@ get_shstrndx (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e) } static Elf_Shdr * -find_section (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, const char *name) +find_section (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, const char *name, size_t module_size) { Elf_Shdr *s; const char *str; unsigned i; - s = get_shdr (arch, e, get_shstrndx (arch, e)); + s = get_shdr (arch, e, get_shstrndx (arch, e, module_size), module_size); str = (char *) e + grub_target_to_host (s->sh_offset); - for (i = 0, s = get_shdr (arch, e, 0); - i < get_shnum (arch, e); - i++, s = get_shdr (arch, e, i)) -if (strcmp (str + grub_target_to_host32 (s->sh_name), name) == 0) - return s; + for (i = 0; i < get_shnum (arch, e); i++) +{ + s = get_s
[PATCH 4/4] efi: Fix use-after-free in finish boot services
In grub-core/kern/efi/mm.c, grub_efi_finish_boot_services() has an instance where the memory for the variable finish_mmap_buf is freed, but on the next iteration of a while loop, grub_efi_get_memory_map() uses finish_mmap_buf. To prevent this, we can set finish_mmap_buf to NULL after the free. Signed-off-by: Alec Brown --- grub-core/kern/efi/mm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c index 3705b8b1b..c74ccbb05 100644 --- a/grub-core/kern/efi/mm.c +++ b/grub-core/kern/efi/mm.c @@ -263,6 +263,7 @@ grub_efi_finish_boot_services (grub_efi_uintn_t *outbuf_size, void *outbuf, &finish_desc_size, &finish_desc_version) <= 0) { grub_free (finish_mmap_buf); + finish_mmap_buf = NULL; return grub_error (GRUB_ERR_IO, "couldn't retrieve memory map"); } @@ -275,10 +276,12 @@ grub_efi_finish_boot_services (grub_efi_uintn_t *outbuf_size, void *outbuf, if (status != GRUB_EFI_INVALID_PARAMETER) { grub_free (finish_mmap_buf); + finish_mmap_buf = NULL; return grub_error (GRUB_ERR_IO, "couldn't terminate EFI services"); } grub_free (finish_mmap_buf); + finish_mmap_buf = NULL; grub_printf ("Trying to terminate EFI services again\n"); } grub_efi_is_finished = 1; -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 3/4] elf: check program header offset doesn't exceed constraints
In grub-core/loader/multiboot_elfxx.c, we need to make sure that the program header offset is less than the file size along with the MULTIBOOT_SEARCH constant. We can do so by setting the variable phlimit to the minimum value of the two limits and check it each time we change program header index to insure that the program header offset isn't outside of the limits. Fixes: CID 314029 Fixes: CID 314038 Signed-off-by: Alec Brown --- grub-core/loader/multiboot_elfxx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/grub-core/loader/multiboot_elfxx.c b/grub-core/loader/multiboot_elfxx.c index 52eaf9184..72b376cd5 100644 --- a/grub-core/loader/multiboot_elfxx.c +++ b/grub-core/loader/multiboot_elfxx.c @@ -70,6 +70,7 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld) grub_uint32_t load_offset = 0, load_size = 0; Elf_Shnum shnum; Elf_Word shstrndx, phnum; + grub_off_t phlimit; unsigned int i; void *source = NULL; @@ -100,7 +101,8 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld) return err; /* FIXME: Should we support program headers at strange locations? */ - if (ehdr->e_phoff + phnum * ehdr->e_phentsize > MULTIBOOT_SEARCH) + phlimit = grub_min (MULTIBOOT_SEARCH, grub_file_size (mld->file)); + if ((grub_off_t) ehdr->e_phoff + phnum * ehdr->e_phentsize > phlimit) return grub_error (GRUB_ERR_BAD_OS, "program header at a too high offset"); phdr_base = (char *) mld->buffer + ehdr->e_phoff; -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 1/4] elf: Check program memory isn't larger than allocated memory size
In grub-core/loader/multiboot_elfxx.c, the code is filling an area of memory with grub_memset() but doesn't check if there is space in the allocated memory before doing so. To make sure we aren't zeroing memory past the allocated memory region, we need to check that the offset into the allocated memory region plus the memory size of the program is smaller than the allocated memory size. Fixes: CID 314029 Fixes: CID 314038 Signed-off-by: Alec Brown --- grub-core/loader/multiboot_elfxx.c | 15 +++ 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/grub-core/loader/multiboot_elfxx.c b/grub-core/loader/multiboot_elfxx.c index e067d2d84..69f567588 100644 --- a/grub-core/loader/multiboot_elfxx.c +++ b/grub-core/loader/multiboot_elfxx.c @@ -67,7 +67,7 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld) char *phdr_base; grub_err_t err; grub_relocator_chunk_t ch; - grub_uint32_t load_offset = 0, load_size; + grub_uint32_t load_offset = 0, load_size = 0; Elf_Shnum shnum; Elf_Word shstrndx, phnum; unsigned int i; @@ -170,8 +170,9 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld) } else { + load_size = phdr(i)->p_memsz; err = grub_relocator_alloc_chunk_addr (GRUB_MULTIBOOT (relocator), &ch, -phdr(i)->p_paddr, phdr(i)->p_memsz); +phdr(i)->p_paddr, load_size); if (err != GRUB_ERR_NONE) { @@ -199,8 +200,14 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld) } if (phdr(i)->p_filesz < phdr(i)->p_memsz) -grub_memset ((grub_uint8_t *) source + load_offset + phdr(i)->p_filesz, 0, -phdr(i)->p_memsz - phdr(i)->p_filesz); + { + /* Need to insure that the memory being set isn't larger than the allocated memory*/ + if (load_offset + phdr(i)->p_memsz - phdr(i)->p_filesz > load_size) + return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("memory being set is larger than allocated memory")); + + grub_memset ((grub_uint8_t *) source + load_offset + phdr(i)->p_filesz, 0, + phdr(i)->p_memsz - phdr(i)->p_filesz); + } } } -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 2/4] elf: Check section header region before allocating memory
In grub-core/loader/multiboot_elfxx.c, space is being allocated for the section header region, but isn't verifying if the region is within the file's size. Before calling grub_calloc(), we can add a conditional to check if the section header region is smaller than the file size. Fixes: CID 314029 Fixes: CID 314038 Signed-off-by: Alec Brown --- grub-core/loader/multiboot_elfxx.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/grub-core/loader/multiboot_elfxx.c b/grub-core/loader/multiboot_elfxx.c index 69f567588..52eaf9184 100644 --- a/grub-core/loader/multiboot_elfxx.c +++ b/grub-core/loader/multiboot_elfxx.c @@ -248,6 +248,9 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld) { grub_uint8_t *shdr, *shdrptr; + if ((grub_off_t) ehdr->e_shoff + shnum * ehdr->e_shentsize > grub_file_size (mld->file)) + return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("ELF section header region is larger than the file size")); + shdr = grub_calloc (shnum, ehdr->e_shentsize); if (!shdr) return grub_errno; -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 0/4] Address coverity untrusted loop bound bugs in multiboot_elfxx.c
Coverity has listed two untrusted loop bound bugs in grub-core/loader/multiboot_elfxx.c. They are CID 314029 and CID 314038. After testing the first patch, the CID changed to an untrusted loop bound for line 244: shdr = grub_calloc (shnum, ehdr->e_shentsize);. I added a second patch to address this, but after making these changes, it reverted to the original bug of using tainted data in grub_memset(). The third patch addresses Coverity's issue with phdr() in grub_memset() and reduces the bug to only having an issue with using phnum as an untrusted loop bound. However, we can ignore this since phnum is already getting checked earlier in the function. I've also bundled a use-after-free patch with this patch set at the end. Alec Brown (4): elf: Check program memory isn't larger than allocated memory size elf: Check section header region before allocating memory elf: check program header offset doesn't exceed constraints efi: Fix use-after-free in finish boot services grub-core/kern/efi/mm.c| 3 +++ grub-core/loader/multiboot_elfxx.c | 22 +- 2 files changed, 20 insertions(+), 5 deletions(-) ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
Re: [PATCH] bootstrap: Fix patching warnings
On Thu, Jun 15, 2023 at 04:47:09PM +0200, Daniel Kiper wrote: > Currently bootstrap complains in the following way when > patching gnulib files: > > patching file argp-help.c > Hunk #1 succeeded at 52 (offset 1 line). > Hunk #2 succeeded at 1548 (offset 115 lines). > patching file mbswidth.c > patching file mbswidth.h > Hunk #1 succeeded at 40 (offset -5 lines). > > Let's fix it by amending line numbers in the patch. > > Signed-off-by: Daniel Kiper Looks good to me! Reviewed-by: Alec Brown > --- > grub-core/lib/gnulib-patches/fix-width.patch | 6 +++--- > 1 file changed, 3 insertions(+), 3 deletions(-) > > diff --git a/grub-core/lib/gnulib-patches/fix-width.patch > b/grub-core/lib/gnulib-patches/fix-width.patch > index 0a208ad08..15f091c0d 100644 > --- a/grub-core/lib/gnulib-patches/fix-width.patch > +++ b/grub-core/lib/gnulib-patches/fix-width.patch > @@ -143,7 +143,7 @@ diff --git a/lib/argp-help.c b/lib/argp-help.c > index e5375a0f0..5d8f451ec 100644 > --- a/lib/argp-help.c > +++ b/lib/argp-help.c > -@@ -51,6 +51,7 @@ > +@@ -52,6 +52,7 @@ > #include "argp.h" > #include "argp-fmtstream.h" > #include "argp-namefrob.h" > @@ -151,7 +151,7 @@ index e5375a0f0..5d8f451ec 100644 > > #ifndef SIZE_MAX > # define SIZE_MAX ((size_t) -1) > -@@ -1432,7 +1433,7 @@ argp_args_usage (const struct argp *argp, const struct > argp_state *state, > +@@ -1547,7 +1548,7 @@ argp_args_usage (const struct argp *argp, const struct > argp_state *state, > > /* Manually do line wrapping so that it (probably) won't get wrapped > at >any embedded spaces. */ > @@ -204,7 +204,7 @@ diff --git a/lib/mbswidth.h b/lib/mbswidth.h > index 2b5c53c37..45a123e63 100644 > --- a/lib/mbswidth.h > +++ b/lib/mbswidth.h > -@@ -45,6 +45,10 @@ extern "C" { > +@@ -40,6 +40,10 @@ extern "C" { > control characters and 1 otherwise. */ > #define MBSW_REJECT_UNPRINTABLE 2 > > -- > 2.11.0 > ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH] gfxmenu/gui_image.c: Fix double free of bitmap
In grub-core/gfxmenu/gui_image.c, coverity detected a double free in the function load_image(). The function checks if self->bitmap and self->raw_bitmap aren't NULL and then frees them. In the case self->bitmap and self->raw_bitmap are the same, only self->raw_bitmap is freed which would also free the memory used by self->bitmap. However, in this case self->bitmap isn't being set to NULL which could lead to a double free later in the code. After self->raw_bitmap is freed, it gets set to the variable bitmap. If this variable is NULL, the code could have a path that would free self->bitmap a second time in the function rescale_image(). Fixes: CID 292472 Signed-off-by: Alec Brown --- grub-core/gfxmenu/gui_image.c | 11 +++ 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/grub-core/gfxmenu/gui_image.c b/grub-core/gfxmenu/gui_image.c index 6b2e976f1..e619fa4ba 100644 --- a/grub-core/gfxmenu/gui_image.c +++ b/grub-core/gfxmenu/gui_image.c @@ -195,13 +195,16 @@ load_image (grub_gui_image_t self, const char *path) return grub_errno; if (self->bitmap && (self->bitmap != self->raw_bitmap)) -{ - grub_video_bitmap_destroy (self->bitmap); - self->bitmap = 0; -} +grub_video_bitmap_destroy (self->bitmap); if (self->raw_bitmap) grub_video_bitmap_destroy (self->raw_bitmap); + /* + * Either self->bitmap is being freed or it shares memory with + * self->raw_bitmap which is being freed. To ensure self->bitmap doesn't + * point to memory that has been freed, we can set it to NULL. + */ + self->bitmap = NULL; self->raw_bitmap = bitmap; return rescale_image (self); } -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 0/3] Clean up unused values
Coverity listed three unused value bugs in the GRUB. These patches help clean up and remove these uneccessary bits of code. The Coverity bugs being addressed are: CID 428875 CID 428876 CID 428877 Alec Brown (3): fs/jfs.c: Clean up redundant code osdep/unix/getroot.c: Clean up redundant code loader/i386/multiboot_mbi.c: Clean up redundant code grub-core/fs/jfs.c| 1 - grub-core/loader/i386/multiboot_mbi.c | 2 +- grub-core/osdep/unix/getroot.c| 1 - 3 files changed, 1 insertion(+), 3 deletions(-) ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 3/3] loader/i386/multiboot_mbi.c: Clean up redundant code
In grub-core/loader/i386/multiboot_mbi.c, coverity spotted redundant code where the variable err was being set to GRUB_ERR_NONE and then being overwritten later without being used. Since this is unnecessary, we can remove the code that sets err to GRUB_ERR_NONE. Fixes: CID 428877 Signed-off-by: Alec Brown --- grub-core/loader/i386/multiboot_mbi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grub-core/loader/i386/multiboot_mbi.c b/grub-core/loader/i386/multiboot_mbi.c index 11a6e224f..fae5d6fb8 100644 --- a/grub-core/loader/i386/multiboot_mbi.c +++ b/grub-core/loader/i386/multiboot_mbi.c @@ -86,7 +86,7 @@ load_kernel (grub_file_t file, const char *filename, return GRUB_ERR_NONE; } if (err == GRUB_ERR_UNKNOWN_OS && (header->flags & MULTIBOOT_AOUT_KLUDGE)) - grub_errno = err = GRUB_ERR_NONE; + grub_errno = GRUB_ERR_NONE; } if (header->flags & MULTIBOOT_AOUT_KLUDGE) { -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 1/3] fs/jfs.c: Clean up redundant code
In grub-core/fs/jfs.c, coverity spotted redundant code where the pointer diro was being set to 0 and then being overwritten later without being used. Since this is unnecessary, we can remove the code that sets diro to 0. Fixes: CID 428876 Signed-off-by: Alec Brown --- grub-core/fs/jfs.c | 1 - 1 file changed, 1 deletion(-) diff --git a/grub-core/fs/jfs.c b/grub-core/fs/jfs.c index 6f7c43904..62e20ef6f 100644 --- a/grub-core/fs/jfs.c +++ b/grub-core/fs/jfs.c @@ -716,7 +716,6 @@ grub_jfs_find_file (struct grub_jfs_data *data, const char *path, grub_uint32_t dirino = grub_le_to_cpu32 (data->currinode.inode); grub_jfs_closedir (diro); - diro = 0; if (grub_jfs_read_inode (data, ino, &data->currinode)) break; -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 2/3] osdep/unix/getroot.c: Clean up redundant code
In grub-core/osdep/unix/getroot.c, coverity spotted redundant code where the double pointer os_dev was being set to 0 and then being overwritten later without being used. Since this is unnecessary, we can remove the code that sets os_dev to 0. Fixes: CID 428875 Signed-off-by: Alec Brown --- grub-core/osdep/unix/getroot.c | 1 - 1 file changed, 1 deletion(-) diff --git a/grub-core/osdep/unix/getroot.c b/grub-core/osdep/unix/getroot.c index cde821eb9..12b111634 100644 --- a/grub-core/osdep/unix/getroot.c +++ b/grub-core/osdep/unix/getroot.c @@ -540,7 +540,6 @@ grub_guess_root_devices (const char *dir_in) for (cur = os_dev; *cur; cur++) free (*cur); free (os_dev); - os_dev = 0; } if (stat (dir, &st) < 0) -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH] cli_lock: Added build option to block command line interface
Added functionality to disable command line interface access and editing of GRUB menu entries if GRUB image is built with --disable-cli. Signed-off-by: Alec Brown --- docs/grub.texi | 6 -- grub-core/kern/main.c | 28 grub-core/kern/rescue_reader.c | 13 + grub-core/normal/auth.c| 3 +++ grub-core/normal/menu_text.c | 31 +-- include/grub/kernel.h | 3 ++- include/grub/misc.h| 2 ++ include/grub/util/install.h| 8 ++-- util/grub-install-common.c | 11 --- util/grub-mkimage.c| 9 - util/mkimage.c | 16 +++- 11 files changed, 106 insertions(+), 24 deletions(-) diff --git a/docs/grub.texi b/docs/grub.texi index a225f9a88..96ab17d5b 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -6412,8 +6412,10 @@ the GRUB command line, edit menu entries, and execute any menu entry. If @samp{superusers} is set, then use of the command line and editing of menu entries are automatically restricted to superusers. Setting @samp{superusers} to empty string effectively disables both access to CLI and editing of menu -entries. Note: The environment variable needs to be exported to also affect -the section defined by the @samp{submenu} command (@pxref{submenu}). +entries. Building a grub image with @samp{--disable-cli} option will also +disable access to CLI and editing of menu entries, as well as disabling rescue +mode. Note: The environment variable needs to be exported to also affect the +section defined by the @samp{submenu} command (@pxref{submenu}). Other users may be allowed to execute specific menu entries by giving a list of usernames (as above) using the @option{--users} option to the diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c index 731c07c29..30643164e 100644 --- a/grub-core/kern/main.c +++ b/grub-core/kern/main.c @@ -30,11 +30,14 @@ #include #include #include +#include #ifdef GRUB_MACHINE_PCBIOS #include #endif +static bool cli_disabled = false; + grub_addr_t grub_modules_get_end (void) { @@ -237,6 +240,28 @@ grub_load_normal_mode (void) grub_command_execute ("normal", 0, 0); } +bool +grub_is_cli_disabled (void) +{ + return cli_disabled; +} + +static void +check_is_cli_disabled (void) +{ + struct grub_module_header *header; + header = 0; + + FOR_MODULES (header) +{ + if (header->type == OBJ_TYPE_DISABLE_CLI) + { + cli_disabled = true; + return; + } +} +} + static void reclaim_module_space (void) { @@ -294,6 +319,9 @@ grub_main (void) grub_boot_time ("After loading embedded modules."); + /* Check if the CLI should be disabled */ + check_is_cli_disabled (); + /* It is better to set the root device as soon as possible, for convenience. */ grub_set_prefix_and_root (); diff --git a/grub-core/kern/rescue_reader.c b/grub-core/kern/rescue_reader.c index dcd7d4439..4259857ba 100644 --- a/grub-core/kern/rescue_reader.c +++ b/grub-core/kern/rescue_reader.c @@ -78,6 +78,19 @@ grub_rescue_read_line (char **line, int cont, void __attribute__ ((noreturn)) grub_rescue_run (void) { + /* Stall if the CLI has been disabled */ + if (grub_is_cli_disabled ()) +{ + grub_printf ("Rescue mode has been disabled...\n"); + + do + { + /* Do not optimize out the loop. */ + asm volatile (""); + } + while (1); +} + grub_printf ("Entering rescue mode...\n"); while (1) diff --git a/grub-core/normal/auth.c b/grub-core/normal/auth.c index 517fc623f..d94020186 100644 --- a/grub-core/normal/auth.c +++ b/grub-core/normal/auth.c @@ -209,6 +209,9 @@ grub_auth_check_authentication (const char *userlist) char entered[GRUB_AUTH_MAX_PASSLEN]; struct grub_auth_user *user; + if (grub_is_cli_disabled ()) +return GRUB_ACCESS_DENIED; + grub_memset (login, 0, sizeof (login)); if (is_authenticated (userlist)) diff --git a/grub-core/normal/menu_text.c b/grub-core/normal/menu_text.c index b1321eb26..9c383e64a 100644 --- a/grub-core/normal/menu_text.c +++ b/grub-core/normal/menu_text.c @@ -178,21 +178,24 @@ command-line or ESC to discard edits and return to the GRUB menu."), grub_free (msg_translated); - if (nested) + if (!grub_is_cli_disabled ()) { - ret += grub_print_message_indented_real - (_("Press enter to boot the selected OS, " - "`e' to edit the commands before booting " - "or `c' for a command-line. ESC to return previous menu."), -STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run); - } - else - { - ret += grub_print_message_indented_real - (_("Press enter to boot the selected OS, " - "`e' to edit the comma
RE: [External] : Re: [PATCH] Allow background to be set when theme is set
Hey, So a few suggestions. You should use git send-email to send your patch. This will format the patch nicely and make it easier to apply your patch to the rest of the GRUB code. Also, when sending an update of your patch, instead of replying to the initial patch, you should send a separate email with an updated version number, i.e. [PATCH v2]. You will also need a signed-off-by at the end of your commit message for the patch. Alec Brown On Tue, Oct 22, 2024 at 2:50 PM, Lin wrote: > On 13.06.24 17:28, Lin wrote: > > > > Hello, first time contributor here. > > I'm not experienced with mailing lists and mailing patches so just let > > me know if I do anything wrong :) > > > > This patch simply allows that if GRUB_BACKGROUND and GRUB_THEME is set > > at the same time, both pieces of code gets generated into grub.cfg by > > grub-mkconfig. > > > > If a theme is loaded, the background image will be visible inside the > > console. > > > Already made my first mistake and got my patch reversed lol. Corrected > patch is below. > > Again, when setting a GRUB_THEME, the elif disallows the GRUB_BACKGROUND > to be used, yet with my patch applied a set background image will not > interfere with the theme, but only be visible as the background for the > console when opened with 'c'. > > Thanks, > Lin > > > diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in > index f86b69bad..4e8f25702 100644 > --- a/util/grub.d/00_header.in > +++ b/util/grub.d/00_header.in > @@ -263,7 +263,9 @@ EOF > Â set theme=(\$root)`make_system_path_relative_to_its_root $GRUB_THEME` > Â export theme > Â EOF > -Â Â Â elif [ "x$GRUB_BACKGROUND" != x ] && [ -f "$GRUB_BACKGROUND" ] \ > +Â Â Â fi > + > +Â Â Â if [ "x$GRUB_BACKGROUND" != x ] && [ -f "$GRUB_BACKGROUND" ] \ > && is_path_readable_by_grub "$GRUB_BACKGROUND"; then > gettext_printf "Found background: %s\n" "$GRUB_BACKGROUND" >&2 > case "$GRUB_BACKGROUND" in > > > > ___ > Grub-devel mailing list > Grub-devel@gnu.org > https://urldefense.com/v3/__https://lists.gnu.org/mailman/listinfo/grub- > devel__;!!ACWV5N9M2RV99hQ!PLGidopsW7qPo_wRq33QaUvrp0eXPF- > Qo0P_D2qJ8UL7kJdBXudmjssK0vWbpxFukgrhEoPThYgtOPZhaSDX$ ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
RE: [External] : [PATCH v3 8/8] i386: Add CRx, MMIO, MSR and extend CPUID definitions
On 9/22/24 1:18 PM, Sergii Dmytruk wrote: > From: Ross Philipson > > Control registers and flags: > - CR0 read/write and flags (PE, MP, EM, TS, PG, NE, WP, AM, NW, CD) > - CR4 read/write and flags (VME, PVI, TSD, DE, PSE, PAE, MCE, PGE, PCE, >FXSR, XMM, VMXE, SMXE, PCIDE) > - EFLAGS read/write and flags (CF, PF, AF, ZF, SF, TF, IF, DF, OF, >IOPL, NT, RF, VM, AC, VIF, VIP, ID) > > MMIO: > - read/write 8bit values > - read/write 32bit values > - read/write 64bit values > > MSRs: > - platform ID > - APIC base > - feature control > - MTRR (capability, bases, masks, types) > - MCG (global machine check; capability, status) > - MISC_ENABLE > - MC0 (machine check error reporting status) > - EFER (LME, LMA, SVEM (AMD-V)) > - AMD: SVM control > > CPUID: > - flags for availability of vendor, features > - Intel: VMX, SMX > - AMD: SVM > > Signed-off-by: Ross Philipson > Signed-off-by: Daniel Kiper > Signed-off-by: Krystian Hebel > Signed-off-by: Sergii Dmytruk Reviewed-by: Alec Brown > --- > include/grub/i386/cpuid.h | 11 > include/grub/i386/crfr.h | 127 ++ > include/grub/i386/mmio.h | 72 + > include/grub/i386/msr.h | 63 +++ > 4 files changed, 273 insertions(+) > create mode 100644 include/grub/i386/crfr.h > create mode 100644 include/grub/i386/mmio.h > > diff --git a/include/grub/i386/cpuid.h b/include/grub/i386/cpuid.h > index f7ae4b0a4..bf2a39ec3 100644 > --- a/include/grub/i386/cpuid.h > +++ b/include/grub/i386/cpuid.h > @@ -19,6 +19,17 @@ > #ifndef GRUB_CPU_CPUID_HEADER > #define GRUB_CPU_CPUID_HEADER 1 > > +/* General */ > +#define GRUB_X86_CPUID_VENDOR 0x > +#define GRUB_X86_CPUID_FEATURES 0x0001 > +/* Intel */ > +#define GRUB_X86_CPUID_FEATURES_ECX_VMX (1<<5) > +#define GRUB_X86_CPUID_FEATURES_ECX_SMX (1<<6) > +/* AMD */ > +#define GRUB_AMD_CPUID_FEATURES 0x8001 > +#define GRUB_AMD_CPUID_FEATURES_ECX_SVM (1<<2) > +#define GRUB_AMD_CPUID_FUNC 0x800a > + > extern unsigned char grub_cpuid_has_longmode; > extern unsigned char grub_cpuid_has_pae; > > diff --git a/include/grub/i386/crfr.h b/include/grub/i386/crfr.h > new file mode 100644 > index 0..aeb696a91 > --- /dev/null > +++ b/include/grub/i386/crfr.h > @@ -0,0 +1,127 @@ > +/* > + * GRUB -- GRand Unified Bootloader > + * Copyright (C) 2020 Oracle and/or its affiliates. > + * > + * 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 > <https://urldefense.com/v3/__https://www.gnu.org/licenses/__;!!ACWV5N9M2RV99hQ!Kp- > 6csQGLflhBa0f91yu7uYC6I4_2epaqrkQiX07KlWjbI_XcuW9yg4OjYxptQIRM_000Klz9NGpDqSuzdu4XXISwiwO$ > >. > + */ > + > +#ifndef GRUB_CRFR_H > +#define GRUB_CRFR_H 1 > + > +#include > + > +/* Routines for R/W of control and flags registers */ > + > +#define GRUB_CR0_X86_PE0x0001 /* Enable Protected Mode */ > +#define GRUB_CR0_X86_MP0x0002 /* "Math" (FPU) Present */ > +#define GRUB_CR0_X86_EM0x0004 /* EMulate FPU */ > +#define GRUB_CR0_X86_TS0x0008 /* Task Switched */ > +#define GRUB_CR0_X86_PG0x8000 /* Enable PaGing */ > + > +#define GRUB_CR0_X86_NE0x0020 /* Numeric Error enable (EX16 vs > IRQ13) */ > +#define GRUB_CR0_X86_WP0x0001 /* Write Protect */ > +#define GRUB_CR0_X86_AM0x0004 /* Alignment Mask */ > +#define GRUB_CR0_X86_NW0x2000 /* Not Write-through */ > +#define GRUB_CR0_X86_CD0x4000 /* Cache Disable */ > + > +#define GRUB_CR4_X86_VME 0x0001 /* Virtual 8086 mode extensions */ > +#define GRUB_CR4_X86_PVI 0x0002 /* Protected-mode virtual interrupts */ > +#define GRUB_CR4_X86_TSD 0x0004 /* Time stamp disable */ > +#define GRUB_CR4_X86_DE0x0008 /* Debugging extensions */ > +#define GRUB_CR4_X86_PSE 0x0010 /* Page size extensions */ > +#define GRUB_CR4_X86_PAE 0x0020 /* Physical address extension */ > +#define GRUB_CR4_X86_MCE 0x0040 /* Enable Machine check enable */ >
[PATCH 0/3] Add commands to load BLS and UKI files
This patch set is introducing BootLoaderSpec support to upstream GRUB from Fedora GRUB. I've also added a uki command to load Unified Kernel Images since it shares similar code to loading BLS config files. Alec Brown Alec Brown (1): blsuki: Add uki command to load Unified Kernel Image entries Peter Jones (1): blsuki: Add blscfg command to parse Boot Loader Specification snippets Robbie Harwood (1): blsuki: Check for mounted /boot in emu Makefile.util.def | 16 ++ docs/grub.texi | 53 + grub-core/Makefile.core.def | 14 ++ grub-core/commands/blsuki.c | 1426 grub-core/commands/legacycfg.c |4 +- grub-core/commands/menuentry.c |8 +- grub-core/lib/vercmp.c | 312 ++ grub-core/normal/main.c |6 + grub-core/osdep/linux/getroot.c |8 + grub-core/osdep/unix/getroot.c | 10 + include/grub/emu/misc.h |2 +- include/grub/lib/vercmp.h | 28 +++ include/grub/menu.h | 17 ++ include/grub/normal.h |2 +- tests/vercmp_unit_test.c| 65 ++ 15 files changed, 1964 insertions(+), 7 deletions(-) ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v2 3/3] blsuki: Add uki command to load Unified Kernel Image entries
A Unified Kernel Image is a single UEFI PE file that combines a UEFI boot stub, a Linux kernel image, an initrd, and further resources. The uki command will locate where the uki file is and create a GRUB menu entry to load it. Signed-off-by: Alec Brown --- docs/grub.texi | 26 +++ grub-core/commands/blsuki.c | 415 ++-- include/grub/menu.h | 2 + 3 files changed, 428 insertions(+), 15 deletions(-) diff --git a/docs/grub.texi b/docs/grub.texi index 19b0cc024..9317b4130 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -6491,6 +6491,7 @@ you forget a command, you can run the command @command{help} * tpm2_key_protector_clear::Clear the TPM2 key protector * true::Do nothing, successfully * trust:: Add public key to list of trusted keys +* uki:: Load Unified Kernel Image menu entries * unset:: Unset an environment variable @comment * vbeinfo:: List available video modes * verify_detached:: Verify detached digital signature @@ -8164,6 +8165,31 @@ Unset the environment variable @var{envvar}. @end deffn +@node uki +@subsection uki + +@deffn Command uki [@option{--path} dir] [@option{--show-default}] [@option{--show-non-default}] [@option{--entry} file] +Load Unified Kernel Image entries into the GRUB menu. + +The @option{--path} option overrides the default path to the directory containing +the UKI entries. If this option isn't used, the default location is +/EFI/Linux in the EFI system partition. + +The @option{--show-default} option allows the default boot entry to be added to the +GRUB menu from the UKI entries. + +The @option{--show-non-default} option allows non-default boot entries to be added to +the GRUB menu from the UKI entries. + +The @option{--entry} option allows specific boot entries to be added to the GRUB menu +from the UKI entries. + +The @option{--entry}, @option{--show-default}, and @option{--show-non-default} options +are used to filter which UKI entries are added to the GRUB menu. If none are +used, all entries in the default location or the location specified by @option{--path} +will be added to the GRUB menu. +@end deffn + @ignore @node vbeinfo @subsection vbeinfo diff --git a/grub-core/commands/blsuki.c b/grub-core/commands/blsuki.c index 12a9a1ed1..bf284e002 100644 --- a/grub-core/commands/blsuki.c +++ b/grub-core/commands/blsuki.c @@ -39,9 +39,21 @@ #define GRUB_BOOT_DEVICE "" #endif +#ifdef GRUB_MACHINE_EFI +#include +#include +#include +#endif + GRUB_MOD_LICENSE ("GPLv3+"); #define GRUB_BLS_CONFIG_PATH "/loader/entries/" +#define GRUB_UKI_CONFIG_PATH "/EFI/Linux" + +#define GRUB_BLS_CMD 1 +#define GRUB_UKI_CMD 2 + +static int cmd_type = 0; static const struct grub_arg_option bls_opt[] = { @@ -52,6 +64,17 @@ static const struct grub_arg_option bls_opt[] = {0, 0, 0, 0, 0, 0} }; +#ifdef GRUB_MACHINE_EFI +static const struct grub_arg_option uki_opt[] = + { +{"path", 'p', 0, N_("Specify path to find UKI entries."), N_("DIR"), ARG_TYPE_PATHNAME}, +{"show-default", 'd', 0, N_("Allow the default UKI entry to be added to the GRUB menu."), 0, ARG_TYPE_NONE}, +{"show-non-default", 'n', 0, N_("Allow the non-default UKI entries to be added to the GRUB menu."), 0, ARG_TYPE_NONE}, +{"entry", 'e', 0, N_("Allow specificUKII entries to be added to the GRUB menu."), N_("FILE"), ARG_TYPE_FILE}, +{0, 0, 0, 0, 0, 0} + }; +#endif + struct keyval { const char *key; @@ -288,6 +311,206 @@ bls_read_entry (grub_file_t f, grub_blsuki_entry_t *entry) return err; } +#ifdef GRUB_MACHINE_EFI +static grub_err_t +uki_read_entry (grub_file_t f, grub_blsuki_entry_t *entry) +{ + struct grub_msdos_image_header *dos = NULL; + struct grub_pe_image_header *pe = NULL; + grub_off_t section_offset = 0; + struct grub_pe32_section_table *section = NULL; + struct grub_pe32_coff_header *coff_header = NULL; + char *val = NULL; + char *key = NULL; + const char *target[] = {".cmdline", ".osrel", ".linux", NULL}; + bool has_linux = false; + grub_err_t err = GRUB_ERR_NONE; + + dos = grub_zalloc (sizeof (*dos)); + if (dos == NULL) +return grub_errno; + if (grub_file_read (f, dos, sizeof (*dos)) < (grub_ssize_t) sizeof (*dos)) +{ + err = grub_error (GRUB_ERR_FILE_READ_ERROR, "failed to read UKI image header"); + goto fail; +} + if (dos->msdos_magic != GRUB_PE32_MAGIC) +{ + err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, N_("plain image kernel not supported")); + goto fail; +} + + grub_dprintf ("blsuki", "PE/COFF header @ %08x\n", dos->pe_image
RE: [PATCH v2 2/3] blsuki: Check for mounted /boot in emu
On Tue, Mar 25, 2025 at 8:26 AM, Vladimir 'phcoder' Serbinenko wrote: > Le mar. 25 mars 2025, 10:15, Alec Brown a écrit : > >> Irritatingly, BLS defines paths relatives to the mountpoint of the >> filesystem which contains its snippets, not / or any other fixed >> location. So grub2-emu needs to know whether /boot is a separate >> filesystem from / and conditionally prepend a path. >> >> Signed-off-by: Robbie Harwood >> Signed-off-by: Alec Brown >> --- >> grub-core/Makefile.core.def | 4 +++ >> grub-core/commands/blsuki.c | 54 - >> grub-core/osdep/linux/getroot.c | 8 + >> grub-core/osdep/unix/getroot.c | 10 ++ >> include/grub/emu/misc.h | 2 +- >> 5 files changed, 70 insertions(+), 8 deletions(-) >> >> diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def >> index f3b776c0a..9a0e7bc55 100644 >> --- a/grub-core/Makefile.core.def >> +++ b/grub-core/Makefile.core.def >> @@ -367,6 +367,10 @@ kernel = { >>emu = kern/emu/cache_s.S; >>emu = kern/emu/hostdisk.c; >>emu = osdep/unix/hostdisk.c; >> + emu = osdep/relpath.c; >> + emu = osdep/getroot.c; >> + emu = osdep/unix/getroot.c; >> + emu = osdep/devmapper/getroot.c; >>emu = osdep/exec.c; >>extra_dist = osdep/unix/exec.c; >>emu = osdep/devmapper/hostdisk.c; >> diff --git a/grub-core/commands/blsuki.c b/grub-core/commands/blsuki.c >> index 0f77fb568..12a9a1ed1 100644 >> --- a/grub-core/commands/blsuki.c >> +++ b/grub-core/commands/blsuki.c >> @@ -32,6 +32,13 @@ >> #include >> #include >> >> +#ifdef GRUB_MACHINE_EMU >> +#include >> +#define GRUB_BOOT_DEVICE "/boot" >> +#else >> +#define GRUB_BOOT_DEVICE "" >> +#endif >> + >> GRUB_MOD_LICENSE ("GPLv3+"); >> >> #define GRUB_BLS_CONFIG_PATH "/loader/entries/" >> @@ -53,8 +60,40 @@ struct keyval >> >> static grub_blsuki_entry_t *entries = NULL; >> >> +/* >> + * Cache probing in blsuki_update_boot_device(). Used for linux entry >> also. >> + */ >> +static int separate_boot = -1; >> > > On non-emu it's an unused static. It might trigger a warning. I'd prefer > this to be inside ifdef. There's one instance where this value gets used to check if we add the GRUB_BOOT_DEVICE to the start of the Linux kernel path, but this could be changed to use the blsuki_update_boot_device() instead. > >> + >> #define FOR_BLSUKI_ENTRIES(var) FOR_LIST_ELEMENTS (var, entries) >> >> +/* >> + * BLS appears to make paths relative to the filesystem that snippets are >> + * on, not /. Attempt to cope. >> + */ >> +static char *blsuki_update_boot_device (char *tmp) >> +{ >> +#ifdef GRUB_MACHINE_EMU >> + char *ret; >> + >> + if (separate_boot != -1) >> +goto probed; >> + >> + separate_boot = 0; >> + >> + ret = grub_make_system_path_relative_to_its_root (GRUB_BOOT_DEVICE); >> + >> + if (ret != NULL) >> +separate_boot = 1; >> > Are you sure that != NULL is the right check? It looks like it should be > strcmp with "/". How do you get a NULL here? Shouldn't happen if the path > exists. Ah you are correct. I think I confused this with the output of grub_make_system_path_relative_to_its_root_os(). Upon review of the function, if the path given is the mount point, it will return an empty string since it won't return a trailing "/". I'll fix my code to reflect this. > >> + >> + probed: >> + if (!separate_boot) >> +return grub_stpcpy (tmp, " "); >> +#endif >> + >> + return grub_stpcpy (tmp, " " GRUB_BOOT_DEVICE); >> +} >> + ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
RE: [PATCH v2 3/3] blsuki: Add uki command to load Unified Kernel Image entries
On Wed, Mar 26, 2025 at 5:43 AM, Vladimir 'phcoder' Serbinenko wrote: >> >> >> >> +#ifdef GRUB_MACHINE_EFI >> +#include >> +#include >> +#include >> +#endif >> + >> > Can UKI work without EFI? I think of scenario of putting e.g. EFI disk into > coreboot or BIOS machine. No UKI only works EFI systems. > >> GRUB_MOD_LICENSE ("GPLv3+"); >> >> #define GRUB_BLS_CONFIG_PATH "/loader/entries/" >> +#define GRUB_UKI_CONFIG_PATH "/EFI/Linux" >> + >> +#define GRUB_BLS_CMD 1 >> +#define GRUB_UKI_CMD 2 >> + >> +static int cmd_type = 0; >> > Can we make this into an enum? Sure thing! > >> >> >> >> + if (pe->optional_header.magic != GRUB_PE32_NATIVE_MAGIC) >> +{ >> + err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "non-native image >> not supported"); >> > Maybe it's a bad kernel and not not implemented yet? Later indicates that > sick a config is valid, just not supported yet. Is it so? Ah. I copied this error from a comparison that checks the same magic number in grub-core/loader/efi/linux.c. I'll adjust this error statement. > >> + >> +static char * >> +uki_read_osrel (char *content, grub_off_t *pos, char **key_ret, char >> **val_ret) >> +{ >> + char *line; >> + char *value; >> + grub_size_t linelen; >> + >> + skip: >> + line = content + *pos; >> + if (*line == '\0') >> +return NULL; >> + >> + linelen = 0; >> + while (line[linelen] != '\0' && !grub_strchr ("\n\r", line[linelen])) >> > While I recognize the elegance of strchr, we don't use this trick in the > code and it makes it more difficult to read. Can you use 2 comparisons > instead? Sure I'll do that instead. > >> +linelen++; >> + >> + /* Move pos to the next line */ >> + *pos += linelen; >> + if (content[*pos] != '\0') >> +(*pos)++; >> + >> + /* Skip empty line */ >> + if (linelen == 0) >> +goto skip; >> + >> + line[linelen] = '\0'; >> + >> + /* Remove leading white space */ >> + while (grub_strchr (" \t", *line)) >> > Ditto > >> +{ >> + line++; >> + linelen--; >> +} >> + >> + /* Remove trailing whitespace */ >> + while (linelen > 0 && grub_strchr ("=", line[linelen - 1])) >> +linelen--; >> > Comment doesn't match what really happens here. Also strchr with single > character string makes no sense. > >> + line[linelen] = '\0'; >> + >> + if (*line == '#') >> +goto skip; >> + >> + /* Split key/value */ >> + value = line; >> + while (*value != '\0' && !grub_strchr ("=", *value)) >> +value++; >> > Ditto > >> + if (*value == '\0') >> +goto skip; >> + *value = '\0'; >> + value++; >> + while (*value != '\0' && grub_strchr ("=", *value)) >> +value++; >> > Ditto > >> >> + if (grub_mul (argc + 1, sizeof (char *), &size)) >> +{ >> + grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected creating >> argv list")); >> > Not worth translating. Generally the code which is only to guard against > malicious input is not worth translating > >> + goto finish; >> +} >> + argv = grub_malloc (size); >> + if (argv == NULL) >> +{ >> + grub_error (GRUB_ERR_OUT_OF_MEMORY, "failed to allocate argv list"); >> > Grub_malloc already sets err no. > >> + goto finish; >> +} >> + argv[0] = title; >> + argv[argc] = NULL; >> + >> + src = grub_xasprintf ("insmod chain\n" >> > Why do you need insmod? Didn't automatic insmod work? I didn't realize there was an automatic insmod. I just tested this without the insmod call and you are correct that I don't need this. > >> + "chainloader (%s)%s/%s%s%s\n", >> + entry->devid, entry->dirname, >> + entry->filename, options ? " " : "", options ? >> options : ""); >> > Can we have a Linux variant for non-EFI? > >> >> >>/* >> * If we aren't able to find BLS entries in the directory given by >> info->dirname, >> * we can fallback to the default location "/boot/loader/entries/" and >> see if we >> - * can find the files there. >> + * can find the files there. If we can't find UKI entries, fallback to >> + * "/boot/efi/EFI/Linux". >> */ >> > What's the purpose of fallback? It's not what user/script has requested. It > needs to be at very least disableable The fallback code was from some of the old blscfg code I was working with and I added the UKI default directory. I'll add an option in case the user wants this behavior. > >> >> >> + } >> + else if (cmd_type == GRUB_UKI_CMD) >> + { >> +#ifdef GRUB_MACHINE_EFI >> + grub_efi_loaded_image_t *image; >> + image = grub_efi_get_loaded_image (grub_efi_image_handle); >> + devid = grub_efidisk_get_device_name (image->device_handle); >> +#endif >> > This uses grub image location. What about a scenario when booted from > external drive and I want to boot into install on primary disk? Maybe I might not understand this scenario very well, but would it be better to load the UKI directory using the "--path" option? This bit of code is trying to locate t
[PATCH v3 2/3] blsuki: Check for mounted /boot in emu
Irritatingly, BLS defines paths relatives to the mountpoint of the filesystem which contains its snippets, not / or any other fixed location. So grub2-emu needs to know whether /boot is a separate filesystem from / and conditionally prepend a path. Signed-off-by: Robbie Harwood Signed-off-by: Alec Brown --- grub-core/Makefile.core.def | 4 ++ grub-core/commands/blsuki.c | 92 ++--- grub-core/osdep/linux/getroot.c | 8 +++ grub-core/osdep/unix/getroot.c | 10 include/grub/emu/misc.h | 2 +- 5 files changed, 107 insertions(+), 9 deletions(-) diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index f3b776c0a..9a0e7bc55 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -367,6 +367,10 @@ kernel = { emu = kern/emu/cache_s.S; emu = kern/emu/hostdisk.c; emu = osdep/unix/hostdisk.c; + emu = osdep/relpath.c; + emu = osdep/getroot.c; + emu = osdep/unix/getroot.c; + emu = osdep/devmapper/getroot.c; emu = osdep/exec.c; extra_dist = osdep/unix/exec.c; emu = osdep/devmapper/hostdisk.c; diff --git a/grub-core/commands/blsuki.c b/grub-core/commands/blsuki.c index 0fb4f870a..7b7b3e0e4 100644 --- a/grub-core/commands/blsuki.c +++ b/grub-core/commands/blsuki.c @@ -32,6 +32,13 @@ #include #include +#ifdef GRUB_MACHINE_EMU +#include +#define GRUB_BOOT_DEVICE "/boot" +#else +#define GRUB_BOOT_DEVICE "" +#endif + GRUB_MOD_LICENSE ("GPLv3+"); #define GRUB_BLS_CONFIG_PATH "/loader/entries/" @@ -56,6 +63,40 @@ static grub_blsuki_entry_t *entries = NULL; #define FOR_BLSUKI_ENTRIES(var) FOR_LIST_ELEMENTS (var, entries) +#ifdef GRUB_MACHINE_EMU +/* + * Cache probing in blsuki_update_boot_device(). + */ +static int separate_boot = -1; +#endif + +/* + * BLS appears to make paths relative to the filesystem that snippets are + * on, not /. Attempt to cope. + */ +static char *blsuki_update_boot_device (char *tmp) +{ +#ifdef GRUB_MACHINE_EMU + char *ret = NULL; + + if (separate_boot != -1) +goto probed; + + separate_boot = 0; + + ret = grub_make_system_path_relative_to_its_root (GRUB_BOOT_DEVICE); + + if (ret != NULL && ret[0] == '\0') +separate_boot = 1; + + probed: + if (!separate_boot) +return tmp; +#endif + + return grub_stpcpy (tmp, GRUB_BOOT_DEVICE); +} + static grub_err_t blsuki_add_keyval (grub_blsuki_entry_t *entry, char *key, char *val) { @@ -561,7 +602,7 @@ bls_create_entry (grub_blsuki_entry_t *entry) goto finish; } - if (grub_add (sizeof ("linux "), grub_strlen (linux_path), &linux_size)) + if (grub_add (sizeof ("linux " GRUB_BOOT_DEVICE), grub_strlen (linux_path), &linux_size)) { grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected calculating linux buffer size"); goto finish; @@ -572,6 +613,7 @@ bls_create_entry (grub_blsuki_entry_t *entry) tmp = clinux; tmp = grub_stpcpy (tmp, "linux"); tmp = grub_stpcpy (tmp, " "); + tmp = blsuki_update_boot_device (tmp); tmp = grub_stpcpy (tmp, linux_path); /* Strip the ".conf" off the end before we make it our "id" field. */ @@ -655,7 +697,7 @@ bls_create_entry (grub_blsuki_entry_t *entry) for (i = 0; early_initrds != NULL && early_initrds[i] != NULL; i++) { - if (grub_add (initrd_size, sizeof (" "), &initrd_size) || + if (grub_add (initrd_size, sizeof (" " GRUB_BOOT_DEVICE), &initrd_size) || grub_add (initrd_size, grub_strlen (initrd_prefix), &initrd_size) || grub_add (initrd_size, grub_strlen (early_initrds[i]), &initrd_size) || grub_add (initrd_size, 1, &initrd_size)) @@ -667,7 +709,7 @@ bls_create_entry (grub_blsuki_entry_t *entry) for (i = 0; initrds != NULL && initrds[i] != NULL; i++) { - if (grub_add (initrd_size, sizeof (" "), &initrd_size) || + if (grub_add (initrd_size, sizeof (" " GRUB_BOOT_DEVICE), &initrd_size) || grub_add (initrd_size, grub_strlen (initrds[i]), &initrd_size) || grub_add (initrd_size, 1, &initrd_size)) { @@ -691,6 +733,7 @@ bls_create_entry (grub_blsuki_entry_t *entry) { grub_dprintf ("blsuki", "adding early initrd %s\n", early_initrds[i]); tmp = grub_stpcpy (tmp, " "); + tmp = blsuki_update_boot_device (tmp); tmp = grub_stpcpy (tmp, initrd_prefix); tmp = grub_stpcpy (tmp, early_initrds[i]); grub_free (early_initrds[i]); @@ -700,6 +743,7 @@ bls_create_entry (grub_blsuki_entry_t *entry) { grub_dprintf ("blsuki", "adding initrd %s\n", initrds[i]); tmp = grub_stpcpy (tmp, " "); + tmp = blsuki_update_boot_device
[PATCH v3 0/3] Add commands to load BLS and UKI files
v3: - Added --enable-fallback option to check the default directory if the --path option isn't able to find entries. - Added the function blsuki_set_find_entry_info() to help set the path and device of BLS and UKI entries. - Removed grub_strchr uses in uki_read_osrel(). - Converted the static variable "cmd_type" into a parameter and added enums. - Fixed improper handling of the output of grub_make_system_path_relative_to_its_root(). This patch set is introducing BootLoaderSpec support to upstream GRUB from Fedora GRUB. I've also added a uki command to load Unified Kernel Images since it shares similar code to loading BLS config files. Alec Brown Alec Brown (1): blsuki: Add uki command to load Unified Kernel Image entries Peter Jones (1): blsuki: Add blscfg command to parse Boot Loader Specification snippets Robbie Harwood (1): blsuki: Check for mounted /boot in emu Makefile.util.def | 16 +++ docs/grub.texi | 55 grub-core/Makefile.core.def | 14 ++ grub-core/commands/blsuki.c | 1519 +++ grub-core/commands/legacycfg.c |4 +- grub-core/commands/menuentry.c |8 +- grub-core/lib/vercmp.c | 317 + grub-core/normal/main.c |6 + grub-core/osdep/linux/getroot.c |8 ++ grub-core/osdep/unix/getroot.c | 10 ++ include/grub/emu/misc.h |2 +- include/grub/lib/vercmp.h | 35 + include/grub/menu.h | 17 +++ include/grub/normal.h |2 +- tests/vercmp_unit_test.c| 65 + 15 files changed, 2071 insertions(+), 7 deletions(-) ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v3 1/3] blsuki: Add blscfg command to parse Boot Loader Specification snippets
The BootLoaderSpec (BLS) defines a scheme where different bootloaders can share a format for boot items and a configuration directory that accepts these common configurations as drop-in files. Signed-off-by: Peter Jones Signed-off-by: Javier Martinez Canillas Signed-off-by: Will Thompson Signed-off-by: Alec Brown --- Makefile.util.def | 16 + docs/grub.texi | 29 + grub-core/Makefile.core.def| 10 + grub-core/commands/blsuki.c| 1057 grub-core/commands/legacycfg.c |4 +- grub-core/commands/menuentry.c |8 +- grub-core/lib/vercmp.c | 317 ++ grub-core/normal/main.c|6 + include/grub/lib/vercmp.h | 35 ++ include/grub/menu.h| 15 + include/grub/normal.h |2 +- tests/vercmp_unit_test.c | 65 ++ 12 files changed, 1558 insertions(+), 6 deletions(-) create mode 100644 grub-core/commands/blsuki.c create mode 100644 grub-core/lib/vercmp.c create mode 100644 include/grub/lib/vercmp.h create mode 100644 tests/vercmp_unit_test.c diff --git a/Makefile.util.def b/Makefile.util.def index 038253b37..a911f2e0a 100644 --- a/Makefile.util.def +++ b/Makefile.util.def @@ -1373,6 +1373,22 @@ program = { ldadd = '$(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; }; +program = { + testcase = native; + name = vercmp_unit_test; + common = tests/vercmp_unit_test.c; + common = tests/lib/unit_test.c; + common = grub-core/kern/list.c; + common = grub-core/kern/misc.c; + common = grub-core/tests/lib/test.c; + common = grub-core/lib/vercmp.c; + ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; + ldadd = libgrubkern.a; + ldadd = grub-core/lib/gnulib/libgnu.a; + ldadd = '$(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; +}; + program = { name = grub-menulst2cfg; mansection = 1; diff --git a/docs/grub.texi b/docs/grub.texi index d9b26fa36..ea7a13953 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -6417,6 +6417,7 @@ you forget a command, you can run the command @command{help} * background_image::Load background image for active terminal * badram:: Filter out bad regions of RAM * blocklist:: Print a block list +* blscfg:: Load Boot Loader Specification menu entries * boot::Start up your operating system * cat:: Show the contents of a file * clear:: Clear the screen @@ -6603,6 +6604,34 @@ Print a block list (@pxref{Block list syntax}) for @var{file}. @end deffn +@node blscfg +@subsection blscfg + +@deffn Command blscfg [@option{--path} dir] [@option{--enable-fallback}] [@option{--show-default}] [@option{--show-non-default}] [@option{--entry} file] +Load Boot Loader Specification entries into the GRUB menu. + +The @option{--path} option overrides the default path to the directory containing +the BLS entries. If this option isn't used, the default location is +/loader/entries in @code{$BOOT}. If no BLS entries are found, the +@option{--enable-fallback} option can be used to check for entries in the default +directory. + +The @option{--show-default} option allows the default boot entry to be added to the +GRUB menu from the BLS entries. + +The @option{--show-non-default} option allows non-default boot entries to be added to +the GRUB menu from the BLS entries. + +The @option{--entry} option allows specific boot entries to be added to the GRUB menu +from the BLS entries. + +The @option{--entry}, @option{--show-default}, and @option{--show-non-default} options +are used to filter which BLS entries are added to the GRUB menu. If none are +used, all entries in the default location or the location specified by @option{--path} +will be added to the GRUB menu. +@end deffn + + @node boot @subsection boot diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index f70e02e69..f3b776c0a 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -845,6 +845,16 @@ module = { common = commands/blocklist.c; }; +module = { + name = blsuki; + common = commands/blsuki.c; + common = lib/vercmp.c; + enable = powerpc_ieee1275; + enable = efi; + enable = i386_pc; + enable = emu; +}; + module = { name = boot; common = commands/boot.c; diff --git a/grub-core/commands/blsuki.c b/grub-core/commands/blsuki.c new file mode 100644 index 0..0fb4f870a --- /dev/null +++ b/grub-core/commands/blsuki.c @@ -0,0 +1,1057 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2025 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 use
[PATCH v3 3/3] blsuki: Add uki command to load Unified Kernel Image entries
A Unified Kernel Image is a single UEFI PE file that combines a UEFI boot stub, a Linux kernel image, an initrd, and further resources. The uki command will locate where the uki file is and create a GRUB menu entry to load it. Signed-off-by: Alec Brown --- docs/grub.texi | 26 +++ grub-core/commands/blsuki.c | 438 +--- include/grub/menu.h | 2 + 3 files changed, 440 insertions(+), 26 deletions(-) diff --git a/docs/grub.texi b/docs/grub.texi index ea7a13953..df206dad3 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -6491,6 +6491,7 @@ you forget a command, you can run the command @command{help} * tpm2_key_protector_clear::Clear the TPM2 key protector * true::Do nothing, successfully * trust:: Add public key to list of trusted keys +* uki:: Load Unified Kernel Image menu entries * unset:: Unset an environment variable @comment * vbeinfo:: List available video modes * verify_detached:: Verify detached digital signature @@ -8166,6 +8167,31 @@ Unset the environment variable @var{envvar}. @end deffn +@node uki +@subsection uki + +@deffn Command uki [@option{--path} dir] [@option{--show-default}] [@option{--show-non-default}] [@option{--entry} file] +Load Unified Kernel Image entries into the GRUB menu. + +The @option{--path} option overrides the default path to the directory containing +the UKI entries. If this option isn't used, the default location is +/EFI/Linux in the EFI system partition. + +The @option{--show-default} option allows the default boot entry to be added to the +GRUB menu from the UKI entries. + +The @option{--show-non-default} option allows non-default boot entries to be added to +the GRUB menu from the UKI entries. + +The @option{--entry} option allows specific boot entries to be added to the GRUB menu +from the UKI entries. + +The @option{--entry}, @option{--show-default}, and @option{--show-non-default} options +are used to filter which UKI entries are added to the GRUB menu. If none are +used, all entries in the default location or the location specified by @option{--path} +will be added to the GRUB menu. +@end deffn + @ignore @node vbeinfo @subsection vbeinfo diff --git a/grub-core/commands/blsuki.c b/grub-core/commands/blsuki.c index 7b7b3e0e4..77f59b530 100644 --- a/grub-core/commands/blsuki.c +++ b/grub-core/commands/blsuki.c @@ -32,6 +32,12 @@ #include #include +#ifdef GRUB_MACHINE_EFI +#include +#include +#include +#endif + #ifdef GRUB_MACHINE_EMU #include #define GRUB_BOOT_DEVICE "/boot" @@ -42,6 +48,13 @@ GRUB_MOD_LICENSE ("GPLv3+"); #define GRUB_BLS_CONFIG_PATH "/loader/entries/" +#define GRUB_UKI_CONFIG_PATH "/EFI/Linux" + +enum + { +BLSUKI_BLS_CMD = 1, +BLSUKI_UKI_CMD = 2, + }; static const struct grub_arg_option bls_opt[] = { @@ -53,6 +66,18 @@ static const struct grub_arg_option bls_opt[] = {0, 0, 0, 0, 0, 0} }; +#ifdef GRUB_MACHINE_EFI +static const struct grub_arg_option uki_opt[] = + { +{"path", 'p', 0, N_("Specify path to find UKI entries."), N_("DIR"), ARG_TYPE_PATHNAME}, +{"enable-fallback", 'f', 0, "Fallback to the default BLS path if --path fails to find UKI entries.", 0, ARG_TYPE_NONE}, +{"show-default", 'd', 0, N_("Allow the default UKI entry to be added to the GRUB menu."), 0, ARG_TYPE_NONE}, +{"show-non-default", 'n', 0, N_("Allow the non-default UKI entries to be added to the GRUB menu."), 0, ARG_TYPE_NONE}, +{"entry", 'e', 0, N_("Allow specificUKII entries to be added to the GRUB menu."), N_("FILE"), ARG_TYPE_FILE}, +{0, 0, 0, 0, 0, 0} + }; +#endif + struct keyval { const char *key; @@ -291,10 +316,211 @@ bls_read_entry (grub_file_t f, grub_blsuki_entry_t *entry) return err; } +#ifdef GRUB_MACHINE_EFI +static grub_err_t +uki_read_entry (grub_file_t f, grub_blsuki_entry_t *entry) +{ + struct grub_msdos_image_header *dos = NULL; + struct grub_pe_image_header *pe = NULL; + grub_off_t section_offset = 0; + struct grub_pe32_section_table *section = NULL; + struct grub_pe32_coff_header *coff_header = NULL; + char *val = NULL; + char *key = NULL; + const char *target[] = {".cmdline", ".osrel", ".linux", NULL}; + bool has_linux = false; + grub_err_t err = GRUB_ERR_NONE; + + dos = grub_zalloc (sizeof (*dos)); + if (dos == NULL) +return grub_errno; + if (grub_file_read (f, dos, sizeof (*dos)) < (grub_ssize_t) sizeof (*dos)) +{ + err = grub_error (GRUB_ERR_FILE_READ_ERROR, "failed to read UKI image header"); + goto fail; +} + if (dos->msdos_magic != GRUB_PE32_MAGIC) +
RE: [PATCH v2 3/3] blsuki: Add uki command to load Unified Kernel Image entries
On Tue, Apr 1, 2025 at 6:35 AM, Vladimir 'phcoder' Serbinenko wrote: > Le jeu. 27 mars 2025, 23:44, Alec Brown a écrit : > >> On Wed, Mar 26, 2025 at 5:43 AM, Vladimir 'phcoder' Serbinenko < >> phco...@gmail.com> wrote: >> >> >> >> >> >> >> >> +#ifdef GRUB_MACHINE_EFI >> >> +#include >> >> +#include >> >> +#include >> >> +#endif >> >> + >> >> >> > Can UKI work without EFI? I think of scenario of putting e.g. EFI disk >> into >> > coreboot or BIOS machine. >> >> No UKI only works EFI systems. >> > > Can GRUB parse image and get kernel and initrd out of it and load like > Linux? What prevents add doing so. This is not a problem for this patch per > se but I want to understand If we aren't utilizing the EFI stub in the UKI, we could parse the kernel and initrd from the section data and load it from there. In that case, I suppose it would be possible to load it for a coreboot or BIOS machine. > >> >> >> >> > What's the purpose of fallback? It's not what user/script has requested. >> It >> > needs to be at very least disableable >> >> The fallback code was from some of the old blscfg code I was working with >> and >> I added the UKI default directory. I'll add an option in case the user >> wants >> this behavior. >> >> > >> >> >> >> >> >> + } >> >> + else if (cmd_type == GRUB_UKI_CMD) >> >> + { >> >> +#ifdef GRUB_MACHINE_EFI >> >> + grub_efi_loaded_image_t *image; >> >> + image = grub_efi_get_loaded_image (grub_efi_image_handle); >> >> + devid = grub_efidisk_get_device_name (image->device_handle); >> >> +#endif >> >> >> > This uses grub image location. What about a scenario when booted from >> > external drive and I want to boot into install on primary disk? >> >> Maybe I might not understand this scenario very well, but would it be >> better >> to load the UKI directory using the "--path" option? This bit of code is >> trying to locate the EFI system partition of the default directory. I'm not >> entirely sure the best way to find the default directory if it were to be >> on >> a different drive. >> > Does --path disable default path scanning? In this version, it does not. But in the newest version, I've added an option to enable or disable a fallback that would scan for the default path. ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 1/3] blsuki: Add blscfg command to parse Boot Loader Specification snippets
The BootLoaderSpec (BLS) defines a scheme where different bootloaders can share a format for boot items and a configuration directory that accepts these common configurations as drop-in files. Signed-off-by: Peter Jones Signed-off-by: Javier Martinez Canillas Signed-off-by: Will Thompson Signed-off-by: Alec Brown --- Makefile.util.def | 16 + docs/grub.texi | 27 + grub-core/Makefile.core.def| 10 + grub-core/commands/blsuki.c| 1030 grub-core/commands/legacycfg.c |4 +- grub-core/commands/menuentry.c |8 +- grub-core/lib/vercmp.c | 312 ++ grub-core/normal/main.c|6 + include/grub/lib/vercmp.h | 28 + include/grub/menu.h| 15 + include/grub/normal.h |2 +- tests/vercmp_unit_test.c | 65 ++ 12 files changed, 1517 insertions(+), 6 deletions(-) create mode 100644 grub-core/commands/blsuki.c create mode 100644 grub-core/lib/vercmp.c create mode 100644 include/grub/lib/vercmp.h create mode 100644 tests/vercmp_unit_test.c diff --git a/Makefile.util.def b/Makefile.util.def index 6fe08efd8..7770e7755 100644 --- a/Makefile.util.def +++ b/Makefile.util.def @@ -1327,6 +1327,22 @@ program = { ldadd = '$(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; }; +program = { + testcase = native; + name = vercmp_unit_test; + common = tests/vercmp_unit_test.c; + common = tests/lib/unit_test.c; + common = grub-core/kern/list.c; + common = grub-core/kern/misc.c; + common = grub-core/tests/lib/test.c; + common = grub-core/lib/vercmp.c; + ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; + ldadd = libgrubkern.a; + ldadd = grub-core/lib/gnulib/libgnu.a; + ldadd = '$(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; +}; + program = { name = grub-menulst2cfg; mansection = 1; diff --git a/docs/grub.texi b/docs/grub.texi index 975e521d1..a8465fc0b 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -4333,6 +4333,7 @@ you forget a command, you can run the command @command{help} * background_image::Load background image for active terminal * badram:: Filter out bad regions of RAM * blocklist:: Print a block list +* blscfg:: Load Boot Loader Specification menu entries * boot::Start up your operating system * cat:: Show the contents of a file * clear:: Clear the screen @@ -4515,6 +4516,32 @@ Print a block list (@pxref{Block list syntax}) for @var{file}. @end deffn +@node blscfg +@subsection blscfg + +@deffn Command blscfg [@option{--path} dir] [@option{--show-default}] [@option{--show-non-default}] [@option{--entry} file] +Load Boot Loader Specification entries into the GRUB menu. + +The @option{--path} option overrides the default path to the directory containing +the BLS entries. If this option isn't used, the default location is +/loader/entries in @code{$BOOT}. + +The @option{--show-default} option allows the default boot entry to be added to the +GRUB menu from the BLS entries. + +The @option{--show-non-default} option allows non-default boot entries to be added to +the GRUB menu from the BLS entries. + +The @option{--entry} option allows specific boot entries to be added to the GRUB menu +from the BLS entries. + +The @option{--entry}, @option{--show-default}, and @option{--show-non-default} options +are used to filter which BLS entries are added to the GRUB menu. If none are +used, all entries in the default location or the location specified by @option{--path} +will be added to the GRUB menu. +@end deffn + + @node boot @subsection boot diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index d2cf29584..2cf4e9708 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -841,6 +841,16 @@ module = { common = commands/blocklist.c; }; +module = { + name = blsuki; + common = commands/blsuki.c; + common = lib/vercmp.c; + enable = powerpc_ieee1275; + enable = efi; + enable = i386_pc; + enable = emu; +}; + module = { name = boot; common = commands/boot.c; diff --git a/grub-core/commands/blsuki.c b/grub-core/commands/blsuki.c new file mode 100644 index 0..5203e4707 --- /dev/null +++ b/grub-core/commands/blsuki.c @@ -0,0 +1,1030 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2025 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
[PATCH 2/3] blsuki: Check for mounted /boot in emu
Irritatingly, BLS defines paths relatives to the mountpoint of the filesystem which contains its snippets, not / or any other fixed location. So grub2-emu needs to know whether /boot is a separate filesysem from / and conditionally prepend a path. Signed-off-by: Robbie Harwood Signed-off-by: Alec Brown --- grub-core/Makefile.core.def | 4 +++ grub-core/commands/blsuki.c | 50 + grub-core/osdep/linux/getroot.c | 8 ++ grub-core/osdep/unix/getroot.c | 10 +++ include/grub/emu/misc.h | 2 +- 5 files changed, 68 insertions(+), 6 deletions(-) diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 2cf4e9708..1f86111ad 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -367,6 +367,10 @@ kernel = { emu = kern/emu/cache_s.S; emu = kern/emu/hostdisk.c; emu = osdep/unix/hostdisk.c; + emu = osdep/relpath.c; + emu = osdep/getroot.c; + emu = osdep/unix/getroot.c; + emu = osdep/devmapper/getroot.c; emu = osdep/exec.c; extra_dist = osdep/unix/exec.c; emu = osdep/devmapper/hostdisk.c; diff --git a/grub-core/commands/blsuki.c b/grub-core/commands/blsuki.c index 5203e4707..8a3c5818f 100644 --- a/grub-core/commands/blsuki.c +++ b/grub-core/commands/blsuki.c @@ -32,10 +32,16 @@ #include #include +#ifdef GRUB_MACHINE_EMU +#include +#define GRUB_BOOT_DEVICE "/boot" +#else +#define GRUB_BOOT_DEVICE "/" +#endif + GRUB_MOD_LICENSE ("GPLv3+"); #define GRUB_BLS_CONFIG_PATH "/loader/entries/" -#define GRUB_BOOT_DEVICE "/" static const struct grub_arg_option opt[] = { @@ -54,8 +60,41 @@ struct keyval static grub_blsuki_entry_t *entries = NULL; +/* + * Cache probing in frob_boot_device(). Used for linux entry also. + * Always true in non-emu, meaning to prefix things with GRUB_BOOT_DEVICE. + */ +static int separate_boot = -1; + #define FOR_BLSUKI_ENTRIES(var) FOR_LIST_ELEMENTS (var, entries) +/* + * BLS appears to make paths relative to the filesystem that snippets are + * on, not /. Attempt to cope. + */ +static char *frob_boot_device (char *tmp) +{ +#ifdef GRUB_MACHINE_EMU + char *ret; + + if (separate_boot != -1) +goto probed; + + separate_boot = 0; + + ret = grub_make_system_path_relative_to_its_root (GRUB_BOOT_DEVICE); + + if (ret != NULL) +separate_boot = 1; + + probed: + if (!separate_boot) +return grub_stpcpy (tmp, " "); +#endif + + return grub_stpcpy (tmp, " " GRUB_BOOT_DEVICE); +} + static int blsuki_add_keyval (grub_blsuki_entry_t *entry, char *key, char *val) { @@ -682,7 +721,7 @@ create_entry (grub_blsuki_entry_t *entry) for (i = 0; early_initrds != NULL && early_initrds[i] != NULL; i++) { grub_dprintf ("blsuki", "adding early initrd %s\n", early_initrds[i]); - tmp = grub_stpcpy (tmp, " " GRUB_BOOT_DEVICE); + tmp = frob_boot_device (tmp); tmp = grub_stpcpy (tmp, initrd_prefix); tmp = grub_stpcpy (tmp, early_initrds[i]); grub_free (early_initrds[i]); @@ -691,7 +730,7 @@ create_entry (grub_blsuki_entry_t *entry) for (i = 0; initrds != NULL && initrds[i] != NULL; i++) { grub_dprintf ("blsuki", "adding initrd %s\n", initrds[i]); - tmp = grub_stpcpy (tmp, " " GRUB_BOOT_DEVICE); + tmp = frob_boot_device (tmp); tmp = grub_stpcpy (tmp, initrds[i]); } tmp = grub_stpcpy (tmp, "\n"); @@ -734,7 +773,7 @@ create_entry (grub_blsuki_entry_t *entry) } tmp = dt; tmp = grub_stpcpy (dt, "devicetree"); - tmp = grub_stpcpy (tmp, " " GRUB_BOOT_DEVICE); + tmp = frob_boot_device (tmp); if (add_dt_prefix == true) tmp = grub_stpcpy (tmp, prefix); tmp = grub_stpcpy (tmp, devicetree); @@ -753,7 +792,8 @@ create_entry (grub_blsuki_entry_t *entry) "linux %s%s%s%s\n" "%s%s", savedefault ? "savedefault\n" : "", - GRUB_BOOT_DEVICE, clinux, options ? " " : "", options ? options : "", + separate_boot ? GRUB_BOOT_DEVICE : "", + clinux, options ? " " : "", options ? options : "", initrd ? initrd : "", dt ? dt : ""); grub_normal_add_menu_entry (argc, argv, classes, id, users, hotkey, NULL, src, 0, entry); diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c index 7dd775d2a..37f715469 100644 --- a/grub-core/osdep/linux/getroot.c +++ b/grub-core/osdep/linux/getroot.c @@ -131,6 +131,7 @@ struct mountinfo_entry char fstype[ESCAPED_PATH_MAX + 1], device[ESCAPED_PATH_MAX + 1]; }; +#ifdef GRU
[PATCH 3/3] blsuki: Add uki command to load Unified Kernel Image entries
A Unified Kernel Image is a single UEFI PE file that combines a UEFI boot stub, a Linux kernel image, an initrd, and further resources. The uki command will locate where the uki file is and create a GRUB menu entry to load it. Signed-off-by: Alec Brown --- docs/grub.texi | 26 ++ grub-core/commands/blsuki.c | 712 +++- include/grub/menu.h | 2 + 3 files changed, 562 insertions(+), 178 deletions(-) diff --git a/docs/grub.texi b/docs/grub.texi index a8465fc0b..ecf261717 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -4403,6 +4403,7 @@ you forget a command, you can run the command @command{help} * test::Check file types and compare values * true::Do nothing, successfully * trust:: Add public key to list of trusted keys +* uki:: Load Unified Kernel Image menu entries * unset:: Unset an environment variable @comment * vbeinfo:: List available video modes * verify_detached:: Verify detached digital signature @@ -5904,6 +5905,31 @@ Unset the environment variable @var{envvar}. @end deffn +@node uki +@subsection uki + +@deffn Command uki [@option{--path} dir] [@option{--show-default}] [@option{--show-non-default}] [@option{--entry} file] +Load Unified Kernel Image entries into the GRUB menu. + +The @option{--path} option overrides the default path to the directory containing +the UKI entries. If this option isn't used, the default location is +/EFI/Linux in the EFI system partition. + +The @option{--show-default} option allows the default boot entry to be added to the +GRUB menu from the UKI entries. + +The @option{--show-non-default} option allows non-default boot entries to be added to +the GRUB menu from the UKI entries. + +The @option{--entry} option allows specific boot entries to be added to the GRUB menu +from the UKI entries. + +The @option{--entry}, @option{--show-default}, and @option{--show-non-default} options +are used to filter which UKI entries are added to the GRUB menu. If none are +used, all entries in the default location or the location specified by @option{--path} +will be added to the GRUB menu. +@end deffn + @ignore @node vbeinfo @subsection vbeinfo diff --git a/grub-core/commands/blsuki.c b/grub-core/commands/blsuki.c index 8a3c5818f..3c26f2a56 100644 --- a/grub-core/commands/blsuki.c +++ b/grub-core/commands/blsuki.c @@ -39,11 +39,23 @@ #define GRUB_BOOT_DEVICE "/" #endif +#ifdef GRUB_MACHINE_EFI +#include +#include +#include +#endif + GRUB_MOD_LICENSE ("GPLv3+"); #define GRUB_BLS_CONFIG_PATH "/loader/entries/" +#define GRUB_UKI_CONFIG_PATH "/EFI/Linux" -static const struct grub_arg_option opt[] = +#define GRUB_BLS_CMD 1 +#define GRUB_UKI_CMD 2 + +static int cmd_type = 0; + +static const struct grub_arg_option bls_opt[] = { {"path", 'p', 0, N_("Specify path to find BLS entries."), N_("DIR"), ARG_TYPE_PATHNAME}, {"show-default", 'd', 0, N_("Allow the default BLS entry to be added to the GRUB menu."), 0, ARG_TYPE_NONE}, @@ -52,6 +64,17 @@ static const struct grub_arg_option opt[] = {0, 0, 0, 0, 0, 0} }; +#ifdef GRUB_MACHINE_EFI +static const struct grub_arg_option uki_opt[] = + { +{"path", 'p', 0, N_("Specify path to find UKI entries."), N_("DIR"), ARG_TYPE_PATHNAME}, +{"show-default", 'd', 0, N_("Allow the default UKI entry to be added to the GRUB menu."), 0, ARG_TYPE_NONE}, +{"show-non-default", 'n', 0, N_("Allow the non-default UKI entries to be added to the GRUB menu."), 0, ARG_TYPE_NONE}, +{"entry", 'e', 0, N_("Allow specificUKII entries to be added to the GRUB menu."), N_("FILE"), ARG_TYPE_FILE}, +{0, 0, 0, 0, 0, 0} + }; +#endif + struct keyval { const char *key; @@ -270,7 +293,7 @@ bls_read_entry (grub_file_t f, grub_blsuki_entry_t *entry) break; } - separator[0] = '\0'; + separator[0] = '\0'; do { @@ -287,6 +310,183 @@ bls_read_entry (grub_file_t f, grub_blsuki_entry_t *entry) return rc; } +#ifdef GRUB_MACHINE_EFI +static int +uki_read_entry (grub_file_t f, grub_blsuki_entry_t *entry) +{ + struct grub_msdos_image_header *dos; + struct grub_pe_image_header *pe; + grub_off_t section_offset = 0; + struct grub_pe32_section_table *section; + struct grub_pe32_coff_header *coff_header; + + dos = grub_zalloc (sizeof (*dos)); + if (dos == NULL) +return 1; + if (grub_file_read (f, dos, sizeof (*dos)) < (grub_ssize_t) sizeof (*dos)) +{ + grub_dprintf ("blsuki", "failed to read UKI image header\n"); + grub_free (dos); +
[PATCH v2 1/3] blsuki: Add blscfg command to parse Boot Loader Specification snippets
The BootLoaderSpec (BLS) defines a scheme where different bootloaders can share a format for boot items and a configuration directory that accepts these common configurations as drop-in files. Signed-off-by: Peter Jones Signed-off-by: Javier Martinez Canillas Signed-off-by: Will Thompson Signed-off-by: Alec Brown --- Makefile.util.def | 16 + docs/grub.texi | 27 + grub-core/Makefile.core.def| 10 + grub-core/commands/blsuki.c| 1028 grub-core/commands/legacycfg.c |4 +- grub-core/commands/menuentry.c |8 +- grub-core/lib/vercmp.c | 317 ++ grub-core/normal/main.c|6 + include/grub/lib/vercmp.h | 35 ++ include/grub/menu.h| 15 + include/grub/normal.h |2 +- tests/vercmp_unit_test.c | 65 ++ 12 files changed, 1527 insertions(+), 6 deletions(-) create mode 100644 grub-core/commands/blsuki.c create mode 100644 grub-core/lib/vercmp.c create mode 100644 include/grub/lib/vercmp.h create mode 100644 tests/vercmp_unit_test.c diff --git a/Makefile.util.def b/Makefile.util.def index 038253b37..a911f2e0a 100644 --- a/Makefile.util.def +++ b/Makefile.util.def @@ -1373,6 +1373,22 @@ program = { ldadd = '$(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; }; +program = { + testcase = native; + name = vercmp_unit_test; + common = tests/vercmp_unit_test.c; + common = tests/lib/unit_test.c; + common = grub-core/kern/list.c; + common = grub-core/kern/misc.c; + common = grub-core/tests/lib/test.c; + common = grub-core/lib/vercmp.c; + ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; + ldadd = libgrubkern.a; + ldadd = grub-core/lib/gnulib/libgnu.a; + ldadd = '$(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; +}; + program = { name = grub-menulst2cfg; mansection = 1; diff --git a/docs/grub.texi b/docs/grub.texi index d9b26fa36..19b0cc024 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -6417,6 +6417,7 @@ you forget a command, you can run the command @command{help} * background_image::Load background image for active terminal * badram:: Filter out bad regions of RAM * blocklist:: Print a block list +* blscfg:: Load Boot Loader Specification menu entries * boot::Start up your operating system * cat:: Show the contents of a file * clear:: Clear the screen @@ -6603,6 +6604,32 @@ Print a block list (@pxref{Block list syntax}) for @var{file}. @end deffn +@node blscfg +@subsection blscfg + +@deffn Command blscfg [@option{--path} dir] [@option{--show-default}] [@option{--show-non-default}] [@option{--entry} file] +Load Boot Loader Specification entries into the GRUB menu. + +The @option{--path} option overrides the default path to the directory containing +the BLS entries. If this option isn't used, the default location is +/loader/entries in @code{$BOOT}. + +The @option{--show-default} option allows the default boot entry to be added to the +GRUB menu from the BLS entries. + +The @option{--show-non-default} option allows non-default boot entries to be added to +the GRUB menu from the BLS entries. + +The @option{--entry} option allows specific boot entries to be added to the GRUB menu +from the BLS entries. + +The @option{--entry}, @option{--show-default}, and @option{--show-non-default} options +are used to filter which BLS entries are added to the GRUB menu. If none are +used, all entries in the default location or the location specified by @option{--path} +will be added to the GRUB menu. +@end deffn + + @node boot @subsection boot diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index f70e02e69..f3b776c0a 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -845,6 +845,16 @@ module = { common = commands/blocklist.c; }; +module = { + name = blsuki; + common = commands/blsuki.c; + common = lib/vercmp.c; + enable = powerpc_ieee1275; + enable = efi; + enable = i386_pc; + enable = emu; +}; + module = { name = boot; common = commands/boot.c; diff --git a/grub-core/commands/blsuki.c b/grub-core/commands/blsuki.c new file mode 100644 index 0..0f77fb568 --- /dev/null +++ b/grub-core/commands/blsuki.c @@ -0,0 +1,1028 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2025 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 Genera
[PATCH v2 2/3] blsuki: Check for mounted /boot in emu
Irritatingly, BLS defines paths relatives to the mountpoint of the filesystem which contains its snippets, not / or any other fixed location. So grub2-emu needs to know whether /boot is a separate filesystem from / and conditionally prepend a path. Signed-off-by: Robbie Harwood Signed-off-by: Alec Brown --- grub-core/Makefile.core.def | 4 +++ grub-core/commands/blsuki.c | 54 - grub-core/osdep/linux/getroot.c | 8 + grub-core/osdep/unix/getroot.c | 10 ++ include/grub/emu/misc.h | 2 +- 5 files changed, 70 insertions(+), 8 deletions(-) diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index f3b776c0a..9a0e7bc55 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -367,6 +367,10 @@ kernel = { emu = kern/emu/cache_s.S; emu = kern/emu/hostdisk.c; emu = osdep/unix/hostdisk.c; + emu = osdep/relpath.c; + emu = osdep/getroot.c; + emu = osdep/unix/getroot.c; + emu = osdep/devmapper/getroot.c; emu = osdep/exec.c; extra_dist = osdep/unix/exec.c; emu = osdep/devmapper/hostdisk.c; diff --git a/grub-core/commands/blsuki.c b/grub-core/commands/blsuki.c index 0f77fb568..12a9a1ed1 100644 --- a/grub-core/commands/blsuki.c +++ b/grub-core/commands/blsuki.c @@ -32,6 +32,13 @@ #include #include +#ifdef GRUB_MACHINE_EMU +#include +#define GRUB_BOOT_DEVICE "/boot" +#else +#define GRUB_BOOT_DEVICE "" +#endif + GRUB_MOD_LICENSE ("GPLv3+"); #define GRUB_BLS_CONFIG_PATH "/loader/entries/" @@ -53,8 +60,40 @@ struct keyval static grub_blsuki_entry_t *entries = NULL; +/* + * Cache probing in blsuki_update_boot_device(). Used for linux entry also. + */ +static int separate_boot = -1; + #define FOR_BLSUKI_ENTRIES(var) FOR_LIST_ELEMENTS (var, entries) +/* + * BLS appears to make paths relative to the filesystem that snippets are + * on, not /. Attempt to cope. + */ +static char *blsuki_update_boot_device (char *tmp) +{ +#ifdef GRUB_MACHINE_EMU + char *ret; + + if (separate_boot != -1) +goto probed; + + separate_boot = 0; + + ret = grub_make_system_path_relative_to_its_root (GRUB_BOOT_DEVICE); + + if (ret != NULL) +separate_boot = 1; + + probed: + if (!separate_boot) +return grub_stpcpy (tmp, " "); +#endif + + return grub_stpcpy (tmp, " " GRUB_BOOT_DEVICE); +} + static grub_err_t blsuki_add_keyval (grub_blsuki_entry_t *entry, char *key, char *val) { @@ -645,7 +684,7 @@ bls_create_entry (grub_blsuki_entry_t *entry) for (i = 0; early_initrds != NULL && early_initrds[i] != NULL; i++) { - if (grub_add (initrd_size, sizeof (" "), &initrd_size) || + if (grub_add (initrd_size, sizeof (" " GRUB_BOOT_DEVICE), &initrd_size) || grub_add (initrd_size, grub_strlen (initrd_prefix), &initrd_size) || grub_add (initrd_size, grub_strlen (early_initrds[i]), &initrd_size) || grub_add (initrd_size, 1, &initrd_size)) @@ -657,7 +696,7 @@ bls_create_entry (grub_blsuki_entry_t *entry) for (i = 0; initrds != NULL && initrds[i] != NULL; i++) { - if (grub_add (initrd_size, sizeof (" "), &initrd_size) || + if (grub_add (initrd_size, sizeof (" " GRUB_BOOT_DEVICE), &initrd_size) || grub_add (initrd_size, grub_strlen (initrds[i]), &initrd_size) || grub_add (initrd_size, 1, &initrd_size)) { @@ -683,7 +722,7 @@ bls_create_entry (grub_blsuki_entry_t *entry) for (i = 0; early_initrds != NULL && early_initrds[i] != NULL; i++) { grub_dprintf ("blsuki", "adding early initrd %s\n", early_initrds[i]); - tmp = grub_stpcpy (tmp, " "); + tmp = blsuki_update_boot_device (tmp); tmp = grub_stpcpy (tmp, initrd_prefix); tmp = grub_stpcpy (tmp, early_initrds[i]); grub_free (early_initrds[i]); @@ -692,7 +731,7 @@ bls_create_entry (grub_blsuki_entry_t *entry) for (i = 0; initrds != NULL && initrds[i] != NULL; i++) { grub_dprintf ("blsuki", "adding initrd %s\n", initrds[i]); - tmp = grub_stpcpy (tmp, " "); + tmp = blsuki_update_boot_device (tmp); tmp = grub_stpcpy (tmp, initrds[i]); } tmp = grub_stpcpy (tmp, "\n"); @@ -711,7 +750,7 @@ bls_create_entry (grub_blsuki_entry_t *entry) } } - if (grub_add (sizeof ("devicetree "), grub_strlen (devicetree), &dt_size) || + if (grub_add (sizeof ("devicetree " GRUB_BOOT_DEVICE), grub_strlen (devicetree), &dt_size) || grub_add (dt_size, 1, &dt_size)) { grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected calculating device tree buffer size"); @@ -735,7 +77
[PATCH v2 0/3] Add commands to load BLS and UKI files
v2: - Improved function prefixes to indicate internal blsuki functions. - Added enums to indicate output from vercmp functions. - Separated bls and uki create_entry functions to improve readability. - Updated uki code to only store keyvals of necessary PE sections. - Fixed a bug where an extra '/' was added to the start of kernel and initrd paths. - Removed extra commands added to grub menu output for bls and uki. This patch set is introducing BootLoaderSpec support to upstream GRUB from Fedora GRUB. I've also added a uki command to load Unified Kernel Images since it shares similar code to loading BLS config files. Alec Brown Alec Brown (1): blsuki: Add uki command to load Unified Kernel Image entries Peter Jones (1): blsuki: Add blscfg command to parse Boot Loader Specification snippets Robbie Harwood (1): blsuki: Check for mounted /boot in emu Makefile.util.def | 16 +++ docs/grub.texi | 53 grub-core/Makefile.core.def | 14 ++ grub-core/commands/blsuki.c | 1453 + grub-core/commands/legacycfg.c |4 +- grub-core/commands/menuentry.c |8 +- grub-core/lib/vercmp.c | 317 +++ grub-core/normal/main.c |6 + grub-core/osdep/linux/getroot.c |8 ++ grub-core/osdep/unix/getroot.c | 10 ++ include/grub/emu/misc.h |2 +- include/grub/lib/vercmp.h | 35 + include/grub/menu.h | 17 +++ include/grub/normal.h |2 +- tests/vercmp_unit_test.c| 65 + 15 files changed, 2003 insertions(+), 7 deletions(-) ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v4 1/4] kern/vercmp: Add functionality to compare kernel versions
Add functionality to compare alpha and numeric version segments for kernels. This can be useful in sorting newer from older kernels. Signed-off-by: Alec Brown --- Makefile.util.def| 16 ++ grub-core/kern/vercmp.c | 316 +++ include/grub/vercmp.h| 35 + tests/vercmp_unit_test.c | 65 4 files changed, 432 insertions(+) create mode 100644 grub-core/kern/vercmp.c create mode 100644 include/grub/vercmp.h create mode 100644 tests/vercmp_unit_test.c diff --git a/Makefile.util.def b/Makefile.util.def index 038253b37..15be983f8 100644 --- a/Makefile.util.def +++ b/Makefile.util.def @@ -1373,6 +1373,22 @@ program = { ldadd = '$(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; }; +program = { + testcase = native; + name = vercmp_unit_test; + common = tests/vercmp_unit_test.c; + common = tests/lib/unit_test.c; + common = grub-core/kern/list.c; + common = grub-core/kern/misc.c; + common = grub-core/tests/lib/test.c; + common = grub-core/kern/vercmp.c; + ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; + ldadd = libgrubkern.a; + ldadd = grub-core/lib/gnulib/libgnu.a; + ldadd = '$(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; +}; + program = { name = grub-menulst2cfg; mansection = 1; diff --git a/grub-core/kern/vercmp.c b/grub-core/kern/vercmp.c new file mode 100644 index 0..c2d69d7fd --- /dev/null +++ b/grub-core/kern/vercmp.c @@ -0,0 +1,316 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2025 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 +#include +#include +#include + +#define GOTO_RETURN(x) ({ *ret = (x); goto finish; }) + +/* + * compare alpha and numeric segments of two versions + * return 1: a is newer than b + *0: a and b are the same version + * -1: a is older than b + */ +grub_err_t +grub_vercmp (const char *a, const char *b, int *ret) +{ + char oldch1, oldch2; + char *abuf, *bbuf; + char *str1, *str2; + char *one, *two; + int rc; + bool isnum; + + if (ret == NULL) +return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("return parameter is not set")); + *ret = 0; + + if (grub_strcmp (a, b) == 0) +return GRUB_ERR_NONE; + + abuf = grub_strdup (a); + if (abuf == NULL) +return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't duplicate string to compare versions"); + + bbuf = grub_strdup (b); + if (bbuf == NULL) +{ + grub_free (abuf); + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't duplicate string to compare versions"); +} + + str1 = abuf; + str2 = bbuf; + + one = str1; + two = str2; + + /* Loop through each version segment of str1 and str2 and compare them. */ + while (*one != '\0' || *two != '\0') +{ + while (*one != '\0' && grub_isalnum (*one) == 0 && *one != '~' && *one != '+') +one++; + while (*two != '\0' && grub_isalnum (*two) == 0 && *two != '~' && *two != '+') +two++; + + /* Handle the tilde separator, it sorts before everything else. */ + if (*one == '~' || *two == '~') +{ + if (*one != '~') +GOTO_RETURN (GRUB_VERCMP_NEWER); + if (*two != '~') +GOTO_RETURN (GRUB_VERCMP_OLDER); + one++; + two++; + continue; +} + + /* + * Handle the plus separator. Concept is the same as tilde, except that if + * one of the strings ends (base version), the other is considered as the + * higher version. + */ + if (*one == '+' || *two == '+') +{ + if (*one == '\0') +GOTO_RETURN (GRUB_VERCMP_OLDER); + if (*two == '\0') +GOTO_RETURN (GRUB_VERCMP_NEWER); + if (*one != '+') +GOTO_RETURN (GRUB_VERCMP_NEWER); + if (*two != '+') +GOTO_RETURN (GRUB_VERCMP_OLDER); + one++; + two++; + continue; +} + + /* If we ran to the end of either, we are finished with the loop. */ + if (*one == '\0' || *two == '\0') +
[PATCH v4 2/4] blsuki: Add blscfg command to parse Boot Loader Specification snippets
From: Peter Jones The BootLoaderSpec (BLS) defines a scheme where different bootloaders can share a format for boot items and a configuration directory that accepts these common configurations as drop-in files. The BLS Specification: https://uapi-group.org/specifications/specs/boot_loader_specification/ Signed-off-by: Peter Jones Signed-off-by: Javier Martinez Canillas Signed-off-by: Will Thompson Signed-off-by: Alec Brown --- docs/grub.texi | 47 ++ grub-core/Makefile.core.def| 10 + grub-core/commands/blsuki.c| 1198 grub-core/commands/legacycfg.c |4 +- grub-core/commands/menuentry.c |8 +- grub-core/normal/main.c|6 + include/grub/menu.h| 15 + include/grub/normal.h |2 +- 8 files changed, 1284 insertions(+), 6 deletions(-) create mode 100644 grub-core/commands/blsuki.c diff --git a/docs/grub.texi b/docs/grub.texi index d9b26fa36..adab93668 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -6417,6 +6417,7 @@ you forget a command, you can run the command @command{help} * background_image::Load background image for active terminal * badram:: Filter out bad regions of RAM * blocklist:: Print a block list +* blscfg:: Load Boot Loader Specification menu entries * boot::Start up your operating system * cat:: Show the contents of a file * clear:: Clear the screen @@ -6603,6 +6604,52 @@ Print a block list (@pxref{Block list syntax}) for @var{file}. @end deffn +@node blscfg +@subsection blscfg + +@deffn Command blscfg [@option{-p|--path} dir] [@option{-f|--enable-fallback}] [@option{-d|--show-default}] [@option{-n|--show-non-default}] [@option{-e|--entry} file] +Load Boot Loader Specification (BLS) entries into the GRUB menu. Boot entries +generated from @command{blscfg} won't interfere with entries from @file{grub.cfg} appearing in +the GRUB menu. Also, entries generated from @command{blscfg} only generate in memory and +don't update @file{grub.cfg}. + +The @option{--path} option overrides the default path to the directory containing +the BLS entries. If this option isn't used, the default location is +/loader/entries in @code{$BOOT}. If no BLS entries are found, the +@option{--enable-fallback} option can be used to check for entries in the default +directory. + +The @option{--show-default} option allows the default boot entry to be added to the +GRUB menu from the BLS entries. + +The @option{--show-non-default} option allows non-default boot entries to be added to +the GRUB menu from the BLS entries. + +The @option{--entry} option allows specific boot entries to be added to the GRUB menu +from the BLS entries. + +The @option{--entry}, @option{--show-default}, and @option{--show-non-default} options +are used to filter which BLS entries are added to the GRUB menu. If none are +used, all entries in the default location or the location specified by @option{--path} +will be added to the GRUB menu. + +A BLS config file example: +@example +# /boot/loader/entries/6a9857a393724b7a981ebb5b8495b9ea-3.8.0-2.fc19.x86_64.conf +titleFedora 19 (Rawhide) +sort-key fedora +machine-id 6a9857a393724b7a981ebb5b8495b9ea +version 3.8.0-2.fc19.x86_64 +options root=UUID=6d3376e4-fc93-4509-95ec-a21d68011da2 quiet +architecture x64 +linux/6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.x86_64/linux +initrd /6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.x86_64/initrd +@end example + +References: @uref{https://uapi-group.org/specifications/specs/boot_loader_specification/, The Boot Loader Specification} +@end deffn + + @node boot @subsection boot diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index f70e02e69..67628f65f 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -845,6 +845,16 @@ module = { common = commands/blocklist.c; }; +module = { + name = blsuki; + common = commands/blsuki.c; + common = kern/vercmp.c; + enable = powerpc_ieee1275; + enable = efi; + enable = i386_pc; + enable = emu; +}; + module = { name = boot; common = commands/boot.c; diff --git a/grub-core/commands/blsuki.c b/grub-core/commands/blsuki.c new file mode 100644 index 0..2ad960ae3 --- /dev/null +++ b/grub-core/commands/blsuki.c @@ -0,0 +1,1198 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2025 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 + * MERCHANTABI
[PATCH v4 0/4] Add commands to load BLS and UKI files
v4: - Added comments to describe what most functions are trying to achieve in grub-core/commands/blsuki.c. - Moved vercmp.c code to it's own patch. - Moved all EMU support to the patch 3 (blsuki: Check for mounted /boot in emu) - Split up code in bls_create_entry() into multiple helper functions. - Swapped fallback goto's with for/while loops. - Fixed various nits. This patch set is introducing BootLoaderSpec support to upstream GRUB from Fedora GRUB. I've also added a uki command to load Unified Kernel Images since it shares similar code to loading BLS config files. Alec Brown Alec Brown (1): blsuki: Add uki command to load Unified Kernel Image entries Peter Jones (1): blsuki: Add blscfg command to parse Boot Loader Specification snippets Robbie Harwood (1): blsuki: Check for mounted /boot in emu Makefile.util.def | 16 ++ docs/grub.texi | 80 ++ grub-core/Makefile.core.def | 14 ++ grub-core/commands/blsuki.c | 1667 +++ grub-core/commands/legacycfg.c |4 +- grub-core/commands/menuentry.c |8 +- grub-core/kern/vercmp.c | 316 + grub-core/normal/main.c |6 + grub-core/osdep/linux/getroot.c |8 + grub-core/osdep/unix/getroot.c | 10 ++ include/grub/emu/misc.h |2 +- include/grub/menu.h | 17 ++ include/grub/normal.h |2 +- include/grub/vercmp.h | 35 + tests/vercmp_unit_test.c| 65 15 files changed, 2243 insertions(+), 7 deletions(-) ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v4 4/4] blsuki: Add uki command to load Unified Kernel Image entries
A Unified Kernel Image is a single UEFI PE file that combines a UEFI boot stub, a Linux kernel image, an initrd, and further resources. The uki command will locate where the UKI file is and create a GRUB menu entry to load it. The Unified Kernel Image Specification: https://uapi-group.org/specifications/specs/unified_kernel_image/ Signed-off-by: Alec Brown --- docs/grub.texi | 33 +++ grub-core/commands/blsuki.c | 463 +--- include/grub/menu.h | 2 + 3 files changed, 463 insertions(+), 35 deletions(-) diff --git a/docs/grub.texi b/docs/grub.texi index adab93668..9a63129c7 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -6491,6 +6491,7 @@ you forget a command, you can run the command @command{help} * tpm2_key_protector_clear::Clear the TPM2 key protector * true::Do nothing, successfully * trust:: Add public key to list of trusted keys +* uki:: Load Unified Kernel Image menu entries * unset:: Unset an environment variable @comment * vbeinfo:: List available video modes * verify_detached:: Verify detached digital signature @@ -8184,6 +8185,38 @@ Unset the environment variable @var{envvar}. @end deffn +@node uki +@subsection uki + +@deffn Command uki [@option{-p|--path} dir] [@option{-f|--enable-fallback}] [@option{-d|--show-default}] [@option{-n|--show-non-default}] [@option{-e|--entry} file] +Load Unified Kernel Image (UKI) entries into the GRUB menu. Boot entries +generated from @command{uki} won't interfere with entries from @file{grub.cfg} appearing in the +GRUB menu. Also, entries generated from @command{uki} only generate in memory and don't +update @file{grub.cfg}. + +The @option{--path} option overrides the default path to the directory containing +the UKI entries. If this option isn't used, the default location is +/EFI/Linux in the EFI system partition. If no UKI entries are found, the +@option{--enable-fallback} option can be used to check for entries in the default +directory. + +The @option{--show-default} option allows the default boot entry to be added to the +GRUB menu from the UKI entries. + +The @option{--show-non-default} option allows non-default boot entries to be added to +the GRUB menu from the UKI entries. + +The @option{--entry} option allows specific boot entries to be added to the GRUB menu +from the UKI entries. + +The @option{--entry}, @option{--show-default}, and @option{--show-non-default} options +are used to filter which UKI entries are added to the GRUB menu. If none are +used, all entries in the default location or the location specified by @option{--path} +will be added to the GRUB menu. + +References: @uref{https://uapi-group.org/specifications/specs/unified_kernel_image/, The Unified Kernel Image Specification} +@end deffn + @ignore @node vbeinfo @subsection vbeinfo diff --git a/grub-core/commands/blsuki.c b/grub-core/commands/blsuki.c index bf2edc5ac..3f067281d 100644 --- a/grub-core/commands/blsuki.c +++ b/grub-core/commands/blsuki.c @@ -32,6 +32,12 @@ #include #include +#ifdef GRUB_MACHINE_EFI +#include +#include +#include +#endif + #ifdef GRUB_MACHINE_EMU #include #define GRUB_BOOT_DEVICE "/boot" @@ -42,6 +48,13 @@ GRUB_MOD_LICENSE ("GPLv3+"); #define GRUB_BLS_CONFIG_PATH "/loader/entries/" +#define GRUB_UKI_CONFIG_PATH "/EFI/Linux" + +enum + { +BLSUKI_BLS_CMD, +BLSUKI_UKI_CMD, + }; static const struct grub_arg_option bls_opt[] = { @@ -53,6 +66,18 @@ static const struct grub_arg_option bls_opt[] = {0, 0, 0, 0, 0, 0} }; +#ifdef GRUB_MACHINE_EFI +static const struct grub_arg_option uki_opt[] = + { +{"path", 'p', 0, N_("Specify path to find UKI entries."), N_("DIR"), ARG_TYPE_PATHNAME}, +{"enable-fallback", 'f', 0, "Fallback to the default BLS path if --path fails to find UKI entries.", 0, ARG_TYPE_NONE}, +{"show-default", 'd', 0, N_("Allow the default UKI entry to be added to the GRUB menu."), 0, ARG_TYPE_NONE}, +{"show-non-default", 'n', 0, N_("Allow the non-default UKI entries to be added to the GRUB menu."), 0, ARG_TYPE_NONE}, +{"entry", 'e', 0, N_("Allow specificUKII entries to be added to the GRUB menu."), N_("FILE"), ARG_TYPE_FILE}, +{0, 0, 0, 0, 0, 0} + }; +#endif + struct keyval { const char *key; @@ -162,7 +187,7 @@ blsuki_add_keyval (grub_blsuki_entry_t *entry, char *key, char *val) * Find the value of the key named by keyname. If there are allowed to be * more than one, pass a pointer to an int set to -1 the first time, and pass * the same pointer through each time after, and it'll return them in sorted - * order as defined in
[PATCH v4 3/4] blsuki: Check for mounted /boot in emu
From: Robbie Harwood Irritatingly, BLS defines paths relative to the mountpoint of the filesystem which contains its snippets, not / or any other fixed location. So grub2-emu needs to know whether /boot is a separate filesystem from / and conditionally prepend a path. Signed-off-by: Robbie Harwood Signed-off-by: Alec Brown --- grub-core/Makefile.core.def | 4 ++ grub-core/commands/blsuki.c | 92 ++--- grub-core/osdep/linux/getroot.c | 8 +++ grub-core/osdep/unix/getroot.c | 10 include/grub/emu/misc.h | 2 +- 5 files changed, 107 insertions(+), 9 deletions(-) diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 67628f65f..93b88795e 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -367,6 +367,10 @@ kernel = { emu = kern/emu/cache_s.S; emu = kern/emu/hostdisk.c; emu = osdep/unix/hostdisk.c; + emu = osdep/relpath.c; + emu = osdep/getroot.c; + emu = osdep/unix/getroot.c; + emu = osdep/devmapper/getroot.c; emu = osdep/exec.c; extra_dist = osdep/unix/exec.c; emu = osdep/devmapper/hostdisk.c; diff --git a/grub-core/commands/blsuki.c b/grub-core/commands/blsuki.c index 2ad960ae3..bf2edc5ac 100644 --- a/grub-core/commands/blsuki.c +++ b/grub-core/commands/blsuki.c @@ -32,6 +32,13 @@ #include #include +#ifdef GRUB_MACHINE_EMU +#include +#define GRUB_BOOT_DEVICE "/boot" +#else +#define GRUB_BOOT_DEVICE "" +#endif + GRUB_MOD_LICENSE ("GPLv3+"); #define GRUB_BLS_CONFIG_PATH "/loader/entries/" @@ -56,6 +63,40 @@ static grub_blsuki_entry_t *entries = NULL; #define FOR_BLSUKI_ENTRIES(var) FOR_LIST_ELEMENTS (var, entries) +#ifdef GRUB_MACHINE_EMU +/* + * Cache probing in blsuki_update_boot_device(). + */ +static int separate_boot = -1; +#endif + +/* + * BLS appears to make paths relative to the filesystem that snippets are + * on, not /. Attempt to cope. + */ +static char *blsuki_update_boot_device (char *tmp) +{ +#ifdef GRUB_MACHINE_EMU + char *ret; + + if (separate_boot != -1) +goto probed; + + separate_boot = 0; + + ret = grub_make_system_path_relative_to_its_root (GRUB_BOOT_DEVICE); + + if (ret != NULL && ret[0] == '\0') +separate_boot = 1; + + probed: + if (!separate_boot) +return tmp; +#endif + + return grub_stpcpy (tmp, GRUB_BOOT_DEVICE); +} + /* * This function will add a new keyval pair to a list of keyvals stored in the * entry parameter. @@ -582,7 +623,7 @@ bls_get_linux (grub_blsuki_entry_t *entry) if (options == NULL) options = blsuki_expand_val (grub_env_get ("default_kernelopts")); - if (grub_add (grub_strlen ("linux "), grub_strlen (linux_path), &size)) + if (grub_add (grub_strlen ("linux " GRUB_BOOT_DEVICE), grub_strlen (linux_path), &size)) { grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while calculating linux buffer size"); goto finish; @@ -604,6 +645,7 @@ bls_get_linux (grub_blsuki_entry_t *entry) tmp = linux_cmd; tmp = grub_stpcpy (tmp, "linux "); + tmp = blsuki_update_boot_device (tmp); tmp = grub_stpcpy (tmp, linux_path); if (options != NULL) { @@ -679,7 +721,7 @@ bls_get_initrd (grub_blsuki_entry_t *entry) for (i = 0; early_initrd_list != NULL && early_initrd_list[i] != NULL; i++) { - if (grub_add (size, 1, &size) || + if (grub_add (size, grub_strlen (" " GRUB_BOOT_DEVICE), &size) || grub_add (size, grub_strlen (prefix), &size) || grub_add (size, grub_strlen (early_initrd_list[i]), &size)) { @@ -690,7 +732,7 @@ bls_get_initrd (grub_blsuki_entry_t *entry) for (i = 0; initrd_list != NULL && initrd_list[i] != NULL; i++) { - if (grub_add (size, 1, &size) || + if (grub_add (size, grub_strlen (" " GRUB_BOOT_DEVICE), &size) || grub_add (size, grub_strlen (initrd_list[i]), &size)) { grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected calculating initrd buffer size"); @@ -713,6 +755,7 @@ bls_get_initrd (grub_blsuki_entry_t *entry) { grub_dprintf ("blsuki", "adding early initrd %s\n", early_initrd_list[i]); tmp = grub_stpcpy (tmp, " "); + tmp = blsuki_update_boot_device (tmp); tmp = grub_stpcpy (tmp, prefix); tmp = grub_stpcpy (tmp, early_initrd_list[i]); } @@ -721,6 +764,7 @@ bls_get_initrd (grub_blsuki_entry_t *entry) { grub_dprintf ("blsuki", "adding initrd %s\n", initrd_list[i]); tmp = grub_stpcpy (tmp, " "); + tmp = blsuki_update_boot_device (tmp); tmp = grub_stpcpy (tmp, initrd_list[i]); } tmp = grub_stpcpy (tmp, "\n"); @@ -775,7 +819
RE: [External] : Re: [PATCH v4 2/4] blsuki: Add blscfg command to parse Boot Loader Specification snippets
t; > + > > + initrd_cmd = bls_get_initrd (entry); > > + if (grub_errno != GRUB_ERR_NONE) > > +goto finish; > > + > > + dt_cmd = bls_get_devicetree (entry); > > + if (grub_errno != GRUB_ERR_NONE) > > +goto finish; > > + > > + sdval = grub_env_get ("save_default"); > > + savedefault = ((NULL != sdval) && (grub_strcmp (sdval, "true") == > > 0)); > > + src = grub_xasprintf ("%s%s%s%s", > > + savedefault ? "savedefault\n" : "", > > + linux_cmd, initrd_cmd ? initrd_cmd : "", > > + dt_cmd ? dt_cmd : ""); > > Indentation seems off! > > > + > > + grub_normal_add_menu_entry (argc, argv, classes, id, users, hotkey, > > NULL, src, 0, entry); > > + > > + finish: > > + grub_free (linux_cmd); > > + grub_free (dt_cmd); > > + grub_free (initrd_cmd); > > + grub_free (classes); > > + grub_free (args); > > + grub_free (argv); > > + grub_free (src); > > +} [...] > > +static grub_err_t > > +blsuki_load_entries (char *path, bool enable_fallback) > > +{ > > + grub_size_t len; > > + static grub_err_t r; > > + const char *devid = NULL; > > + char *dir = NULL; > > + struct find_entry_info info = { > > + .dev = NULL, > > + .fs = NULL, > > + .dirname = NULL, > > + }; > > + struct read_entry_info rei = { > > + .devid = NULL, > > + .dirname = NULL, > > + }; > > + > > + if (path != NULL) > > +{ > > + len = grub_strlen (path); > > + if (len >= 5 && grub_strcmp (path + len - 5, ".conf") == 0) > > + { > > + rei.file = grub_file_open (path, GRUB_FILE_TYPE_CONFIG); > > + if (rei.file == NULL) > > + return grub_errno; > > + > > + /* blsuki_read_entry() closes the file. */ > > + return blsuki_read_entry (path, NULL, &rei); > > + } > > + else if (path[0] == '(') > > + { > > + devid = path + 1; > > + > > + dir = grub_strchr (path, ')'); > > + if (dir == NULL) > > + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid file name > > `%s'"), path); > > + > > + *dir = '\0'; > > + > > + /* Check if there is more than the devid in the path. */ > > + if (dir + 1 < path + len) > > + dir = dir + 1; > > + } > > + else if (path[0] == '/') > > + dir = path; > > +} > > Indentation seems off in if else ladder! adding else condition would be > good! Same as before, I don't think there is any code that would require an else condition here. > > > + > > + if (dir == NULL) > > +dir = (char *) GRUB_BLS_CONFIG_PATH; > > + > > + r = blsuki_set_find_entry_info (&info, dir, devid); > > + if (r == GRUB_ERR_NONE) > > +blsuki_find_entry (&info, enable_fallback); > > + > > + if (info.dev != NULL) > > +grub_device_close (info.dev); > > + > > + return r; > > +} [...] > > diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c > > index 04d058f55..2d493f21e 100644 > > --- a/grub-core/normal/main.c > > +++ b/grub-core/normal/main.c > > @@ -21,6 +21,7 @@ > > #include > > #include > > #include > > +#include > > #include > > #include > > #include > > @@ -67,6 +68,11 @@ grub_normal_free_menu (grub_menu_t menu) > > grub_free (entry->args); > > } > > > > + if (entry->blsuki) > > + { > > + entry->blsuki->visible = 0; > > + } > > Brackets not required! Sure thing! I'll fix this! > > Alec , I see many Indentation issues. I have tried pointing out as much > as I can. Please fix! > Thank you! > > Regards, > Avnish Chouhan > Thanks for taking a look at these patches! Alec Brown ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[External] : Re: [PATCH v4 4/4] blsuki: Add uki command to load Unified Kernel Image entries
On Fri, May 30, 2025 at 2:47 AM, Avnish Chouhan wrote: > > Message: 1 > > Date: Wed, 21 May 2025 12:51:26 +0000 > > From: Alec Brown > > To: grub-devel@gnu.org > > Cc: christopher.obb...@linaro.org, daniel.ki...@oracle.com, > > jan.setjeeil...@oracle.com, alec.r.br...@oracle.com, > > mate.ku...@canonical.com, pjo...@redhat.com, > > ross.philip...@oracle.com, 93...@debian.org, phco...@gmail.com > > Subject: [PATCH v4 4/4] blsuki: Add uki command to load Unified Kernel > > Image entries > > Message-ID: <20250521125126.3928350-5-alec.r.br...@oracle.com> > > > > A Unified Kernel Image is a single UEFI PE file that combines a UEFI > > boot stub, a Linux kernel image, an initrd, and further resources. The > > uki command will locate where the UKI file is and create a GRUB menu > > entry to load it. > > > > The Unified Kernel Image Specification: > > https://urldefense.com/v3/__https://uapi-group.org/specifications/spec > > s/unified_kernel_image/__;!!ACWV5N9M2RV99hQ!MLcCQykiFNenp16SX023gevWvP > > 4pETCVqAOq96F90j7i6HTTXoeUZAVSGOGc2rcLXQWEEwXZmF02M-W1xmoX$ > > > > Signed-off-by: Alec Brown > > --- > > docs/grub.texi | 33 +++ > > grub-core/commands/blsuki.c | 463 +--- > > include/grub/menu.h | 2 + > > 3 files changed, 463 insertions(+), 35 deletions(-) > > > . > . > . > > > > +/* > > + * This function searches for the .cmdline, .osrel, and .linux > > sections of a > > + * UKI. We only need to store the data for the .cmdline and .osrel > > sections, > > + * but we also need to verify that the .linux section exists. > > + */ > > +#ifdef GRUB_MACHINE_EFI > > +static grub_err_t > > +uki_parse_keyvals (grub_file_t f, grub_blsuki_entry_t *entry) { > . > . > . > > + > > + for (int i = 0; i < coff_header->num_sections; i++) > > +{ > > + key = NULL; > > + val = NULL; > > + section = grub_zalloc (sizeof (*section)); > > + if (section == NULL) > > + { > > + err = grub_errno; > > + goto finish; > > + } > > + > > + if (grub_file_seek (f, section_offset) == (grub_off_t) -1 || > > + grub_file_read (f, section, sizeof (*section)) != sizeof > > (*section)) > > + { > > + err = grub_error (GRUB_ERR_FILE_READ_ERROR, "failed to read > > section header"); > > + goto finish; > > + } > > + > > + key = grub_strndup (section->name, 8); > > + if (key == NULL) > > + { > > + err = grub_errno; > > + goto finish; > > + } > > + > > + for (int j = 0; target[j] != NULL; j++) > > + { > > + if (grub_strcmp (key, target[j]) == 0) > > + { > > + /* > > + * We don't need to read the contents of the .linux PE > > +section, > > but we > > + * should verify that the section exists. > > + */ > > + if (grub_strcmp (key, ".linux") == 0) > > + { > > + has_linux = true; > > + break; > > + } > > + > > + val = grub_zalloc (section->raw_data_size); > > + if (val == NULL) > > + { > > + err = grub_errno; > > + goto finish; > > + } > > + > > + if (grub_file_seek (f, section->raw_data_offset) == > > (grub_off_t) -1 || > > + grub_file_read (f, val, section->raw_data_size) != > > (grub_ssize_t) > > section->raw_data_size) > > + { > > + err = grub_error (GRUB_ERR_FILE_READ_ERROR, "failed to read > > section"); > > + goto finish; > > + } > > + > > + err = blsuki_add_keyval (entry, key, val); > > + if (err != GRUB_ERR_NONE) > > + goto finish; > > + > > + break; > > + } > > + } > > + > > + section_offset += sizeof (*section); > > + grub_free (section); > > + grub_free (val); > > + grub_free (key); > > + section = NULL; > > + val = NULL; > > + key = NULL; > > Hi Alec, > > These couple of NULL statements above seems redundant as you are doing the > same in the starting of > the loop! > Hi Avnish, I moved them to the end of the loop so that we won't have to worry about a double free once the loop finishes but it looks like I forgot to remove the NULL statements at the start. I'll fix that. > And it seems there are some indentation issues in "if" conditions and "loops" > in multiple places > which probably needs to be checked/fixed. Same thing with the other patches, the indentation looks strange because tabs are being used in place of 8 spaces and the formatting of the patch looks strange because of it. > > Suggestion : Adding a new line after the loop or a condition would be good! I > see some statements > has, some doesn't. Sure thing! > > Thank you, > > Regards, > Avnish Chouhan > Thanks for looking over these patches! Alec Brown ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[External] : Re: [PATCH v4 3/4] blsuki: Check for mounted /boot in emu
On Tue, June 3, 2025 at 5:04 AM, Avnish Chouhan wrote: > > Message: 1 > > Date: Wed, 21 May 2025 12:51:25 +0000 > > From: Alec Brown > > To: grub-devel@gnu.org > > Cc: christopher.obb...@linaro.org, daniel.ki...@oracle.com, > > jan.setjeeil...@oracle.com, alec.r.br...@oracle.com, > > mate.ku...@canonical.com, pjo...@redhat.com, > > ross.philip...@oracle.com, 93...@debian.org, phco...@gmail.com > > Subject: [PATCH v4 3/4] blsuki: Check for mounted /boot in emu > > Message-ID: <20250521125126.3928350-4-alec.r.br...@oracle.com> > > > > From: Robbie Harwood > > > > Irritatingly, BLS defines paths relative to the mountpoint of the > > filesystem which contains its snippets, not / or any other fixed > > location. So grub2-emu needs to know whether /boot is a separate > > filesystem from / and conditionally prepend a path. > > > > Signed-off-by: Robbie Harwood > > Signed-off-by: Alec Brown > > --- > > grub-core/Makefile.core.def | 4 ++ > > grub-core/commands/blsuki.c | 92 ++--- > > grub-core/osdep/linux/getroot.c | 8 +++ > > grub-core/osdep/unix/getroot.c | 10 > > include/grub/emu/misc.h | 2 +- > > 5 files changed, 107 insertions(+), 9 deletions(-) > > > > diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def > > index 67628f65f..93b88795e 100644 > > --- a/grub-core/Makefile.core.def > > +++ b/grub-core/Makefile.core.def > > @@ -367,6 +367,10 @@ kernel = { > >emu = kern/emu/cache_s.S; > >emu = kern/emu/hostdisk.c; > >emu = osdep/unix/hostdisk.c; > > + emu = osdep/relpath.c; > > + emu = osdep/getroot.c; > > + emu = osdep/unix/getroot.c; > > + emu = osdep/devmapper/getroot.c; > >emu = osdep/exec.c; > >extra_dist = osdep/unix/exec.c; > >emu = osdep/devmapper/hostdisk.c; > > diff --git a/grub-core/commands/blsuki.c b/grub-core/commands/blsuki.c > > index 2ad960ae3..bf2edc5ac 100644 > > --- a/grub-core/commands/blsuki.c > > +++ b/grub-core/commands/blsuki.c > > @@ -32,6 +32,13 @@ > > #include > > #include > > > > +#ifdef GRUB_MACHINE_EMU > > +#include > > +#define GRUB_BOOT_DEVICE "/boot" > > +#else > > +#define GRUB_BOOT_DEVICE "" > > +#endif > > + > > GRUB_MOD_LICENSE ("GPLv3+"); > > > > #define GRUB_BLS_CONFIG_PATH "/loader/entries/" > > @@ -56,6 +63,40 @@ static grub_blsuki_entry_t *entries = NULL; > > > > #define FOR_BLSUKI_ENTRIES(var) FOR_LIST_ELEMENTS (var, entries) > > > > +#ifdef GRUB_MACHINE_EMU > > +/* > > + * Cache probing in blsuki_update_boot_device(). > > + */ > > Hi Alec, > > /* Cache probing in blsuki_update_boot_device(). */ > > > +static int separate_boot = -1; > > +#endif > > + > > +/* > > + * BLS appears to make paths relative to the filesystem that snippets > > are > > + * on, not /. Attempt to cope. > > + */ > > +static char *blsuki_update_boot_device (char *tmp) > > +{ > > +#ifdef GRUB_MACHINE_EMU > > + char *ret; > > char *ret = NULL; Hi Avnish, I don't think it is necessary for this variable to be initialized to NULL since it will be overwritten by grub_make_system_path_relative_to_its_root(). > > > + > > + if (separate_boot != -1) > > +goto probed; > > + > > + separate_boot = 0; > > + > > + ret = grub_make_system_path_relative_to_its_root (GRUB_BOOT_DEVICE); > > + > > + if (ret != NULL && ret[0] == '\0') > > +separate_boot = 1; > > + > > + probed: > > + if (!separate_boot) > > +return tmp; > > +#endif > > + > > + return grub_stpcpy (tmp, GRUB_BOOT_DEVICE); > > +} > > + > > /* > > * This function will add a new keyval pair to a list of keyvals > > stored in the > > * entry parameter. > > @@ -582,7 +623,7 @@ bls_get_linux (grub_blsuki_entry_t *entry) > >if (options == NULL) > > options = blsuki_expand_val (grub_env_get ("default_kernelopts")); > > > > - if (grub_add (grub_strlen ("linux "), grub_strlen (linux_path), > > &size)) > > + if (grub_add (grub_strlen ("linux " GRUB_BOOT_DEVICE), grub_strlen > > (linux_path), &size)) > > { > >grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while > > calculating linux buffer size"); > >goto finish; > > @@ -
RE: : Re: [PATCH v4 2/4] blsuki: Add blscfg command to parse Boot Loader Specification snippets
On Thu, June 5, 2025 at 2:02 AM, Avnish Chouhan wrote: > On 2025-06-04 01:17, Alec Brown wrote: > > On Thu, May 29, 2025 at 6:59 AM, Avnish Chouhan > > wrote: > >> On 2025-05-21 18:21, grub-devel-requ...@gnu.org wrote: > [...] > >> > + while (*separator == ' ' || *separator == '\t'); > >> > >> What's the use of this while condition? It may result in an infinite > >> loop... > >> > > > > The purpose of this while loop is to remove any additional spaces or > > tabs > > separating the key from the value. I don't believe this would result in > > an > > infinite loop unless the rest of memory was a space or tab. However, an > > issue > > I do see is we aren't checking if there is a value after removing the > > excess > > spaces and tabs in the loop. I'll fix this. > > Hi Alec, > > In my opinion, if we have any of the given condition evaluates as > 'True', it will be an infinite loop. We are't incriminating the pointer > and we will be in a loop forever if "*separator == ' ' or *separator == > '\t'" evaluates 'True'. > Hi Avnish, For the loop, we are incrementing the 'separator' pointer but since we are using a do-while loop, it's happening before we check the escape condition of the loop. > If I understood the purpose of this loop correctly, I would do something > like this below: > > while (*separator == ' ' || *separator == '\t') >{ > ... > separator++; >} > We could write it this way but we would still need to increment the 'separator' pointer before entering the loop since we just wrote an end of string character where the previous space or tab was. Alec Brown > > Thank you! > > Regards, > Avnish Chouhan ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 1/2] gnulib/regcomp: Fix resource leak
In the functions create_initial_state() and calc_eclosure_iter(), memory is allocated for the elems member of a re_node_set structure but that memory isn't freed on error. Before returning an error, a call to re_node_set_free() should be made to prevent the resource leak. This issue has been fixed in the latest version of gnulib and I've backported this change to maintain consistency. This issue was found by a Coverity Scan of GRUB2 under the following CIDs: CID: 473869 CID: 473888 Signed-off-by: Alec Brown --- bootstrap.conf| 5 +- conf/Makefile.extra-dist | 1 + .../fix-regcomp-resource-leak.patch | 110 ++ 3 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 grub-core/lib/gnulib-patches/fix-regcomp-resource-leak.patch diff --git a/bootstrap.conf b/bootstrap.conf index 7a7813d28..7a464a289 100644 --- a/bootstrap.conf +++ b/bootstrap.conf @@ -84,7 +84,10 @@ bootstrap_post_import_hook () { # Instead of patching our gnulib and therefore maintaining a fork, submit # changes to gnulib and update the hash above when they've merged. Do not # add new patches here. - patch -d grub-core/lib/gnulib -p2 < grub-core/lib/gnulib-patches/fix-width.patch + for patchname in fix-width fix-regcomp-resource-leak; do +patch -d grub-core/lib/gnulib -p2 \ + < "grub-core/lib/gnulib-patches/$patchname.patch" + done for patchname in \ 0001-Support-POTFILES-shell \ diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist index d9e2b8cc7..5bf3da429 100644 --- a/conf/Makefile.extra-dist +++ b/conf/Makefile.extra-dist @@ -30,6 +30,7 @@ EXTRA_DIST += grub-core/genemuinit.sh EXTRA_DIST += grub-core/genemuinitheader.sh EXTRA_DIST += grub-core/lib/gnulib-patches/fix-width.patch +EXTRA_DIST += grub-core/lib/gnulib-patches/fix-regcomp-resource-leak.patch EXTRA_DIST += grub-core/lib/libgcrypt EXTRA_DIST += grub-core/lib/libgcrypt-grub/mpi/generic diff --git a/grub-core/lib/gnulib-patches/fix-regcomp-resource-leak.patch b/grub-core/lib/gnulib-patches/fix-regcomp-resource-leak.patch new file mode 100644 index 0..b2e900023 --- /dev/null +++ b/grub-core/lib/gnulib-patches/fix-regcomp-resource-leak.patch @@ -0,0 +1,110 @@ +--- a/lib/regcomp.c b/lib/regcomp.c +@@ -1001,21 +1001,25 @@ create_initial_state (re_dfa_t *dfa) + Idx dest_idx = dfa->edests[node_idx].elems[0]; + if (!re_node_set_contains (&init_nodes, dest_idx)) + { +- reg_errcode_t merge_err ++ err + = re_node_set_merge (&init_nodes, dfa->eclosures + dest_idx); +- if (merge_err != REG_NOERROR) +-return merge_err; ++ if (err != REG_NOERROR) ++break; + i = 0; + } + } + } + + /* It must be the first time to invoke acquire_state. */ +- dfa->init_state = re_acquire_state_context (&err, dfa, &init_nodes, 0); +- /* We don't check ERR here, since the initial state must not be NULL. */ ++ dfa->init_state ++= (err == REG_NOERROR ++ ? re_acquire_state_context (&err, dfa, &init_nodes, 0) ++ : NULL); + if (__glibc_unlikely (dfa->init_state == NULL)) +-return err; +- if (dfa->init_state->has_constraint) ++{ ++ /* Don't check ERR here, as the initial state must not be null. */ ++} ++ else if (dfa->init_state->has_constraint) + { + dfa->init_state_word = re_acquire_state_context (&err, dfa, &init_nodes, + CONTEXT_WORD); +@@ -1025,17 +1029,13 @@ create_initial_state (re_dfa_t *dfa) +&init_nodes, +CONTEXT_NEWLINE +| CONTEXT_BEGBUF); +- if (__glibc_unlikely (dfa->init_state_word == NULL +- || dfa->init_state_nl == NULL +- || dfa->init_state_begbuf == NULL)) +- return err; + } + else + dfa->init_state_word = dfa->init_state_nl + = dfa->init_state_begbuf = dfa->init_state; + + re_node_set_free (&init_nodes); +- return REG_NOERROR; ++ return err; + } + + /* If it is possible to do searching in single byte encoding instead of UTF-8 +@@ -1677,12 +1677,11 @@ calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, Idx node, bool root) + { + err = duplicate_node_closure (dfa, node, node, node, + dfa->nodes[node].constraint); +- if (__glibc_unlikely (err != REG_NOERROR)) +- return err; + } + + /* Expand each epsilon destination nodes. */ +- if (IS_EPSILON_NODE(dfa->nodes[node].type)) ++ if (__glibc_likely (err == REG_NOER
[PATCH 0/2] Fix resource leaks in gnulib
Coverity found a couple resource leaks in gnulib code that the GRUB is using. These fixes have been made in the latest version of gnulib and I've backported these changes to maintain consistency. This patch set fixes the following CIDs: CID: 473869 CID: 473887 CID: 473888 Alec Brown (2): gnulib/regcomp: Fix resource leak gnulib/regexec: Fix resource leak bootstrap.conf | 7 ++- conf/Makefile.extra-dist | 2 + grub-core/lib/gnulib-patches/fix-regcomp-resource-leak.patch | 110 grub-core/lib/gnulib-patches/fix-regexec-resource-leak.patch | 11 + 4 files changed, 129 insertions(+), 1 deletion(-) ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 2/2] gnulib/regexec: Fix resource leak
In the function merge_state_with_log(), memory is allocated for the variable next_nodes when creating a union of the variables table_nodes and log_nodes. However, if next_state->entrance_nodes is NULL, then table_nodes becomes NULL and we still allocate memory to copy the content of log_nodes. This can cause a resource leak since we only free the memory for next_nodes if table_nodes isn't NULL. To prevent this, we need to check that next_state->entrance_nodes isn't NULL before allocating memory for the union. This issue has been fixed in the latest version of gnulib and I've backported this change to maintain consistency. This issue was found by a Coverity Scan of GRUB2 under the following CID: CID: 473887 Signed-off-by: Alec Brown --- bootstrap.conf| 4 +++- conf/Makefile.extra-dist | 1 + .../gnulib-patches/fix-regexec-resource-leak.patch| 11 +++ 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 grub-core/lib/gnulib-patches/fix-regexec-resource-leak.patch diff --git a/bootstrap.conf b/bootstrap.conf index 7a464a289..7cd375ba9 100644 --- a/bootstrap.conf +++ b/bootstrap.conf @@ -84,7 +84,9 @@ bootstrap_post_import_hook () { # Instead of patching our gnulib and therefore maintaining a fork, submit # changes to gnulib and update the hash above when they've merged. Do not # add new patches here. - for patchname in fix-width fix-regcomp-resource-leak; do + for patchname in fix-width \ + fix-regcomp-resource-leak \ + fix-regexec-resource-leak; do patch -d grub-core/lib/gnulib -p2 \ < "grub-core/lib/gnulib-patches/$patchname.patch" done diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist index 5bf3da429..07eee1956 100644 --- a/conf/Makefile.extra-dist +++ b/conf/Makefile.extra-dist @@ -31,6 +31,7 @@ EXTRA_DIST += grub-core/genemuinitheader.sh EXTRA_DIST += grub-core/lib/gnulib-patches/fix-width.patch EXTRA_DIST += grub-core/lib/gnulib-patches/fix-regcomp-resource-leak.patch +EXTRA_DIST += grub-core/lib/gnulib-patches/fix-regexec-resource-leak.patch EXTRA_DIST += grub-core/lib/libgcrypt EXTRA_DIST += grub-core/lib/libgcrypt-grub/mpi/generic diff --git a/grub-core/lib/gnulib-patches/fix-regexec-resource-leak.patch b/grub-core/lib/gnulib-patches/fix-regexec-resource-leak.patch new file mode 100644 index 0..f490e05fb --- /dev/null +++ b/grub-core/lib/gnulib-patches/fix-regexec-resource-leak.patch @@ -0,0 +1,11 @@ +--- a/lib/regexec.c b/lib/regexec.c +@@ -2270,7 +2270,7 @@ merge_state_with_log (reg_errcode_t *err, re_match_context_t *mctx, +these destinations and the results of the transition table. */ + pstate = mctx->state_log[cur_idx]; + log_nodes = pstate->entrance_nodes; +- if (next_state != NULL) ++ if (next_state != NULL && next_state->entrance_nodes != NULL) + { + table_nodes = next_state->entrance_nodes; + *err = re_node_set_init_union (&next_nodes, table_nodes, -- 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v5 2/5] blsuki: Add blscfg command to parse Boot Loader Specification snippets
From: Peter Jones The BootLoaderSpec (BLS) defines a scheme where different bootloaders can share a format for boot items and a configuration directory that accepts these common configurations as drop-in files. The BLS Specification: https://uapi-group.org/specifications/specs/boot_loader_specification/ Signed-off-by: Peter Jones Signed-off-by: Javier Martinez Canillas Signed-off-by: Will Thompson Signed-off-by: Alec Brown --- bootstrap.conf |1 + docs/grub.texi | 67 +++ grub-core/Makefile.core.def| 12 + grub-core/commands/blsuki.c| 1032 grub-core/commands/legacycfg.c |4 +- grub-core/commands/menuentry.c |8 +- grub-core/normal/main.c|6 + include/grub/menu.h| 15 + include/grub/normal.h |2 +- 9 files changed, 1141 insertions(+), 6 deletions(-) create mode 100644 grub-core/commands/blsuki.c diff --git a/bootstrap.conf b/bootstrap.conf index 3590aba99..8eff35b45 100644 --- a/bootstrap.conf +++ b/bootstrap.conf @@ -24,6 +24,7 @@ gnulib_modules=" argp base64 error + filevercmp fnmatch getdelim getline diff --git a/docs/grub.texi b/docs/grub.texi index 34b3484dc..1186f274f 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -6419,6 +6419,7 @@ you forget a command, you can run the command @command{help} * background_image::Load background image for active terminal * badram:: Filter out bad regions of RAM * blocklist:: Print a block list +* blscfg:: Load Boot Loader Specification menu entries * boot::Start up your operating system * cat:: Show the contents of a file * clear:: Clear the screen @@ -6607,6 +6608,72 @@ Print a block list (@pxref{Block list syntax}) for @var{file}. @end deffn +@node blscfg +@subsection blscfg + +@deffn Command blscfg [@option{-p|--path} dir] [@option{-f|--enable-fallback}] [@option{-d|--show-default}] [@option{-n|--show-non-default}] [@option{-e|--entry} file] +Load Boot Loader Specification (BLS) entries into the GRUB menu. Boot entries +generated from @command{blscfg} won't interfere with entries from @file{grub.cfg} appearing in +the GRUB menu. Also, entries generated from @command{blscfg} exists only in memory and +don't update @file{grub.cfg}. + +By default, the BLS entries are stored in the @file{/loader/entries} directory in the +boot partition. If BLS entries are stored elsewhere, the @option{--path} option can be +used to check a different directory instead of the default location. If no BLS +entries are found while using the @option{--path} option, the @option{--enable-fallback} option +can be used to check for entries in the default location. + +The @option{--show-default} option allows the default boot entry to be added to the +GRUB menu from the BLS entries. + +The @option{--show-non-default} option allows non-default boot entries to be added to +the GRUB menu from the BLS entries. + +The @option{--entry} option allows specific boot entries to be added to the GRUB menu +from the BLS entries. + +The @option{--entry}, @option{--show-default}, and @option{--show-non-default} options +are used to filter which BLS entries are added to the GRUB menu. If none are +used, all entries in the default location or the location specified by @option{--path} +will be added to the GRUB menu. + +A BLS config file example: +@example +# /boot/loader/entries/6a9857a393724b7a981ebb5b8495b9ea-3.8.0-2.fc19.x86_64.conf +titleFedora 19 (Rawhide) +sort-key fedora +machine-id 6a9857a393724b7a981ebb5b8495b9ea +version 3.8.0-2.fc19.x86_64 +options root=UUID=6d3376e4-fc93-4509-95ec-a21d68011da2 quiet +architecture x64 +linux/6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.x86_64/linux +initrd /6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.x86_64/initrd +@end example + +For more information on BLS entry keys as well as other information on BLS, +see: @uref{https://uapi-group.org/specifications/specs/boot_loader_specification/, The Boot Loader Specification}. For the GRUB, there are a few additional +BLS entry keys based on the @command{menuentry} command (@pxref{menuentry}). + +The @code{grub_class} key may be used any number of times to group menu entries into +classes. Menu themes may display different classes using different styles. + +The @code{grub_users} key grants specific users access to specific menu +entries. @xref{Security}. + +The @code{grub_hotkey} key associates a hotkey with a menu entry. +@var{key} may be a single letter, or one of the aliases @samp{backspace}, +@samp{tab}, or @samp{delete}. + +The @code{grub_args} key can be used for any other argument to be passed as positonal +parameters when the list of commands generated from the BLS config file are +executed. + +Variable expansion using the @sa