[RFC PATCH 1/2] efi/x86: Check number of arguments to variadic functions

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On x86 we need to thunk through assembler stubs to call the EFI services
in many cases. The assembler stub has 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@xxxxxxxxxxxx>
---
 arch/x86/include/asm/efi.h | 52 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index c49619a28be8..c9800802894f 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -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,47 @@
 
 #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_(0, ##__VA_ARGS__)
+#define __efi_nargs_(...) __efi_nargs__(__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, ##__VA_ARGS__)
+#define __efi_nargs_check_(...) __efi_nargs_check__(__VA_ARGS__)
+#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
 
 extern asmlinkage
@@ -62,6 +104,11 @@ unsigned long efi_call_phys(void *, unsigned long, unsigned long, u32, void *);
 
 extern asmlinkage u64 efi_call(void *fp, ...);
 
+#define efi_call(...) ({						\
+	__efi_nargs_check(efi_call, 7, __VA_ARGS__);			\
+	efi_call(__VA_ARGS__);						\
+})
+
 #define efi_call_phys(f, args...)		efi_call((f), args)
 
 /*
@@ -149,6 +196,11 @@ extern u64 efi_setup;
 #ifdef CONFIG_EFI
 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)
 {
 	if (!IS_ENABLED(CONFIG_EFI_MIXED))
-- 
2.24.1




[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux