efi/x86: Check number of arguments to variadic functions
On x86 we need to thunk through assembler stubs to call the EFI services for mixed mode, and for runtime services in 64-bit mode. The assembler stubs have limits on how many arguments it handles. Introduce a few macros to check that we do not try to pass too many arguments to the stubs. Signed-off-by: Arvind Sankar <nivedita@alum.mit.edu> Signed-off-by: Ard Biesheuvel <ardb@kernel.org> Cc: Andy Lutomirski <luto@kernel.org> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org> Cc: Matthew Garrett <mjg59@google.com> Cc: linux-efi@vger.kernel.org Link: https://lkml.kernel.org/r/20200103113953.9571-16-ardb@kernel.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
Родитель
4684abe375
Коммит
14b864f4b5
|
@ -23,7 +23,7 @@
|
|||
|
||||
.code64
|
||||
.text
|
||||
SYM_FUNC_START(efi64_thunk)
|
||||
SYM_FUNC_START(__efi64_thunk)
|
||||
push %rbp
|
||||
push %rbx
|
||||
|
||||
|
@ -95,7 +95,7 @@ SYM_FUNC_START(efi64_thunk)
|
|||
pop %rbx
|
||||
pop %rbp
|
||||
ret
|
||||
SYM_FUNC_END(efi64_thunk)
|
||||
SYM_FUNC_END(__efi64_thunk)
|
||||
|
||||
.code32
|
||||
/*
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <asm/tlb.h>
|
||||
#include <asm/nospec-branch.h>
|
||||
#include <asm/mmu_context.h>
|
||||
#include <linux/build_bug.h>
|
||||
|
||||
/*
|
||||
* We map the EFI regions needed for runtime services non-contiguously,
|
||||
|
@ -34,6 +35,45 @@
|
|||
|
||||
#define ARCH_EFI_IRQ_FLAGS_MASK X86_EFLAGS_IF
|
||||
|
||||
/*
|
||||
* The EFI services are called through variadic functions in many cases. These
|
||||
* functions are implemented in assembler and support only a fixed number of
|
||||
* arguments. The macros below allows us to check at build time that we don't
|
||||
* try to call them with too many arguments.
|
||||
*
|
||||
* __efi_nargs() will return the number of arguments if it is 7 or less, and
|
||||
* cause a BUILD_BUG otherwise. The limitations of the C preprocessor make it
|
||||
* impossible to calculate the exact number of arguments beyond some
|
||||
* pre-defined limit. The maximum number of arguments currently supported by
|
||||
* any of the thunks is 7, so this is good enough for now and can be extended
|
||||
* in the obvious way if we ever need more.
|
||||
*/
|
||||
|
||||
#define __efi_nargs(...) __efi_nargs_(__VA_ARGS__)
|
||||
#define __efi_nargs_(...) __efi_nargs__(0, ##__VA_ARGS__, \
|
||||
__efi_arg_sentinel(7), __efi_arg_sentinel(6), \
|
||||
__efi_arg_sentinel(5), __efi_arg_sentinel(4), \
|
||||
__efi_arg_sentinel(3), __efi_arg_sentinel(2), \
|
||||
__efi_arg_sentinel(1), __efi_arg_sentinel(0))
|
||||
#define __efi_nargs__(_0, _1, _2, _3, _4, _5, _6, _7, n, ...) \
|
||||
__take_second_arg(n, \
|
||||
({ BUILD_BUG_ON_MSG(1, "__efi_nargs limit exceeded"); 8; }))
|
||||
#define __efi_arg_sentinel(n) , n
|
||||
|
||||
/*
|
||||
* __efi_nargs_check(f, n, ...) will cause a BUILD_BUG if the ellipsis
|
||||
* represents more than n arguments.
|
||||
*/
|
||||
|
||||
#define __efi_nargs_check(f, n, ...) \
|
||||
__efi_nargs_check_(f, __efi_nargs(__VA_ARGS__), n)
|
||||
#define __efi_nargs_check_(f, p, n) __efi_nargs_check__(f, p, n)
|
||||
#define __efi_nargs_check__(f, p, n) ({ \
|
||||
BUILD_BUG_ON_MSG( \
|
||||
(p) > (n), \
|
||||
#f " called with too many arguments (" #p ">" #n ")"); \
|
||||
})
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
#define arch_efi_call_virt_setup() \
|
||||
({ \
|
||||
|
@ -56,7 +96,12 @@
|
|||
|
||||
#define EFI_LOADER_SIGNATURE "EL64"
|
||||
|
||||
extern asmlinkage u64 efi_call(void *fp, ...);
|
||||
extern asmlinkage u64 __efi_call(void *fp, ...);
|
||||
|
||||
#define efi_call(...) ({ \
|
||||
__efi_nargs_check(efi_call, 7, __VA_ARGS__); \
|
||||
__efi_call(__VA_ARGS__); \
|
||||
})
|
||||
|
||||
/*
|
||||
* struct efi_scratch - Scratch space used while switching to/from efi_mm
|
||||
|
@ -139,7 +184,12 @@ struct efi_setup_data {
|
|||
extern u64 efi_setup;
|
||||
|
||||
#ifdef CONFIG_EFI
|
||||
extern efi_status_t efi64_thunk(u32, ...);
|
||||
extern efi_status_t __efi64_thunk(u32, ...);
|
||||
|
||||
#define efi64_thunk(...) ({ \
|
||||
__efi_nargs_check(efi64_thunk, 6, __VA_ARGS__); \
|
||||
__efi64_thunk(__VA_ARGS__); \
|
||||
})
|
||||
|
||||
static inline bool efi_is_mixed(void)
|
||||
{
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include <linux/linkage.h>
|
||||
#include <asm/nospec-branch.h>
|
||||
|
||||
SYM_FUNC_START(efi_call)
|
||||
SYM_FUNC_START(__efi_call)
|
||||
pushq %rbp
|
||||
movq %rsp, %rbp
|
||||
and $~0xf, %rsp
|
||||
|
@ -24,4 +24,4 @@ SYM_FUNC_START(efi_call)
|
|||
CALL_NOSPEC %rdi
|
||||
leave
|
||||
ret
|
||||
SYM_FUNC_END(efi_call)
|
||||
SYM_FUNC_END(__efi_call)
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
.text
|
||||
.code64
|
||||
SYM_CODE_START(efi64_thunk)
|
||||
SYM_CODE_START(__efi64_thunk)
|
||||
push %rbp
|
||||
push %rbx
|
||||
|
||||
|
@ -69,4 +69,4 @@ SYM_CODE_START(efi64_thunk)
|
|||
2: pushl $__KERNEL_CS
|
||||
pushl %ebp
|
||||
lret
|
||||
SYM_CODE_END(efi64_thunk)
|
||||
SYM_CODE_END(__efi64_thunk)
|
||||
|
|
Загрузка…
Ссылка в новой задаче