one patch, on grub-2.02

This commit is contained in:
Vincent Batts 2020-10-29 15:33:00 -04:00
parent e54c99aaff
commit 518e65a341
70 changed files with 5169 additions and 103 deletions

View file

@ -92,6 +92,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/term.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/time.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/mm_private.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/net.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/tpm.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/memory.h
if COND_i386_pc

View file

@ -126,6 +126,7 @@ kernel = {
common = kern/rescue_parser.c;
common = kern/rescue_reader.c;
common = kern/term.c;
common = kern/tpm.c;
noemu = kern/compiler-rt.c;
noemu = kern/mm.c;
@ -173,6 +174,7 @@ kernel = {
efi = term/efi/console.c;
efi = kern/acpi.c;
efi = kern/efi/acpi.c;
efi = kern/efi/tpm.c;
i386_coreboot = kern/i386/pc/acpi.c;
i386_multiboot = kern/i386/pc/acpi.c;
i386_coreboot = kern/acpi.c;
@ -219,6 +221,7 @@ kernel = {
i386_pc = kern/i386/pc/init.c;
i386_pc = kern/i386/pc/mmap.c;
i386_pc = kern/i386/pc/tpm.c;
i386_pc = term/i386/pc/console.c;
i386_qemu = bus/pci.c;
@ -816,11 +819,32 @@ module = {
enable = x86_64_efi;
};
module = {
name = getenv;
common = commands/efi/getenv.c;
enable = efi;
};
module = {
name = gptsync;
common = commands/gptsync.c;
};
module = {
name = gptrepair;
common = commands/gptrepair.c;
};
module = {
name = gptprio;
common = commands/gptprio.c;
};
module = {
name = gpt;
common = lib/gpt.c;
};
module = {
name = halt;
nopc = commands/halt.c;
@ -998,6 +1022,21 @@ module = {
common = commands/search_label.c;
};
module = {
name = search_part_uuid;
common = commands/search_part_uuid.c;
};
module = {
name = search_part_label;
common = commands/search_part_label.c;
};
module = {
name = search_disk_uuid;
common = commands/search_disk_uuid.c;
};
module = {
name = setpci;
common = commands/setpci.c;
@ -1015,6 +1054,21 @@ module = {
common = commands/sleep.c;
};
module = {
name = smbios;
common = commands/smbios.c;
efi = commands/efi/smbios.c;
i386_pc = commands/i386/pc/smbios.c;
i386_coreboot = commands/i386/pc/smbios.c;
i386_multiboot = commands/i386/pc/smbios.c;
enable = efi;
enable = i386_pc;
enable = i386_coreboot;
enable = i386_multiboot;
};
module = {
name = suspend;
ieee1275 = commands/ieee1275/suspend.c;
@ -1733,6 +1787,14 @@ module = {
enable = x86_64_efi;
};
module = {
name = linuxefi;
efi = loader/i386/efi/linux.c;
efi = lib/cmdline.c;
enable = i386_efi;
enable = x86_64_efi;
};
module = {
name = chain;
efi = loader/efi/chainloader.c;
@ -2355,3 +2417,9 @@ module = {
common = loader/i386/xen_file64.c;
extra_dist = loader/i386/xen_fileXX.c;
};
module = {
name = fwconfig;
common = commands/fwconfig.c;
enable = x86;
};

View file

@ -24,11 +24,14 @@
* defines for the code go here
*/
#define TPM 1
/* Print message string */
#define MSG(x) movw $x, %si; call LOCAL(message)
#define ERR(x) movw $x, %si; jmp LOCAL(error_message)
.macro floppy
#ifndef TPM
part_start:
LOCAL(probe_values):
@ -85,6 +88,7 @@ fd_probe_error_string: .asciz "Floppy"
movb MACRO_DOLLAR(79), %ch
jmp LOCAL(final_init)
#endif
.endm
.macro scratch
@ -255,6 +259,7 @@ real_start:
/* set %si to the disk address packet */
movw $disk_address_packet, %si
#ifndef TPM
/* check if LBA is supported */
movb $0x41, %ah
movw $0x55aa, %bx
@ -274,6 +279,7 @@ real_start:
andw $1, %cx
jz LOCAL(chs_mode)
#endif
LOCAL(lba_mode):
xorw %ax, %ax
@ -317,6 +323,9 @@ LOCAL(lba_mode):
jmp LOCAL(copy_buffer)
LOCAL(chs_mode):
#ifdef TPM
jmp LOCAL(general_error)
#else
/*
* Determine the hard disk geometry from the BIOS!
* We do this first, so that LS-120 IDE floppies work correctly.
@ -428,7 +437,7 @@ setup_sectors:
jc LOCAL(read_error)
movw %es, %bx
#endif /* TPM */
LOCAL(copy_buffer):
/*
* We need to save %cx and %si because the startup code in
@ -451,6 +460,25 @@ LOCAL(copy_buffer):
popw %ds
popa
#ifdef TPM
pusha
movw $0xBB00, %ax /* TCG_StatusCheck */
int $0x1A
test %eax, %eax
jnz boot /* No TPM or TPM deactivated */
movw $0xBB07, %ax /* TCG_CompactHashLogExtendEvent */
movw $GRUB_BOOT_MACHINE_KERNEL_ADDR, %di
xorl %esi, %esi
movl $0x41504354, %ebx /* TCPA */
movl $0x200, %ecx /* Measure 512 bytes */
movl $0x8, %edx /* PCR 8 */
int $0x1A
boot:
popa
#endif
/* boot kernel */
jmp *(LOCAL(kernel_address))

View file

@ -19,6 +19,8 @@
#include <grub/symbol.h>
#include <grub/machine/boot.h>
#define TPM 1
/*
* defines for the code go here
*/
@ -58,6 +60,21 @@ _start:
/* this sets up for the first run through "bootloop" */
movw $LOCAL(firstlist), %di
#ifdef TPM
/* clear EAX to remove potential garbage */
xorl %eax, %eax
/* 8(%di) = number of sectors to read */
movw 8(%di), %ax
/* Multiply number of sectors to read with 512 bytes. EAX is 32bit
* which is large enough to hold values of up to 4GB. I doubt there
* will ever be a core.img larger than that. ;-) */
shll $9, %eax
/* write result to bytes_to_measure var */
movl %eax, bytes_to_measure
#endif
/* save the sector number of the second sector in %ebp */
movl (%di), %ebp
@ -295,6 +312,29 @@ LOCAL(copy_buffer):
/* END OF MAIN LOOP */
LOCAL(bootit):
#ifdef TPM
pusha
movw $0xBB07, %ax /* TCG_CompactHashLogExtendEvent */
movw $0x0, %bx
movw %bx, %es
/* We've already measured the first 512 bytes, now measure the rest */
xorl %edi, %edi
movw $(GRUB_BOOT_MACHINE_KERNEL_ADDR + 0x200), %di
movl $0x41504354, %ebx /* EBX = "TCPA" */
/* %ecx = The length, in bytes, of the buffer to measure */
movl $bytes_to_measure, %esi
movl (%esi), %ecx
xorl %esi, %esi
movl $0x9, %edx /* PCR 9 */
int $0x1A
popa
#endif
/* print a newline */
MSG(notification_done)
popw %dx /* this makes sure %dl is our "boot" drive */
@ -329,6 +369,10 @@ geometry_error_string: .asciz "Geom"
read_error_string: .asciz "Read"
general_error_string: .asciz " Error"
#ifdef TPM
bytes_to_measure: .long 0
#endif
/*
* message: write the string pointed to by %si
*

View file

@ -0,0 +1,153 @@
/* getenv.c - retrieve EFI variables. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2009 Free Software Foundation, Inc.
* Copyright (C) 2014 CoreOS, 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 <grub/efi/efi.h>
#include <grub/dl.h>
#include <grub/env.h>
#include <grub/err.h>
#include <grub/extcmd.h>
#include <grub/i18n.h>
#include <grub/misc.h>
#include <grub/mm.h>
GRUB_MOD_LICENSE ("GPLv3+");
static const struct grub_arg_option options_getenv[] = {
{"var-name", 'e', 0,
N_("Environment variable to query"),
N_("VARNAME"), ARG_TYPE_STRING},
{"var-guid", 'g', 0,
N_("GUID of environment variable to query"),
N_("GUID"), ARG_TYPE_STRING},
{"binary", 'b', 0,
N_("Read binary data and represent it as hex"),
0, ARG_TYPE_NONE},
{0, 0, 0, 0, 0, 0}
};
enum options_getenv
{
GETENV_VAR_NAME,
GETENV_VAR_GUID,
GETENV_BINARY,
};
static grub_err_t
grub_cmd_getenv (grub_extcmd_context_t ctxt, int argc, char **args)
{
struct grub_arg_list *state = ctxt->state;
char *envvar = NULL, *guid = NULL, *bindata = NULL, *data = NULL;
grub_size_t datasize;
grub_efi_guid_t efi_var_guid;
grub_efi_boolean_t binary = state[GETENV_BINARY].set;
unsigned int i;
if (!state[GETENV_VAR_NAME].set || !state[GETENV_VAR_GUID].set)
{
grub_error (GRUB_ERR_INVALID_COMMAND, N_("-e and -g are required"));
goto done;
}
if (argc != 1)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unexpected arguments"));
goto done;
}
envvar = state[GETENV_VAR_NAME].arg;
guid = state[GETENV_VAR_GUID].arg;
if (grub_strlen(guid) != 36 ||
guid[8] != '-' ||
guid[13] != '-' ||
guid[18] != '-' ||
guid[23] != '-')
{
grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid GUID"));
goto done;
}
/* Forgive me father for I have sinned */
guid[8] = 0;
efi_var_guid.data1 = grub_strtoul(guid, NULL, 16);
guid[13] = 0;
efi_var_guid.data2 = grub_strtoul(guid + 9, NULL, 16);
guid[18] = 0;
efi_var_guid.data3 = grub_strtoul(guid + 14, NULL, 16);
efi_var_guid.data4[7] = grub_strtoul(guid + 34, NULL, 16);
guid[34] = 0;
efi_var_guid.data4[6] = grub_strtoul(guid + 32, NULL, 16);
guid[32] = 0;
efi_var_guid.data4[5] = grub_strtoul(guid + 30, NULL, 16);
guid[30] = 0;
efi_var_guid.data4[4] = grub_strtoul(guid + 28, NULL, 16);
guid[28] = 0;
efi_var_guid.data4[3] = grub_strtoul(guid + 26, NULL, 16);
guid[26] = 0;
efi_var_guid.data4[2] = grub_strtoul(guid + 24, NULL, 16);
guid[23] = 0;
efi_var_guid.data4[1] = grub_strtoul(guid + 21, NULL, 16);
guid[21] = 0;
efi_var_guid.data4[0] = grub_strtoul(guid + 19, NULL, 16);
data = grub_efi_get_variable(envvar, &efi_var_guid, &datasize);
if (!data || !datasize)
{
grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("No such variable"));
goto done;
}
if (binary)
{
bindata = grub_zalloc(datasize * 2 + 1);
for (i=0; i<datasize; i++)
grub_snprintf(bindata + i*2, 3, "%02x", data[i] & 0xff);
if (grub_env_set (args[0], bindata))
goto done;
}
else if (grub_env_set (args[0], data))
{
goto done;
}
grub_errno = GRUB_ERR_NONE;
done:
grub_free(bindata);
grub_free(data);
return grub_errno;
}
static grub_extcmd_t cmd_getenv;
GRUB_MOD_INIT(getenv)
{
cmd_getenv = grub_register_extcmd ("getenv", grub_cmd_getenv, 0,
N_("-e envvar -g guidenv setvar"),
N_("Read a firmware environment variable"),
options_getenv);
}
GRUB_MOD_FINI(getenv)
{
grub_unregister_extcmd (cmd_getenv);
}

View file

@ -30,6 +30,7 @@ GRUB_MOD_LICENSE ("GPLv3+");
static grub_efi_guid_t acpi_guid = GRUB_EFI_ACPI_TABLE_GUID;
static grub_efi_guid_t acpi2_guid = GRUB_EFI_ACPI_20_TABLE_GUID;
static grub_efi_guid_t smbios_guid = GRUB_EFI_SMBIOS_TABLE_GUID;
static grub_efi_guid_t smbios3_guid = GRUB_EFI_SMBIOS3_TABLE_GUID;
#define EBDA_SEG_ADDR 0x40e
#define LOW_MEM_ADDR 0x413
@ -93,7 +94,7 @@ static void
fake_bios_data (int use_rom)
{
unsigned i;
void *acpi, *smbios;
void *acpi, *smbios, *smbios3;
grub_uint16_t *ebda_seg_ptr, *low_mem_ptr;
ebda_seg_ptr = (grub_uint16_t *) EBDA_SEG_ADDR;
@ -103,6 +104,7 @@ fake_bios_data (int use_rom)
acpi = 0;
smbios = 0;
smbios3 = 0;
for (i = 0; i < grub_efi_system_table->num_table_entries; i++)
{
grub_efi_packed_guid_t *guid =
@ -127,6 +129,11 @@ fake_bios_data (int use_rom)
smbios = grub_efi_system_table->configuration_table[i].vendor_table;
grub_dprintf ("efi", "SMBIOS: %p\n", smbios);
}
else if (! grub_memcmp (guid, &smbios3_guid, sizeof (grub_efi_guid_t)))
{
smbios3 = grub_efi_system_table->configuration_table[i].vendor_table;
grub_dprintf ("efi", "SMBIOS3: %p\n", smbios3);
}
}
*ebda_seg_ptr = FAKE_EBDA_SEG;
@ -137,8 +144,13 @@ fake_bios_data (int use_rom)
if (acpi)
grub_memcpy ((char *) ((FAKE_EBDA_SEG << 4) + 16), acpi, 1024 - 16);
if ((use_rom) && (smbios))
grub_memcpy ((char *) SBIOS_ADDR, (char *) smbios + 16, 16);
if (use_rom)
{
if (smbios)
grub_memcpy ((char *) SBIOS_ADDR, (char *) smbios, 31);
if (smbios3)
grub_memcpy ((char *) SBIOS_ADDR + 32, (char *) smbios3, 24);
}
}
static grub_err_t

View file

@ -48,6 +48,7 @@ static const struct guid_mapping guid_mappings[] =
{ GRUB_EFI_MPS_TABLE_GUID, "MPS"},
{ GRUB_EFI_SAL_TABLE_GUID, "SAL"},
{ GRUB_EFI_SMBIOS_TABLE_GUID, "SMBIOS"},
{ GRUB_EFI_SMBIOS3_TABLE_GUID, "SMBIOS3"},
{ GRUB_EFI_SYSTEM_RESOURCE_TABLE_GUID, "SYSTEM RESOURCE TABLE"},
{ GRUB_EFI_TIANO_CUSTOM_DECOMPRESS_GUID, "TIANO CUSTOM DECOMPRESS"},
{ GRUB_EFI_TSC_FREQUENCY_GUID, "TSC FREQUENCY"},

View file

@ -0,0 +1,59 @@
/* smbios.c - get smbios tables. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2015 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 <grub/smbios.h>
#include <grub/misc.h>
#include <grub/efi/efi.h>
#include <grub/efi/api.h>
struct grub_smbios_eps *
grub_machine_smbios_get_eps (void)
{
unsigned i;
static grub_efi_packed_guid_t smbios_guid = GRUB_EFI_SMBIOS_TABLE_GUID;
for (i = 0; i < grub_efi_system_table->num_table_entries; i++)
{
grub_efi_packed_guid_t *guid =
&grub_efi_system_table->configuration_table[i].vendor_guid;
if (! grub_memcmp (guid, &smbios_guid, sizeof (grub_efi_packed_guid_t)))
return (struct grub_smbios_eps *)
grub_efi_system_table->configuration_table[i].vendor_table;
}
return 0;
}
struct grub_smbios_eps3 *
grub_machine_smbios_get_eps3 (void)
{
unsigned i;
static grub_efi_packed_guid_t smbios3_guid = GRUB_EFI_SMBIOS3_TABLE_GUID;
for (i = 0; i < grub_efi_system_table->num_table_entries; i++)
{
grub_efi_packed_guid_t *guid =
&grub_efi_system_table->configuration_table[i].vendor_guid;
if (! grub_memcmp (guid, &smbios3_guid, sizeof (grub_efi_packed_guid_t)))
return (struct grub_smbios_eps3 *)
grub_efi_system_table->configuration_table[i].vendor_table;
}
return 0;
}

View file

@ -0,0 +1,122 @@
/* fwconfig.c - command to read config from qemu fwconfig */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2015 CoreOS, 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 <grub/dl.h>
#include <grub/misc.h>
#include <grub/extcmd.h>
#include <grub/env.h>
#include <grub/cpu/io.h>
#include <grub/i18n.h>
#include <grub/mm.h>
GRUB_MOD_LICENSE ("GPLv3+");
#define SELECTOR 0x510
#define DATA 0x511
#define SIGNATURE_INDEX 0x00
#define DIRECTORY_INDEX 0x19
static grub_extcmd_t cmd_read_fwconfig;
struct grub_qemu_fwcfgfile {
grub_uint32_t size;
grub_uint16_t select;
grub_uint16_t reserved;
char name[56];
};
static const struct grub_arg_option options[] =
{
{0, 'v', 0, N_("Save read value into variable VARNAME."),
N_("VARNAME"), ARG_TYPE_STRING},
{0, 0, 0, 0, 0, 0}
};
static grub_err_t
grub_cmd_fwconfig (grub_extcmd_context_t ctxt __attribute__ ((unused)),
int argc, char **argv)
{
grub_uint32_t i, j, value = 0;
struct grub_qemu_fwcfgfile file;
char fwsig[4], signature[4] = { 'Q', 'E', 'M', 'U' };
if (argc != 2)
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("two arguments expected"));
/* Verify that we have meaningful hardware here */
grub_outw(SIGNATURE_INDEX, SELECTOR);
for (i=0; i<sizeof(fwsig); i++)
fwsig[i] = grub_inb(DATA);
if (grub_memcmp(fwsig, signature, sizeof(signature)) != 0)
return grub_error (GRUB_ERR_BAD_DEVICE, N_("invalid fwconfig hardware signature: got 0x%x%x%x%x"), fwsig[0], fwsig[1], fwsig[2], fwsig[3]);
/* Find out how many file entries we have */
grub_outw(DIRECTORY_INDEX, SELECTOR);
value = grub_inb(DATA) | grub_inb(DATA) << 8 | grub_inb(DATA) << 16 | grub_inb(DATA) << 24;
value = grub_be_to_cpu32(value);
/* Read the file description for each file */
for (i=0; i<value; i++)
{
for (j=0; j<sizeof(file); j++)
{
((char *)&file)[j] = grub_inb(DATA);
}
/* Check whether it matches what we're looking for, and if so read the file */
if (grub_strncmp(file.name, argv[0], sizeof(file.name)) == 0)
{
grub_uint32_t filesize = grub_be_to_cpu32(file.size);
grub_uint16_t location = grub_be_to_cpu16(file.select);
char *data = grub_malloc(filesize+1);
if (!data)
return grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate buffer for data"));
grub_outw(location, SELECTOR);
for (j=0; j<filesize; j++)
{
data[j] = grub_inb(DATA);
}
data[filesize] = '\0';
grub_env_set (argv[1], data);
grub_free(data);
return 0;
}
}
return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("couldn't find entry %s"), argv[0]);
}
GRUB_MOD_INIT(fwconfig)
{
cmd_read_fwconfig =
grub_register_extcmd ("fwconfig", grub_cmd_fwconfig, 0,
N_("PATH VAR"),
N_("Set VAR to the contents of fwconfig PATH"),
options);
}
GRUB_MOD_FINI(fwconfig)
{
grub_unregister_extcmd (cmd_read_fwconfig);
}

View file

@ -0,0 +1,223 @@
/* gptprio.c - manage priority based partition selection. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2009 Free Software Foundation, Inc.
* Copyright (C) 2014 CoreOS, 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 <grub/device.h>
#include <grub/env.h>
#include <grub/err.h>
#include <grub/extcmd.h>
#include <grub/gpt_partition.h>
#include <grub/i18n.h>
#include <grub/misc.h>
GRUB_MOD_LICENSE ("GPLv3+");
static const struct grub_arg_option options_next[] = {
{"set-device", 'd', 0,
N_("Set a variable to the name of selected partition."),
N_("VARNAME"), ARG_TYPE_STRING},
{"set-uuid", 'u', 0,
N_("Set a variable to the GPT UUID of selected partition."),
N_("VARNAME"), ARG_TYPE_STRING},
{0, 0, 0, 0, 0, 0}
};
enum options_next
{
NEXT_SET_DEVICE,
NEXT_SET_UUID,
};
static unsigned int
grub_gptprio_priority (struct grub_gpt_partentry *entry)
{
return (unsigned int) grub_gpt_entry_attribute
(entry, GRUB_GPT_PART_ATTR_OFFSET_GPTPRIO_PRIORITY, 4);
}
static unsigned int
grub_gptprio_tries_left (struct grub_gpt_partentry *entry)
{
return (unsigned int) grub_gpt_entry_attribute
(entry, GRUB_GPT_PART_ATTR_OFFSET_GPTPRIO_TRIES_LEFT, 4);
}
static void
grub_gptprio_set_tries_left (struct grub_gpt_partentry *entry,
unsigned int tries_left)
{
grub_gpt_entry_set_attribute
(entry, tries_left, GRUB_GPT_PART_ATTR_OFFSET_GPTPRIO_TRIES_LEFT, 4);
}
static unsigned int
grub_gptprio_successful (struct grub_gpt_partentry *entry)
{
return (unsigned int) grub_gpt_entry_attribute
(entry, GRUB_GPT_PART_ATTR_OFFSET_GPTPRIO_SUCCESSFUL, 1);
}
static grub_err_t
grub_find_next (const char *disk_name,
const grub_gpt_part_type_t *part_type,
char **part_name, char **part_guid)
{
struct grub_gpt_partentry *part, *part_found = NULL;
grub_device_t dev = NULL;
grub_gpt_t gpt = NULL;
grub_uint32_t i, part_index;
dev = grub_device_open (disk_name);
if (!dev)
goto done;
gpt = grub_gpt_read (dev->disk);
if (!gpt)
goto done;
if (grub_gpt_repair (dev->disk, gpt))
goto done;
for (i = 0; (part = grub_gpt_get_partentry (gpt, i)) != NULL; i++)
{
if (grub_memcmp (part_type, &part->type, sizeof (*part_type)) == 0)
{
unsigned int priority, tries_left, successful, old_priority = 0;
priority = grub_gptprio_priority (part);
tries_left = grub_gptprio_tries_left (part);
successful = grub_gptprio_successful (part);
if (part_found)
old_priority = grub_gptprio_priority (part_found);
if ((tries_left || successful) && priority > old_priority)
{
part_index = i;
part_found = part;
}
}
}
if (!part_found)
{
grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("no such partition"));
goto done;
}
if (grub_gptprio_tries_left (part_found))
{
unsigned int tries_left = grub_gptprio_tries_left (part_found);
grub_gptprio_set_tries_left (part_found, tries_left - 1);
if (grub_gpt_update (gpt))
goto done;
if (grub_gpt_write (dev->disk, gpt))
goto done;
}
*part_name = grub_xasprintf ("%s,gpt%u", disk_name, part_index + 1);
if (!*part_name)
goto done;
*part_guid = grub_gpt_guid_to_str (&part_found->guid);
if (!*part_guid)
goto done;
grub_errno = GRUB_ERR_NONE;
done:
grub_gpt_free (gpt);
if (dev)
grub_device_close (dev);
return grub_errno;
}
static grub_err_t
grub_cmd_next (grub_extcmd_context_t ctxt, int argc, char **args)
{
struct grub_arg_list *state = ctxt->state;
char *p, *root = NULL, *part_name = NULL, *part_guid = NULL;
/* TODO: Add a uuid parser and a command line flag for providing type. */
grub_gpt_part_type_t part_type = GRUB_GPT_PARTITION_TYPE_USR_X86_64;
if (!state[NEXT_SET_DEVICE].set || !state[NEXT_SET_UUID].set)
{
grub_error (GRUB_ERR_INVALID_COMMAND, N_("-d and -u are required"));
goto done;
}
if (argc == 0)
root = grub_strdup (grub_env_get ("root"));
else if (argc == 1)
root = grub_strdup (args[0]);
else
{
grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unexpected arguments"));
goto done;
}
if (!root)
goto done;
/* To make using $root practical strip off the partition name. */
p = grub_strchr (root, ',');
if (p)
*p = '\0';
if (grub_find_next (root, &part_type, &part_name, &part_guid))
goto done;
if (grub_env_set (state[NEXT_SET_DEVICE].arg, part_name))
goto done;
if (grub_env_set (state[NEXT_SET_UUID].arg, part_guid))
goto done;
grub_errno = GRUB_ERR_NONE;
done:
grub_free (root);
grub_free (part_name);
grub_free (part_guid);
return grub_errno;
}
static grub_extcmd_t cmd_next;
GRUB_MOD_INIT(gptprio)
{
cmd_next = grub_register_extcmd ("gptprio.next", grub_cmd_next, 0,
N_("-d VARNAME -u VARNAME [DEVICE]"),
N_("Select next partition to boot."),
options_next);
}
GRUB_MOD_FINI(gptprio)
{
grub_unregister_extcmd (cmd_next);
}

View file

@ -0,0 +1,110 @@
/* gptrepair.c - verify and restore GPT info from alternate location. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2009 Free Software Foundation, Inc.
* Copyright (C) 2014 CoreOS, 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 <grub/command.h>
#include <grub/device.h>
#include <grub/err.h>
#include <grub/gpt_partition.h>
#include <grub/i18n.h>
#include <grub/misc.h>
GRUB_MOD_LICENSE ("GPLv3+");
static char *
trim_dev_name (char *name)
{
grub_size_t len = grub_strlen (name);
if (len && name[0] == '(' && name[len - 1] == ')')
{
name[len - 1] = '\0';
name = name + 1;
}
return name;
}
static grub_err_t
grub_cmd_gptrepair (grub_command_t cmd __attribute__ ((unused)),
int argc, char **args)
{
grub_device_t dev = NULL;
grub_gpt_t gpt = NULL;
char *dev_name;
if (argc != 1 || !grub_strlen(args[0]))
return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required");
dev_name = trim_dev_name (args[0]);
dev = grub_device_open (dev_name);
if (!dev)
goto done;
if (!dev->disk)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, "not a disk");
goto done;
}
gpt = grub_gpt_read (dev->disk);
if (!gpt)
goto done;
if (grub_gpt_both_valid (gpt))
{
grub_printf_ (N_("GPT already valid, %s unmodified.\n"), dev_name);
goto done;
}
if (!grub_gpt_primary_valid (gpt))
grub_printf_ (N_("Found invalid primary GPT on %s\n"), dev_name);
if (!grub_gpt_backup_valid (gpt))
grub_printf_ (N_("Found invalid backup GPT on %s\n"), dev_name);
if (grub_gpt_repair (dev->disk, gpt))
goto done;
if (grub_gpt_write (dev->disk, gpt))
goto done;
grub_printf_ (N_("Repaired GPT on %s\n"), dev_name);
done:
if (gpt)
grub_gpt_free (gpt);
if (dev)
grub_device_close (dev);
return grub_errno;
}
static grub_command_t cmd;
GRUB_MOD_INIT(gptrepair)
{
cmd = grub_register_command ("gptrepair", grub_cmd_gptrepair,
N_("DEVICE"),
N_("Verify and repair GPT on drive DEVICE."));
}
GRUB_MOD_FINI(gptrepair)
{
grub_unregister_command (cmd);
}

View file

@ -0,0 +1,50 @@
/* smbios.c - get smbios tables. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2015 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 <grub/acpi.h>
#include <grub/smbios.h>
#include <grub/misc.h>
struct grub_smbios_eps *
grub_machine_smbios_get_eps (void)
{
grub_uint8_t *ptr;
grub_dprintf ("smbios", "Looking for SMBIOS EPS. Scanning BIOS\n");
for (ptr = (grub_uint8_t *) 0xf0000; ptr < (grub_uint8_t *) 0x100000;
ptr += 16)
if (grub_memcmp (ptr, "_SM_", 4) == 0
&& grub_byte_checksum (ptr, sizeof (struct grub_smbios_eps)) == 0)
return (struct grub_smbios_eps *) ptr;
return 0;
}
struct grub_smbios_eps3 *
grub_machine_smbios_get_eps3 (void)
{
grub_uint8_t *ptr;
grub_dprintf ("smbios", "Looking for SMBIOS3 EPS. Scanning BIOS\n");
for (ptr = (grub_uint8_t *) 0xf0000; ptr < (grub_uint8_t *) 0x100000;
ptr += 16)
if (grub_memcmp (ptr, "_SM3_", 5) == 0
&& grub_byte_checksum (ptr, sizeof (struct grub_smbios_eps3)) == 0)
return (struct grub_smbios_eps3 *) ptr;
return 0;
}

View file

@ -30,6 +30,10 @@
#include <grub/i18n.h>
#include <grub/disk.h>
#include <grub/partition.h>
#if defined(DO_SEARCH_PART_UUID) || defined(DO_SEARCH_PART_LABEL) || \
defined(DO_SEARCH_DISK_UUID)
#include <grub/gpt_partition.h>
#endif
GRUB_MOD_LICENSE ("GPLv3+");
@ -66,7 +70,7 @@ iterate_device (const char *name, void *data)
name[0] == 'f' && name[1] == 'd' && name[2] >= '0' && name[2] <= '9')
return 1;
#ifdef DO_SEARCH_FS_UUID
#if defined(DO_SEARCH_FS_UUID) || defined(DO_SEARCH_DISK_UUID)
#define compare_fn grub_strcasecmp
#else
#define compare_fn grub_strcmp
@ -90,6 +94,63 @@ iterate_device (const char *name, void *data)
}
grub_free (buf);
}
#elif defined(DO_SEARCH_PART_UUID)
{
grub_device_t dev;
char *quid;
dev = grub_device_open (name);
if (dev)
{
if (grub_gpt_part_uuid (dev, &quid) == GRUB_ERR_NONE)
{
if (grub_strcasecmp (quid, ctx->key) == 0)
found = 1;
grub_free (quid);
}
grub_device_close (dev);
}
}
#elif defined(DO_SEARCH_PART_LABEL)
{
grub_device_t dev;
char *quid;
dev = grub_device_open (name);
if (dev)
{
if (grub_gpt_part_label (dev, &quid) == GRUB_ERR_NONE)
{
if (grub_strcmp (quid, ctx->key) == 0)
found = 1;
grub_free (quid);
}
grub_device_close (dev);
}
}
#elif defined(DO_SEARCH_DISK_UUID)
{
grub_device_t dev;
char *quid;
dev = grub_device_open (name);
if (dev)
{
if (grub_gpt_disk_uuid (dev, &quid) == GRUB_ERR_NONE)
{
if (grub_strcmp (quid, ctx->key) == 0)
found = 1;
grub_free (quid);
}
grub_device_close (dev);
}
}
#else
{
/* SEARCH_FS_UUID or SEARCH_LABEL */
@ -313,8 +374,14 @@ static grub_command_t cmd;
#ifdef DO_SEARCH_FILE
GRUB_MOD_INIT(search_fs_file)
#elif defined(DO_SEARCH_PART_UUID)
GRUB_MOD_INIT(search_part_uuid)
#elif defined(DO_SEARCH_PART_LABEL)
GRUB_MOD_INIT(search_part_label)
#elif defined (DO_SEARCH_FS_UUID)
GRUB_MOD_INIT(search_fs_uuid)
#elif defined (DO_SEARCH_DISK_UUID)
GRUB_MOD_INIT(search_disk_uuid)
#else
GRUB_MOD_INIT(search_label)
#endif
@ -327,8 +394,14 @@ GRUB_MOD_INIT(search_label)
#ifdef DO_SEARCH_FILE
GRUB_MOD_FINI(search_fs_file)
#elif defined(DO_SEARCH_PART_UUID)
GRUB_MOD_FINI(search_part_uuid)
#elif defined(DO_SEARCH_PART_LABEL)
GRUB_MOD_FINI(search_part_label)
#elif defined (DO_SEARCH_FS_UUID)
GRUB_MOD_FINI(search_fs_uuid)
#elif defined (DO_SEARCH_DISK_UUID)
GRUB_MOD_FINI(search_disk_uuid)
#else
GRUB_MOD_FINI(search_label)
#endif

View file

@ -0,0 +1,5 @@
#define DO_SEARCH_DISK_UUID 1
#define FUNC_NAME grub_search_disk_uuid
#define COMMAND_NAME "search.disk_uuid"
#define HELP_MESSAGE N_("Search devices by disk UUID. If VARIABLE is specified, the first device found is set to a variable.")
#include "search.c"

View file

@ -0,0 +1,5 @@
#define DO_SEARCH_PART_LABEL 1
#define FUNC_NAME grub_search_part_label
#define COMMAND_NAME "search.part_label"
#define HELP_MESSAGE N_("Search devices by partition label. If VARIABLE is specified, the first device found is set to a variable.")
#include "search.c"

View file

@ -0,0 +1,5 @@
#define DO_SEARCH_PART_UUID 1
#define FUNC_NAME grub_search_part_uuid
#define COMMAND_NAME "search.part_uuid"
#define HELP_MESSAGE N_("Search devices by partition UUID. If VARIABLE is specified, the first device found is set to a variable.")
#include "search.c"

View file

@ -36,6 +36,12 @@ static const struct grub_arg_option options[] =
0, 0},
{"fs-uuid", 'u', 0, N_("Search devices by a filesystem UUID."),
0, 0},
{"part-label", 'L', 0, N_("Search devices by a partition label."),
0, 0},
{"part-uuid", 'U', 0, N_("Search devices by a partition UUID."),
0, 0},
{"disk-uuid", 'U', 0, N_("Search devices by a disk UUID."),
0, 0},
{"set", 's', GRUB_ARG_OPTION_OPTIONAL,
N_("Set a variable to the first device found."), N_("VARNAME"),
ARG_TYPE_STRING},
@ -71,6 +77,9 @@ enum options
SEARCH_FILE,
SEARCH_LABEL,
SEARCH_FS_UUID,
SEARCH_PART_LABEL,
SEARCH_PART_UUID,
SEARCH_DISK_UUID,
SEARCH_SET,
SEARCH_NO_FLOPPY,
SEARCH_HINT,
@ -186,6 +195,15 @@ grub_cmd_search (grub_extcmd_context_t ctxt, int argc, char **args)
else if (state[SEARCH_FS_UUID].set)
grub_search_fs_uuid (id, var, state[SEARCH_NO_FLOPPY].set,
hints, nhints);
else if (state[SEARCH_PART_LABEL].set)
grub_search_part_label (id, var, state[SEARCH_NO_FLOPPY].set,
hints, nhints);
else if (state[SEARCH_PART_UUID].set)
grub_search_part_uuid (id, var, state[SEARCH_NO_FLOPPY].set,
hints, nhints);
else if (state[SEARCH_DISK_UUID].set)
grub_search_disk_uuid (id, var, state[SEARCH_NO_FLOPPY].set,
hints, nhints);
else if (state[SEARCH_FILE].set)
grub_search_fs_file (id, var, state[SEARCH_NO_FLOPPY].set,
hints, nhints);

372
grub-core/commands/smbios.c Normal file
View file

@ -0,0 +1,372 @@
/* smbios.c - retrieve smbios information. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2013,2014,2015 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 <grub/dl.h>
#include <grub/env.h>
#include <grub/extcmd.h>
#include <grub/i18n.h>
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/smbios.h>
GRUB_MOD_LICENSE ("GPLv3+");
/* Locate the SMBIOS entry point structure depending on the hardware. */
struct grub_smbios_eps *
grub_smbios_get_eps (void)
{
static struct grub_smbios_eps *eps = NULL;
if (eps != NULL)
return eps;
eps = grub_machine_smbios_get_eps ();
return eps;
}
/* Locate the SMBIOS3 entry point structure depending on the hardware. */
struct grub_smbios_eps3 *
grub_smbios_get_eps3 (void)
{
static struct grub_smbios_eps3 *eps = NULL;
if (eps != NULL)
return eps;
eps = grub_machine_smbios_get_eps3 ();
return eps;
}
/* Abstract useful values found in either the SMBIOS3 or SMBIOS EPS. */
static struct {
grub_addr_t start;
grub_addr_t end;
grub_uint16_t structures;
} table_desc = {0, 0, 0};
/*
* These functions convert values from the various SMBIOS structure field types
* into a string formatted to be returned to the user. They expect that the
* structure and offset were already validated. The given buffer stores the
* newly formatted string if needed. When the requested data is successfully
* retrieved and formatted, the pointer to the string is returned; otherwise,
* NULL is returned on failure.
*/
static const char *
grub_smbios_format_byte (char *buffer, grub_size_t size,
const grub_uint8_t *structure, grub_uint8_t offset)
{
grub_snprintf (buffer, size, "%u", structure[offset]);
return (const char *)buffer;
}
static const char *
grub_smbios_format_word (char *buffer, grub_size_t size,
const grub_uint8_t *structure, grub_uint8_t offset)
{
grub_uint16_t value = grub_get_unaligned16 (structure + offset);
grub_snprintf (buffer, size, "%u", value);
return (const char *)buffer;
}
static const char *
grub_smbios_format_dword (char *buffer, grub_size_t size,
const grub_uint8_t *structure, grub_uint8_t offset)
{
grub_uint32_t value = grub_get_unaligned32 (structure + offset);
grub_snprintf (buffer, size, "%" PRIuGRUB_UINT32_T, value);
return (const char *)buffer;
}
static const char *
grub_smbios_format_qword (char *buffer, grub_size_t size,
const grub_uint8_t *structure, grub_uint8_t offset)
{
grub_uint64_t value = grub_get_unaligned64 (structure + offset);
grub_snprintf (buffer, size, "%" PRIuGRUB_UINT64_T, value);
return (const char *)buffer;
}
/* The matching string pointer is returned directly to avoid extra copying. */
static const char *
grub_smbios_get_string (char *buffer __attribute__ ((unused)),
grub_size_t size __attribute__ ((unused)),
const grub_uint8_t *structure, grub_uint8_t offset)
{
const grub_uint8_t *ptr = structure + structure[1];
const grub_uint8_t *table_end = (const grub_uint8_t *)table_desc.end;
const grub_uint8_t referenced_string_number = structure[offset];
grub_uint8_t i;
/* A string referenced with zero is interpreted as unset. */
if (referenced_string_number == 0)
return NULL;
/* Search the string set. */
for (i = 1; *ptr != 0 && ptr < table_end; i++)
if (i == referenced_string_number)
{
const char *str = (const char *)ptr;
while (*ptr++ != 0)
if (ptr >= table_end)
return NULL; /* The string isn't terminated. */
return str;
}
else
while (*ptr++ != 0 && ptr < table_end);
/* The string number is greater than the number of strings in the set. */
return NULL;
}
static const char *
grub_smbios_format_uuid (char *buffer, grub_size_t size,
const grub_uint8_t *structure, grub_uint8_t offset)
{
const grub_uint8_t *f = structure + offset; /* little-endian fields */
const grub_uint8_t *g = f + 8; /* byte-by-byte fields */
grub_snprintf (buffer, size,
"%02x%02x%02x%02x-%02x%02x-%02x%02x-"
"%02x%02x-%02x%02x%02x%02x%02x%02x",
f[3], f[2], f[1], f[0], f[5], f[4], f[7], f[6],
g[0], g[1], g[2], g[3], g[4], g[5], g[6], g[7]);
return (const char *)buffer;
}
/* List the field formatting functions and the number of bytes they need. */
#define MAXIMUM_FORMAT_LENGTH (sizeof ("ffffffff-ffff-ffff-ffff-ffffffffffff"))
static const struct {
const char *(*format) (char *buffer, grub_size_t size,
const grub_uint8_t *structure, grub_uint8_t offset);
grub_uint8_t field_length;
} field_extractors[] = {
{grub_smbios_format_byte, 1},
{grub_smbios_format_word, 2},
{grub_smbios_format_dword, 4},
{grub_smbios_format_qword, 8},
{grub_smbios_get_string, 1},
{grub_smbios_format_uuid, 16}
};
/* List command options, with structure field getters ordered as above. */
#define FIRST_GETTER_OPT (3)
#define SETTER_OPT (FIRST_GETTER_OPT + ARRAY_SIZE(field_extractors))
static const struct grub_arg_option options[] = {
{"type", 't', 0, N_("Match entries with the given type."),
N_("type"), ARG_TYPE_INT},
{"handle", 'h', 0, N_("Match entries with the given handle."),
N_("handle"), ARG_TYPE_INT},
{"match", 'm', 0, N_("Select a structure when several match."),
N_("match"), ARG_TYPE_INT},
{"get-byte", 'b', 0, N_("Get the byte's value at the given offset."),
N_("offset"), ARG_TYPE_INT},
{"get-word", 'w', 0, N_("Get two bytes' value at the given offset."),
N_("offset"), ARG_TYPE_INT},
{"get-dword", 'd', 0, N_("Get four bytes' value at the given offset."),
N_("offset"), ARG_TYPE_INT},
{"get-qword", 'q', 0, N_("Get eight bytes' value at the given offset."),
N_("offset"), ARG_TYPE_INT},
{"get-string", 's', 0, N_("Get the string specified at the given offset."),
N_("offset"), ARG_TYPE_INT},
{"get-uuid", 'u', 0, N_("Get the UUID's value at the given offset."),
N_("offset"), ARG_TYPE_INT},
{"set", '\0', 0, N_("Store the value in the given variable name."),
N_("variable"), ARG_TYPE_STRING},
{0, 0, 0, 0, 0, 0}
};
/*
* Return a matching SMBIOS structure.
*
* This method can use up to three criteria for selecting a structure:
* - The "type" field (use -1 to ignore)
* - The "handle" field (use -1 to ignore)
* - Which to return if several match (use 0 to ignore)
*
* The return value is a pointer to the first matching structure. If no
* structures match the given parameters, NULL is returned.
*/
static const grub_uint8_t *
grub_smbios_match_structure (const grub_int16_t type,
const grub_int32_t handle,
const grub_uint16_t match)
{
const grub_uint8_t *ptr = (const grub_uint8_t *)table_desc.start;
const grub_uint8_t *table_end = (const grub_uint8_t *)table_desc.end;
grub_uint16_t structures = table_desc.structures;
grub_uint16_t structure_count = 0;
grub_uint16_t matches = 0;
while (ptr < table_end
&& ptr[1] >= 4 /* Valid structures include the 4-byte header. */
&& (structure_count++ < structures || structures == 0))
{
grub_uint16_t structure_handle = grub_get_unaligned16 (ptr + 2);
grub_uint8_t structure_type = ptr[0];
if ((handle < 0 || handle == structure_handle)
&& (type < 0 || type == structure_type)
&& (match == 0 || match == ++matches))
return ptr;
else
{
ptr += ptr[1];
while ((*ptr++ != 0 || *ptr++ != 0) && ptr < table_end);
}
if (structure_type == GRUB_SMBIOS_TYPE_END_OF_TABLE)
break;
}
return NULL;
}
static grub_err_t
grub_cmd_smbios (grub_extcmd_context_t ctxt,
int argc __attribute__ ((unused)),
char **argv __attribute__ ((unused)))
{
struct grub_arg_list *state = ctxt->state;
grub_int16_t type = -1;
grub_int32_t handle = -1;
grub_uint16_t match = 0;
grub_uint8_t offset = 0;
const grub_uint8_t *structure;
const char *value;
char buffer[MAXIMUM_FORMAT_LENGTH];
grub_int32_t option;
grub_int8_t field_type = -1;
grub_uint8_t i;
if (table_desc.start == 0)
return grub_error (GRUB_ERR_IO,
N_("the SMBIOS entry point structure was not found"));
/* Read the given filtering options. */
if (state[0].set)
{
option = grub_strtol (state[0].arg, NULL, 0);
if (option < 0 || option > 255)
return grub_error (GRUB_ERR_BAD_ARGUMENT,
N_("the type must be between 0 and 255"));
type = (grub_int16_t)option;
}
if (state[1].set)
{
option = grub_strtol (state[1].arg, NULL, 0);
if (option < 0 || option > 65535)
return grub_error (GRUB_ERR_BAD_ARGUMENT,
N_("the handle must be between 0 and 65535"));
handle = (grub_int32_t)option;
}
if (state[2].set)
{
option = grub_strtol (state[2].arg, NULL, 0);
if (option <= 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT,
N_("the match must be a positive integer"));
match = (grub_uint16_t)option;
}
/* Determine the data type of the structure field to retrieve. */
for (i = 0; i < ARRAY_SIZE(field_extractors); i++)
if (state[FIRST_GETTER_OPT + i].set)
{
if (field_type >= 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT,
N_("only one --get option is usable at a time"));
field_type = i;
}
/* Require a choice of a structure field to return. */
if (field_type < 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT,
N_("one of the --get options is required"));
/* Locate a matching SMBIOS structure. */
structure = grub_smbios_match_structure (type, handle, match);
if (structure == NULL)
return grub_error (GRUB_ERR_IO,
N_("no structure matched the given options"));
/* Ensure the requested byte offset is inside the structure. */
option = grub_strtol (state[FIRST_GETTER_OPT + field_type].arg, NULL, 0);
if (option < 0 || option >= structure[1])
return grub_error (GRUB_ERR_OUT_OF_RANGE,
N_("the given offset is outside the structure"));
/* Ensure the requested data type at the offset is inside the structure. */
offset = (grub_uint8_t)option;
if (offset + field_extractors[field_type].field_length > structure[1])
return grub_error (GRUB_ERR_OUT_OF_RANGE,
N_("the field ends outside the structure"));
/* Format the requested structure field into a readable string. */
value = field_extractors[field_type].format (buffer, sizeof (buffer),
structure, offset);
if (value == NULL)
return grub_error (GRUB_ERR_IO,
N_("failed to retrieve the structure field"));
/* Store or print the formatted value. */
if (state[SETTER_OPT].set)
grub_env_set (state[SETTER_OPT].arg, value);
else
grub_printf ("%s\n", value);
return GRUB_ERR_NONE;
}
static grub_extcmd_t cmd;
GRUB_MOD_INIT(smbios)
{
struct grub_smbios_eps3 *eps3;
struct grub_smbios_eps *eps;
if ((eps3 = grub_smbios_get_eps3 ()))
{
table_desc.start = (grub_addr_t)eps3->table_address;
table_desc.end = table_desc.start + eps3->maximum_table_length;
table_desc.structures = 0; /* SMBIOS3 drops the structure count. */
}
else if ((eps = grub_smbios_get_eps ()))
{
table_desc.start = (grub_addr_t)eps->intermediate.table_address;
table_desc.end = table_desc.start + eps->intermediate.table_length;
table_desc.structures = eps->intermediate.structures;
}
cmd = grub_register_extcmd ("smbios", grub_cmd_smbios, 0,
N_("[-t type] [-h handle] [-m match] "
"(-b|-w|-d|-q|-s|-u) offset "
"[--set variable]"),
N_("Retrieve SMBIOS information."), options);
}
GRUB_MOD_FINI(smbios)
{
grub_unregister_extcmd (cmd);
}

View file

@ -52,6 +52,20 @@ static const struct grub_arg_option options[] =
{0, 0, 0, 0, 0, 0}
};
static grub_ssize_t
pseudo_read (struct grub_file *file, char *buf, grub_size_t len)
{
grub_memcpy (buf, (grub_uint8_t *) file->data + file->offset, len);
return len;
}
/* Filesystem descriptor. */
struct grub_fs pseudo_fs =
{
.name = "pseudo",
.read = pseudo_read
};
static grub_err_t
read_packet_header (grub_file_t sig, grub_uint8_t *out_type, grub_size_t *len)
{
@ -700,6 +714,64 @@ grub_cmd_trust (grub_extcmd_context_t ctxt,
return GRUB_ERR_NONE;
}
static grub_err_t
grub_cmd_trust_var (grub_command_t cmd __attribute__ ((unused)),
int argc, char **args)
{
struct grub_file pseudo_file;
const char *var;
char *data;
struct grub_public_key *pk = NULL;
unsigned int i, idx0, idx1;
if (argc < 1)
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
var = grub_env_get (args[0]);
if (!var)
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unknown variable"));
data = grub_zalloc (grub_strlen (var) / 2);
if (!data)
return grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate memory for key"));
/* For the want of sscanf() */
for (i = 0; i < grub_strlen (var); i += 2)
{
if (var[i] < 0x40)
idx0 = var[i] - 0x30;
else
idx0 = var[i] - 0x57;
if (var[i+1] < 0x40)
idx1 = var[i+1] - 0x30;
else
idx1 = var[i+1] - 0x57;
data[i/2] = ((idx0 << 4) & 0xf0) | (idx1 & 0x0f);
}
grub_memset (&pseudo_file, 0, sizeof (pseudo_file));
pseudo_file.fs = &pseudo_fs;
pseudo_file.size = grub_strlen (var) / 2;
pseudo_file.data = data;
pk = grub_load_public_key (&pseudo_file);
if (!pk)
{
grub_free(data);
return grub_errno;
}
pk->next = grub_pk_trusted;
grub_pk_trusted = pk;
grub_free(data);
return GRUB_ERR_NONE;
}
static grub_err_t
grub_cmd_list (grub_command_t cmd __attribute__ ((unused)),
int argc __attribute__ ((unused)),
@ -954,24 +1026,8 @@ grub_env_write_sec (struct grub_env_var *var __attribute__ ((unused)),
return grub_strdup (sec ? "enforce" : "no");
}
static grub_ssize_t
pseudo_read (struct grub_file *file, char *buf, grub_size_t len)
{
grub_memcpy (buf, (grub_uint8_t *) file->data + file->offset, len);
return len;
}
/* Filesystem descriptor. */
struct grub_fs pseudo_fs =
{
.name = "pseudo",
.read = pseudo_read
};
static grub_extcmd_t cmd, cmd_trust;
static grub_command_t cmd_distrust, cmd_list;
static grub_command_t cmd_trust_var, cmd_distrust, cmd_list;
GRUB_MOD_INIT(verify)
{
@ -1024,6 +1080,9 @@ GRUB_MOD_INIT(verify)
N_("[-s|--skip-sig] PUBKEY_FILE"),
N_("Add PUBKEY_FILE to trusted keys."),
options);
cmd_trust_var = grub_register_command ("trust_var", grub_cmd_trust_var,
N_("PUBKEY_VAR"),
N_("Add the contents of PUBKEY_VAR to trusted keys."));
cmd_list = grub_register_command ("list_trusted", grub_cmd_list,
0,
N_("Show the list of trusted keys."));
@ -1037,6 +1096,7 @@ GRUB_MOD_FINI(verify)
grub_file_filter_unregister (GRUB_FILE_FILTER_PUBKEY);
grub_unregister_extcmd (cmd);
grub_unregister_extcmd (cmd_trust);
grub_unregister_command (cmd_trust_var);
grub_unregister_command (cmd_list);
grub_unregister_command (cmd_distrust);
}

View file

@ -278,10 +278,14 @@ grub_biosdisk_call_hook (grub_disk_dev_iterate_hook_t hook, void *hook_data,
char name[10];
if (cd_drive && drive == cd_drive)
return hook ("cd", hook_data);
{
grub_dprintf ("biosdisk", "iterating cd\n");
return hook ("cd", hook_data);
}
grub_snprintf (name, sizeof (name),
(drive & 0x80) ? "hd%d" : "fd%d", drive & (~0x80));
grub_dprintf ("biosdisk", "iterating %s\n", name);
return hook (name, hook_data);
}
@ -301,7 +305,7 @@ grub_biosdisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data,
if (grub_biosdisk_rw_standard (0x02, drive, 0, 0, 1, 1,
GRUB_MEMORY_MACHINE_SCRATCH_SEG) != 0)
{
grub_dprintf ("disk", "Read error when probing drive 0x%2x\n", drive);
grub_dprintf ("biosdisk", "Read error when probing drive 0x%2x\n", drive);
break;
}
@ -336,6 +340,8 @@ grub_biosdisk_open (const char *name, grub_disk_t disk)
int drive;
struct grub_biosdisk_data *data;
grub_dprintf ("biosdisk", "opening %s\n", name);
drive = grub_biosdisk_get_drive (name);
if (drive < 0)
return grub_errno;
@ -393,6 +399,11 @@ grub_biosdisk_open (const char *name, grub_disk_t disk)
(1 << disk->log_sector_size) < drp->bytes_per_sector;
disk->log_sector_size++);
}
grub_dprintf ("biosdisk",
"LBA total = 0x%llx block size = 0x%lx\n",
(unsigned long long) total_sectors,
1L << disk->log_sector_size);
}
}
}
@ -428,6 +439,9 @@ grub_biosdisk_open (const char *name, grub_disk_t disk)
if (! total_sectors)
total_sectors = ((grub_uint64_t) data->cylinders)
* data->heads * data->sectors;
grub_dprintf ("biosdisk", "C/H/S %lu/%lu/%lu\n",
data->cylinders, data->heads, data->sectors);
}
disk->total_sectors = total_sectors;
@ -440,12 +454,15 @@ grub_biosdisk_open (const char *name, grub_disk_t disk)
disk->data = data;
grub_dprintf ("biosdisk", "opening %s succeeded\n", name);
return GRUB_ERR_NONE;
}
static void
grub_biosdisk_close (grub_disk_t disk)
{
grub_dprintf ("biosdisk", "closing %s\n", disk->name);
grub_free (disk->data);
}
@ -577,6 +594,9 @@ static grub_err_t
grub_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector,
grub_size_t size, char *buf)
{
grub_dprintf ("biosdisk", "reading 0x%lx sectors at 0x%llx from %s\n",
(unsigned long) size, (unsigned long long) sector, disk->name);
while (size)
{
grub_size_t len;
@ -607,6 +627,9 @@ grub_biosdisk_write (grub_disk_t disk, grub_disk_addr_t sector,
{
struct grub_biosdisk_data *data = disk->data;
grub_dprintf ("biosdisk", "writing 0x%lx sectors at 0x%llx to %s\n",
(unsigned long) size, (unsigned long long) sector, disk->name);
if (data->flags & GRUB_BIOSDISK_FLAG_CDROM)
return grub_error (GRUB_ERR_IO, N_("cannot write to CD-ROM"));

View file

@ -98,6 +98,7 @@ grub_arch_efiemu_relocate_symbols64 (grub_efiemu_segment_t segs,
break;
case R_X86_64_PC32:
case R_X86_64_PLT32:
err = grub_efiemu_write_value (addr,
*addr32 + rel->r_addend
+ sym.off

View file

@ -22,18 +22,22 @@
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/acpi.h>
#include <grub/smbios.h>
grub_err_t
grub_machine_efiemu_init_tables (void)
{
grub_uint8_t *ptr;
void *table;
grub_err_t err;
grub_efi_guid_t smbios = GRUB_EFI_SMBIOS_TABLE_GUID;
grub_efi_guid_t smbios3 = GRUB_EFI_SMBIOS3_TABLE_GUID;
grub_efi_guid_t acpi20 = GRUB_EFI_ACPI_20_TABLE_GUID;
grub_efi_guid_t acpi = GRUB_EFI_ACPI_TABLE_GUID;
err = grub_efiemu_unregister_configuration_table (smbios);
if (err)
return err;
err = grub_efiemu_unregister_configuration_table (smbios3);
if (err)
return err;
err = grub_efiemu_unregister_configuration_table (acpi);
@ -43,6 +47,20 @@ grub_machine_efiemu_init_tables (void)
if (err)
return err;
table = grub_smbios_get_eps ();
if (table)
{
err = grub_efiemu_register_configuration_table (smbios, 0, 0, table);
if (err)
return err;
}
table = grub_smbios_get_eps3 ();
if (table)
{
err = grub_efiemu_register_configuration_table (smbios3, 0, 0, table);
if (err)
return err;
}
table = grub_acpi_get_rsdpv1 ();
if (table)
{
@ -58,19 +76,5 @@ grub_machine_efiemu_init_tables (void)
return err;
}
for (ptr = (grub_uint8_t *) 0xf0000; ptr < (grub_uint8_t *) 0x100000;
ptr += 16)
if (grub_memcmp (ptr, "_SM_", 4) == 0
&& grub_byte_checksum (ptr, *(ptr + 5)) == 0)
break;
if (ptr < (grub_uint8_t *) 0x100000)
{
grub_dprintf ("efiemu", "Registering SMBIOS\n");
err = grub_efiemu_register_configuration_table (smbios, 0, 0, ptr);
if (err)
return err;
}
return GRUB_ERR_NONE;
}

View file

@ -175,7 +175,7 @@ struct grub_btrfs_time
{
grub_int64_t sec;
grub_uint32_t nanosec;
} __attribute__ ((aligned (4)));
} GRUB_PACKED;
struct grub_btrfs_inode
{

View file

@ -32,12 +32,21 @@
#include <grub/env.h>
#include <grub/cache.h>
#include <grub/i18n.h>
#include <grub/tpm.h>
/* Platforms where modules are in a readonly area of memory. */
#if defined(GRUB_MACHINE_QEMU)
#define GRUB_MODULES_MACHINE_READONLY
#endif
#ifdef GRUB_MACHINE_EMU
#include <sys/mman.h>
#endif
#ifdef GRUB_MACHINE_EFI
#include <grub/efi/efi.h>
#endif
#pragma GCC diagnostic ignored "-Wcast-align"
@ -686,6 +695,15 @@ grub_dl_load_file (const char *filename)
void *core = 0;
grub_dl_t mod = 0;
#ifdef GRUB_MACHINE_EFI
if (grub_efi_secure_boot ())
{
grub_error (GRUB_ERR_ACCESS_DENIED,
"Secure Boot forbids loading module from %s", filename);
return 0;
}
#endif
grub_boot_time ("Loading module %s", filename);
file = grub_file_open (filename);
@ -712,6 +730,9 @@ grub_dl_load_file (const char *filename)
opens of the same device. */
grub_file_close (file);
grub_tpm_measure(core, size, GRUB_BINARY_PCR, "grub_module", filename);
grub_print_error();
mod = grub_dl_load_core (core, size);
grub_free (core);
if (! mod)

View file

@ -264,6 +264,34 @@ grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid,
return NULL;
}
grub_efi_boolean_t
grub_efi_secure_boot (void)
{
grub_efi_guid_t efi_var_guid = GRUB_EFI_GLOBAL_VARIABLE_GUID;
grub_size_t datasize;
char *secure_boot = NULL;
char *setup_mode = NULL;
grub_efi_boolean_t ret = 0;
secure_boot = grub_efi_get_variable("SecureBoot", &efi_var_guid, &datasize);
if (datasize != 1 || !secure_boot)
goto out;
setup_mode = grub_efi_get_variable("SetupMode", &efi_var_guid, &datasize);
if (datasize != 1 || !setup_mode)
goto out;
if (*secure_boot && !*setup_mode)
ret = 1;
out:
grub_free (secure_boot);
grub_free (setup_mode);
return ret;
}
#pragma GCC diagnostic ignored "-Wcast-align"
/* Search the mods section from the PE32/PE32+ image. This code uses

View file

@ -49,6 +49,38 @@ static grub_efi_uintn_t finish_desc_size;
static grub_efi_uint32_t finish_desc_version;
int grub_efi_is_finished = 0;
/* Allocate pages below a specified address */
void *
grub_efi_allocate_pages_max (grub_efi_physical_address_t max,
grub_efi_uintn_t pages)
{
grub_efi_status_t status;
grub_efi_boot_services_t *b;
grub_efi_physical_address_t address = max;
if (max > 0xffffffff)
return 0;
b = grub_efi_system_table->boot_services;
status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_MAX_ADDRESS, GRUB_EFI_LOADER_DATA, pages, &address);
if (status != GRUB_EFI_SUCCESS)
return 0;
if (address == 0)
{
/* Uggh, the address 0 was allocated... This is too annoying,
so reallocate another one. */
address = max;
status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_MAX_ADDRESS, GRUB_EFI_LOADER_DATA, pages, &address);
grub_efi_free_pages (0, pages);
if (status != GRUB_EFI_SUCCESS)
return 0;
}
return (void *) ((grub_addr_t) address);
}
/* Allocate pages. Return the pointer to the first of allocated pages. */
void *
grub_efi_allocate_pages (grub_efi_physical_address_t address,

273
grub-core/kern/efi/tpm.c Normal file
View file

@ -0,0 +1,273 @@
#include <grub/err.h>
#include <grub/i18n.h>
#include <grub/efi/api.h>
#include <grub/efi/efi.h>
#include <grub/efi/tpm.h>
#include <grub/mm.h>
#include <grub/tpm.h>
#include <grub/term.h>
static grub_efi_guid_t tpm_guid = EFI_TPM_GUID;
static grub_efi_guid_t tpm2_guid = EFI_TPM2_GUID;
static grub_efi_boolean_t grub_tpm_present(grub_efi_tpm_protocol_t *tpm)
{
grub_efi_status_t status;
TCG_EFI_BOOT_SERVICE_CAPABILITY caps;
grub_uint32_t flags;
grub_efi_physical_address_t eventlog, lastevent;
caps.Size = (grub_uint8_t)sizeof(caps);
status = efi_call_5(tpm->status_check, tpm, &caps, &flags, &eventlog,
&lastevent);
if (status != GRUB_EFI_SUCCESS || caps.TPMDeactivatedFlag
|| !caps.TPMPresentFlag)
return 0;
return 1;
}
static grub_efi_boolean_t grub_tpm2_present(grub_efi_tpm2_protocol_t *tpm)
{
grub_efi_status_t status;
EFI_TCG2_BOOT_SERVICE_CAPABILITY caps;
caps.Size = (grub_uint8_t)sizeof(caps);
status = efi_call_2(tpm->get_capability, tpm, &caps);
if (status != GRUB_EFI_SUCCESS || !caps.TPMPresentFlag)
return 0;
return 1;
}
static grub_efi_boolean_t grub_tpm_handle_find(grub_efi_handle_t *tpm_handle,
grub_efi_uint8_t *protocol_version)
{
grub_efi_handle_t *handles;
grub_efi_uintn_t num_handles;
handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &tpm_guid, NULL,
&num_handles);
if (handles && num_handles > 0) {
*tpm_handle = handles[0];
*protocol_version = 1;
return 1;
}
handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &tpm2_guid, NULL,
&num_handles);
if (handles && num_handles > 0) {
*tpm_handle = handles[0];
*protocol_version = 2;
return 1;
}
return 0;
}
static grub_err_t
grub_tpm1_execute(grub_efi_handle_t tpm_handle,
PassThroughToTPM_InputParamBlock *inbuf,
PassThroughToTPM_OutputParamBlock *outbuf)
{
grub_efi_status_t status;
grub_efi_tpm_protocol_t *tpm;
grub_uint32_t inhdrsize = sizeof(*inbuf) - sizeof(inbuf->TPMOperandIn);
grub_uint32_t outhdrsize = sizeof(*outbuf) - sizeof(outbuf->TPMOperandOut);
tpm = grub_efi_open_protocol (tpm_handle, &tpm_guid,
GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
if (!grub_tpm_present(tpm))
return 0;
/* UEFI TPM protocol takes the raw operand block, no param block header */
status = efi_call_5 (tpm->pass_through_to_tpm, tpm,
inbuf->IPBLength - inhdrsize, inbuf->TPMOperandIn,
outbuf->OPBLength - outhdrsize, outbuf->TPMOperandOut);
switch (status) {
case GRUB_EFI_SUCCESS:
return 0;
case GRUB_EFI_DEVICE_ERROR:
return grub_error (GRUB_ERR_IO, N_("Command failed"));
case GRUB_EFI_INVALID_PARAMETER:
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Invalid parameter"));
case GRUB_EFI_BUFFER_TOO_SMALL:
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Output buffer too small"));
case GRUB_EFI_NOT_FOUND:
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("TPM unavailable"));
default:
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("Unknown TPM error"));
}
}
static grub_err_t
grub_tpm2_execute(grub_efi_handle_t tpm_handle,
PassThroughToTPM_InputParamBlock *inbuf,
PassThroughToTPM_OutputParamBlock *outbuf)
{
grub_efi_status_t status;
grub_efi_tpm2_protocol_t *tpm;
grub_uint32_t inhdrsize = sizeof(*inbuf) - sizeof(inbuf->TPMOperandIn);
grub_uint32_t outhdrsize = sizeof(*outbuf) - sizeof(outbuf->TPMOperandOut);
tpm = grub_efi_open_protocol (tpm_handle, &tpm2_guid,
GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
if (!grub_tpm2_present(tpm))
return 0;
/* UEFI TPM protocol takes the raw operand block, no param block header */
status = efi_call_5 (tpm->submit_command, tpm,
inbuf->IPBLength - inhdrsize, inbuf->TPMOperandIn,
outbuf->OPBLength - outhdrsize, outbuf->TPMOperandOut);
switch (status) {
case GRUB_EFI_SUCCESS:
return 0;
case GRUB_EFI_DEVICE_ERROR:
return grub_error (GRUB_ERR_IO, N_("Command failed"));
case GRUB_EFI_INVALID_PARAMETER:
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Invalid parameter"));
case GRUB_EFI_BUFFER_TOO_SMALL:
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Output buffer too small"));
case GRUB_EFI_NOT_FOUND:
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("TPM unavailable"));
default:
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("Unknown TPM error"));
}
}
grub_err_t
grub_tpm_execute(PassThroughToTPM_InputParamBlock *inbuf,
PassThroughToTPM_OutputParamBlock *outbuf)
{
grub_efi_handle_t tpm_handle;
grub_uint8_t protocol_version;
/* It's not a hard failure for there to be no TPM */
if (!grub_tpm_handle_find(&tpm_handle, &protocol_version))
return 0;
if (protocol_version == 1) {
return grub_tpm1_execute(tpm_handle, inbuf, outbuf);
} else {
return grub_tpm2_execute(tpm_handle, inbuf, outbuf);
}
}
static grub_err_t
grub_tpm1_log_event(grub_efi_handle_t tpm_handle, unsigned char *buf,
grub_size_t size, grub_uint8_t pcr,
const char *description)
{
TCG_PCR_EVENT *event;
grub_efi_status_t status;
grub_efi_tpm_protocol_t *tpm;
grub_efi_physical_address_t lastevent;
grub_uint32_t algorithm;
grub_uint32_t eventnum = 0;
tpm = grub_efi_open_protocol (tpm_handle, &tpm_guid,
GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
if (!grub_tpm_present(tpm))
return 0;
event = grub_zalloc(sizeof (TCG_PCR_EVENT) + grub_strlen(description) + 1);
if (!event)
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
N_("cannot allocate TPM event buffer"));
event->PCRIndex = pcr;
event->EventType = EV_IPL;
event->EventSize = grub_strlen(description) + 1;
grub_memcpy(event->Event, description, event->EventSize);
algorithm = TCG_ALG_SHA;
status = efi_call_7 (tpm->log_extend_event, tpm, (grub_efi_physical_address_t)buf, (grub_uint64_t) size,
algorithm, event, &eventnum, &lastevent);
switch (status) {
case GRUB_EFI_SUCCESS:
return 0;
case GRUB_EFI_DEVICE_ERROR:
return grub_error (GRUB_ERR_IO, N_("Command failed"));
case GRUB_EFI_INVALID_PARAMETER:
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Invalid parameter"));
case GRUB_EFI_BUFFER_TOO_SMALL:
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Output buffer too small"));
case GRUB_EFI_NOT_FOUND:
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("TPM unavailable"));
default:
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("Unknown TPM error"));
}
}
static grub_err_t
grub_tpm2_log_event(grub_efi_handle_t tpm_handle, unsigned char *buf,
grub_size_t size, grub_uint8_t pcr,
const char *description)
{
EFI_TCG2_EVENT *event;
grub_efi_status_t status;
grub_efi_tpm2_protocol_t *tpm;
tpm = grub_efi_open_protocol (tpm_handle, &tpm2_guid,
GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
if (!grub_tpm2_present(tpm))
return 0;
event = grub_zalloc(sizeof (EFI_TCG2_EVENT) + grub_strlen(description) + 1);
if (!event)
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
N_("cannot allocate TPM event buffer"));
event->Header.HeaderSize = sizeof(EFI_TCG2_EVENT_HEADER);
event->Header.HeaderVersion = 1;
event->Header.PCRIndex = pcr;
event->Header.EventType = EV_IPL;
event->Size = sizeof(*event) - sizeof(event->Event) + grub_strlen(description) + 1;
grub_memcpy(event->Event, description, grub_strlen(description) + 1);
status = efi_call_5 (tpm->hash_log_extend_event, tpm, 0, (grub_efi_physical_address_t)buf,
(grub_uint64_t) size, event);
switch (status) {
case GRUB_EFI_SUCCESS:
return 0;
case GRUB_EFI_DEVICE_ERROR:
return grub_error (GRUB_ERR_IO, N_("Command failed"));
case GRUB_EFI_INVALID_PARAMETER:
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Invalid parameter"));
case GRUB_EFI_BUFFER_TOO_SMALL:
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Output buffer too small"));
case GRUB_EFI_NOT_FOUND:
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("TPM unavailable"));
default:
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("Unknown TPM error"));
}
}
grub_err_t
grub_tpm_log_event(unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
const char *description)
{
grub_efi_handle_t tpm_handle;
grub_efi_uint8_t protocol_version;
if (!grub_tpm_handle_find(&tpm_handle, &protocol_version))
return 0;
if (protocol_version == 1) {
return grub_tpm1_log_event(tpm_handle, buf, size, pcr, description);
} else {
return grub_tpm2_log_event(tpm_handle, buf, size, pcr, description);
}
}

View file

@ -0,0 +1,145 @@
#include <grub/err.h>
#include <grub/i18n.h>
#include <grub/mm.h>
#include <grub/tpm.h>
#include <grub/misc.h>
#include <grub/i386/pc/int.h>
#define TCPA_MAGIC 0x41504354
static int tpm_presence = -1;
int tpm_present(void);
int tpm_present(void)
{
struct grub_bios_int_registers regs;
if (tpm_presence != -1)
return tpm_presence;
regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
regs.eax = 0xbb00;
regs.ebx = TCPA_MAGIC;
grub_bios_interrupt (0x1a, &regs);
if (regs.eax == 0)
tpm_presence = 1;
else
tpm_presence = 0;
return tpm_presence;
}
grub_err_t
grub_tpm_execute(PassThroughToTPM_InputParamBlock *inbuf,
PassThroughToTPM_OutputParamBlock *outbuf)
{
struct grub_bios_int_registers regs;
grub_addr_t inaddr, outaddr;
if (!tpm_present())
return 0;
inaddr = (grub_addr_t) inbuf;
outaddr = (grub_addr_t) outbuf;
regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
regs.eax = 0xbb02;
regs.ebx = TCPA_MAGIC;
regs.ecx = 0;
regs.edx = 0;
regs.es = (inaddr & 0xffff0000) >> 4;
regs.edi = inaddr & 0xffff;
regs.ds = outaddr >> 4;
regs.esi = outaddr & 0xf;
grub_bios_interrupt (0x1a, &regs);
if (regs.eax)
{
tpm_presence = 0;
return grub_error (GRUB_ERR_IO, N_("TPM error %x, disabling TPM"), regs.eax);
}
return 0;
}
typedef struct {
grub_uint32_t pcrindex;
grub_uint32_t eventtype;
grub_uint8_t digest[20];
grub_uint32_t eventdatasize;
grub_uint8_t event[0];
} GRUB_PACKED Event;
typedef struct {
grub_uint16_t ipblength;
grub_uint16_t reserved;
grub_uint32_t hashdataptr;
grub_uint32_t hashdatalen;
grub_uint32_t pcr;
grub_uint32_t reserved2;
grub_uint32_t logdataptr;
grub_uint32_t logdatalen;
} GRUB_PACKED EventIncoming;
typedef struct {
grub_uint16_t opblength;
grub_uint16_t reserved;
grub_uint32_t eventnum;
grub_uint8_t hashvalue[20];
} GRUB_PACKED EventOutgoing;
grub_err_t
grub_tpm_log_event(unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
const char *description)
{
struct grub_bios_int_registers regs;
EventIncoming incoming;
EventOutgoing outgoing;
Event *event;
grub_uint32_t datalength;
if (!tpm_present())
return 0;
datalength = grub_strlen(description);
event = grub_zalloc(datalength + sizeof(Event));
if (!event)
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
N_("cannot allocate TPM event buffer"));
event->pcrindex = pcr;
event->eventtype = 0x0d;
event->eventdatasize = grub_strlen(description);
grub_memcpy(event->event, description, datalength);
incoming.ipblength = sizeof(incoming);
incoming.hashdataptr = (grub_uint32_t)buf;
incoming.hashdatalen = size;
incoming.pcr = pcr;
incoming.logdataptr = (grub_uint32_t)event;
incoming.logdatalen = datalength + sizeof(Event);
regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
regs.eax = 0xbb01;
regs.ebx = TCPA_MAGIC;
regs.ecx = 0;
regs.edx = 0;
regs.es = (((grub_addr_t) &incoming) & 0xffff0000) >> 4;
regs.edi = ((grub_addr_t) &incoming) & 0xffff;
regs.ds = (((grub_addr_t) &outgoing) & 0xffff0000) >> 4;
regs.esi = ((grub_addr_t) &outgoing) & 0xffff;
grub_bios_interrupt (0x1a, &regs);
grub_free(event);
if (regs.eax)
{
tpm_presence = 0;
return grub_error (GRUB_ERR_IO, N_("TPM error %x, disabling TPM"), regs.eax);
}
return 0;
}

View file

@ -131,6 +131,9 @@ grub_set_prefix_and_root (void)
{
char *cmdpath;
grub_env_set ("cmddevice", fwdevice);
grub_env_export ("cmddevice");
cmdpath = grub_xasprintf ("(%s)%s", fwdevice, fwpath ? : "");
if (cmdpath)
{

19
grub-core/kern/tpm.c Normal file
View file

@ -0,0 +1,19 @@
#include <grub/err.h>
#include <grub/i18n.h>
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/tpm.h>
#include <grub/term.h>
grub_err_t
grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
const char *kind, const char *description)
{
grub_err_t ret;
char *desc = grub_xasprintf("%s %s", kind, description);
if (!desc)
return GRUB_ERR_OUT_OF_MEMORY;
ret = grub_tpm_log_event(buf, size, pcr, desc);
grub_free(desc);
return ret;
}

View file

@ -70,6 +70,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
break;
case R_X86_64_PC32:
case R_X86_64_PLT32:
{
grub_int64_t value;
value = ((grub_int32_t) *addr32) + rel->r_addend + sym->st_value -

View file

@ -19,6 +19,7 @@
#include <grub/lib/cmdline.h>
#include <grub/misc.h>
#include <grub/tpm.h>
static unsigned int check_arg (char *c, int *has_space)
{
@ -67,7 +68,7 @@ int grub_create_loader_cmdline (int argc, char *argv[], char *buf,
{
int i, space;
unsigned int arg_size;
char *c;
char *c, *orig = buf;
for (i = 0; i < argc; i++)
{
@ -104,5 +105,9 @@ int grub_create_loader_cmdline (int argc, char *argv[], char *buf,
*buf = 0;
grub_tpm_measure ((void *)orig, grub_strlen (orig), GRUB_ASCII_PCR,
"grub_kernel_cmdline", orig);
grub_print_error();
return i;
}

777
grub-core/lib/gpt.c Normal file
View file

@ -0,0 +1,777 @@
/* gpt.c - Read/Verify/Write GUID Partition Tables (GPT). */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2002,2005,2006,2007,2008 Free Software Foundation, Inc.
* Copyright (C) 2014 CoreOS, 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 <grub/charset.h>
#include <grub/crypto.h>
#include <grub/device.h>
#include <grub/disk.h>
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/dl.h>
#include <grub/msdos_partition.h>
#include <grub/gpt_partition.h>
GRUB_MOD_LICENSE ("GPLv3+");
static grub_uint8_t grub_gpt_magic[] = GRUB_GPT_HEADER_MAGIC;
static grub_err_t
grub_gpt_read_entries (grub_disk_t disk, grub_gpt_t gpt,
struct grub_gpt_header *header,
void **ret_entries,
grub_size_t *ret_entries_size);
char *
grub_gpt_guid_to_str (grub_gpt_guid_t *guid)
{
return grub_xasprintf ("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
grub_le_to_cpu32 (guid->data1),
grub_le_to_cpu16 (guid->data2),
grub_le_to_cpu16 (guid->data3),
guid->data4[0], guid->data4[1],
guid->data4[2], guid->data4[3],
guid->data4[4], guid->data4[5],
guid->data4[6], guid->data4[7]);
}
static grub_err_t
grub_gpt_device_partentry (grub_device_t device,
struct grub_gpt_partentry *entry)
{
grub_disk_t disk = device->disk;
grub_partition_t p;
grub_err_t err;
if (!disk || !disk->partition)
return grub_error (GRUB_ERR_BUG, "not a partition");
if (grub_strcmp (disk->partition->partmap->name, "gpt"))
return grub_error (GRUB_ERR_BAD_ARGUMENT, "not a GPT partition");
p = disk->partition;
disk->partition = p->parent;
err = grub_disk_read (disk, p->offset, p->index, sizeof (*entry), entry);
disk->partition = p;
return err;
}
grub_err_t
grub_gpt_part_label (grub_device_t device, char **label)
{
struct grub_gpt_partentry entry;
const grub_size_t name_len = ARRAY_SIZE (entry.name);
const grub_size_t label_len = name_len * GRUB_MAX_UTF8_PER_UTF16 + 1;
grub_size_t i;
grub_uint8_t *end;
if (grub_gpt_device_partentry (device, &entry))
return grub_errno;
*label = grub_malloc (label_len);
if (!*label)
return grub_errno;
for (i = 0; i < name_len; i++)
entry.name[i] = grub_le_to_cpu16 (entry.name[i]);
end = grub_utf16_to_utf8 ((grub_uint8_t *) *label, entry.name, name_len);
*end = '\0';
return GRUB_ERR_NONE;
}
grub_err_t
grub_gpt_part_uuid (grub_device_t device, char **uuid)
{
struct grub_gpt_partentry entry;
if (grub_gpt_device_partentry (device, &entry))
return grub_errno;
*uuid = grub_gpt_guid_to_str (&entry.guid);
if (!*uuid)
return grub_errno;
return GRUB_ERR_NONE;
}
static struct grub_gpt_header *
grub_gpt_get_header (grub_gpt_t gpt)
{
if (gpt->status & GRUB_GPT_PRIMARY_HEADER_VALID)
return &gpt->primary;
else if (gpt->status & GRUB_GPT_BACKUP_HEADER_VALID)
return &gpt->backup;
grub_error (GRUB_ERR_BUG, "No valid GPT header");
return NULL;
}
grub_err_t
grub_gpt_disk_uuid (grub_device_t device, char **uuid)
{
struct grub_gpt_header *header;
grub_gpt_t gpt = grub_gpt_read (device->disk);
if (!gpt)
goto done;
header = grub_gpt_get_header (gpt);
if (!header)
goto done;
*uuid = grub_gpt_guid_to_str (&header->guid);
done:
grub_gpt_free (gpt);
return grub_errno;
}
static grub_uint64_t
grub_gpt_size_to_sectors (grub_gpt_t gpt, grub_size_t size)
{
unsigned int sector_size;
grub_uint64_t sectors;
sector_size = 1U << gpt->log_sector_size;
sectors = size / sector_size;
if (size % sector_size)
sectors++;
return sectors;
}
/* Copied from grub-core/kern/disk_common.c grub_disk_adjust_range so we can
* avoid attempting to use disk->total_sectors when GRUB won't let us.
* TODO: Why is disk->total_sectors not set to GRUB_DISK_SIZE_UNKNOWN? */
static int
grub_gpt_disk_size_valid (grub_disk_t disk)
{
grub_disk_addr_t total_sectors;
/* Transform total_sectors to number of 512B blocks. */
total_sectors = disk->total_sectors << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS);
/* Some drivers have problems with disks above reasonable.
Treat unknown as 1EiB disk. While on it, clamp the size to 1EiB.
Just one condition is enough since GRUB_DISK_UNKNOWN_SIZE << ls is always
above 9EiB.
*/
if (total_sectors > (1ULL << 51))
return 0;
return 1;
}
static void
grub_gpt_lecrc32 (grub_uint32_t *crc, const void *data, grub_size_t len)
{
grub_uint32_t crc32_val;
grub_crypto_hash (GRUB_MD_CRC32, &crc32_val, data, len);
/* GRUB_MD_CRC32 always uses big endian, gpt is always little. */
*crc = grub_swap_bytes32 (crc32_val);
}
static void
grub_gpt_header_lecrc32 (grub_uint32_t *crc, struct grub_gpt_header *header)
{
grub_uint32_t old, new;
/* crc32 must be computed with the field cleared. */
old = header->crc32;
header->crc32 = 0;
grub_gpt_lecrc32 (&new, header, sizeof (*header));
header->crc32 = old;
*crc = new;
}
/* Make sure the MBR is a protective MBR and not a normal MBR. */
grub_err_t
grub_gpt_pmbr_check (struct grub_msdos_partition_mbr *mbr)
{
unsigned int i;
if (mbr->signature !=
grub_cpu_to_le16_compile_time (GRUB_PC_PARTITION_SIGNATURE))
return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid MBR signature");
for (i = 0; i < sizeof (mbr->entries); i++)
if (mbr->entries[i].type == GRUB_PC_PARTITION_TYPE_GPT_DISK)
return GRUB_ERR_NONE;
return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid protective MBR");
}
static grub_uint64_t
grub_gpt_entries_size (struct grub_gpt_header *gpt)
{
return (grub_uint64_t) grub_le_to_cpu32 (gpt->maxpart) *
(grub_uint64_t) grub_le_to_cpu32 (gpt->partentry_size);
}
static grub_uint64_t
grub_gpt_entries_sectors (struct grub_gpt_header *gpt,
unsigned int log_sector_size)
{
grub_uint64_t sector_bytes, entries_bytes;
sector_bytes = 1ULL << log_sector_size;
entries_bytes = grub_gpt_entries_size (gpt);
return grub_divmod64(entries_bytes + sector_bytes - 1, sector_bytes, NULL);
}
static int
is_pow2 (grub_uint32_t n)
{
return (n & (n - 1)) == 0;
}
grub_err_t
grub_gpt_header_check (struct grub_gpt_header *gpt,
unsigned int log_sector_size)
{
grub_uint32_t crc = 0, size;
grub_uint64_t start, end;
if (grub_memcmp (gpt->magic, grub_gpt_magic, sizeof (grub_gpt_magic)) != 0)
return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid GPT signature");
if (gpt->version != GRUB_GPT_HEADER_VERSION)
return grub_error (GRUB_ERR_BAD_PART_TABLE, "unknown GPT version");
grub_gpt_header_lecrc32 (&crc, gpt);
if (gpt->crc32 != crc)
return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid GPT header crc32");
/* The header size "must be greater than or equal to 92 and must be less
* than or equal to the logical block size." */
size = grub_le_to_cpu32 (gpt->headersize);
if (size < 92U || size > (1U << log_sector_size))
return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid GPT header size");
/* The partition entry size must be "a value of 128*(2^n) where n is an
* integer greater than or equal to zero (e.g., 128, 256, 512, etc.)." */
size = grub_le_to_cpu32 (gpt->partentry_size);
if (size < 128U || size % 128U || !is_pow2 (size / 128U))
return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid GPT entry size");
/* The minimum entries table size is specified in terms of bytes,
* regardless of how large the individual entry size is. */
if (grub_gpt_entries_size (gpt) < GRUB_GPT_DEFAULT_ENTRIES_SIZE)
return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid GPT entry table size");
/* And of course there better be some space for partitions! */
start = grub_le_to_cpu64 (gpt->start);
end = grub_le_to_cpu64 (gpt->end);
if (start > end)
return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid usable sectors");
return GRUB_ERR_NONE;
}
static int
grub_gpt_headers_equal (grub_gpt_t gpt)
{
/* Assume headers passed grub_gpt_header_check so skip magic and version.
* Individual fields must be checked instead of just using memcmp because
* crc32, header, alternate, and partitions will all normally differ. */
if (gpt->primary.headersize != gpt->backup.headersize ||
gpt->primary.header_lba != gpt->backup.alternate_lba ||
gpt->primary.alternate_lba != gpt->backup.header_lba ||
gpt->primary.start != gpt->backup.start ||
gpt->primary.end != gpt->backup.end ||
gpt->primary.maxpart != gpt->backup.maxpart ||
gpt->primary.partentry_size != gpt->backup.partentry_size ||
gpt->primary.partentry_crc32 != gpt->backup.partentry_crc32)
return 0;
return grub_memcmp(&gpt->primary.guid, &gpt->backup.guid,
sizeof(grub_gpt_guid_t)) == 0;
}
static grub_err_t
grub_gpt_check_primary (grub_gpt_t gpt)
{
grub_uint64_t backup, primary, entries, entries_len, start, end;
primary = grub_le_to_cpu64 (gpt->primary.header_lba);
backup = grub_le_to_cpu64 (gpt->primary.alternate_lba);
entries = grub_le_to_cpu64 (gpt->primary.partitions);
entries_len = grub_gpt_entries_sectors(&gpt->primary, gpt->log_sector_size);
start = grub_le_to_cpu64 (gpt->primary.start);
end = grub_le_to_cpu64 (gpt->primary.end);
grub_dprintf ("gpt", "Primary GPT layout:\n"
"primary header = 0x%llx backup header = 0x%llx\n"
"entries location = 0x%llx length = 0x%llx\n"
"first usable = 0x%llx last usable = 0x%llx\n",
(unsigned long long) primary,
(unsigned long long) backup,
(unsigned long long) entries,
(unsigned long long) entries_len,
(unsigned long long) start,
(unsigned long long) end);
if (grub_gpt_header_check (&gpt->primary, gpt->log_sector_size))
return grub_errno;
if (primary != 1)
return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid primary GPT LBA");
if (entries <= 1 || entries+entries_len > start)
return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid entries location");
if (backup <= end)
return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid backup GPT LBA");
return GRUB_ERR_NONE;
}
static grub_err_t
grub_gpt_check_backup (grub_gpt_t gpt)
{
grub_uint64_t backup, primary, entries, entries_len, start, end;
backup = grub_le_to_cpu64 (gpt->backup.header_lba);
primary = grub_le_to_cpu64 (gpt->backup.alternate_lba);
entries = grub_le_to_cpu64 (gpt->backup.partitions);
entries_len = grub_gpt_entries_sectors(&gpt->backup, gpt->log_sector_size);
start = grub_le_to_cpu64 (gpt->backup.start);
end = grub_le_to_cpu64 (gpt->backup.end);
grub_dprintf ("gpt", "Backup GPT layout:\n"
"primary header = 0x%llx backup header = 0x%llx\n"
"entries location = 0x%llx length = 0x%llx\n"
"first usable = 0x%llx last usable = 0x%llx\n",
(unsigned long long) primary,
(unsigned long long) backup,
(unsigned long long) entries,
(unsigned long long) entries_len,
(unsigned long long) start,
(unsigned long long) end);
if (grub_gpt_header_check (&gpt->backup, gpt->log_sector_size))
return grub_errno;
if (primary != 1)
return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid primary GPT LBA");
if (entries <= end || entries+entries_len > backup)
return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid entries location");
if (backup <= end)
return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid backup GPT LBA");
/* If both primary and backup are valid but differ prefer the primary. */
if ((gpt->status & GRUB_GPT_PRIMARY_HEADER_VALID) &&
!grub_gpt_headers_equal (gpt))
return grub_error (GRUB_ERR_BAD_PART_TABLE, "backup GPT out of sync");
return GRUB_ERR_NONE;
}
static grub_err_t
grub_gpt_read_primary (grub_disk_t disk, grub_gpt_t gpt)
{
grub_disk_addr_t addr;
/* TODO: The gpt partmap module searches for the primary header instead
* of relying on the disk's sector size. For now trust the disk driver
* but eventually this code should match the existing behavior. */
gpt->log_sector_size = disk->log_sector_size;
grub_dprintf ("gpt", "reading primary GPT from sector 0x1\n");
addr = grub_gpt_sector_to_addr (gpt, 1);
if (grub_disk_read (disk, addr, 0, sizeof (gpt->primary), &gpt->primary))
return grub_errno;
if (grub_gpt_check_primary (gpt))
return grub_errno;
gpt->status |= GRUB_GPT_PRIMARY_HEADER_VALID;
if (grub_gpt_read_entries (disk, gpt, &gpt->primary,
&gpt->entries, &gpt->entries_size))
return grub_errno;
gpt->status |= GRUB_GPT_PRIMARY_ENTRIES_VALID;
return GRUB_ERR_NONE;
}
static grub_err_t
grub_gpt_read_backup (grub_disk_t disk, grub_gpt_t gpt)
{
void *entries = NULL;
grub_size_t entries_size;
grub_uint64_t sector;
grub_disk_addr_t addr;
/* Assumes gpt->log_sector_size == disk->log_sector_size */
if (gpt->status & GRUB_GPT_PRIMARY_HEADER_VALID)
{
sector = grub_le_to_cpu64 (gpt->primary.alternate_lba);
if (grub_gpt_disk_size_valid (disk) && sector >= disk->total_sectors)
return grub_error (GRUB_ERR_OUT_OF_RANGE,
"backup GPT located at 0x%llx, "
"beyond last disk sector at 0x%llx",
(unsigned long long) sector,
(unsigned long long) disk->total_sectors - 1);
}
else if (grub_gpt_disk_size_valid (disk))
sector = disk->total_sectors - 1;
else
return grub_error (GRUB_ERR_OUT_OF_RANGE,
"size of disk unknown, cannot locate backup GPT");
grub_dprintf ("gpt", "reading backup GPT from sector 0x%llx\n",
(unsigned long long) sector);
addr = grub_gpt_sector_to_addr (gpt, sector);
if (grub_disk_read (disk, addr, 0, sizeof (gpt->backup), &gpt->backup))
return grub_errno;
if (grub_gpt_check_backup (gpt))
return grub_errno;
/* Ensure the backup header thinks it is located where we found it. */
if (grub_le_to_cpu64 (gpt->backup.header_lba) != sector)
return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid backup GPT LBA");
gpt->status |= GRUB_GPT_BACKUP_HEADER_VALID;
if (grub_gpt_read_entries (disk, gpt, &gpt->backup,
&entries, &entries_size))
return grub_errno;
if (gpt->status & GRUB_GPT_PRIMARY_ENTRIES_VALID)
{
if (entries_size != gpt->entries_size ||
grub_memcmp (entries, gpt->entries, entries_size) != 0)
return grub_error (GRUB_ERR_BAD_PART_TABLE, "backup GPT out of sync");
grub_free (entries);
}
else
{
gpt->entries = entries;
gpt->entries_size = entries_size;
}
gpt->status |= GRUB_GPT_BACKUP_ENTRIES_VALID;
return GRUB_ERR_NONE;
}
static grub_err_t
grub_gpt_read_entries (grub_disk_t disk, grub_gpt_t gpt,
struct grub_gpt_header *header,
void **ret_entries,
grub_size_t *ret_entries_size)
{
void *entries = NULL;
grub_uint32_t count, size, crc;
grub_uint64_t sector;
grub_disk_addr_t addr;
grub_size_t entries_size;
/* Grub doesn't include calloc, hence the manual overflow check. */
count = grub_le_to_cpu32 (header->maxpart);
size = grub_le_to_cpu32 (header->partentry_size);
entries_size = count *size;
if (size && entries_size / size != count)
{
grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
goto fail;
}
/* Double check that the header was validated properly. */
if (entries_size < GRUB_GPT_DEFAULT_ENTRIES_SIZE)
return grub_error (GRUB_ERR_BUG, "invalid GPT entries table size");
entries = grub_malloc (entries_size);
if (!entries)
goto fail;
sector = grub_le_to_cpu64 (header->partitions);
grub_dprintf ("gpt", "reading GPT %lu entries from sector 0x%llx\n",
(unsigned long) count,
(unsigned long long) sector);
addr = grub_gpt_sector_to_addr (gpt, sector);
if (grub_disk_read (disk, addr, 0, entries_size, entries))
goto fail;
grub_gpt_lecrc32 (&crc, entries, entries_size);
if (crc != header->partentry_crc32)
{
grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid GPT entry crc32");
goto fail;
}
*ret_entries = entries;
*ret_entries_size = entries_size;
return GRUB_ERR_NONE;
fail:
grub_free (entries);
return grub_errno;
}
grub_gpt_t
grub_gpt_read (grub_disk_t disk)
{
grub_gpt_t gpt;
grub_dprintf ("gpt", "reading GPT from %s\n", disk->name);
gpt = grub_zalloc (sizeof (*gpt));
if (!gpt)
goto fail;
if (grub_disk_read (disk, 0, 0, sizeof (gpt->mbr), &gpt->mbr))
goto fail;
/* Check the MBR but errors aren't reported beyond the status bit. */
if (grub_gpt_pmbr_check (&gpt->mbr))
grub_errno = GRUB_ERR_NONE;
else
gpt->status |= GRUB_GPT_PROTECTIVE_MBR;
/* If both the primary and backup fail report the primary's error. */
if (grub_gpt_read_primary (disk, gpt))
{
grub_error_push ();
grub_gpt_read_backup (disk, gpt);
grub_error_pop ();
}
else
grub_gpt_read_backup (disk, gpt);
/* If either succeeded clear any possible error from the other. */
if (grub_gpt_primary_valid (gpt) || grub_gpt_backup_valid (gpt))
grub_errno = GRUB_ERR_NONE;
else
goto fail;
return gpt;
fail:
grub_gpt_free (gpt);
return NULL;
}
struct grub_gpt_partentry *
grub_gpt_get_partentry (grub_gpt_t gpt, grub_uint32_t n)
{
struct grub_gpt_header *header;
grub_size_t offset;
header = grub_gpt_get_header (gpt);
if (!header)
return NULL;
if (n >= grub_le_to_cpu32 (header->maxpart))
return NULL;
offset = (grub_size_t) grub_le_to_cpu32 (header->partentry_size) * n;
return (struct grub_gpt_partentry *) ((char *) gpt->entries + offset);
}
grub_err_t
grub_gpt_repair (grub_disk_t disk, grub_gpt_t gpt)
{
/* Skip if there is nothing to do. */
if (grub_gpt_both_valid (gpt))
return GRUB_ERR_NONE;
grub_dprintf ("gpt", "repairing GPT for %s\n", disk->name);
if (disk->log_sector_size != gpt->log_sector_size)
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"GPT sector size must match disk sector size");
if (grub_gpt_primary_valid (gpt))
{
grub_uint64_t backup_header;
grub_dprintf ("gpt", "primary GPT is valid\n");
/* Relocate backup to end if disk if the disk has grown. */
backup_header = grub_le_to_cpu64 (gpt->primary.alternate_lba);
if (grub_gpt_disk_size_valid (disk) &&
disk->total_sectors - 1 > backup_header)
{
backup_header = disk->total_sectors - 1;
grub_dprintf ("gpt", "backup GPT header relocated to 0x%llx\n",
(unsigned long long) backup_header);
gpt->primary.alternate_lba = grub_cpu_to_le64 (backup_header);
}
grub_memcpy (&gpt->backup, &gpt->primary, sizeof (gpt->backup));
gpt->backup.header_lba = gpt->primary.alternate_lba;
gpt->backup.alternate_lba = gpt->primary.header_lba;
gpt->backup.partitions = grub_cpu_to_le64 (backup_header -
grub_gpt_size_to_sectors (gpt, gpt->entries_size));
}
else if (grub_gpt_backup_valid (gpt))
{
grub_dprintf ("gpt", "backup GPT is valid\n");
grub_memcpy (&gpt->primary, &gpt->backup, sizeof (gpt->primary));
gpt->primary.header_lba = gpt->backup.alternate_lba;
gpt->primary.alternate_lba = gpt->backup.header_lba;
gpt->primary.partitions = grub_cpu_to_le64_compile_time (2);
}
else
return grub_error (GRUB_ERR_BUG, "No valid GPT");
if (grub_gpt_update (gpt))
return grub_errno;
grub_dprintf ("gpt", "repairing GPT for %s successful\n", disk->name);
return GRUB_ERR_NONE;
}
grub_err_t
grub_gpt_update (grub_gpt_t gpt)
{
grub_uint32_t crc;
/* Clear status bits, require revalidation of everything. */
gpt->status &= ~(GRUB_GPT_PRIMARY_HEADER_VALID |
GRUB_GPT_PRIMARY_ENTRIES_VALID |
GRUB_GPT_BACKUP_HEADER_VALID |
GRUB_GPT_BACKUP_ENTRIES_VALID);
/* Writing headers larger than our header structure are unsupported. */
gpt->primary.headersize =
grub_cpu_to_le32_compile_time (sizeof (gpt->primary));
gpt->backup.headersize =
grub_cpu_to_le32_compile_time (sizeof (gpt->backup));
grub_gpt_lecrc32 (&crc, gpt->entries, gpt->entries_size);
gpt->primary.partentry_crc32 = crc;
gpt->backup.partentry_crc32 = crc;
grub_gpt_header_lecrc32 (&gpt->primary.crc32, &gpt->primary);
grub_gpt_header_lecrc32 (&gpt->backup.crc32, &gpt->backup);
if (grub_gpt_check_primary (gpt))
{
grub_error_push ();
return grub_error (GRUB_ERR_BUG, "Generated invalid GPT primary header");
}
gpt->status |= (GRUB_GPT_PRIMARY_HEADER_VALID |
GRUB_GPT_PRIMARY_ENTRIES_VALID);
if (grub_gpt_check_backup (gpt))
{
grub_error_push ();
return grub_error (GRUB_ERR_BUG, "Generated invalid GPT backup header");
}
gpt->status |= (GRUB_GPT_BACKUP_HEADER_VALID |
GRUB_GPT_BACKUP_ENTRIES_VALID);
return GRUB_ERR_NONE;
}
static grub_err_t
grub_gpt_write_table (grub_disk_t disk, grub_gpt_t gpt,
struct grub_gpt_header *header)
{
grub_disk_addr_t addr;
if (grub_le_to_cpu32 (header->headersize) != sizeof (*header))
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"Header size is %u, must be %u",
grub_le_to_cpu32 (header->headersize),
sizeof (*header));
addr = grub_gpt_sector_to_addr (gpt, grub_le_to_cpu64 (header->header_lba));
if (addr == 0)
return grub_error (GRUB_ERR_BUG,
"Refusing to write GPT header to address 0x0");
if (grub_disk_write (disk, addr, 0, sizeof (*header), header))
return grub_errno;
addr = grub_gpt_sector_to_addr (gpt, grub_le_to_cpu64 (header->partitions));
if (addr < 2)
return grub_error (GRUB_ERR_BUG,
"Refusing to write GPT entries to address 0x%llx",
(unsigned long long) addr);
if (grub_disk_write (disk, addr, 0, gpt->entries_size, gpt->entries))
return grub_errno;
return GRUB_ERR_NONE;
}
grub_err_t
grub_gpt_write (grub_disk_t disk, grub_gpt_t gpt)
{
grub_uint64_t backup_header;
/* TODO: update/repair protective MBRs too. */
if (!grub_gpt_both_valid (gpt))
return grub_error (GRUB_ERR_BAD_PART_TABLE, "Invalid GPT data");
/* Write the backup GPT first so if writing fails the update is aborted
* and the primary is left intact. However if the backup location is
* inaccessible we have to just skip and hope for the best, the backup
* will need to be repaired in the OS. */
backup_header = grub_le_to_cpu64 (gpt->backup.header_lba);
if (grub_gpt_disk_size_valid (disk) &&
backup_header >= disk->total_sectors)
{
grub_printf ("warning: backup GPT located at 0x%llx, "
"beyond last disk sector at 0x%llx\n",
(unsigned long long) backup_header,
(unsigned long long) disk->total_sectors - 1);
grub_printf ("warning: only writing primary GPT, "
"the backup GPT must be repaired from the OS\n");
}
else
{
grub_dprintf ("gpt", "writing backup GPT to %s\n", disk->name);
if (grub_gpt_write_table (disk, gpt, &gpt->backup))
return grub_errno;
}
grub_dprintf ("gpt", "writing primary GPT to %s\n", disk->name);
if (grub_gpt_write_table (disk, gpt, &gpt->primary))
return grub_errno;
return GRUB_ERR_NONE;
}
void
grub_gpt_free (grub_gpt_t gpt)
{
if (!gpt)
return;
grub_free (gpt->entries);
grub_free (gpt);
}

View file

@ -32,6 +32,8 @@
#include <grub/i18n.h>
#include <grub/lib/cmdline.h>
#include <grub/verity-hash.h>
GRUB_MOD_LICENSE ("GPLv3+");
static grub_dl_t my_mod;
@ -297,7 +299,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
grub_dprintf ("linux", "kernel @ %p\n", kernel_addr);
cmdline_size = grub_loader_cmdline_size (argc, argv) + sizeof (LINUX_IMAGE);
cmdline_size = grub_loader_cmdline_size (argc, argv) + sizeof (LINUX_IMAGE)
+ VERITY_CMDLINE_LENGTH;
linux_args = grub_malloc (cmdline_size);
if (!linux_args)
{
@ -311,6 +314,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
if (grub_errno == GRUB_ERR_NONE)
{
grub_pass_verity_hash (kernel_addr, linux_args, cmdline_size);
grub_loader_set (grub_linux_boot, grub_linux_unload, 0);
loaded = 1;
}

View file

@ -0,0 +1,361 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2012 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 <grub/loader.h>
#include <grub/file.h>
#include <grub/err.h>
#include <grub/types.h>
#include <grub/mm.h>
#include <grub/cpu/linux.h>
#include <grub/command.h>
#include <grub/i18n.h>
#include <grub/lib/cmdline.h>
#include <grub/efi/efi.h>
#include <grub/tpm.h>
#include <grub/verity-hash.h>
GRUB_MOD_LICENSE ("GPLv3+");
static grub_dl_t my_mod;
static int loaded;
static void *kernel_mem;
static grub_uint64_t kernel_size;
static grub_uint8_t *initrd_mem;
static grub_uint32_t handover_offset;
struct linux_kernel_params *params;
static char *linux_cmdline;
#define BYTES_TO_PAGES(bytes) (((bytes) + 0xfff) >> 12)
#define SHIM_LOCK_GUID \
{ 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} }
struct grub_efi_shim_lock
{
grub_efi_status_t (*verify) (void *buffer, grub_uint32_t size);
};
typedef struct grub_efi_shim_lock grub_efi_shim_lock_t;
static grub_efi_boolean_t
grub_linuxefi_secure_validate (void *data, grub_uint32_t size)
{
grub_efi_guid_t guid = SHIM_LOCK_GUID;
grub_efi_shim_lock_t *shim_lock;
shim_lock = grub_efi_locate_protocol(&guid, NULL);
if (!shim_lock) {
if (grub_efi_secure_boot())
return 0;
else
return 1;
}
if (shim_lock->verify(data, size) == GRUB_EFI_SUCCESS)
return 1;
return 0;
}
typedef void(*handover_func)(void *, grub_efi_system_table_t *, struct linux_kernel_params *);
static grub_err_t
grub_linuxefi_boot (void)
{
handover_func hf;
int offset = 0;
#ifdef __x86_64__
offset = 512;
#endif
hf = (handover_func)((char *)kernel_mem + handover_offset + offset);
asm volatile ("cli");
hf (grub_efi_image_handle, grub_efi_system_table, params);
/* Not reached */
return GRUB_ERR_NONE;
}
static grub_err_t
grub_linuxefi_unload (void)
{
grub_dl_unref (my_mod);
loaded = 0;
if (initrd_mem)
grub_efi_free_pages((grub_efi_physical_address_t)initrd_mem, BYTES_TO_PAGES(params->ramdisk_size));
if (linux_cmdline)
grub_efi_free_pages((grub_efi_physical_address_t)linux_cmdline, BYTES_TO_PAGES(params->cmdline_size + 1));
if (kernel_mem)
grub_efi_free_pages((grub_efi_physical_address_t)kernel_mem, BYTES_TO_PAGES(kernel_size));
if (params)
grub_efi_free_pages((grub_efi_physical_address_t)params, BYTES_TO_PAGES(16384));
return GRUB_ERR_NONE;
}
static grub_err_t
grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{
grub_file_t *files = 0;
int i, nfiles = 0;
grub_size_t size = 0;
grub_uint8_t *ptr;
if (argc == 0)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
goto fail;
}
if (!loaded)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first"));
goto fail;
}
files = grub_zalloc (argc * sizeof (files[0]));
if (!files)
goto fail;
for (i = 0; i < argc; i++)
{
grub_file_filter_disable_compression ();
files[i] = grub_file_open (argv[i]);
if (! files[i])
goto fail;
nfiles++;
size += ALIGN_UP (grub_file_size (files[i]), 4);
}
initrd_mem = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(size));
if (!initrd_mem)
{
grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate initrd"));
goto fail;
}
params->ramdisk_size = size;
params->ramdisk_image = (grub_uint32_t)(grub_uint64_t) initrd_mem;
ptr = initrd_mem;
for (i = 0; i < nfiles; i++)
{
grub_ssize_t cursize = grub_file_size (files[i]);
if (grub_file_read (files[i], ptr, cursize) != cursize)
{
if (!grub_errno)
grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
argv[i]);
goto fail;
}
grub_tpm_measure (ptr, cursize, GRUB_BINARY_PCR, "grub_linuxefi", "Initrd");
grub_print_error();
ptr += cursize;
grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
ptr += ALIGN_UP_OVERHEAD (cursize, 4);
}
params->ramdisk_size = size;
fail:
for (i = 0; i < nfiles; i++)
grub_file_close (files[i]);
grub_free (files);
if (initrd_mem && grub_errno)
grub_efi_free_pages((grub_efi_physical_address_t)initrd_mem, BYTES_TO_PAGES(size));
return grub_errno;
}
static grub_err_t
grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{
grub_file_t file = 0;
struct linux_kernel_header lh;
grub_ssize_t len, start, filelen;
void *kernel = NULL;
grub_dl_ref (my_mod);
if (argc == 0)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
goto fail;
}
file = grub_file_open (argv[0]);
if (! file)
goto fail;
filelen = grub_file_size (file);
kernel = grub_malloc(filelen);
if (!kernel)
{
grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel buffer"));
goto fail;
}
if (grub_file_read (file, kernel, filelen) != filelen)
{
grub_error (GRUB_ERR_FILE_READ_ERROR, N_("Can't read kernel %s"), argv[0]);
goto fail;
}
grub_tpm_measure (kernel, filelen, GRUB_BINARY_PCR, "grub_linuxefi", "Kernel");
grub_print_error();
if (! grub_linuxefi_secure_validate (kernel, filelen))
{
grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), argv[0]);
grub_free (kernel);
goto fail;
}
params = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(16384));
if (! params)
{
grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters");
goto fail;
}
grub_memset (params, 0, 16384);
grub_memcpy (&lh, kernel, sizeof (lh));
if (lh.boot_flag != grub_cpu_to_le16 (0xaa55))
{
grub_error (GRUB_ERR_BAD_OS, N_("invalid magic number"));
goto fail;
}
if (lh.setup_sects > GRUB_LINUX_MAX_SETUP_SECTS)
{
grub_error (GRUB_ERR_BAD_OS, N_("too many setup sectors"));
goto fail;
}
if (lh.version < grub_cpu_to_le16 (0x020b))
{
grub_error (GRUB_ERR_BAD_OS, N_("kernel too old"));
goto fail;
}
if (!lh.handover_offset)
{
grub_error (GRUB_ERR_BAD_OS, N_("kernel doesn't support EFI handover"));
goto fail;
}
linux_cmdline = grub_efi_allocate_pages_max(0x3fffffff,
BYTES_TO_PAGES(lh.cmdline_size + 1));
if (!linux_cmdline)
{
grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate cmdline"));
goto fail;
}
grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE));
grub_create_loader_cmdline (argc, argv,
linux_cmdline + sizeof (LINUX_IMAGE) - 1,
lh.cmdline_size - (sizeof (LINUX_IMAGE) - 1));
grub_pass_verity_hash(&lh, linux_cmdline, lh.cmdline_size);
lh.cmd_line_ptr = (grub_uint32_t)(grub_uint64_t)linux_cmdline;
handover_offset = lh.handover_offset;
start = (lh.setup_sects + 1) * 512;
len = grub_file_size(file) - start;
kernel_mem = grub_efi_allocate_pages(lh.pref_address,
BYTES_TO_PAGES(lh.init_size));
if (!kernel_mem)
kernel_mem = grub_efi_allocate_pages_max(0x3fffffff,
BYTES_TO_PAGES(lh.init_size));
if (!kernel_mem)
{
grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate kernel"));
goto fail;
}
grub_memcpy (kernel_mem, (char *)kernel + start, len);
grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0);
loaded=1;
lh.code32_start = (grub_uint32_t)(grub_uint64_t) kernel_mem;
grub_memcpy (params, &lh, 2 * 512);
params->type_of_loader = 0x21;
fail:
if (file)
grub_file_close (file);
grub_free (kernel);
if (grub_errno != GRUB_ERR_NONE)
{
grub_dl_unref (my_mod);
loaded = 0;
}
if (linux_cmdline && !loaded)
grub_efi_free_pages((grub_efi_physical_address_t)linux_cmdline, BYTES_TO_PAGES(lh.cmdline_size + 1));
if (kernel_mem && !loaded)
grub_efi_free_pages((grub_efi_physical_address_t)kernel_mem, BYTES_TO_PAGES(kernel_size));
if (params && !loaded)
grub_efi_free_pages((grub_efi_physical_address_t)params, BYTES_TO_PAGES(16384));
return grub_errno;
}
static grub_command_t cmd_linux, cmd_initrd;
GRUB_MOD_INIT(linuxefi)
{
cmd_linux =
grub_register_command ("linuxefi", grub_cmd_linux,
0, N_("Load Linux."));
cmd_initrd =
grub_register_command ("initrdefi", grub_cmd_initrd,
0, N_("Load initrd."));
my_mod = mod;
}
GRUB_MOD_FINI(linuxefi)
{
grub_unregister_command (cmd_linux);
grub_unregister_command (cmd_initrd);
}

View file

@ -35,6 +35,9 @@
#include <grub/i18n.h>
#include <grub/lib/cmdline.h>
#include <grub/linux.h>
#include <grub/tpm.h>
#include <grub/verity-hash.h>
GRUB_MOD_LICENSE ("GPLv3+");
@ -680,12 +683,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
grub_file_t file = 0;
struct linux_kernel_header lh;
grub_uint8_t setup_sects;
grub_size_t real_size, prot_size, prot_file_size;
grub_size_t real_size, prot_size, prot_file_size, kernel_offset;
grub_ssize_t len;
int i;
grub_size_t align, min_align;
int relocatable;
grub_uint64_t preferred_address = GRUB_LINUX_BZIMAGE_ADDR;
grub_uint8_t *kernel = NULL;
grub_dl_ref (my_mod);
@ -699,7 +703,15 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
if (! file)
goto fail;
if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh))
len = grub_file_size (file);
kernel = grub_malloc (len);
if (!kernel)
{
grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel buffer"));
goto fail;
}
if (grub_file_read (file, kernel, len) != len)
{
if (!grub_errno)
grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
@ -707,6 +719,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
goto fail;
}
grub_tpm_measure (kernel, len, GRUB_BINARY_PCR, "grub_linux", "Kernel");
grub_print_error();
grub_memcpy (&lh, kernel, sizeof (lh));
kernel_offset = sizeof (lh);
if (lh.boot_flag != grub_cpu_to_le16_compile_time (0xaa55))
{
grub_error (GRUB_ERR_BAD_OS, "invalid magic number");
@ -806,13 +825,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
linux_params.ps_mouse = linux_params.padding10 = 0;
len = sizeof (linux_params) - 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;
}
grub_memcpy ((char *) &linux_params + sizeof (lh), kernel + kernel_offset, len);
kernel_offset += len;
linux_params.type_of_loader = GRUB_LINUX_BOOT_LOADER_TYPE;
@ -871,7 +886,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
/* The other parameters are filled when booting. */
grub_file_seek (file, real_size + GRUB_DISK_SECTOR_SIZE);
kernel_offset = real_size + GRUB_DISK_SECTOR_SIZE;
grub_dprintf ("linux", "bzImage, setup=0x%x, size=0x%x\n",
(unsigned) real_size, (unsigned) prot_size);
@ -1018,10 +1033,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
maximal_cmdline_size
- (sizeof (LINUX_IMAGE) - 1));
grub_pass_verity_hash(&lh, linux_cmdline, maximal_cmdline_size);
len = prot_file_size;
if (grub_file_read (file, prot_mode_mem, len) != len && !grub_errno)
grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
argv[0]);
grub_memcpy (prot_mode_mem, kernel + kernel_offset, len);
kernel_offset += len;
if (grub_errno == GRUB_ERR_NONE)
{
@ -1032,6 +1047,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
fail:
grub_free (kernel);
if (file)
grub_file_close (file);

View file

@ -36,6 +36,7 @@
#include <grub/net.h>
#include <grub/i18n.h>
#include <grub/lib/cmdline.h>
#include <grub/tpm.h>
#ifdef GRUB_MACHINE_EFI
#include <grub/efi/efi.h>
@ -173,6 +174,9 @@ grub_multiboot_load (grub_file_t file, const char *filename)
return grub_errno;
}
grub_tpm_measure((unsigned char*)buffer, len, GRUB_BINARY_PCR, "grub_multiboot", filename);
grub_print_error();
header = find_header (buffer, len);
if (header == 0)

View file

@ -35,6 +35,7 @@
#include <grub/i386/floppy.h>
#include <grub/lib/cmdline.h>
#include <grub/linux.h>
#include <grub/tpm.h>
GRUB_MOD_LICENSE ("GPLv3+");
@ -123,13 +124,14 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
grub_file_t file = 0;
struct linux_kernel_header lh;
grub_uint8_t setup_sects;
grub_size_t real_size;
grub_size_t real_size, kernel_offset = 0;
grub_ssize_t len;
int i;
char *grub_linux_prot_chunk;
int grub_linux_is_bzimage;
grub_addr_t grub_linux_prot_target;
grub_err_t err;
grub_uint8_t *kernel = NULL;
grub_dl_ref (my_mod);
@ -143,7 +145,15 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
if (! file)
goto fail;
if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh))
len = grub_file_size (file);
kernel = grub_malloc (len);
if (!kernel)
{
grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel buffer"));
goto fail;
}
if (grub_file_read (file, kernel, len) != len)
{
if (!grub_errno)
grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
@ -151,6 +161,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
goto fail;
}
grub_tpm_measure (kernel, len, GRUB_BINARY_PCR, "grub_linux16", "Kernel");
grub_print_error();
grub_memcpy (&lh, kernel, sizeof (lh));
kernel_offset = sizeof (lh);
if (lh.boot_flag != grub_cpu_to_le16_compile_time (0xaa55))
{
grub_error (GRUB_ERR_BAD_OS, "invalid magic number");
@ -314,13 +330,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
grub_memmove (grub_linux_real_chunk, &lh, sizeof (lh));
len = real_size + GRUB_DISK_SECTOR_SIZE - sizeof (lh);
if (grub_file_read (file, grub_linux_real_chunk + sizeof (lh), len) != len)
{
if (!grub_errno)
grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
argv[0]);
goto fail;
}
grub_memcpy (grub_linux_real_chunk + sizeof (lh), kernel + kernel_offset,
len);
kernel_offset += len;
if (lh.header != grub_cpu_to_le32_compile_time (GRUB_LINUX_MAGIC_SIGNATURE)
|| grub_le_to_cpu16 (lh.version) < 0x0200)
@ -355,10 +367,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
}
len = grub_linux16_prot_size;
if (grub_file_read (file, grub_linux_prot_chunk, grub_linux16_prot_size)
!= (grub_ssize_t) grub_linux16_prot_size && !grub_errno)
grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
argv[0]);
grub_memcpy (grub_linux_prot_chunk, kernel + kernel_offset, len);
kernel_offset += len;
if (grub_errno == GRUB_ERR_NONE)
{
@ -368,6 +378,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
fail:
grub_free (kernel);
if (file)
grub_file_close (file);

View file

@ -652,7 +652,9 @@ grub_cmd_xen (grub_command_t cmd __attribute__ ((unused)),
if (!file)
return grub_errno;
elf = grub_xen_file (file);
elf = grub_xen_file_and_cmdline (file,
(char *) xen_state.next_start.cmd_line,
sizeof (xen_state.next_start.cmd_line) - 1);
if (!elf)
goto fail;

View file

@ -19,11 +19,20 @@
#include <grub/xen_file.h>
#include <grub/i386/linux.h>
#include <grub/misc.h>
#include <grub/verity-hash.h>
#define XZ_MAGIC "\3757zXZ\0"
grub_elf_t
grub_xen_file (grub_file_t file)
{
return grub_xen_file_and_cmdline (file, NULL, 0);
}
grub_elf_t
grub_xen_file_and_cmdline (grub_file_t file,
char *cmdline,
grub_size_t cmdline_max_len)
{
grub_elf_t elf;
struct linux_kernel_header lh;
@ -64,6 +73,9 @@ grub_xen_file (grub_file_t file)
(unsigned long long) payload_offset,
(unsigned long long) lh.payload_length);
if (cmdline)
grub_pass_verity_hash (&lh, cmdline, cmdline_max_len);
grub_file_seek (file, payload_offset);
if (grub_file_read (file, &magic, sizeof (magic)) != sizeof (magic))

View file

@ -4,6 +4,7 @@
#include <grub/misc.h>
#include <grub/file.h>
#include <grub/mm.h>
#include <grub/tpm.h>
struct newc_head
{
@ -288,6 +289,9 @@ grub_initrd_load (struct grub_linux_initrd_context *initrd_ctx,
grub_initrd_close (initrd_ctx);
return grub_errno;
}
grub_tpm_measure (ptr, cursize, GRUB_BINARY_PCR, "grub_initrd", "Initrd");
grub_print_error();
ptr += cursize;
}
if (newc)

View file

@ -42,6 +42,7 @@
#include <grub/video.h>
#include <grub/memory.h>
#include <grub/i18n.h>
#include <grub/tpm.h>
GRUB_MOD_LICENSE ("GPLv3+");
@ -424,6 +425,8 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)),
}
grub_file_close (file);
grub_tpm_measure (module, size, GRUB_BINARY_PCR, "grub_multiboot", argv[0]);
grub_print_error();
return GRUB_ERR_NONE;
}

View file

@ -36,6 +36,7 @@
#include <grub/i18n.h>
#include <grub/net.h>
#include <grub/lib/cmdline.h>
#include <grub/tpm.h>
#if defined (GRUB_MACHINE_EFI)
#include <grub/efi/efi.h>
@ -131,6 +132,9 @@ grub_multiboot_load (grub_file_t file, const char *filename)
COMPILE_TIME_ASSERT (MULTIBOOT_HEADER_ALIGN % 4 == 0);
grub_tpm_measure ((unsigned char *)mld.buffer, len, GRUB_BINARY_PCR, "grub_multiboot", filename);
grub_print_error();
header = find_header (mld.buffer, len);
if (header == 0)

View file

@ -25,6 +25,24 @@
#include <grub/net/udp.h>
#include <grub/datetime.h>
#if !defined(GRUB_MACHINE_EFI) && (defined(__i386__) || defined(__x86_64__))
#define GRUB_NET_BOOTP_ARCH 0x0000
#elif defined(GRUB_MACHINE_EFI) && defined(__x86_64__)
#define GRUB_NET_BOOTP_ARCH 0x0007
#elif defined(GRUB_MACHINE_EFI) && defined(__aarch64__)
#define GRUB_NET_BOOTP_ARCH 0x000B
#else
#error "unknown bootp architecture"
#endif
static grub_uint8_t dhcp_option_header[] = {GRUB_NET_BOOTP_RFC1048_MAGIC_0,
GRUB_NET_BOOTP_RFC1048_MAGIC_1,
GRUB_NET_BOOTP_RFC1048_MAGIC_2,
GRUB_NET_BOOTP_RFC1048_MAGIC_3};
static grub_uint8_t grub_userclass[] = {0x4D, 0x06, 0x05, 'G', 'R', 'U', 'B', '2'};
static grub_uint8_t grub_dhcpdiscover[] = {0x35, 0x01, 0x01};
static grub_uint8_t grub_dhcptime[] = {0x33, 0x04, 0x00, 0x00, 0x0e, 0x10};
static void
parse_dhcp_vendor (const char *name, const void *vend, int limit, int *mask)
{
@ -499,10 +517,14 @@ grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)),
struct udphdr *udph;
grub_net_network_level_address_t target;
grub_net_link_level_address_t ll_target;
grub_uint8_t *offset;
if (!ifaces[j].prev)
continue;
nb = grub_netbuff_alloc (sizeof (*pack) + 64 + 128);
nb = grub_netbuff_alloc (sizeof (*pack) + sizeof(dhcp_option_header)
+ sizeof(grub_userclass)
+ sizeof(grub_dhcpdiscover)
+ sizeof(grub_dhcptime) + 64 + 128);
if (!nb)
{
grub_netbuff_free (nb);
@ -536,6 +558,24 @@ grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)),
pack->seconds = grub_cpu_to_be16 (t);
grub_memcpy (&pack->mac_addr, &ifaces[j].hwaddress.mac, 6);
offset = (grub_uint8_t *)&pack->vendor;
grub_memcpy (offset, dhcp_option_header, sizeof(dhcp_option_header));
offset += sizeof(dhcp_option_header);
grub_memcpy (offset, grub_dhcpdiscover, sizeof(grub_dhcpdiscover));
offset += sizeof(grub_dhcpdiscover);
grub_memcpy (offset, grub_userclass, sizeof(grub_userclass));
offset += sizeof(grub_userclass);
grub_memcpy (offset, grub_dhcptime, sizeof(grub_dhcptime));
/* insert Client System Architecture (option 93) */
offset += sizeof(grub_dhcptime);
offset[0] = 93;
offset[1] = 2;
offset[2] = (GRUB_NET_BOOTP_ARCH >> 8);
offset[3] = (GRUB_NET_BOOTP_ARCH & 0xFF);
/* option terminator */
offset[4] = 255;
grub_netbuff_push (nb, sizeof (*udph));

View file

@ -285,8 +285,8 @@ recv_hook (grub_net_udp_socket_t sock __attribute__ ((unused)),
ptr++;
ptr += 4;
}
*data->addresses = grub_malloc (sizeof ((*data->addresses)[0])
* grub_be_to_cpu16 (head->ancount));
*data->addresses = grub_realloc (*data->addresses, sizeof ((*data->addresses)[0])
* (grub_be_to_cpu16 (head->ancount) + *data->naddresses));
if (!*data->addresses)
{
grub_errno = GRUB_ERR_NONE;

View file

@ -309,7 +309,7 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
{
http_data_t data = file->data;
grub_uint8_t *ptr;
int i;
int i, port;
struct grub_net_buff *nb;
grub_err_t err;
@ -390,8 +390,12 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
grub_netbuff_put (nb, 2);
grub_memcpy (ptr, "\r\n", 2);
if (file->device->net->port)
port = file->device->net->port;
else
port = HTTP_PORT;
data->sock = grub_net_tcp_open (file->device->net->server,
HTTP_PORT, http_receive,
port, http_receive,
http_err, http_err,
file);
if (!data->sock)

View file

@ -1261,7 +1261,7 @@ grub_net_open_real (const char *name)
grub_net_app_level_t proto;
const char *protname, *server;
grub_size_t protnamelen;
int try;
int try, port = 0;
if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0)
{
@ -1278,7 +1278,18 @@ grub_net_open_real (const char *name)
else
{
const char *comma;
char *colon;
comma = grub_strchr (name, ',');
if (!comma)
{
comma = grub_strchr (name, ';');
}
colon = grub_strchr (name, ':');
if (colon)
{
port = (int) grub_strtol(colon+1, NULL, 10);
*colon = '\0';
}
if (comma)
{
protnamelen = comma - name;
@ -1313,8 +1324,13 @@ grub_net_open_real (const char *name)
ret->server = grub_strdup (server);
if (!ret->server)
{
grub_free (ret);
return NULL;
ret->server = grub_strdup (server);
ret->port = port;
if (!ret->server)
{
grub_free (ret);
return NULL;
}
}
ret->fs = &grub_net_fs;
return ret;

View file

@ -147,8 +147,8 @@ read_crypto_list (const char *prefix)
if (! cur->modname)
{
grub_errno = GRUB_ERR_NONE;
grub_free (cur);
grub_free (cur->name);
grub_free (cur);
continue;
}
cur->next = crypto_specs;

View file

@ -27,6 +27,7 @@
#include <grub/normal.h>
#include <grub/extcmd.h>
#include <grub/i18n.h>
#include <grub/tpm.h>
/* Max digits for a char is 3 (0xFF is 255), similarly for an int it
is sizeof (int) * 3, and one extra for a possible -ve sign. */
@ -929,8 +930,9 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd)
grub_err_t ret = 0;
grub_script_function_t func = 0;
char errnobuf[18];
char *cmdname;
int argc;
char *cmdname, *cmdstring;
int argc, offset = 0, cmdlen = 0;
unsigned int i;
char **args;
int invert;
struct grub_script_argv argv = { 0, 0, 0 };
@ -939,6 +941,26 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd)
if (grub_script_arglist_to_argv (cmdline->arglist, &argv) || ! argv.args[0])
return grub_errno;
for (i = 0; i < argv.argc; i++) {
cmdlen += grub_strlen (argv.args[i]) + 1;
}
cmdstring = grub_malloc (cmdlen);
if (!cmdstring)
{
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
N_("cannot allocate command buffer"));
}
for (i = 0; i < argv.argc; i++) {
offset += grub_snprintf (cmdstring + offset, cmdlen - offset, "%s ",
argv.args[i]);
}
cmdstring[cmdlen-1]= '\0';
grub_tpm_measure ((unsigned char *)cmdstring, cmdlen, GRUB_ASCII_PCR,
"grub_cmd", cmdstring);
grub_print_error();
grub_free(cmdstring);
invert = 0;
argc = argv.argc - 1;
args = argv.args + 1;