[SPECIFICATION RFC v3] The firmware and bootloader log specification

2021-09-18 Thread Alec Brown
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

2021-10-19 Thread Alec Brown

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

2021-10-19 Thread Alec Brown

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

2021-10-28 Thread Alec Brown
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

2021-11-10 Thread Alec Brown
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

2021-11-10 Thread Alec Brown
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

2021-11-10 Thread Alec Brown
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

2022-02-02 Thread Alec Brown
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

2022-02-02 Thread Alec Brown
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

2022-02-02 Thread Alec Brown
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

2022-02-02 Thread Alec Brown
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

2022-02-02 Thread Alec Brown
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

2022-02-02 Thread Alec Brown
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

2022-03-15 Thread Alec Brown
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

2022-03-15 Thread Alec Brown
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

2022-03-15 Thread Alec Brown
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

2022-03-15 Thread Alec Brown
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

2022-03-15 Thread Alec Brown
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

2022-03-15 Thread Alec Brown
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

2022-03-15 Thread Alec Brown
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

2022-03-15 Thread Alec Brown
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

2022-03-20 Thread Alec Brown
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

2022-03-20 Thread Alec Brown
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

2022-03-20 Thread Alec Brown
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

2022-03-20 Thread Alec Brown
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

2022-03-20 Thread Alec Brown
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

2022-03-20 Thread Alec Brown
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

2022-03-20 Thread Alec Brown
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

2022-03-20 Thread Alec Brown
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

2022-04-20 Thread Alec Brown
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

2022-04-20 Thread Alec Brown
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

2022-04-20 Thread Alec Brown
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 *)

2022-04-20 Thread Alec Brown
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()

2022-04-20 Thread Alec Brown
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

2022-04-20 Thread Alec Brown
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

2022-05-26 Thread Alec Brown
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()

2022-05-26 Thread Alec Brown
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

2022-05-26 Thread Alec Brown
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

2022-05-26 Thread Alec Brown
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 *)

2022-05-26 Thread Alec Brown
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

2022-05-26 Thread Alec Brown
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

2022-05-26 Thread Alec Brown
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

2022-07-15 Thread Alec Brown
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

2022-08-12 Thread Alec Brown
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

2022-08-12 Thread Alec Brown
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

2022-08-12 Thread Alec Brown
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

2022-08-12 Thread Alec Brown
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

2022-08-12 Thread Alec Brown
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

2022-08-12 Thread Alec Brown
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

2022-10-13 Thread Alec Brown
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

2022-10-14 Thread Alec Brown
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

2022-10-20 Thread Alec Brown
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

2022-10-20 Thread Alec Brown
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

2022-10-20 Thread Alec Brown
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

2022-10-26 Thread Alec Brown
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

2022-10-26 Thread Alec Brown
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

2023-02-03 Thread Alec Brown
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

2023-03-09 Thread Alec Brown
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

2023-05-22 Thread Alec Brown
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

2023-05-22 Thread Alec Brown
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

2023-05-22 Thread Alec Brown
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

2023-05-22 Thread Alec Brown
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

2023-05-22 Thread Alec Brown
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

2023-06-22 Thread Alec Brown
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

2023-12-13 Thread Alec Brown
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

2024-01-19 Thread Alec Brown
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

2024-01-19 Thread Alec Brown
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

2024-01-19 Thread Alec Brown
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

2024-01-19 Thread Alec Brown
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

2024-01-23 Thread Alec Brown
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

2024-11-05 Thread Alec Brown via Grub-devel
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

2024-10-01 Thread Alec Brown via Grub-devel
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

2025-02-14 Thread Alec Brown via Grub-devel
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

2025-03-25 Thread Alec Brown via Grub-devel
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

2025-03-27 Thread Alec Brown via Grub-devel
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

2025-03-27 Thread Alec Brown via Grub-devel
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

2025-04-11 Thread Alec Brown via Grub-devel
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

2025-04-11 Thread Alec Brown via Grub-devel
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

2025-04-11 Thread Alec Brown via Grub-devel
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

2025-04-11 Thread Alec Brown via Grub-devel
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

2025-04-11 Thread Alec Brown via Grub-devel
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

2025-02-14 Thread Alec Brown via Grub-devel
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

2025-02-14 Thread Alec Brown via Grub-devel
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

2025-02-14 Thread Alec Brown via Grub-devel
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

2025-03-25 Thread Alec Brown via Grub-devel
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

2025-03-25 Thread Alec Brown via Grub-devel
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

2025-03-25 Thread Alec Brown via Grub-devel
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

2025-05-21 Thread Alec Brown via Grub-devel
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

2025-05-21 Thread Alec Brown via Grub-devel
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

2025-05-21 Thread Alec Brown via Grub-devel
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

2025-05-21 Thread Alec Brown via Grub-devel
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

2025-05-21 Thread Alec Brown via Grub-devel
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

2025-06-03 Thread Alec Brown via Grub-devel
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

2025-06-03 Thread Alec Brown via Grub-devel
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

2025-06-03 Thread Alec Brown via Grub-devel
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

2025-06-05 Thread Alec Brown via Grub-devel

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

2025-06-10 Thread Alec Brown via Grub-devel
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

2025-06-10 Thread Alec Brown via Grub-devel
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

2025-06-10 Thread Alec Brown via Grub-devel
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

2025-07-26 Thread Alec Brown via Grub-devel
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

  1   2   >