Skip to content

Commit 14b864f

Browse files
nivedita76Ingo Molnar
authored andcommitted
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 <[email protected]> Signed-off-by: Ard Biesheuvel <[email protected]> Cc: Andy Lutomirski <[email protected]> Cc: Ard Biesheuvel <[email protected]> Cc: Matthew Garrett <[email protected]> Cc: [email protected] Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Ingo Molnar <[email protected]>
1 parent 4684abe commit 14b864f

File tree

4 files changed

+58
-8
lines changed

4 files changed

+58
-8
lines changed

arch/x86/boot/compressed/efi_thunk_64.S

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
.code64
2525
.text
26-
SYM_FUNC_START(efi64_thunk)
26+
SYM_FUNC_START(__efi64_thunk)
2727
push %rbp
2828
push %rbx
2929

@@ -95,7 +95,7 @@ SYM_FUNC_START(efi64_thunk)
9595
pop %rbx
9696
pop %rbp
9797
ret
98-
SYM_FUNC_END(efi64_thunk)
98+
SYM_FUNC_END(__efi64_thunk)
9999

100100
.code32
101101
/*

arch/x86/include/asm/efi.h

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <asm/tlb.h>
99
#include <asm/nospec-branch.h>
1010
#include <asm/mmu_context.h>
11+
#include <linux/build_bug.h>
1112

1213
/*
1314
* We map the EFI regions needed for runtime services non-contiguously,
@@ -34,6 +35,45 @@
3435

3536
#define ARCH_EFI_IRQ_FLAGS_MASK X86_EFLAGS_IF
3637

38+
/*
39+
* The EFI services are called through variadic functions in many cases. These
40+
* functions are implemented in assembler and support only a fixed number of
41+
* arguments. The macros below allows us to check at build time that we don't
42+
* try to call them with too many arguments.
43+
*
44+
* __efi_nargs() will return the number of arguments if it is 7 or less, and
45+
* cause a BUILD_BUG otherwise. The limitations of the C preprocessor make it
46+
* impossible to calculate the exact number of arguments beyond some
47+
* pre-defined limit. The maximum number of arguments currently supported by
48+
* any of the thunks is 7, so this is good enough for now and can be extended
49+
* in the obvious way if we ever need more.
50+
*/
51+
52+
#define __efi_nargs(...) __efi_nargs_(__VA_ARGS__)
53+
#define __efi_nargs_(...) __efi_nargs__(0, ##__VA_ARGS__, \
54+
__efi_arg_sentinel(7), __efi_arg_sentinel(6), \
55+
__efi_arg_sentinel(5), __efi_arg_sentinel(4), \
56+
__efi_arg_sentinel(3), __efi_arg_sentinel(2), \
57+
__efi_arg_sentinel(1), __efi_arg_sentinel(0))
58+
#define __efi_nargs__(_0, _1, _2, _3, _4, _5, _6, _7, n, ...) \
59+
__take_second_arg(n, \
60+
({ BUILD_BUG_ON_MSG(1, "__efi_nargs limit exceeded"); 8; }))
61+
#define __efi_arg_sentinel(n) , n
62+
63+
/*
64+
* __efi_nargs_check(f, n, ...) will cause a BUILD_BUG if the ellipsis
65+
* represents more than n arguments.
66+
*/
67+
68+
#define __efi_nargs_check(f, n, ...) \
69+
__efi_nargs_check_(f, __efi_nargs(__VA_ARGS__), n)
70+
#define __efi_nargs_check_(f, p, n) __efi_nargs_check__(f, p, n)
71+
#define __efi_nargs_check__(f, p, n) ({ \
72+
BUILD_BUG_ON_MSG( \
73+
(p) > (n), \
74+
#f " called with too many arguments (" #p ">" #n ")"); \
75+
})
76+
3777
#ifdef CONFIG_X86_32
3878
#define arch_efi_call_virt_setup() \
3979
({ \
@@ -56,7 +96,12 @@
5696

5797
#define EFI_LOADER_SIGNATURE "EL64"
5898

59-
extern asmlinkage u64 efi_call(void *fp, ...);
99+
extern asmlinkage u64 __efi_call(void *fp, ...);
100+
101+
#define efi_call(...) ({ \
102+
__efi_nargs_check(efi_call, 7, __VA_ARGS__); \
103+
__efi_call(__VA_ARGS__); \
104+
})
60105

61106
/*
62107
* struct efi_scratch - Scratch space used while switching to/from efi_mm
@@ -139,7 +184,12 @@ struct efi_setup_data {
139184
extern u64 efi_setup;
140185

141186
#ifdef CONFIG_EFI
142-
extern efi_status_t efi64_thunk(u32, ...);
187+
extern efi_status_t __efi64_thunk(u32, ...);
188+
189+
#define efi64_thunk(...) ({ \
190+
__efi_nargs_check(efi64_thunk, 6, __VA_ARGS__); \
191+
__efi64_thunk(__VA_ARGS__); \
192+
})
143193

144194
static inline bool efi_is_mixed(void)
145195
{

arch/x86/platform/efi/efi_stub_64.S

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#include <linux/linkage.h>
1111
#include <asm/nospec-branch.h>
1212

13-
SYM_FUNC_START(efi_call)
13+
SYM_FUNC_START(__efi_call)
1414
pushq %rbp
1515
movq %rsp, %rbp
1616
and $~0xf, %rsp
@@ -24,4 +24,4 @@ SYM_FUNC_START(efi_call)
2424
CALL_NOSPEC %rdi
2525
leave
2626
ret
27-
SYM_FUNC_END(efi_call)
27+
SYM_FUNC_END(__efi_call)

arch/x86/platform/efi/efi_thunk_64.S

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626
.text
2727
.code64
28-
SYM_CODE_START(efi64_thunk)
28+
SYM_CODE_START(__efi64_thunk)
2929
push %rbp
3030
push %rbx
3131

@@ -69,4 +69,4 @@ SYM_CODE_START(efi64_thunk)
6969
2: pushl $__KERNEL_CS
7070
pushl %ebp
7171
lret
72-
SYM_CODE_END(efi64_thunk)
72+
SYM_CODE_END(__efi64_thunk)

0 commit comments

Comments
 (0)