efi/libstub: use EFI provided memcpy/memset routines
authorArd Biesheuvel <ardb@kernel.org>
Tue, 9 Aug 2022 14:45:17 +0000 (16:45 +0200)
committerArd Biesheuvel <ardb@kernel.org>
Sat, 17 Sep 2022 13:13:21 +0000 (15:13 +0200)
The stub is used in different execution environments, but on arm64,
RISC-V and LoongArch, we still use the core kernel's implementation of
memcpy and memset, as they are just a branch instruction away, and can
generally be reused even from code such as the EFI stub that runs in a
completely different address space.

KAsan complicates this slightly, resulting in the need for some hacks to
expose the uninstrumented, __ prefixed versions as the normal ones, as
the latter are instrumented to include the KAsan checks, which only work
in the core kernel.

Unfortunately, #define'ing memcpy to __memcpy when building C code does
not guarantee that no explicit memcpy() calls will be emitted. And with
the upcoming zboot support, which consists of a separate binary which
therefore needs its own implementation of memcpy/memset anyway, it's
better to provide one explicitly instead of linking to the existing one.

Given that EFI exposes implementations of memmove() and memset() via the
boot services table, let's wire those up in the appropriate way, and
drop the references to the core kernel ones.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
arch/arm64/kernel/image-vars.h
arch/loongarch/kernel/image-vars.h
arch/riscv/kernel/image-vars.h
drivers/firmware/efi/libstub/Makefile
drivers/firmware/efi/libstub/efistub.h
drivers/firmware/efi/libstub/intrinsics.c [new file with mode: 0644]

index afa69e04e75eddfb5b303efb61dedb22679f6620..11643f4d864d796e05f9e3f72122c711d16fc2e2 100644 (file)
@@ -24,9 +24,6 @@ PROVIDE(__efistub_primary_entry_offset        = primary_entry - _text);
  */
 PROVIDE(__efistub_memcmp               = __pi_memcmp);
 PROVIDE(__efistub_memchr               = __pi_memchr);
-PROVIDE(__efistub_memcpy               = __pi_memcpy);
-PROVIDE(__efistub_memmove              = __pi_memmove);
-PROVIDE(__efistub_memset               = __pi_memset);
 PROVIDE(__efistub_strlen               = __pi_strlen);
 PROVIDE(__efistub_strnlen              = __pi_strnlen);
 PROVIDE(__efistub_strcmp               = __pi_strcmp);
@@ -40,16 +37,6 @@ PROVIDE(__efistub__edata             = _edata);
 PROVIDE(__efistub_screen_info          = screen_info);
 PROVIDE(__efistub__ctype               = _ctype);
 
-/*
- * The __ prefixed memcpy/memset/memmove symbols are provided by KASAN, which
- * instruments the conventional ones. Therefore, any references from the EFI
- * stub or other position independent, low level C code should be redirected to
- * the non-instrumented versions as well.
- */
-PROVIDE(__efistub___memcpy             = __pi_memcpy);
-PROVIDE(__efistub___memmove            = __pi_memmove);
-PROVIDE(__efistub___memset             = __pi_memset);
-
 PROVIDE(__pi___memcpy                  = __pi_memcpy);
 PROVIDE(__pi___memmove                 = __pi_memmove);
 PROVIDE(__pi___memset                  = __pi_memset);
index c901ebb903f2dd4e0ab7bdbadbd2d27e0e79b50b..88f5d81702dfcf688dd44defac9a1ebd194a6c66 100644 (file)
@@ -9,9 +9,6 @@
 
 __efistub_memcmp               = memcmp;
 __efistub_memchr               = memchr;
-__efistub_memcpy               = memcpy;
-__efistub_memmove              = memmove;
-__efistub_memset               = memset;
 __efistub_strcat               = strcat;
 __efistub_strcmp               = strcmp;
 __efistub_strlen               = strlen;
index 71a76a62325778c4e030b83f24e80d18c49f62bb..d6e5f739905e740c783249424e0f51a37cb7c36a 100644 (file)
  */
 __efistub_memcmp               = memcmp;
 __efistub_memchr               = memchr;
-__efistub_memcpy               = memcpy;
-__efistub_memmove              = memmove;
-__efistub_memset               = memset;
 __efistub_strlen               = strlen;
 __efistub_strnlen              = strnlen;
 __efistub_strcmp               = strcmp;
 __efistub_strncmp              = strncmp;
 __efistub_strrchr              = strrchr;
 
-#ifdef CONFIG_KASAN
-__efistub___memcpy             = memcpy;
-__efistub___memmove            = memmove;
-__efistub___memset             = memset;
-#endif
-
 __efistub__start               = _start;
 __efistub__start_kernel                = _start_kernel;
 __efistub__end                 = _end;
index ec2a7ba9364f0cf2b69e3e7ee02cf0c89c2745f5..834c0bd6503428d480421c65ed8d2cf2a42395c3 100644 (file)
@@ -65,7 +65,7 @@ efi-deps-y := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c fdt_empty_tree.c fdt_sw.c
 $(obj)/lib-%.o: $(srctree)/lib/%.c FORCE
        $(call if_changed_rule,cc_o_c)
 
-lib-$(CONFIG_EFI_GENERIC_STUB) += efi-stub.o fdt.o string.o \
+lib-$(CONFIG_EFI_GENERIC_STUB) += efi-stub.o fdt.o string.o intrinsics.o \
                                   $(patsubst %.c,lib-%.o,$(efi-deps-y))
 
 lib-$(CONFIG_ARM)              += arm32-stub.o
index c7efc404e663d74e936696425f2c8a160bf2c964..54f37e886be79280b63f03eda56fe4493bdb6937 100644 (file)
@@ -301,8 +301,8 @@ union efi_boot_services {
                efi_status_t (__efiapi *install_multiple_protocol_interfaces)(efi_handle_t *, ...);
                efi_status_t (__efiapi *uninstall_multiple_protocol_interfaces)(efi_handle_t, ...);
                void *calculate_crc32;
-               void *copy_mem;
-               void *set_mem;
+               void (__efiapi *copy_mem)(void *, const void *, unsigned long);
+               void (__efiapi *set_mem)(void *, unsigned long, unsigned char);
                void *create_event_ex;
        };
        struct {
diff --git a/drivers/firmware/efi/libstub/intrinsics.c b/drivers/firmware/efi/libstub/intrinsics.c
new file mode 100644 (file)
index 0000000..a04ab39
--- /dev/null
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/efi.h>
+#include <asm/efi.h>
+#include <asm/string.h>
+
+#include "efistub.h"
+
+#ifdef CONFIG_KASAN
+#undef memcpy
+#undef memmove
+#undef memset
+void *__memcpy(void *__dest, const void *__src, size_t __n) __alias(memcpy);
+void *__memmove(void *__dest, const void *__src, size_t count) __alias(memmove);
+void *__memset(void *s, int c, size_t count) __alias(memset);
+#endif
+
+void *memcpy(void *dst, const void *src, size_t len)
+{
+       efi_bs_call(copy_mem, dst, src, len);
+       return dst;
+}
+
+extern void *memmove(void *dst, const void *src, size_t len) __alias(memcpy);
+
+void *memset(void *dst, int c, size_t len)
+{
+       efi_bs_call(set_mem, dst, len, c & U8_MAX);
+       return dst;
+}