Ard Biesheuvel b272ed230e efi: Fix stack protector issues
The "ground truth" stack protector cookie value is kept in a global
variable, and loaded in every function prologue and epilogue to store
it into resp. compare it with the stack slot holding the cookie.

If the comparison fails, the program aborts, and this might occur
spuriously when the global variable changes values between the entry and
exit of a function. This implies that assigning the global variable at
boot should not involve any instrumented function calls, unless special
care is taken to ensure that the live call stack is synchronized, which
is non-trivial.

So avoid any function calls, including grub_memcpy(), which is
unnecessary given that the stack cookie is always a suitably aligned
variable of the native word size.

While at it, leave the last byte 0x0 to avoid inadvertent unbounded
strings on the stack.

Note that the use of __attribute__((optimize)) is described as
unsuitable for production use in the GCC documentation, so let's drop
this as well now that it is no longer needed.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Glenn Washburn <development@efficientek.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
2024-05-09 15:20:05 +02:00

331 lines
7.9 KiB
C

/* main.c - the kernel main routine */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2002,2003,2005,2006,2008,2009 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/kernel.h>
#include <grub/stack_protector.h>
#include <grub/misc.h>
#include <grub/symbol.h>
#include <grub/dl.h>
#include <grub/term.h>
#include <grub/file.h>
#include <grub/device.h>
#include <grub/env.h>
#include <grub/mm.h>
#include <grub/command.h>
#include <grub/reader.h>
#include <grub/parser.h>
#include <grub/verify.h>
#ifdef GRUB_MACHINE_PCBIOS
#include <grub/machine/memory.h>
#endif
grub_addr_t
grub_modules_get_end (void)
{
struct grub_module_info *modinfo;
modinfo = (struct grub_module_info *) grub_modbase;
/* Check if there are any modules. */
if ((modinfo == 0) || modinfo->magic != GRUB_MODULE_MAGIC)
return grub_modbase;
return grub_modbase + modinfo->size;
}
/* Load all modules in core. */
static void
grub_load_modules (void)
{
struct grub_module_header *header;
FOR_MODULES (header)
{
/* Not an ELF module, skip. */
if (header->type != OBJ_TYPE_ELF)
continue;
if (! grub_dl_load_core ((char *) header + sizeof (struct grub_module_header),
(header->size - sizeof (struct grub_module_header))))
grub_fatal ("%s", grub_errmsg);
if (grub_errno)
grub_print_error ();
}
}
static char *load_config;
static void
grub_load_config (void)
{
struct grub_module_header *header;
FOR_MODULES (header)
{
/* Not an embedded config, skip. */
if (header->type != OBJ_TYPE_CONFIG)
continue;
load_config = grub_malloc (header->size - sizeof (struct grub_module_header) + 1);
if (!load_config)
{
grub_print_error ();
break;
}
grub_memcpy (load_config, (char *) header +
sizeof (struct grub_module_header),
header->size - sizeof (struct grub_module_header));
load_config[header->size - sizeof (struct grub_module_header)] = 0;
break;
}
}
/* Write hook for the environment variables of root. Remove surrounding
parentheses, if any. */
static char *
grub_env_write_root (struct grub_env_var *var __attribute__ ((unused)),
const char *val)
{
/* XXX Is it better to check the existence of the device? */
grub_size_t len = grub_strlen (val);
if (val[0] == '(' && val[len - 1] == ')')
return grub_strndup (val + 1, len - 2);
return grub_strdup (val);
}
static void
grub_set_prefix_and_root (void)
{
char *device = NULL;
char *path = NULL;
char *fwdevice = NULL;
char *fwpath = NULL;
char *prefix = NULL;
struct grub_module_header *header;
FOR_MODULES (header)
if (header->type == OBJ_TYPE_PREFIX)
prefix = (char *) header + sizeof (struct grub_module_header);
grub_register_variable_hook ("root", 0, grub_env_write_root);
grub_machine_get_bootlocation (&fwdevice, &fwpath);
if (fwdevice)
{
char *cmdpath;
cmdpath = grub_xasprintf ("(%s)%s", fwdevice, fwpath ? : "");
if (cmdpath)
{
grub_env_set ("cmdpath", cmdpath);
grub_env_export ("cmdpath");
grub_free (cmdpath);
}
}
if (prefix)
{
char *pptr = NULL;
if (prefix[0] == '(')
{
pptr = grub_strrchr (prefix, ')');
if (pptr)
{
device = grub_strndup (prefix + 1, pptr - prefix - 1);
pptr++;
}
}
if (!pptr)
pptr = prefix;
if (pptr[0])
path = grub_strdup (pptr);
}
if (!device && fwdevice)
device = fwdevice;
else if (fwdevice && (device[0] == ',' || !device[0]))
{
/* We have a partition, but still need to fill in the drive. */
char *comma, *new_device;
for (comma = fwdevice; *comma; )
{
if (comma[0] == '\\' && comma[1] == ',')
{
comma += 2;
continue;
}
if (*comma == ',')
break;
comma++;
}
if (*comma)
{
char *drive = grub_strndup (fwdevice, comma - fwdevice);
new_device = grub_xasprintf ("%s%s", drive, device);
grub_free (drive);
}
else
new_device = grub_xasprintf ("%s%s", fwdevice, device);
grub_free (fwdevice);
grub_free (device);
device = new_device;
}
else
grub_free (fwdevice);
if (fwpath && !path)
{
grub_size_t len = grub_strlen (fwpath);
while (len > 1 && fwpath[len - 1] == '/')
fwpath[--len] = 0;
if (len >= sizeof (GRUB_TARGET_CPU "-" GRUB_PLATFORM) - 1
&& grub_memcmp (fwpath + len - (sizeof (GRUB_TARGET_CPU "-" GRUB_PLATFORM) - 1), GRUB_TARGET_CPU "-" GRUB_PLATFORM,
sizeof (GRUB_TARGET_CPU "-" GRUB_PLATFORM) - 1) == 0)
fwpath[len - (sizeof (GRUB_TARGET_CPU "-" GRUB_PLATFORM) - 1)] = 0;
path = fwpath;
}
else
grub_free (fwpath);
if (device)
{
char *prefix_set;
prefix_set = grub_xasprintf ("(%s)%s", device, path ? : "");
if (prefix_set)
{
grub_env_set ("prefix", prefix_set);
grub_free (prefix_set);
}
grub_env_set ("root", device);
}
grub_free (device);
grub_free (path);
grub_print_error ();
}
/* Load the normal mode module and execute the normal mode if possible. */
static void
grub_load_normal_mode (void)
{
/* Load the module. */
grub_dl_load ("normal");
/* Print errors if any. */
grub_print_error ();
grub_errno = 0;
grub_command_execute ("normal", 0, 0);
}
static void
reclaim_module_space (void)
{
grub_addr_t modstart, modend;
if (!grub_modbase)
return;
#ifdef GRUB_MACHINE_PCBIOS
modstart = GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR;
#else
modstart = grub_modbase;
#endif
modend = grub_modules_get_end ();
grub_modbase = 0;
#if GRUB_KERNEL_PRELOAD_SPACE_REUSABLE
grub_mm_init_region ((void *) modstart, modend - modstart);
#else
(void) modstart;
(void) modend;
#endif
}
/* The main routine. */
void __attribute__ ((noreturn))
grub_main (void)
{
#ifdef GRUB_STACK_PROTECTOR
/*
* This call should only be made from a function that does not return because
* functions that return will get instrumented to check that the stack cookie
* does not change and this call will change the stack cookie. Thus a stack
* guard failure will be triggered.
*/
grub_update_stack_guard ();
#endif
/* First of all, initialize the machine. */
grub_machine_init ();
grub_boot_time ("After machine init.");
/* This breaks flicker-free boot on EFI systems, so disable it there. */
#ifndef GRUB_MACHINE_EFI
/* Hello. */
grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT);
grub_printf ("Welcome to GRUB!\n\n");
grub_setcolorstate (GRUB_TERM_COLOR_STANDARD);
#endif
/* Init verifiers API. */
grub_verifiers_init ();
grub_load_config ();
grub_boot_time ("Before loading embedded modules.");
/* Load pre-loaded modules and free the space. */
grub_register_exported_symbols ();
#ifdef GRUB_LINKER_HAVE_INIT
grub_arch_dl_init_linker ();
#endif
grub_load_modules ();
grub_boot_time ("After loading embedded modules.");
/* It is better to set the root device as soon as possible,
for convenience. */
grub_set_prefix_and_root ();
grub_env_export ("root");
grub_env_export ("prefix");
/* Reclaim space used for modules. */
reclaim_module_space ();
grub_boot_time ("After reclaiming module space.");
grub_register_core_commands ();
grub_boot_time ("Before execution of embedded config.");
if (load_config)
grub_parser_execute (load_config);
grub_boot_time ("After execution of embedded config. Attempt to go to normal mode");
grub_load_normal_mode ();
grub_rescue_run ();
}