|
Message-ID: <796148b8-471f-1a55-b5eb-b870cb5ca33d@linux.com> Date: Mon, 24 Jul 2017 15:15:32 +0300 From: Alexander Popov <alex.popov@...ux.com> To: Laura Abbott <labbott@...hat.com>, kernel-hardening@...ts.openwall.com, keescook@...omium.org, pageexec@...email.hu, spender@...ecurity.net, tycho@...ker.com, Mark Rutland <mark.rutland@....com>, Ard Biesheuvel <ard.biesheuvel@...aro.org>, x86@...nel.org, Andy Lutomirski <luto@...capital.net> Subject: Re: [PATCH RFC v3 1/1] gcc-plugins: Add stackleak feature erasing the kernel stack at the end of syscalls Hello Laura, On 15.07.2017 00:44, Laura Abbott wrote: > On 07/12/2017 11:17 AM, Alexander Popov wrote: >> This is the third version of the patch introducing STACKLEAK to the >> mainline kernel. STACKLEAK is a security feature developed by Grsecurity/PaX >> (kudos to them again), which: >> - reduces the information that can be revealed by some kernel stack leak bugs >> (e.g. CVE-2016-4569 and CVE-2016-4578); >> - blocks some uninitialized stack variable attacks (e.g. CVE-2010-2963); >> - introduces some runtime checks for kernel stack overflow detection. >> >> Changes in v3 (rebased on the recent rc) >> >> 1. Added the detailed comments describing the STACKLEAK gcc plugin. >> Read the plugin from bottom up, like you do for Linux kernel drivers. >> Additional information: >> - gcc internals documentation, which is available from gcc sources; >> - wonderful slides by Diego Novillo >> https://www.airs.com/dnovillo/200711-GCC-Internals/ >> - nice introduction to gcc plugins at LWN >> https://lwn.net/Articles/457543/ >> >> 2. Improved the commit message and Kconfig description according the >> feedback from Kees Cook. Also added the original notice describing >> the performance impact of the STACKLEAK feature. >> >> 3. Removed arch-specific ix86_cmodel check from stackleak_track_stack_gate(). >> It caused skipping the kernel code instrumentation for i386. >> >> 4. Fixed a minor mistake in stackleak_tree_instrument_execute(). >> First versions of the plugin used ENTRY_BLOCK_PTR_FOR_FN(cfun)->next_bb >> to get the basic block with the function prologue. That was not correct >> since the control flow graph edge from the ENTRY_BLOCK_PTR doesn't always >> go to that basic block. >> >> So later it was changed it to single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun)), >> but not completely. next_bb was still used for entry_bb assignment, >> which could cause the wrong value of the prologue_instrumented variable. >> >> I've reported this issue to Grsecurity and proposed the fix for it, but >> unfortunately didn't get any reply. >> >> 5. Introduced the STACKLEAK_POISON macro and renamed the config option >> according the feedback from Kees Cook. >> >> More things to be done: >> - carefully look into the assertions in track_stack() and check_alloca(); >> - find answers to the questions marked with TODO in the comments; >> - think of erasing the kernel stack after invoking EFI runtime services; >> - update self-protection.rst. >> >> Parallel work (thanks for that!): >> - Tycho Andersen is developing tests for STACKLEAK; >> - Laura Abbott is working on porting STACKLEAK to arm64. >> >> -- >8 -- [...] >> +#ifdef CONFIG_GCC_PLUGIN_STACKLEAK >> + p->thread.lowest_stack = (unsigned long)task_stack_page(p) + >> + 2 * sizeof(unsigned long); >> +#endif >> + > > Do you know why this initialization value was chosen? In clear_kstack, > this gets reset to sp0. It seems like this forces a clear of the entire > stack on the first call of clear_kstack? Do you mean erase_kstack()? The first erase_kstack() call will clear almost whole stack anyway. But initializing lowest_stack with that value helps to skip first useless searching for STACKLEAK_POISON. >> savesegment(gs, p->thread.gsindex); >> p->thread.gsbase = p->thread.gsindex ? 0 : me->thread.gsbase; >> savesegment(fs, p->thread.fsindex); >> diff --git a/fs/exec.c b/fs/exec.c >> index 62175cb..22ba66d 100644 >> --- a/fs/exec.c >> +++ b/fs/exec.c >> @@ -1949,3 +1949,20 @@ COMPAT_SYSCALL_DEFINE5(execveat, int, fd, >> argv, envp, flags); >> } >> #endif >> + >> +#ifdef CONFIG_GCC_PLUGIN_STACKLEAK >> +void __used track_stack(void) >> +{ >> + unsigned long sp = (unsigned long)&sp; >> + > > Mark Rutland pointed out in the review of my arm64 draft that > using current_stack_pointer() is cleaner. Ok. >> + if (sp < current->thread.lowest_stack && >> + sp >= (unsigned long)task_stack_page(current) + >> + 2 * sizeof(unsigned long)) { >> + current->thread.lowest_stack = sp; >> + } >> + >> + if (unlikely((sp & ~(THREAD_SIZE - 1)) < (THREAD_SIZE / 16))) >> + BUG(); >> +} > > All of the above checks have the x86-isms. Can this either be > cleaned up or made architecture specific? Excuse me, I didn't understand what you mean. I can describe these checks a bit. The conditions on setting lowest_stack are caused by the fact that x86 has some specialized stacks associated with each CPU in addition to the per thread stacks (see Documentation/x86/kernel-stacks for more info). As I understand, the following assertion detects stack exhaustion. It's important, although I don't like how it looks: it is checked for different kernel stacks (which have different size), but involves THREAD_SIZE macro. >> +EXPORT_SYMBOL(track_stack); >> +#endif >> diff --git a/include/linux/compiler.h b/include/linux/compiler.h >> index 219f82f..a97d334 100644 >> --- a/include/linux/compiler.h >> +++ b/include/linux/compiler.h >> @@ -585,4 +585,8 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s >> (_________p1); \ >> }) >> >> +#ifdef CONFIG_GCC_PLUGIN_STACKLEAK >> +# define STACKLEAK_POISON -0xBEEF >> +#endif >> + > > Pulling out the poison to be common is certainly good, compiler.h doesn't seem > quite right though. I don't have a strong opinion if there are no other > objections or better ideas. Ok. >> #endif /* __LINUX_COMPILER_H */ >> diff --git a/scripts/Makefile.gcc-plugins b/scripts/Makefile.gcc-plugins >> index 2e0e2ea..aab824d 100644 >> --- a/scripts/Makefile.gcc-plugins >> +++ b/scripts/Makefile.gcc-plugins >> @@ -33,6 +33,9 @@ ifdef CONFIG_GCC_PLUGINS >> gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_RANDSTRUCT) += -DRANDSTRUCT_PLUGIN >> gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_RANDSTRUCT_PERFORMANCE) += -fplugin-arg-randomize_layout_plugin-performance-mode >> >> + gcc-plugin-$(CONFIG_GCC_PLUGIN_STACKLEAK) += stackleak_plugin.so >> + gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STACKLEAK) += -DSTACKLEAK_PLUGIN -fplugin-arg-stackleak_plugin-track-lowest-sp=100 >> + > > Might be useful to make the bytes limit a Kconfig > for tuning. Nice idea, thanks! Added to TODO for the next version. Best regards, Alexander
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.