]> git.ipfire.org Git - thirdparty/grub.git/log
thirdparty/grub.git
5 months agoterm/ns8250-spcr: Return if redirection is disabled
Benjamin Herrenschmidt [Tue, 21 Jan 2025 17:01:26 +0000 (11:01 -0600)] 
term/ns8250-spcr: Return if redirection is disabled

The Microsoft spec for SPCR says "The base address of the Serial Port
register set described using the ACPI Generic Address Structure, or
0 if console redirection is disabled". So, return early if redirection
is disabled (base address = 0). If this check is not done we may get
invalid ports on machines with redirection disabled and boot may hang
when reading the grub.cfg file.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Reviewed-by: Leo Sandoval <lsandova@redhat.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agocommands/file: Fix NULL dereference in the knetbsd tests
Lukas Fink [Sun, 5 Jan 2025 08:24:11 +0000 (02:24 -0600)] 
commands/file: Fix NULL dereference in the knetbsd tests

The pointer returned by grub_elf_file() is not checked to verify it is
not NULL before use. A NULL pointer may be returned when the given file
does not have a valid ELF header.

Fixes: https://savannah.gnu.org/bugs/?61960
Signed-off-by: Glenn Washburn <development@efficientek.com>
Signed-off-by: Lukas Fink <lukas.fink1@gmail.com>
Reviewed-by: Ross Philipson <ross.philipson@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agogdb_helper: Typo hueristic
Heinrich Schuchardt [Thu, 16 Jan 2025 12:25:14 +0000 (13:25 +0100)] 
gdb_helper: Typo hueristic

%s/hueristic/heuristic/

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Ross Philipson <ross.philipson@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agokern/efi/mm: Reset grub_mm_add_region_fn after ExitBootServices() call
Ruihan Li [Mon, 16 Dec 2024 04:26:58 +0000 (12:26 +0800)] 
kern/efi/mm: Reset grub_mm_add_region_fn after ExitBootServices() call

The EFI Boot Services can be used after ExitBootServices() call because
the GRUB code still may allocate memory.

An example call stack is:

  grub_multiboot_boot
    grub_multiboot2_make_mbi
      grub_efi_finish_boot_services
        b->exit_boot_services
    normal_boot
      grub_relocator32_boot
        grub_relocator_alloc_chunk_align_safe
          grub_relocator_alloc_chunk_align
            grub_malloc
              grub_memalign
                grub_mm_add_region_fn
                [= grub_efi_mm_add_regions]
                  grub_efi_allocate_any_pages
                    grub_efi_allocate_pages_real
                      b->allocate_pages

This can lead to confusing errors. After ExitBootServices() call
b->allocate_pages may point to the NULL address resulting in something like:

  !!!! X64 Exception Type - 01(#DB - Debug)  CPU Apic ID - 00000000 !!!!
  RIP  - 000000000000201F, CS  - 0000000000000038, RFLAGS - 0000000000200002
  RAX  - 000000007F9EE010, RCX - 0000000000000001, RDX - 0000000000000002
  RBX  - 0000000000000006, RSP - 00000000001CFBEC, RBP - 0000000000000000
  RSI  - 0000000000000000, RDI - 00000000FFFFFFFF
  R8   - 0000000000000006, R9  - 000000007FEDFFB8, R10 - 0000000000000000
  R11  - 0000000000000475, R12 - 0000000000000001, R13 - 0000000000000002
  R14  - 00000000FFFFFFFF, R15 - 000000007E432C08
  DS   - 0000000000000030, ES  - 0000000000000030, FS  - 0000000000000030
  GS   - 0000000000000030, SS  - 0000000000000030
  CR0  - 0000000080010033, CR2 - 0000000000000000, CR3 - 000000007FC01000
  CR4  - 0000000000000668, CR8 - 0000000000000000
  DR0  - 0000000000000000, DR1 - 0000000000000000, DR2 - 0000000000000000
  DR3  - 0000000000000000, DR6 - 00000000FFFF0FF0, DR7 - 0000000000000400
  GDTR - 000000007F9DE000 0000000000000047, LDTR - 0000000000000000
  IDTR - 000000007F470018 0000000000000FFF,   TR - 0000000000000000
  FXSAVE_STATE - 00000000001CF840

Ideally we would like to avoid all memory allocations after exiting EFI
Boot Services altogether but that requires significant code changes. This
patch adds a simple workaround that resets grub_mm_add_region_fn to NULL
after ExitBootServices() call, so:

  - Memory allocations have a better chance of succeeding because grub_memalign()
    will try to reclaim the disk cache if it sees a NULL in grub_mm_add_region_fn.

  - At worst it will fail to allocate memory but it will explicitly tell users
    that it's out of memory, which is still much better than the current
    situation where it fails in a fairly random way and triggers a CPU fault.

Signed-off-by: Ruihan Li <lrh2000@pku.edu.cn>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agoi386/tsc: The GRUB menu gets stuck due to unserialized rdtsc
Duan Yayong [Mon, 9 Dec 2024 06:48:32 +0000 (14:48 +0800)] 
i386/tsc: The GRUB menu gets stuck due to unserialized rdtsc

This patch is used to fix GRUB menu gets stuck in server AC
poweron/poweroff stress test of x86_64, which is reproduced with
1/200 ratio. The root cause analysis as below:

Q: What's the code logic?

A: The grub_tsc_init() function will init tsc by setting grub_tsc_rate,
   which call stack is:

     grub_tsc_init() -> grub_tsc_calibrate_from_pmtimer() -> grub_divmod64()

   Among, grub_divmod64() function needs tsc_diff as the second parameter.
   In grub_pmtimer_wait_count_tsc(), we will call grub_get_tsc() function
   to get time stamp counter value to assign to start_tsc variable, and
   get into while (1) loop space to get end_tsc variable value with same
   function, after 3580 ticks, return "end_tsc - start_tsc". Actually,
   rdtsc instruction will be called in grub_get_tsc, but rdtsc instruction
   is not reliable (for the reason see the next question), which will cause
   tsc_diff to be a very big number larger than (1UL << 32) or a negative
   number, so that grub_tsc_rate will be zero. When run_menu() function is
   startup, and calls grub_tsc_get_time_ms() function to get current time
   to check if timeout time reach, at this time, grub_tsc_get_time_ms()
   function will return zero due to zero grub_tsc_rate variable, then GRUB
   menu gets stuck...

Q: What's the difference between rdtsc and rdtscp instructions in x86_64
   architecture? Here is more explanations from Intel® 64 and IA-32
   Architectures Software Developer’s Manual Volume 2B (December 2024):
   https://cdrdv2.intel.com/v1/dl/getContent/671241

A: In page 4-558 -> RDTSC—Read Time-Stamp Counter:
   The RDTSC instruction is not a serializing instruction. It does not
   necessarily wait until all previous instructions have been executed
   before reading the counter. Similarly, subsequent instructions may
   begin execution before the read operation is performed. The following
   items may guide software seeking to order executions of RDTSC:
     - If software requires RDTSC to be executed only after all previous
       instructions have executed and all previous loads are globally
       visible, it can execute LFENCE immediately before RDTSC.
     - If software requires RDTSC to be executed only after all previous
       instructions have executed and all previous loads and stores are
       globally visible, it can execute the sequence MFENCE;LFENCE
       immediately before RDTSC.
     - If software requires RDTSC to be executed prior to execution of any
       subsequent instruction (including any memory accesses), it can execute
       the sequence LFENCE immediately after RDTSC.

A: In page 4-560 -> RDTSCP—Read Time-Stamp Counter and Processor ID:
   The RDTSCP instruction is not a serializing instruction, but it does wait
   until all previous instructions have executed and all previous loads are
   globally visible. But it does not wait for previous stores to be globally
   visible, and subsequent instructions may begin execution before the read
   operation is performed. The following items may guide software seeking to
   order executions of RDTSCP:
     - If software requires RDTSCP to be executed only after all previous
       stores are globally visible, it can execute MFENCE immediately before
       RDTSCP.
     - If software requires RDTSCP to be executed prior to execution of any
       subsequent instruction (including any memory accesses), it can execute
       LFENCE immediately after RDTSCP.

Q: Why there is a cpuid serializing instruction before rdtsc instruction,
   but "grub_get_tsc" still cannot work as expect?

A: From Intel® 64 and IA-32 Architectures Software Developer's Manual
   Volume 2A: Instruction Set Reference, A-L (December 2024):
   https://cdrdv2.intel.com/v1/dl/getContent/671199

   In page 3-222 -> CPUID—CPU Identification:
   CPUID can be executed at any privilege level to serialize instruction execution.
   Serializing instruction execution guarantees that any modifications to flags,
   registers, and memory for previous instructions are completed before
   the next instruction is fetched and executed.

   So we only kept the instruction rdtsc and its previous instruction in order
   currently. But it is still out-of-order possibility between rdtsc instruction
   and its subsequent instruction.

Q: Why do we do this fix?

A: In the one hand, add cpuid instruction after rdtsc instruction to make sure
   rdtsc instruction to be executed prior to execution of any subsequent instruction,
   about serializing execution that all previous instructions have been executed
   before rdtsc, there is a cpuid usage in original code. In the other hand, using
   cpuid instruction rather than lfence can make sure a forward compatibility for
   previous HW.

   Base this fix, we did 1500 cycles power on/off stress test, and did not reproduce
   this issue again.

Fixes: https://savannah.gnu.org/bugs/?66257
Signed-off-by: Duan Yayong <duanyayong@bytedance.com>
Signed-off-by: Li Yongqiang <liyongqiang@huaqin.com>
Signed-off-by: Sun Ming <simon.sun@huaqin.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agokern/i386/tsc_pmtimer: The GRUB menu gets stuck due to failed calibration
Duan Yayong [Thu, 28 Nov 2024 03:48:26 +0000 (11:48 +0800)] 
kern/i386/tsc_pmtimer: The GRUB menu gets stuck due to failed calibration

The grub_divmod64() may return 0 but grub_tsc_calibrate_from_pmtimer()
still returns 1 saying calibration succeeded. Of course it is not true.
So, return 0 when grub_divmod64() returns 0. This way other calibration
functions can be called subsequently.

Signed-off-by: Duan Yayong <duanyayong@bytedance.com>
Signed-off-by: Li Yongqiang <liyongqiang@huaqin.com>
Signed-off-by: Sun Ming <simon.sun@huaqin.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agoloader/i386/linux: Fix cleanup if kernel doesn't support 64-bit addressing
Sergii Dmytruk [Fri, 1 Nov 2024 22:54:40 +0000 (00:54 +0200)] 
loader/i386/linux: Fix cleanup if kernel doesn't support 64-bit addressing

Simply returning from grub_cmd_linux() doesn't free "file" resource nor
calls grub_dl_ref(my_mod). Jump to "fail" label for proper cleanup like
other error checks do.

Signed-off-by: Sergii Dmytruk <sergii.dmytruk@3mdeb.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agoloader/i386/bsd: Use safe math to avoid underflow
Alec Brown [Wed, 5 Feb 2025 22:04:08 +0000 (22:04 +0000)] 
loader/i386/bsd: Use safe math to avoid underflow

The operation kern_end - kern_start may underflow when we input it into
grub_relocator_alloc_chunk_addr() call. To avoid this we can use safe
math for this subtraction.

Fixes: CID 73845
Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agoloader/i386/linux: Cast left shift to grub_uint32_t
Alec Brown [Fri, 7 Feb 2025 01:47:57 +0000 (01:47 +0000)] 
loader/i386/linux: Cast left shift to grub_uint32_t

The Coverity complains that we might overflow into a negative value when
setting linux_params.kernel_alignment to (1 << align). We can remedy
this by casting it to grub_uint32_t.

Fixes: CID 473876
Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agokern/misc: Add sanity check after grub_strtoul() call
Lidong Chen [Thu, 6 Feb 2025 18:16:57 +0000 (18:16 +0000)] 
kern/misc: Add sanity check after grub_strtoul() call

When the format string, fmt0, includes a positional argument
grub_strtoul() or grub_strtoull() is called to extract the argument
position. However, the returned argument position isn't fully validated.
If the format is something like "%0$x" then these functions return
0 which leads to an underflow in the calculation of the args index, curn.
The fix is to add a check to ensure the extracted argument position is
greater than 0 before computing curn. Additionally, replace one
grub_strtoull() with grub_strtoul() and change curn type to make code
more correct.

Fixes: CID 473841
Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agokern/partition: Add sanity check after grub_strtoul() call
Lidong Chen [Thu, 6 Feb 2025 18:16:56 +0000 (18:16 +0000)] 
kern/partition: Add sanity check after grub_strtoul() call

The current code incorrectly assumes that both the input and the values
returned by grub_strtoul() are always valid which can lead to potential
errors. This fix ensures proper validation to prevent any unintended issues.

Fixes: CID 473843
Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agonormal/menu: Use safe math to avoid an integer overflow
Alec Brown [Tue, 4 Feb 2025 15:11:11 +0000 (15:11 +0000)] 
normal/menu: Use safe math to avoid an integer overflow

The Coverity indicates that the variable current_entry might overflow.
To prevent this use safe math when adding GRUB_MENU_PAGE_SIZE to current_entry.

On the occasion fix limiting condition which was broken.

Fixes: CID 473853
Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agobus/usb/ehci: Define GRUB_EHCI_TOGGLE as grub_uint32_t
Alec Brown [Tue, 4 Feb 2025 15:11:10 +0000 (15:11 +0000)] 
bus/usb/ehci: Define GRUB_EHCI_TOGGLE as grub_uint32_t

The Coverity indicates that GRUB_EHCI_TOGGLE is an int that contains
a negative value and we are using it for the variable token which is
grub_uint32_t. To remedy this we can cast the definition to grub_uint32_t.

Fixes: CID 473851
Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agomisc: Ensure consistent overflow error messages
Lidong Chen [Tue, 21 Jan 2025 19:02:39 +0000 (19:02 +0000)] 
misc: Ensure consistent overflow error messages

Update the overflow error messages to make them consistent
across the GRUB code.

Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agoosdep/unix/getroot: Fix potential underflow
Lidong Chen [Wed, 29 Jan 2025 06:48:38 +0000 (06:48 +0000)] 
osdep/unix/getroot: Fix potential underflow

The entry_len is initialized in grub_find_root_devices_from_mountinfo()
to 0 before the while loop iterates through /proc/self/mountinfo. If the
file is empty or contains only invalid entries entry_len remains
0 causing entry_len - 1 in the subsequent for loop initialization
to underflow. To prevent this add a check to ensure entry_len > 0 before
entering the for loop.

Fixes: CID 473877
Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Reviewed-by: Ross Philipson <ross.philipson@oracle.com>
5 months agoscript/execute: Fix potential underflow and NULL dereference
Lidong Chen [Wed, 29 Jan 2025 06:48:37 +0000 (06:48 +0000)] 
script/execute: Fix potential underflow and NULL dereference

The result is initialized to 0 in grub_script_arglist_to_argv().
If the for loop condition is not met both result.args and result.argc
remain 0 causing result.argc - 1 to underflow and/or result.args NULL
dereference. Fix the issues by adding relevant checks.

Fixes: CID 473880
Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agofs/sfs: Check if allocated memory is NULL
Alec Brown [Tue, 28 Jan 2025 05:15:50 +0000 (05:15 +0000)] 
fs/sfs: Check if allocated memory is NULL

When using grub_zalloc(), if we are out of memory, this function can fail.
After allocating memory, we should check if grub_zalloc() returns NULL.
If so, we should handle this error.

Fixes: CID 473856
Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Ross Philipson <ross.philipson@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agonet: Check if returned pointer for allocated memory is NULL
Alec Brown [Wed, 22 Jan 2025 18:04:44 +0000 (18:04 +0000)] 
net: Check if returned pointer for allocated memory is NULL

When using grub_malloc(), the function can fail if we are out of memory.
After allocating memory we should check if this function returned NULL
and handle this error if it did.

Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agonet: Prevent overflows when allocating memory for arrays
Lidong Chen [Wed, 22 Jan 2025 18:04:43 +0000 (18:04 +0000)] 
net: Prevent overflows when allocating memory for arrays

Use grub_calloc() when allocating memory for arrays to ensure proper
overflow checks are in place.

Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agonet: Use safe math macros to prevent overflows
Lidong Chen [Wed, 22 Jan 2025 18:04:42 +0000 (18:04 +0000)] 
net: Use safe math macros to prevent overflows

Replace direct arithmetic operations with macros from include/grub/safemath.h
to prevent potential overflow issues when calculating the memory sizes.

Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agofs/zfs: Add missing NULL check after grub_strdup() call
Lidong Chen [Wed, 22 Jan 2025 07:17:04 +0000 (07:17 +0000)] 
fs/zfs: Add missing NULL check after grub_strdup() call

Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agofs/zfs: Check if returned pointer for allocated memory is NULL
Lidong Chen [Wed, 22 Jan 2025 07:17:01 +0000 (07:17 +0000)] 
fs/zfs: Check if returned pointer for allocated memory is NULL

When using grub_malloc() or grub_zalloc(), these functions can fail if
we are out of memory. After allocating memory we should check if these
functions returned NULL and handle this error if they did.

Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agofs/zfs: Prevent overflows when allocating memory for arrays
Lidong Chen [Wed, 22 Jan 2025 07:17:03 +0000 (07:17 +0000)] 
fs/zfs: Prevent overflows when allocating memory for arrays

Use grub_calloc() when allocating memory for arrays to ensure proper
overflow checks are in place.

Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agofs/zfs: Use safe math macros to prevent overflows
Lidong Chen [Wed, 22 Jan 2025 07:17:02 +0000 (07:17 +0000)] 
fs/zfs: Use safe math macros to prevent overflows

Replace direct arithmetic operations with macros from include/grub/safemath.h
to prevent potential overflow issues when calculating the memory sizes.

Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agofs: Prevent overflows when assigning returned values from read_number()
Lidong Chen [Tue, 21 Jan 2025 19:02:38 +0000 (19:02 +0000)] 
fs: Prevent overflows when assigning returned values from read_number()

The direct assignment of the unsigned long long value returned by
read_number() can potentially lead to an overflow on a 32-bit systems.
The fix replaces the direct assignments with calls to grub_cast()
which detects the overflows and safely assigns the values if no
overflow is detected.

Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agofs: Prevent overflows when allocating memory for arrays
Lidong Chen [Tue, 21 Jan 2025 19:02:37 +0000 (19:02 +0000)] 
fs: Prevent overflows when allocating memory for arrays

Use grub_calloc() when allocating memory for arrays to ensure proper
overflow checks are in place.

The HFS+ and squash4 security vulnerabilities were reported by
Jonathan Bar Or <jonathanbaror@gmail.com>.

Fixes: CVE-2025-0678
Fixes: CVE-2025-1125
Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agofs: Use safe math macros to prevent overflows
Lidong Chen [Tue, 21 Jan 2025 19:02:36 +0000 (19:02 +0000)] 
fs: Use safe math macros to prevent overflows

Replace direct arithmetic operations with macros from include/grub/safemath.h
to prevent potential overflow issues when calculating the memory sizes.

Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agodisk/ieee1275/ofdisk: Call grub_ieee1275_close() when grub_malloc() fails
Alec Brown [Wed, 22 Jan 2025 02:55:12 +0000 (02:55 +0000)] 
disk/ieee1275/ofdisk: Call grub_ieee1275_close() when grub_malloc() fails

In the dev_iterate() function a handle is opened but isn't closed when
grub_malloc() returns NULL. We should fix this by closing it on error.

Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agodisk: Check if returned pointer for allocated memory is NULL
Alec Brown [Wed, 22 Jan 2025 02:55:11 +0000 (02:55 +0000)] 
disk: Check if returned pointer for allocated memory is NULL

When using grub_malloc(), grub_zalloc() or grub_calloc(), these functions can
fail if we are out of memory. After allocating memory we should check if these
functions returned NULL and handle this error if they did.

On the occasion make a NULL check in ATA code more obvious.

Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agodisk: Prevent overflows when allocating memory for arrays
Alec Brown [Wed, 22 Jan 2025 02:55:10 +0000 (02:55 +0000)] 
disk: Prevent overflows when allocating memory for arrays

Use grub_calloc() when allocating memory for arrays to ensure proper
overflow checks are in place.

Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agodisk: Use safe math macros to prevent overflows
Alec Brown [Wed, 22 Jan 2025 02:55:09 +0000 (02:55 +0000)] 
disk: Use safe math macros to prevent overflows

Replace direct arithmetic operations with macros from include/grub/safemath.h
to prevent potential overflow issues when calculating the memory sizes.

Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agofs: Disable many filesystems under lockdown
Daniel Axtens [Sat, 23 Mar 2024 05:20:45 +0000 (16:20 +1100)] 
fs: Disable many filesystems under lockdown

The idea is to permit the following: btrfs, cpio, exfat, ext, f2fs, fat,
hfsplus, iso9660, squash4, tar, xfs and zfs.

The JFS, ReiserFS, romfs, UDF and UFS security vulnerabilities were
reported by Jonathan Bar Or <jonathanbaror@gmail.com>.

Fixes: CVE-2025-0677
Fixes: CVE-2025-0684
Fixes: CVE-2025-0685
Fixes: CVE-2025-0686
Fixes: CVE-2025-0689
Suggested-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agofs/bfs: Disable under lockdown
Daniel Axtens [Sat, 23 Mar 2024 04:59:43 +0000 (15:59 +1100)] 
fs/bfs: Disable under lockdown

The BFS is not fuzz-clean. Don't allow it to be loaded under lockdown.
This will also disable the AFS.

Fixes: CVE-2024-45778
Fixes: CVE-2024-45779
Reported-by: Nils Langius <nils@langius.de>
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agocommands/hexdump: Disable memory reading in lockdown mode
B Horn [Fri, 19 Apr 2024 21:31:45 +0000 (22:31 +0100)] 
commands/hexdump: Disable memory reading in lockdown mode

Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agocommands/memrw: Disable memory reading in lockdown mode
B Horn [Thu, 18 Apr 2024 19:37:10 +0000 (20:37 +0100)] 
commands/memrw: Disable memory reading in lockdown mode

With the rest of module being blocked in lockdown mode it does not make
a lot of sense to leave memory reading enabled. This also goes in par
with disabling the dump command.

Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agocommands/minicmd: Block the dump command in lockdown mode
B Horn [Thu, 18 Apr 2024 19:29:39 +0000 (20:29 +0100)] 
commands/minicmd: Block the dump command in lockdown mode

The dump enables a user to read memory which should not be possible
in lockdown mode.

Fixes: CVE-2025-1118
Reported-by: B Horn <b@horn.uk>
Reported-by: Jonathan Bar Or <jonathanbaror@gmail.com>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agocommands/test: Stack overflow due to unlimited recursion depth
Lidong Chen [Mon, 16 Dec 2024 20:22:41 +0000 (20:22 +0000)] 
commands/test: Stack overflow due to unlimited recursion depth

The test_parse() evaluates test expression recursively. Due to lack of
recursion depth check a specially crafted expression may cause a stack
overflow. The recursion is only triggered by the parentheses usage and
it can be unlimited. However, sensible expressions are unlikely to
contain more than a few parentheses. So, this patch limits the recursion
depth to 100, which should be sufficient.

Reported-by: Nils Langius <nils@langius.de>
Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agocommands/read: Fix an integer overflow when supplying more than 2^31 characters
Jonathan Bar Or [Thu, 23 Jan 2025 18:17:05 +0000 (19:17 +0100)] 
commands/read: Fix an integer overflow when supplying more than 2^31 characters

The grub_getline() function currently has a signed integer variable "i"
that can be overflown when user supplies more than 2^31 characters.
It results in a memory corruption of the allocated line buffer as well
as supplying large negative values to grub_realloc().

Fixes: CVE-2025-0690
Reported-by: Jonathan Bar Or <jonathanbaror@gmail.com>
Signed-off-by: Jonathan Bar Or <jonathanbaror@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agogettext: Integer overflow leads to heap OOB write
Lidong Chen [Fri, 22 Nov 2024 06:27:57 +0000 (06:27 +0000)] 
gettext: Integer overflow leads to heap OOB write

The size calculation of the translation buffer in
grub_gettext_getstr_from_position() may overflow
to 0 leading to heap OOB write. This patch fixes
the issue by using grub_add() and checking for
an overflow.

Fixes: CVE-2024-45777
Reported-by: Nils Langius <nils@langius.de>
Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Reviewed-by: Alec Brown <alec.r.brown@oracle.com>
5 months agogettext: Integer overflow leads to heap OOB write or read
Lidong Chen [Fri, 22 Nov 2024 06:27:56 +0000 (06:27 +0000)] 
gettext: Integer overflow leads to heap OOB write or read

Calculation of ctx->grub_gettext_msg_list size in grub_mofile_open() may
overflow leading to subsequent OOB write or read. This patch fixes the
issue by replacing grub_zalloc() and explicit multiplication with
grub_calloc() which does the same thing in safe manner.

Fixes: CVE-2024-45776
Reported-by: Nils Langius <nils@langius.de>
Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Reviewed-by: Alec Brown <alec.r.brown@oracle.com>
5 months agogettext: Remove variables hooks on module unload
B Horn [Fri, 1 Nov 2024 23:52:06 +0000 (23:52 +0000)] 
gettext: Remove variables hooks on module unload

The gettext module does not entirely cleanup after itself in
its GRUB_MOD_FINI() leaving a few variables hooks in place.
It is not possible to unload gettext module because normal
module depends on it. Though fix the issues for completeness.

Fixes: CVE-2025-0622
Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agonormal: Remove variables hooks on module unload
B Horn [Fri, 1 Nov 2024 23:46:55 +0000 (23:46 +0000)] 
normal: Remove variables hooks on module unload

The normal module does not entirely cleanup after itself in
its GRUB_MOD_FINI() leaving a few variables hooks in place.
It is not possible to unload normal module now but fix the
issues for completeness.

On the occasion replace 0s with NULLs for "pager" variable
hooks unregister.

Fixes: CVE-2025-0622
Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agocommands/pgp: Unregister the "check_signatures" hooks on module unload
B Horn [Fri, 1 Nov 2024 19:24:29 +0000 (19:24 +0000)] 
commands/pgp: Unregister the "check_signatures" hooks on module unload

If the hooks are not removed they can be called after the module has
been unloaded leading to an use-after-free.

Fixes: CVE-2025-0622
Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agocommands/ls: Fix NULL dereference
B Horn [Sun, 12 May 2024 10:08:23 +0000 (11:08 +0100)] 
commands/ls: Fix NULL dereference

The grub_strrchr() may return NULL when the dirname do not contain "/".
This can happen on broken filesystems.

Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agocommands/extcmd: Missing check for failed allocation
Lidong Chen [Fri, 22 Nov 2024 06:27:55 +0000 (06:27 +0000)] 
commands/extcmd: Missing check for failed allocation

The grub_extcmd_dispatcher() calls grub_arg_list_alloc() to allocate
a grub_arg_list struct but it does not verify the allocation was successful.
In case of failed allocation the NULL state pointer can be accessed in
parse_option() through grub_arg_parse() which may lead to a security issue.

Fixes: CVE-2024-45775
Reported-by: Nils Langius <nils@langius.de>
Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Reviewed-by: Alec Brown <alec.r.brown@oracle.com>
5 months agokern/dl: Check for the SHF_INFO_LINK flag in grub_dl_relocate_symbols()
B Horn [Thu, 7 Nov 2024 06:00:36 +0000 (06:00 +0000)] 
kern/dl: Check for the SHF_INFO_LINK flag in grub_dl_relocate_symbols()

The grub_dl_relocate_symbols() iterates through the sections in
an ELF looking for relocation sections. According to the spec [1]
the SHF_INFO_LINK flag should be set if the sh_info field is meant
to be a section index.

[1] https://refspecs.linuxbase.org/elf/gabi4+/ch4.sheader.html

Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agokern/dl: Use correct segment in grub_dl_set_mem_attrs()
B Horn [Fri, 1 Nov 2024 19:37:32 +0000 (19:37 +0000)] 
kern/dl: Use correct segment in grub_dl_set_mem_attrs()

The previous code would never actually call grub_update_mem_attrs()
as sh_info will always be zero for the sections that exist in memory.

Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agokern/dl: Fix for an integer overflow in grub_dl_ref()
B Horn [Thu, 18 Apr 2024 14:59:26 +0000 (15:59 +0100)] 
kern/dl: Fix for an integer overflow in grub_dl_ref()

It was possible to overflow the value of mod->ref_count, a signed
integer, by repeatedly invoking insmod on an already loaded module.
This led to a use-after-free. As once ref_count was overflowed it became
possible to unload the module while there was still references to it.

This resolves the issue by using grub_add() to check if the ref_count
will overflow and then stops further increments. Further changes were
also made to grub_dl_unref() to check for the underflow condition and
the reference count was changed to an unsigned 64-bit integer.

Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agovideo/readers/jpeg: Do not permit duplicate SOF0 markers in JPEG
Daniel Axtens [Fri, 8 Mar 2024 11:47:20 +0000 (22:47 +1100)] 
video/readers/jpeg: Do not permit duplicate SOF0 markers in JPEG

Otherwise a subsequent header could change the height and width
allowing future OOB writes.

Fixes: CVE-2024-45774
Reported-by: Nils Langius <nils@langius.de>
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agonet/tftp: Fix stack buffer overflow in tftp_open()
B Horn [Thu, 18 Apr 2024 16:32:34 +0000 (17:32 +0100)] 
net/tftp: Fix stack buffer overflow in tftp_open()

An overly long filename can be passed to tftp_open() which would cause
grub_normalize_filename() to write out of bounds.

Fixed by adding an extra argument to grub_normalize_filename() for the
space available, making it act closer to a strlcpy(). As several fixed
strings are strcpy()'d after into the same buffer, their total length is
checked to see if they exceed the remaining space in the buffer. If so,
return an error.

On the occasion simplify code a bit by removing unneeded rrqlen zeroing.

Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5 months agonet: Fix OOB write in grub_net_search_config_file()
B Horn [Fri, 15 Nov 2024 13:12:09 +0000 (13:12 +0000)] 
net: Fix OOB write in grub_net_search_config_file()

The function included a call to grub_strcpy() which copied data from an
environment variable to a buffer allocated in grub_cmd_normal(). The
grub_cmd_normal() didn't consider the length of the environment variable.
So, the copy operation could exceed the allocation and lead to an OOB
write. Fix the issue by replacing grub_strcpy() with grub_strlcpy() and
pass the underlying buffers size to the grub_net_search_config_file().

Fixes: CVE-2025-0624
Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
6 months agonet: Remove variables hooks when interface is unregisted
B Horn [Fri, 1 Nov 2024 23:49:48 +0000 (23:49 +0000)] 
net: Remove variables hooks when interface is unregisted

The grub_net_network_level_interface_unregister(), previously
implemented in a header, did not remove the variables hooks that
were registered in grub_net_network_level_interface_register().
Fix this by implementing the same logic used to register the
variables and move the function into the grub-core/net/net.c.

Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
6 months agonet: Unregister net_default_ip and net_default_mac variables hooks on unload
B Horn [Thu, 28 Nov 2024 04:05:04 +0000 (04:05 +0000)] 
net: Unregister net_default_ip and net_default_mac variables hooks on unload

The net module is a dependency of normal. So, it shouldn't be possible
to unload the net. Though unregister variables hooks as a precaution.
It also gets in line with unregistering the other net module hooks.

Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
6 months agoscript/execute: Limit the recursion depth
B Horn [Thu, 18 Apr 2024 18:04:13 +0000 (19:04 +0100)] 
script/execute: Limit the recursion depth

If unbounded recursion is allowed it becomes possible to collide the
stack with the heap. As UEFI firmware often lacks guard pages this
becomes an exploitable issue as it is possible in some cases to do
a controlled overwrite of a section of this heap region with
arbitrary data.

Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
6 months agokern/partition: Limit recursion in part_iterate()
B Horn [Sat, 16 Nov 2024 21:24:19 +0000 (21:24 +0000)] 
kern/partition: Limit recursion in part_iterate()

The part_iterate() is used by grub_partition_iterate() as a callback in
the partition iterate functions. However, part_iterate() may also call
the partition iterate functions which may lead to recursion. Fix potential
issue by limiting the recursion depth.

Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
6 months agokern/disk: Limit recursion depth
B Horn [Sun, 12 May 2024 03:09:24 +0000 (04:09 +0100)] 
kern/disk: Limit recursion depth

The grub_disk_read() may trigger other disk reads, e.g. via loopbacks.
This may lead to very deep recursion which can corrupt the heap. So, fix
the issue by limiting reads depth.

Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
6 months agodisk/loopback: Reference tracking for the loopback
B Horn [Sun, 12 May 2024 02:26:19 +0000 (03:26 +0100)] 
disk/loopback: Reference tracking for the loopback

It was possible to delete a loopback while there were still references
to it. This led to an exploitable use-after-free.

Fixed by implementing a reference counting in the grub_loopback struct.

Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
6 months agodisk/cryptodisk: Require authentication after TPM unlock for CLI access
Michael Chang [Thu, 29 Aug 2024 05:27:30 +0000 (13:27 +0800)] 
disk/cryptodisk: Require authentication after TPM unlock for CLI access

The GRUB may use TPM to verify the integrity of boot components and the
result can determine whether a previously sealed key can be released. If
everything checks out, showing nothing has been tampered with, the key
is released and GRUB unlocks the encrypted root partition for the next
stage of booting.

However, the liberal Command Line Interface (CLI) can be misused by
anyone in this case to access files in the encrypted partition one way
or another. Despite efforts to keep the CLI secure by preventing utility
command output from leaking file content, many techniques in the wild
could still be used to exploit the CLI, enabling attacks or learning
methods to attack. It's nearly impossible to account for all scenarios
where a hack could be applied.

Therefore, to mitigate potential misuse of the CLI after the root device
has been successfully unlocked via TPM, the user should be required to
authenticate using the LUKS password. This added layer of security
ensures that only authorized users can access the CLI reducing the risk
of exploitation or unauthorized access to the encrypted partition.

Fixes: CVE-2024-49504
Signed-off-by: Michael Chang <mchang@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
6 months agokern/file: Implement filesystem reference counting
B Horn [Sun, 12 May 2024 09:15:03 +0000 (10:15 +0100)] 
kern/file: Implement filesystem reference counting

The grub_file_open() and grub_file_close() should be the only places
that allow a reference to a filesystem to stay open. So, add grub_dl_t
to grub_fs_t and set this in the GRUB_MOD_INIT() for each filesystem to
avoid issues when filesystems forget to do it themselves or do not track
their own references, e.g. squash4.

The fs_label(), fs_uuid(), fs_mtime() and fs_read() should all ref and
unref in the same function but it is essentially redundant in GRUB
single threaded model.

Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
6 months agokern/file: Ensure file->data is set
B Horn [Sun, 12 May 2024 02:01:40 +0000 (03:01 +0100)] 
kern/file: Ensure file->data is set

This is to avoid a generic issue were some filesystems would not set
data and also not set a grub_errno. This meant it was possible for many
filesystems to grub_dl_unref() themselves multiple times resulting in
it being possible to unload the filesystems while there were still
references to them, e.g., via a loopback.

Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
6 months agofs/xfs: Ensuring failing to mount sets a grub_errno
B Horn [Sun, 12 May 2024 05:03:58 +0000 (06:03 +0100)] 
fs/xfs: Ensuring failing to mount sets a grub_errno

It was previously possible for grub_xfs_mount() to return NULL without
setting grub_errno if the XFS version was invalid. This resulted in it
being possible for grub_dl_unref() to be called twice allowing the XFS
module to be unloaded while there were still references to it.

Fixing this problem in general by ensuring a grub_errno is set if the
fail label is reached.

Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
6 months agofs/xfs: Fix out-of-bounds read
Michael Chang [Fri, 31 May 2024 07:14:57 +0000 (15:14 +0800)] 
fs/xfs: Fix out-of-bounds read

The number of records in the root key array read from disk was not being
validated against the size of the root node. This could lead to an
out-of-bounds read.

This patch adds a check to ensure that the number of records in the root
key array does not exceed the expected size of a root node read from
disk. If this check detects an out-of-bounds condition the operation is
aborted to prevent random errors due to metadata corruption.

Reported-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Michael Chang <mchang@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
6 months agofs/ntfs: Implement attribute verification
B Horn [Tue, 14 May 2024 11:39:56 +0000 (12:39 +0100)] 
fs/ntfs: Implement attribute verification

It was possible to read OOB when an attribute had a size that exceeded
the allocated buffer. This resolves that by making sure all attributes
that get read are fully in the allocated space by implementing
a function to validate them.

Defining the offsets in include/grub/ntfs.h but they are only used in
the validation function and not across the rest of the NTFS code.

Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
6 months agofs/ntfs: Use a helper function to access attributes
B Horn [Tue, 14 May 2024 11:39:56 +0000 (12:39 +0100)] 
fs/ntfs: Use a helper function to access attributes

Right now to access the next attribute the code reads the length of the
current attribute and adds that to the current pointer. This is error
prone as bounds checking needs to be performed all over the place. So,
implement a helper and ensure its used across find_attr() and read_attr().

This commit does *not* implement full bounds checking. It is just the
preparation work for this to be added into the helper.

Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
6 months agofs/ntfs: Track the end of the MFT attribute buffer
B Horn [Tue, 7 Jan 2025 11:38:34 +0000 (11:38 +0000)] 
fs/ntfs: Track the end of the MFT attribute buffer

The end of the attribute buffer should be stored alongside the rest of
the attribute struct as right now it is not possible to implement bounds
checking when accessing attributes sequentially.

This is done via:
  - updating init_attr() to set at->end and check is is not initially out of bounds,
  - implementing checks as init_attr() had its type change in its callers,
  - updating the value of at->end when needed.

Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
6 months agofs/ntfs: Fix out-of-bounds read
Michael Chang [Mon, 3 Jun 2024 04:12:06 +0000 (12:12 +0800)] 
fs/ntfs: Fix out-of-bounds read

When parsing NTFS file records the presence of the 0xFF marker indicates
the end of the attribute list. This value signifies that there are no
more attributes to process.

However, when the end marker is missing due to corrupted metadata the
loop continues to read beyond the attribute list resulting in out-of-bounds
reads and potentially entering an infinite loop.

This patch adds a check to provide a stop condition for the loop ensuring
it stops at the end of the attribute list or at the end of the Master File
Table. This guards against out-of-bounds reads and prevents infinite loops.

Reported-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Michael Chang <mchang@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
6 months agofs/ext2: Fix out-of-bounds read for inline extents
Michael Chang [Fri, 31 May 2024 07:14:23 +0000 (15:14 +0800)] 
fs/ext2: Fix out-of-bounds read for inline extents

When inline extents are used, i.e. the extent tree depth equals zero,
a maximum of four entries can fit into the inode's data block. If the
extent header states a number of entries greater than four the current
ext2 implementation causes an out-of-bounds read. Fix this issue by
capping the number of extents to four when reading inline extents.

Reported-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Michael Chang <mchang@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
6 months agofs/jfs: Inconsistent signed/unsigned types usage in return values
Lidong Chen [Mon, 16 Dec 2024 20:22:40 +0000 (20:22 +0000)] 
fs/jfs: Inconsistent signed/unsigned types usage in return values

The getblk() returns a value of type grub_int64_t which is assigned to
iagblk and inoblk, both of type grub_uint64_t, in grub_jfs_read_inode()
via grub_jfs_blkno(). This patch fixes the type mismatch in the
functions. Additionally, the getblk() will return 0 instead of -1 on
failure cases. This change is safe because grub_errno is always set in
getblk() to indicate errors and it is later checked in the callers.

Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Ross Philipson <ross.philipson@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
6 months agofs/jfs: Use full 40 bits offset and address for a data extent
Lidong Chen [Mon, 16 Dec 2024 20:22:39 +0000 (20:22 +0000)] 
fs/jfs: Use full 40 bits offset and address for a data extent

An extent's logical offset and address are represented as a 40-bit value
split into two parts: the most significant 8 bits and the least
significant 32 bits. Currently the JFS code uses only the least
significant 32 bits value for offsets and addresses assuming the data
size will never exceed the 32-bit range. This approach ignores the most
significant 8 bits potentially leading to incorrect offsets and
addresses for larger values. The patch fixes it by incorporating the
most significant 8 bits into the calculation to get the full 40-bits
value for offsets and addresses.

https://jfs.sourceforge.net/project/pub/jfslayout.pdf

  "off1,off2 is a 40-bit field, containing the logical offset of the first
   block in the extent.
   ...
   addr1,addr2 is a 40-bit field, containing the address of the extent."

Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Ross Philipson <ross.philipson@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
6 months agofs/jfs: Fix OOB read caused by invalid dir slot index
Lidong Chen [Fri, 22 Nov 2024 06:28:00 +0000 (06:28 +0000)] 
fs/jfs: Fix OOB read caused by invalid dir slot index

While fuzz testing JFS with ASAN enabled an OOB read was detected in
grub_jfs_opendir(). The issue occurred due to an invalid directory slot
index in the first entry of the sorted directory slot array in the inode
directory header. The fix ensures the slot index is validated before
accessing it. Given that an internal or a leaf node in a directory B+
tree is a 4 KiB in size and each directory slot is always 32 bytes, the
max number of slots in a node is 128. The validation ensures that the
slot index doesn't exceed this limit.

[1] https://jfs.sourceforge.net/project/pub/jfslayout.pdf

  JFS will allocate 4K of disk space for an internal node of the B+ tree.
  An internal node looks the same as a leaf node.
          - page 10

  Fixed number of Directory Slots depending on the size of the node. These are
  the slots to be used for storing the directory slot array and the directory
  entries or router entries. A directory slot is always 32 bytes.
  ...
  A Directory Slot Array which is a sorted array of indices to the directory
  slots that are currently in use.
  ...
  An internal or a leaf node in the directory B+ tree is a 4K page.
          - page 25

Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Reviewed-by: Alec Brown <alec.r.brown@oracle.com>
6 months agofs/jfs: Fix OOB read in jfs_getent()
Lidong Chen [Fri, 22 Nov 2024 06:27:59 +0000 (06:27 +0000)] 
fs/jfs: Fix OOB read in jfs_getent()

The JFS fuzzing revealed an OOB read in grub_jfs_getent(). The crash
was caused by an invalid leaf nodes count, diro->dirpage->header.count,
which was larger than the maximum number of leaf nodes allowed in an
inode. This fix is to ensure that the leaf nodes count is validated in
grub_jfs_opendir() before calling grub_jfs_getent().

On the occasion replace existing raw numbers with newly defined constant.

Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Reviewed-by: Alec Brown <alec.r.brown@oracle.com>
6 months agofs/iso9660: Fix invalid free
Michael Chang [Fri, 31 May 2024 07:14:42 +0000 (15:14 +0800)] 
fs/iso9660: Fix invalid free

The ctx->filename can point to either a string literal or a dynamically
allocated string. The ctx->filename_alloc field is used to indicate the
type of allocation.

An issue has been identified where ctx->filename is reassigned to
a string literal in susp_iterate_dir() but ctx->filename_alloc is not
correctly handled. This oversight causes a memory leak and an invalid
free operation later.

The fix involves checking ctx->filename_alloc, freeing the allocated
string if necessary and clearing ctx->filename_alloc for string literals.

Reported-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Michael Chang <mchang@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
6 months agofs/iso9660: Set a grub_errno if mount fails
B Horn [Sun, 12 May 2024 05:37:08 +0000 (06:37 +0100)] 
fs/iso9660: Set a grub_errno if mount fails

It was possible for a grub_errno to not be set if mount of an ISO 9660
filesystem failed when set_rockridge() returned 0.

This isn't known to be exploitable as the other filesystems due to
filesystem helper checking the requested file type. Though fixing
as a precaution.

Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
6 months agofs/hfsplus: Set a grub_errno if mount fails
B Horn [Sun, 12 May 2024 05:22:51 +0000 (06:22 +0100)] 
fs/hfsplus: Set a grub_errno if mount fails

It was possible for mount to fail but not set grub_errno. This led to
a possible double decrement of the module reference count if the NULL
page was mapped.

Fixing in general as a similar bug was fixed in commit 61b13c187
(fs/hfsplus: Set grub_errno to prevent NULL pointer access) and there
are likely more variants around.

Fixes: CVE-2024-45783
Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
6 months agofs/f2fs: Set a grub_errno if mount fails
B Horn [Sun, 12 May 2024 05:15:03 +0000 (06:15 +0100)] 
fs/f2fs: Set a grub_errno if mount fails

It was previously possible for grub_errno to not be set when
grub_f2fs_mount() failed if nat_bitmap_ptr() returned NULL.

This issue is solved by ensuring a grub_errno is set in the fail case.

Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
6 months agofs/tar: Integer overflow leads to heap OOB write
Lidong Chen [Fri, 22 Nov 2024 06:27:58 +0000 (06:27 +0000)] 
fs/tar: Integer overflow leads to heap OOB write

Both namesize and linksize are derived from hd.size, a 12-digit octal
number parsed by read_number(). Later direct arithmetic calculation like
"namesize + 1" and "linksize + 1" may exceed the maximum value of
grub_size_t leading to heap OOB write. This patch fixes the issue by
using grub_add() and checking for an overflow.

Fixes: CVE-2024-45780
Reported-by: Nils Langius <nils@langius.de>
Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Reviewed-by: Alec Brown <alec.r.brown@oracle.com>
6 months agofs/tar: Initialize name in grub_cpio_find_file()
B Horn [Sun, 12 May 2024 01:47:54 +0000 (02:47 +0100)] 
fs/tar: Initialize name in grub_cpio_find_file()

It was possible to iterate through grub_cpio_find_file() without
allocating name and not setting mode to GRUB_ARCHELP_ATTR_END, which
would cause the uninitialized value for name to be used as an argument
for canonicalize() in grub_archelp_dir().

Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
6 months agofs/hfs: Fix stack OOB write with grub_strcpy()
B Horn [Sun, 12 May 2024 01:48:33 +0000 (02:48 +0100)] 
fs/hfs: Fix stack OOB write with grub_strcpy()

Replaced with grub_strlcpy().

Fixes: CVE-2024-45782
Fixes: CVE-2024-56737
Fixes: https://savannah.gnu.org/bugs/?66599
Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
8 months agofs/ufs: Fix a heap OOB write
B Horn [Sun, 12 May 2024 01:03:33 +0000 (02:03 +0100)] 
fs/ufs: Fix a heap OOB write

grub_strcpy() was used to copy a symlink name from the filesystem
image to a heap allocated buffer. This led to a OOB write to adjacent
heap allocations. Fix by using grub_strlcpy().

Fixes: CVE-2024-45781
Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
8 months agomisc: Implement grub_strlcpy()
B Horn [Sat, 15 Jun 2024 01:33:08 +0000 (02:33 +0100)] 
misc: Implement grub_strlcpy()

grub_strlcpy() acts the same way as strlcpy() does on most *NIX,
returning the length of src and ensuring dest is always NUL
terminated except when size is 0.

Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
8 months agotpm2_key_protector: Enable build for powerpc_ieee1275
Stefan Berger [Tue, 26 Nov 2024 20:39:46 +0000 (15:39 -0500)] 
tpm2_key_protector: Enable build for powerpc_ieee1275

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
8 months agoieee1275/tcg2: Add TCG2 driver for ieee1275 PowerPC firmware
Stefan Berger [Tue, 26 Nov 2024 20:39:45 +0000 (15:39 -0500)] 
ieee1275/tcg2: Add TCG2 driver for ieee1275 PowerPC firmware

Follow recent extensions of EFI support providing a TCG2 driver with
a public API for getting the maximum TPM command size and passing a TPM
command through to the TPM 2. Implement this functionality using ieee1275
PowerPC firmware API calls. Move tcg2.c into the TCG2 driver.

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
8 months agoieee1275/tcg2: Refactor grub_ieee1275_tpm_init()
Stefan Berger [Tue, 26 Nov 2024 20:39:44 +0000 (15:39 -0500)] 
ieee1275/tcg2: Refactor grub_ieee1275_tpm_init()

Move tpm_get_tpm_version() into grub_ieee1275_tpm_init() and invalidate
grub_ieee1275_tpm_ihandle in case no TPM 2 could be detected. Try the
initialization only once so that grub_tpm_present() will always return
the same result. Use the grub_ieee1275_tpm_ihandle as indicator for an
available TPM instead of grub_ieee1275_tpm_version, which can now be
removed.

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
8 months agoieee1275/ibmvpm: Move TPM initialization functions to own file
Stefan Berger [Tue, 26 Nov 2024 20:39:43 +0000 (15:39 -0500)] 
ieee1275/ibmvpm: Move TPM initialization functions to own file

Move common initialization functions from the ibmvtpm driver module into
tcg2.c that will be moved into the new TCG2 driver in a subsequent patch.
Make the functions available to the ibmvtpm driver as public functions
and variables.

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
8 months agoieee1275: Consolidate repeated definitions of IEEE1275_IHANDLE_INVALID
Stefan Berger [Tue, 26 Nov 2024 20:39:42 +0000 (15:39 -0500)] 
ieee1275: Consolidate repeated definitions of IEEE1275_IHANDLE_INVALID

Consolidate repeated definitions of IEEE1275_IHANDLE_INVALID that are cast
to the type grub_ieee1275_ihandle_t. On the occasion add "GRUB_" prefix to
the constant name.

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
8 months agoterm/ieee1275/serial: Cast 0 to proper type
Stefan Berger [Tue, 26 Nov 2024 20:39:41 +0000 (15:39 -0500)] 
term/ieee1275/serial: Cast 0 to proper type

Cast 0 to proper type grub_ieee1275_ihandle_t. This type is
used for struct grub_serial_port's handle that assigns or
compares with IEEE1275_IHANDLE_INVALID.

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
8 months agotss2: Adjust bit fields for big endian targets
Stefan Berger [Tue, 26 Nov 2024 20:39:40 +0000 (15:39 -0500)] 
tss2: Adjust bit fields for big endian targets

The TPM bit fields need to be in reverse order for big endian targets,
such as ieee1275 PowerPC platforms that run GRUB in big endian mode.

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Gary Lin <glin@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
8 months agodocs: Document TPM2 key protector
Gary Lin [Fri, 15 Nov 2024 07:35:01 +0000 (15:35 +0800)] 
docs: Document TPM2 key protector

Update the user manual to address TPM2 key protector including the two
related commands, tpm2_key_protector_init and tpm2_key_protector_clear,
and the user-space utility: grub-protect.

Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Tested-by: Stefan Berger <stefanb@linux.ibm.com>
8 months agotests: Add tpm2_key_protector_test
Gary Lin [Fri, 15 Nov 2024 07:35:00 +0000 (15:35 +0800)] 
tests: Add tpm2_key_protector_test

For the tpm2_key_protector module, the TCG2 command submission function
is the only difference between a QEMU instance and grub-emu. To test
TPM2 key unsealing with a QEMU instance, it requires an extra OS image
to invoke grub-protect to seal the LUKS key, rather than a simple
grub-shell rescue CD image. On the other hand, grub-emu can share the
emulated TPM2 device with the host, so that we can seal the LUKS key on
host and test key unsealing with grub-emu.

This test script firstly creates a simple LUKS image to be loaded as a
loopback device in grub-emu. Then an emulated TPM2 device is created by
"swtpm chardev" and PCR 0 and 1 are extended.

There are several test cases in the script to test various settings. Each
test case uses grub-protect or tpm2-tools to seal the LUKS password
with PCR 0 and PCR 1. Then grub-emu is launched to load the LUKS image,
try to mount the image with tpm2_key_protector_init and cryptomount, and
verify the result.

Based on the idea from Michael Chang.

Cc: Michael Chang <mchang@suse.com>
Cc: Stefan Berger <stefanb@linux.ibm.com>
Cc: Glenn Washburn <development@efficientek.com>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Tested-by: Stefan Berger <stefanb@linux.ibm.com>
8 months agotpm2_key_protector: Add grub-emu support
Gary Lin [Fri, 15 Nov 2024 07:34:59 +0000 (15:34 +0800)] 
tpm2_key_protector: Add grub-emu support

As a preparation to test tpm2_key_protector with grub-emu, the new
option, --tpm-device, is introduced to specify the TPM device for
grub-emu so that grub-emu can access an emulated TPM device from
the host.

Since grub-emu can directly access the device on host, it's easy to
implement the essential TCG2 command submission function with the
read/write functions and enable tpm2_key_protector module for grub-emu,
so that we can further test TPM2 key unsealing with grub-emu.

Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Tested-by: Stefan Berger <stefanb@linux.ibm.com>
8 months agodiskfilter: Look up cryptodisk devices first
Gary Lin [Fri, 15 Nov 2024 07:34:58 +0000 (15:34 +0800)] 
diskfilter: Look up cryptodisk devices first

When using disk auto-unlocking with TPM 2.0, the typical grub.cfg may
look like this:

  tpm2_key_protector_init --tpm2key=(hd0,gpt1)/boot/grub/sealed.tpm
  cryptomount -u <PART-UUID> -P tpm2
  search --fs-uuid --set=root <FS-UUID>

Since the disk search order is based on the order of module loading, the
attacker could insert a malicious disk with the same FS-UUID root to
trick GRUB to boot into the malicious root and further dump memory to
steal the unsealed key.

Do defend against such an attack, we can specify the hint provided by
"grub-probe" to search the encrypted partition first:

  search --fs-uuid --set=root --hint='cryptouuid/<PART-UUID>' <FS-UUID>

However, for LVM on an encrypted partition, the search hint provided by
"grub-probe" is:

  --hint='lvmid/<VG-UUID>/<LV-UUID>'

It doesn't guarantee to look up the logical volume from the encrypted
partition, so the attacker may have the chance to fool GRUB to boot
into the malicious disk.

To minimize the attack surface, this commit tweaks the disk device search
in diskfilter to look up cryptodisk devices first and then others, so
that the auto-unlocked disk will be found first, not the attacker's disk.

Cc: Fabian Vogt <fvogt@suse.com>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Tested-by: Stefan Berger <stefanb@linux.ibm.com>
8 months agocryptodisk: Wipe out the cached keys from protectors
Gary Lin [Fri, 15 Nov 2024 07:34:57 +0000 (15:34 +0800)] 
cryptodisk: Wipe out the cached keys from protectors

An attacker may insert a malicious disk with the same crypto UUID and
trick GRUB to mount the fake root. Even though the key from the key
protector fails to unlock the fake root, it's not wiped out cleanly so
the attacker could dump the memory to retrieve the secret key. To defend
such attack, wipe out the cached key when we don't need it.

Cc: Fabian Vogt <fvogt@suse.com>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Tested-by: Stefan Berger <stefanb@linux.ibm.com>
8 months agocryptodisk: Fallback to passphrase
Patrick Colp [Fri, 15 Nov 2024 07:34:56 +0000 (15:34 +0800)] 
cryptodisk: Fallback to passphrase

If a protector is specified, but it fails to unlock the disk, fall back
to asking for the passphrase.

Before requesting the passphrase, the error from the key protector(s)
has to be cleared, or the later code, e.g., LUKS code, may stop as
grub_errno is set. This commit prints error from the key protector(s)
and sets grub_errno to GRUB_ERR_NONE to have a fresh start.

Signed-off-by: Patrick Colp <patrick.colp@oracle.com>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Tested-by: Stefan Berger <stefanb@linux.ibm.com>
8 months agotpm2_key_protector: Implement NV index
Patrick Colp [Fri, 15 Nov 2024 07:34:55 +0000 (15:34 +0800)] 
tpm2_key_protector: Implement NV index

Currently with the TPM2 protector, only SRK mode is supported and
NV index support is just a stub. Implement the NV index option.

Note: This only extends support on the unseal path. grub-protect
has not been updated. tpm2-tools can be used to insert a key into
the NV index.

An example of inserting a key using tpm2-tools:

  # Get random key.
  tpm2_getrandom 32 > key.dat

  # Create primary object.
  tpm2_createprimary -C o -g sha256 -G ecc -c primary.ctx

  # Create policy object. `pcrs.dat` contains the PCR values to seal against.
  tpm2_startauthsession -S session.dat
  tpm2_policypcr -S session.dat -l sha256:7,11 -f pcrs.dat -L policy.dat
  tpm2_flushcontext session.dat

  # Seal key into TPM.
  cat key.dat | tpm2_create -C primary.ctx -u key.pub -r key.priv -L policy.dat -i-
  tpm2_load -C primary.ctx -u key.pub -r key.priv -n sealing.name -c sealing.ctx
  tpm2_evictcontrol -C o -c sealing.ctx 0x81000000

Then to unseal the key in GRUB, add this to grub.cfg:

  tpm2_key_protector_init --mode=nv --nvindex=0x81000000 --pcrs=7,11
  cryptomount -u <UUID> --protector tpm2

Signed-off-by: Patrick Colp <patrick.colp@oracle.com>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Tested-by: Stefan Berger <stefanb@linux.ibm.com>
8 months agotpm2_key_protector: Support authorized policy
Gary Lin [Fri, 15 Nov 2024 07:34:54 +0000 (15:34 +0800)] 
tpm2_key_protector: Support authorized policy

This commit handles the TPM2_PolicyAuthorize command from the key file
in TPM 2.0 Key File format.

TPM2_PolicyAuthorize is the essential command to support authorized
policy which allows the users to sign TPM policies with their own keys.
Per TPM 2.0 Key File [1], CommandPolicy for TPM2_PolicyAuthorize
comprises "TPM2B_PUBLIC pubkey", "TPM2B_DIGEST policy_ref", and
"TPMT_SIGNATURE signature". To verify the signature, the current policy
digest is hashed with the hash algorithm written in "signature", and then
"signature" is verified with the hashed policy digest and "pubkey". Once
TPM accepts "signature", TPM2_PolicyAuthorize is invoked to authorize the
signed policy.

To create the key file with authorized policy, here are the pcr-oracle [2]
commands:

  # Generate the RSA key and create the authorized policy file
  $ pcr-oracle \
--rsa-generate-key \
--private-key policy-key.pem \
--auth authorized.policy \
create-authorized-policy 0,2,4,7,9

  # Seal the secret with the authorized policy
  $ pcr-oracle \
--key-format tpm2.0 \
--auth authorized.policy \
--input disk-secret.txt \
--output sealed.key \
seal-secret

  # Sign the predicted PCR policy
  $ pcr-oracle \
--key-format tpm2.0 \
--private-key policy-key.pem \
--from eventlog \
--stop-event "grub-file=grub.cfg" \
--after \
--input sealed.key \
--output /boot/efi/efi/grub/sealed.tpm \
sign 0,2,4,7,9

Then specify the key file and the key protector to grub.cfg in the EFI
system partition:

  tpm2_key_protector_init -a RSA --tpm2key=(hd0,gpt1)/efi/grub/sealed.tpm
  cryptomount -u <PART_UUID> -P tpm2

For any change in the boot components, just run the "sign" command again
to update the signature in sealed.tpm, and TPM can unseal the key file
with the updated PCR policy.

[1] https://www.hansenpartnership.com/draft-bottomley-tpm2-keys.html
[2] https://github.com/okirch/pcr-oracle

Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Tested-by: Stefan Berger <stefanb@linux.ibm.com>
8 months agoutil/grub-protect: Add new tool
Hernan Gatta [Fri, 15 Nov 2024 07:34:53 +0000 (15:34 +0800)] 
util/grub-protect: Add new tool

To utilize the key protectors framework, there must be a way to protect
full-disk encryption keys in the first place. The grub-protect tool
includes support for the TPM2 key protector but other protectors that
require setup ahead of time can be supported in the future.

For the TPM2 key protector, the intended flow is for a user to have
a LUKS 1 or LUKS 2-protected fully-encrypted disk. The user then creates
a new LUKS key file, say by reading /dev/urandom into a file, and creates
a new LUKS key slot for this key. Then, the user invokes the grub-protect
tool to seal this key file to a set of PCRs using the system's TPM 2.0.
The resulting sealed key file is stored in an unencrypted partition such
as the EFI System Partition (ESP) so that GRUB may read it. The user also
has to ensure the cryptomount command is included in GRUB's boot script
and that it carries the requisite key protector (-P) parameter.

Sample usage:

  $ dd if=/dev/urandom of=luks-key bs=1 count=32
  $ sudo cryptsetup luksAddKey /dev/sdb1 luks-key --pbkdf=pbkdf2 --hash=sha512

To seal the key with TPM 2.0 Key File (recommended):

  $ sudo grub-protect --action=add \
                      --protector=tpm2 \
                      --tpm2-pcrs=0,2,4,7,9 \
                      --tpm2key \
                      --tpm2-keyfile=luks-key \
                      --tpm2-outfile=/boot/efi/efi/grub/sealed.tpm

Or, to seal the key with the raw sealed key:

  $ sudo grub-protect --action=add \
                      --protector=tpm2 \
                      --tpm2-pcrs=0,2,4,7,9 \
                      --tpm2-keyfile=luks-key \
                      --tpm2-outfile=/boot/efi/efi/grub/sealed.key

Then, in the boot script, for TPM 2.0 Key File:

  tpm2_key_protector_init --tpm2key=(hd0,gpt1)/efi/grub/sealed.tpm
  cryptomount -u <SDB1_UUID> -P tpm2

Or, for the raw sealed key:

  tpm2_key_protector_init --keyfile=(hd0,gpt1)/efi/grub/sealed.key --pcrs=0,2,4,7,9
  cryptomount -u <SDB1_UUID> -P tpm2

The benefit of using TPM 2.0 Key File is that the PCR set is already
written in the key file, so there is no need to specify PCRs when
invoking tpm2_key_protector_init.

Signed-off-by: Hernan Gatta <hegatta@linux.microsoft.com>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Tested-by: Stefan Berger <stefanb@linux.ibm.com>
8 months agocryptodisk: Support key protectors
Hernan Gatta [Fri, 15 Nov 2024 07:34:52 +0000 (15:34 +0800)] 
cryptodisk: Support key protectors

Add a new parameter to cryptomount to support the key protectors framework: -P.
The parameter is used to automatically retrieve a key from specified key
protectors. The parameter may be repeated to specify any number of key
protectors. These are tried in order until one provides a usable key for any
given disk.

Signed-off-by: Hernan Gatta <hegatta@linux.microsoft.com>
Signed-off-by: Michael Chang <mchang@suse.com>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Glenn Washburn <development@efficientek.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Tested-by: Stefan Berger <stefanb@linux.ibm.com>
8 months agokey_protector: Add TPM2 Key Protector
Hernan Gatta [Fri, 15 Nov 2024 07:34:51 +0000 (15:34 +0800)] 
key_protector: Add TPM2 Key Protector

The TPM2 key protector is a module that enables the automatic retrieval
of a fully-encrypted disk's unlocking key from a TPM 2.0.

The theory of operation is such that the module accepts various
arguments, most of which are optional and therefore possess reasonable
defaults. One of these arguments is the keyfile/tpm2key parameter, which
is mandatory. There are two supported key formats:

1. Raw Sealed Key (--keyfile)
   When sealing a key with TPM2_Create, the public portion of the sealed
   key is stored in TPM2B_PUBLIC, and the private portion is in
   TPM2B_PRIVATE. The raw sealed key glues the fully marshalled
   TPM2B_PUBLIC and TPM2B_PRIVATE into one file.

2. TPM 2.0 Key (--tpm2key)
   The following is the ASN.1 definition of TPM 2.0 Key File:

   TPMPolicy ::= SEQUENCE {
     CommandCode   [0] EXPLICIT INTEGER
     CommandPolicy [1] EXPLICIT OCTET STRING
   }

   TPMAuthPolicy ::= SEQUENCE {
     Name    [0] EXPLICIT UTF8STRING OPTIONAL
     Policy  [1] EXPLICIT SEQUENCE OF TPMPolicy
   }

   TPMKey ::= SEQUENCE {
     type        OBJECT IDENTIFIER
     emptyAuth   [0] EXPLICIT BOOLEAN OPTIONAL
     policy      [1] EXPLICIT SEQUENCE OF TPMPolicy OPTIONAL
     secret      [2] EXPLICIT OCTET STRING OPTIONAL
     authPolicy  [3] EXPLICIT SEQUENCE OF TPMAuthPolicy OPTIONAL
     description [4] EXPLICIT UTF8String OPTIONAL,
     rsaParent   [5] EXPLICIT BOOLEAN OPTIONAL,
     parent      INTEGER
     pubkey      OCTET STRING
     privkey     OCTET STRING
   }

  The TPM2 key protector only expects a "sealed" key in DER encoding,
  so "type" is always 2.23.133.10.1.5, "emptyAuth" is "TRUE", and
  "secret" is empty. "policy" and "authPolicy" are the possible policy
  command sequences to construct the policy digest to unseal the key.
  Similar to the raw sealed key, the public portion (TPM2B_PUBLIC) of
  the sealed key is stored in "pubkey", and the private portion
  (TPM2B_PRIVATE) is in "privkey".

  For more details: https://www.hansenpartnership.com/draft-bottomley-tpm2-keys.html

This sealed key file is created via the grub-protect tool. The tool
utilizes the TPM's sealing functionality to seal (i.e., encrypt) an
unlocking key using a Storage Root Key (SRK) to the values of various
Platform Configuration Registers (PCRs). These PCRs reflect the state
of the system as it boots. If the values are as expected, the system
may be considered trustworthy, at which point the TPM allows for a
caller to utilize the private component of the SRK to unseal (i.e.,
decrypt) the sealed key file. The caller, in this case, is this key
protector.

The TPM2 key protector registers two commands:

  - tpm2_key_protector_init: Initializes the state of the TPM2 key
                             protector for later usage, clearing any
                             previous state, too, if any.

  - tpm2_key_protector_clear: Clears any state set by tpm2_key_protector_init.

The way this is expected to be used requires the user to, either
interactively or, normally, via a boot script, initialize/configure
the key protector and then specify that it be used by the "cryptomount"
command (modifications to this command are in a different patch).

For instance, to unseal the raw sealed key file:

  tpm2_key_protector_init --keyfile=(hd0,gpt1)/efi/grub/sealed-1.key
  cryptomount -u <PART1_UUID> -P tpm2

  tpm2_key_protector_init --keyfile=(hd0,gpt1)/efi/grub/sealed-2.key --pcrs=7,11
  cryptomount -u <PART2_UUID> -P tpm2

Or, to unseal the TPM 2.0 Key file:

  tpm2_key_protector_init --tpm2key=(hd0,gpt1)/efi/grub/sealed-1.tpm
  cryptomount -u <PART1_UUID> -P tpm2

  tpm2_key_protector_init --tpm2key=(hd0,gpt1)/efi/grub/sealed-2.tpm --pcrs=7,11
  cryptomount -u <PART2_UUID> -P tpm2

If a user does not initialize the key protector and attempts to use it
anyway, the protector returns an error.

Before unsealing the key, the TPM2 key protector follows the "TPMPolicy"
sequences to enforce the TPM policy commands to construct a valid policy
digest to unseal the key.

For the TPM 2.0 Key files, "authPolicy" may contain multiple "TPMPolicy"
sequences, the TPM2 key protector iterates "authPolicy" to find a valid
sequence to unseal key. If "authPolicy" is empty or all sequences in
"authPolicy" fail, the protector tries the one from "policy". In case
"policy" is also empty, the protector creates a "TPMPolicy" sequence
based on the given PCR selection.

For the raw sealed key, the TPM2 key protector treats the key file as a
TPM 2.0 Key file without "authPolicy" and "policy", so the "TPMPolicy"
sequence is always based on the PCR selection from the command
parameters.

This commit only supports one policy command: TPM2_PolicyPCR. The
command set will be extended to support advanced features, such as
authorized policy, in the later commits.

Cc: James Bottomley <jejb@linux.ibm.com>
Signed-off-by: Hernan Gatta <hegatta@linux.microsoft.com>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Tested-by: Stefan Berger <stefanb@linux.ibm.com>
8 months agotss2: Add TPM2 Software Stack (TSS2) support
Gary Lin [Fri, 15 Nov 2024 07:34:50 +0000 (15:34 +0800)] 
tss2: Add TPM2 Software Stack (TSS2) support

A Trusted Platform Module (TPM) Software Stack (TSS) provides logic to
compose and submit TPM commands and parse responses.

A limited number of TPM commands may be accessed via the EFI TCG2
protocol. This protocol exposes functionality that is primarily geared
toward TPM usage within the context of Secure Boot. For all other TPM
commands, however, such as sealing and unsealing, this protocol does not
provide any help, with the exception of passthrough command submission.

The SubmitCommand method allows a caller to send raw commands to the
system's TPM and to receive the corresponding response. These
command/response pairs are formatted using the TPM wire protocol. To
construct commands in this way, and to parse the TPM's response, it is
necessary to, first, possess knowledge of the various TPM structures, and,
second, of the TPM wire protocol itself.

As such, this patch includes implementations of various grub_tpm2_* functions
(inventoried below), and logic to write and read command and response
buffers, respectively, using the TPM wire protocol.

Functions:
  - grub_tpm2_create(),
  - grub_tpm2_createprimary(),
  - grub_tpm2_evictcontrol(),
  - grub_tpm2_flushcontext(),
  - grub_tpm2_load(),
  - grub_tpm2_pcr_read(),
  - grub_tpm2_policygetdigest(),
  - grub_tpm2_policypcr(),
  - grub_tpm2_readpublic(),
  - grub_tpm2_startauthsession(),
  - grub_tpm2_unseal(),
  - grub_tpm2_loadexternal(),
  - grub_tpm2_hash(),
  - grub_tpm2_verifysignature(),
  - grub_tpm2_policyauthorize(),
  - grub_tpm2_testparms().

Signed-off-by: Hernan Gatta <hegatta@linux.microsoft.com>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Tested-by: Stefan Berger <stefanb@linux.ibm.com>
8 months agotss2: Add TPM2 types and Marshal/Unmarshal functions
Gary Lin [Fri, 15 Nov 2024 07:34:49 +0000 (15:34 +0800)] 
tss2: Add TPM2 types and Marshal/Unmarshal functions

This commit adds the necessary TPM2 types and structs as the preparation
for the TPM2 Software Stack (TSS2) support. The Marshal/Unmarshal
functions are also added to handle the data structure to be submitted to
TPM2 commands and to be received from the response.

Signed-off-by: Hernan Gatta <hegatta@linux.microsoft.com>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Tested-by: Stefan Berger <stefanb@linux.ibm.com>