]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
loader/i386/linux: Calculate the setup_header length
authorAndrew Jeddeloh <andrew.jeddeloh@coreos.com>
Fri, 29 Mar 2019 15:09:54 +0000 (16:09 +0100)
committerDaniel Kiper <daniel.kiper@oracle.com>
Tue, 2 Apr 2019 11:09:54 +0000 (13:09 +0200)
Previously the setup_header length was just assumed to be the size of the
linux_kernel_params struct. The linux x86 32-bit boot protocol says that the
end of the linux_i386_kernel_header is at 0x202 + the byte value at 0x201 in
the linux_i386_kernel_header. So, calculate the size of the header using the
end of the linux_i386_kernel_header, rather than assume it is the size of the
linux_kernel_params struct.

Additionally, add some required members to the linux_kernel_params
struct and align the content of linux_i386_kernel_header struct with
it. New members naming was taken directly from Linux kernel source.

linux_kernel_params and linux_i386_kernel_header structs require more
cleanup. However, this is not urgent, so, let's do this after release.
Just in case...

Signed-off-by: Andrew Jeddeloh <andrew.jeddeloh@coreos.com>
Signed-off-by: Daniel Kiper <daniel.kiper@oracle.com>
Reviewed-by: Vladimir Serbinenko <phcoder@google.com>
Reviewed-by: Ross Philipson <ross.philipson@oracle.com>
grub-core/loader/i386/linux.c
include/grub/i386/linux.h

index b6015913b2ae4a24437a2c0e5f1efa0c37f6885d..d0501e229571bca3e6d8fc0327afb603fd3ddb35 100644 (file)
@@ -767,7 +767,21 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
   linux_params.kernel_alignment = (1 << align);
   linux_params.ps_mouse = linux_params.padding10 =  0;
 
-  len = sizeof (linux_params) - sizeof (lh);
+  /*
+   * The Linux 32-bit boot protocol defines the setup header end
+   * to be at 0x202 + the byte value at 0x201.
+   */
+  len = 0x202 + *((char *) &linux_params.jump + 1);
+
+  /* Verify the struct is big enough so we do not write past the end. */
+  if (len > (char *) &linux_params.edd_mbr_sig_buffer - (char *) &linux_params) {
+    grub_error (GRUB_ERR_BAD_OS, "Linux setup header too big");
+    goto fail;
+  }
+
+  /* We've already read lh so there is no need to read it second time. */
+  len -= sizeof(lh);
+
   if (grub_file_read (file, (char *) &linux_params + sizeof (lh), len) != len)
     {
       if (!grub_errno)
index a960593119e5bcd20dd419f977c45be1919f8cc1..ce30e7fb01b924ec5ed8064bc691b9b349d24707 100644 (file)
@@ -46,6 +46,9 @@
 #define VIDEO_CAPABILITY_SKIP_QUIRKS   (1 << 0)
 #define VIDEO_CAPABILITY_64BIT_BASE    (1 << 1)        /* Frame buffer base is 64-bit. */
 
+/* Maximum number of MBR signatures to store. */
+#define EDD_MBR_SIG_MAX                        16
+
 #ifdef __x86_64__
 
 #define GRUB_LINUX_EFI_SIGNATURE       \
@@ -142,6 +145,7 @@ struct linux_i386_kernel_header
   grub_uint64_t setup_data;
   grub_uint64_t pref_address;
   grub_uint32_t init_size;
+  grub_uint32_t handover_offset;
 } GRUB_PACKED;
 
 /* Boot parameters for Linux based on 2.6.12. This is used by the setup
@@ -273,6 +277,7 @@ struct linux_kernel_params
 
   grub_uint8_t padding9[0x1f1 - 0x1e9];
 
+  /* Linux setup header copy - BEGIN. */
   grub_uint8_t setup_sects;            /* The size of the setup in sectors */
   grub_uint16_t root_flags;            /* If the root is mounted readonly */
   grub_uint16_t syssize;               /* obsolete */
@@ -311,9 +316,14 @@ struct linux_kernel_params
   grub_uint32_t payload_offset;
   grub_uint32_t payload_length;
   grub_uint64_t setup_data;
-  grub_uint8_t pad2[120];              /* 258 */
-  struct grub_e820_mmap e820_map[(0x400 - 0x2d0) / 20];        /* 2d0 */
+  grub_uint64_t pref_address;
+  grub_uint32_t init_size;
+  grub_uint32_t handover_offset;
+  /* Linux setup header copy - END. */
 
+  grub_uint8_t _pad7[40];
+  grub_uint32_t edd_mbr_sig_buffer[EDD_MBR_SIG_MAX];   /* 290 */
+  struct grub_e820_mmap e820_map[(0x400 - 0x2d0) / 20];        /* 2d0 */
 } GRUB_PACKED;
 #endif /* ! ASM_FILE */