diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c index 7841d6ce8..98729ba0e 100644 --- a/grub-core/loader/i386/linux.c +++ b/grub-core/loader/i386/linux.c @@ -787,9 +787,28 @@ 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); - grub_memcpy ((char *) &linux_params + sizeof (lh), kernel + kernel_offset, len); + /* 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) + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), + argv[0]); + goto fail; + } kernel_offset += len; linux_params.type_of_loader = GRUB_LINUX_BOOT_LOADER_TYPE; diff --git a/include/grub/i386/linux.h b/include/grub/i386/linux.h index 8f4cf0cd4..ce30e7fb0 100644 --- a/include/grub/i386/linux.h +++ b/include/grub/i386/linux.h @@ -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 \ @@ -274,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 */ @@ -312,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 */