Skip to content
Snippets Groups Projects
Select Git revision
  • 7f2923c4f73f21cfd714d12a2d48de8c21f11cfe
  • vme-testing default
  • ci-test
  • master
  • remoteproc
  • am625-sk-ov5640
  • pcal6534-upstreaming
  • lps22df-upstreaming
  • msc-upstreaming
  • imx8mp
  • iio/noa1305
  • vme-next
  • vme-next-4.14-rc4
  • v4.14-rc4
  • v4.14-rc3
  • v4.14-rc2
  • v4.14-rc1
  • v4.13
  • vme-next-4.13-rc7
  • v4.13-rc7
  • v4.13-rc6
  • v4.13-rc5
  • v4.13-rc4
  • v4.13-rc3
  • v4.13-rc2
  • v4.13-rc1
  • v4.12
  • v4.12-rc7
  • v4.12-rc6
  • v4.12-rc5
  • v4.12-rc4
  • v4.12-rc3
32 results

stackleak.c

Blame
  • stackleak.c 3.92 KiB
    // SPDX-License-Identifier: GPL-2.0
    /*
     * This code fills the used part of the kernel stack with a poison value
     * before returning to userspace. It's part of the STACKLEAK feature
     * ported from grsecurity/PaX.
     *
     * Author: Alexander Popov <alex.popov@linux.com>
     *
     * STACKLEAK reduces the information which kernel stack leak bugs can
     * reveal and blocks some uninitialized stack variable attacks.
     */
    
    #include <linux/stackleak.h>
    #include <linux/kprobes.h>
    
    #ifdef CONFIG_STACKLEAK_RUNTIME_DISABLE
    #include <linux/jump_label.h>
    #include <linux/sysctl.h>
    
    static DEFINE_STATIC_KEY_FALSE(stack_erasing_bypass);
    
    int stack_erasing_sysctl(struct ctl_table *table, int write,
    			void __user *buffer, size_t *lenp, loff_t *ppos)
    {
    	int ret = 0;
    	int state = !static_branch_unlikely(&stack_erasing_bypass);
    	int prev_state = state;
    
    	table->data = &state;
    	table->maxlen = sizeof(int);
    	ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
    	state = !!state;
    	if (ret || !write || state == prev_state)
    		return ret;
    
    	if (state)
    		static_branch_disable(&stack_erasing_bypass);
    	else
    		static_branch_enable(&stack_erasing_bypass);
    
    	pr_warn("stackleak: kernel stack erasing is %s\n",
    					state ? "enabled" : "disabled");
    	return ret;
    }
    
    #define skip_erasing()	static_branch_unlikely(&stack_erasing_bypass)
    #else
    #define skip_erasing()	false
    #endif /* CONFIG_STACKLEAK_RUNTIME_DISABLE */
    
    asmlinkage void notrace stackleak_erase(void)
    {
    	/* It would be nice not to have 'kstack_ptr' and 'boundary' on stack */
    	unsigned long kstack_ptr = current->lowest_stack;
    	unsigned long boundary = (unsigned long)end_of_stack(current);
    	unsigned int poison_count = 0;
    	const unsigned int depth = STACKLEAK_SEARCH_DEPTH / sizeof(unsigned long);
    
    	if (skip_erasing())
    		return;
    
    	/* Check that 'lowest_stack' value is sane */
    	if (unlikely(kstack_ptr - boundary >= THREAD_SIZE))
    		kstack_ptr = boundary;
    
    	/* Search for the poison value in the kernel stack */
    	while (kstack_ptr > boundary && poison_count <= depth) {
    		if (*(unsigned long *)kstack_ptr == STACKLEAK_POISON)
    			poison_count++;
    		else