anthraxx / linux-hardened

Minimal supplement to upstream Kernel Self Protection Project changes. Features already provided by SELinux + Yama and archs other than multiarch arm64 / x86_64 aren't in scope. Only tags have stable history. Shared IRC channel with KSPP: irc.libera.chat #linux-hardening
Other
554 stars 55 forks source link

Stack's lower bits are randomized despite ADDR_NO_RANDOMIZE #52

Closed XeR closed 3 years ago

XeR commented 3 years ago

Issue

The stack's lower bits are randomized when randomize_va_space is not 0 regardless of the ADDR_NO_RANDOMIZE personality.

This is inconvenient when debugging software. It requires to turn off ASLR on the whole system to have deterministic stack addresses.

Test

This can be tested with the following code :

void main()
{
    int a;
    printf("%p\n", &a);
}

On linux-hardened

$ for i in {1..5}; do ./a.out; done
0x73a0feb8e134
0x7d5c898ca584
0x7f2a18026ae4
0x7ff12a7c2e14
0x791eeca04c04
$ for i in {1..5}; do setarch $(uname -m) -R ./a.out; done
0x7fffffffd204
0x7fffffffd304
0x7fffffffde24
0x7fffffffd4c4
0x7fffffffd564
# sysctl -w kernel.randomize_va_space=0
$ for i in {1..5}; do ./a.out; done
0x7fffffffe084
0x7fffffffe084
0x7fffffffe084
0x7fffffffe084
0x7fffffffe084

On a vanilla kernel

$ for i in {1..5}; do ./a.out; done
0x7ffe5ed5cc3c
0x7ffefeaca9bc
0x7ffe8e5b28bc
0x7ffd8144582c
0x7ffd4a0247ec
$ for i in {1..5}; do setarch $(uname -m) -R ./a.out; done`
0x7fffffffe42c
0x7fffffffe42c
0x7fffffffe42c
0x7fffffffe42c
0x7fffffffe42c

Root cause

setup_arg_pages in fs/exec.c calls arch_align_stack (unless CONFIG_STACK_GROWS_UP is set).

arch_align_stack checks both randomize_va_space and ADDR_NO_RANDOMIZE :

if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
    sp -= get_random_int() % 8192;

This results in the lower bits of the stack being randomized in both linux and linux-hardened.

Commit 533d2e008592cc4dc0a4b2e28716555328a3ebae randomizes the stack a second time. This code, only checks for randomize_va_space:

if (randomize_va_space)
    bprm->p ^= get_random_int() & ~PAGE_MASK;

I assume this commit exists since arch_align_stack is not defined for every architecture. Only x86, aarch64, ppc, s390, mips and um. (most notably: arm does not)

cf. arch/um/kernel/process.c:

/*
 * Only x86 and x86_64 have an arch_align_stack().
 * All other arches have "#define arch_align_stack(x) (x)"
 * in their asm/exec.h
 */

Can we check the ADDR_NO_RANDOMIZE personality before xoring the stack pointer with a random value?

anthraxx commented 3 years ago

fixed in 6b2d22e930e6adbcd574e4ccc27a7df0c61d4f4c