From 1278dcba80793bf17876bb83481a222949964321 Mon Sep 17 00:00:00 2001 From: Mike Kravetz Date: Wed, 16 Dec 2015 10:26:40 -0800 Subject: [PATCH] kernel: VirtBox workaround for dynamically allocated text Orabug: 22377612 VirtualBox dynamically allocates space for executable text within the kernel. When these text addresses are encountered by stack trace back code, they are dropped or the stack trace is terminated. Ideally, an interface would be created so that routines could registered to validate kernel text addresses. Drivers like VirtualBox, would register routines which know about dynamically allocated text. However, this will need more use cases from code in the mainline linux tree. As a workaround, assume executable pages in vmalloc or module areas are valid text addresses. The #ifdef CONFIG_X86 is acceptable as VirtualBox only supports x86 architecture. Signed-off-by: Mike Kravetz --- kernel/extable.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/kernel/extable.c b/kernel/extable.c index c98f926277a8..c0367cd4014e 100644 --- a/kernel/extable.c +++ b/kernel/extable.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -59,6 +60,36 @@ const struct exception_table_entry *search_exception_tables(unsigned long addr) return e; } +/* + * VirtualBox dynamically adds kernel executable code to the module + * and vmalloc areas. As a UEK specific workaround, look for pages + * in these areas that are executable. The longer term solution is + * to have VirtualBox register a routine to validate kernel executable + * code it adds. However, this will need more use cases from kernel + * code in the mainline linux tree. + */ +static inline int vmalloc_or_module_exec_page(unsigned long vaddr) +{ + int ret = 0; + +#ifdef CONFIG_X86 + /* + * The following code (lookup_address) is not available on + * all architectures. This is only needed on x86, as this + * is the only architecture supported by VirtualBox. + */ + if (is_vmalloc_or_module_addr((void *)vaddr)) { + unsigned int level; + pte_t *pte = lookup_address(vaddr, &level); + + if (pte && pte_present(*pte) && pte_exec(*pte)) + ret = 1; + } +#endif + + return ret; +} + static inline int init_kernel_text(unsigned long addr) { if (addr >= (unsigned long)_sinittext && @@ -115,6 +146,13 @@ int __kernel_text_address(unsigned long addr) */ if (init_kernel_text(addr)) return 1; + + /* + * UEK specific workaround for VirtualBox + */ + if (vmalloc_or_module_exec_page(addr)) + return 1; + return 0; } @@ -124,7 +162,12 @@ int kernel_text_address(unsigned long addr) return 1; if (is_module_text_address(addr)) return 1; - return is_ftrace_trampoline(addr); + if (is_ftrace_trampoline(addr)) + return 1; + /* + * UEK specific workaround for VirtualBox + */ + return vmalloc_or_module_exec_page(addr); } /* -- 2.50.1