From: Kyle McMartin kmcmarti@redhat.com
Message-id: 20140513222526.GC26038@redacted.bos.redhat.com Patchwork-id: 79789 O-Subject: [ACADIA PATCH] arm64: don't set READ_IMPLIES_EXEC for EM_AARCH64 ELF objects Bugzilla: 1085528
BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1085528 Upstream: submitted soon
[Sadly this isn't (yet) sufficient... but it fixes at least one issue here... cat /proc/$$/personality shows READ_IMPLIES_EXEC before. I'll try to figure the rest out tomorrow.]
Currently, we're accidentally ending up with executable stacks on AArch64 when the ABI says we shouldn't be, and relying on glibc to fix things up for us when we're loaded. However, SELinux will deny us mucking with the stack, and hit us with execmem AVCs.
The reason this is happening is somewhat complex:
fs/binfmt_elf.c:load_elf_binary() - initializes executable_stack = EXSTACK_DEFAULT implying the architecture should make up its mind. - does a pile of loading goo - runs through the program headers, looking for PT_GNU_STACK and setting (or unsetting) executable_stack if it finds it.
This is our first problem, we won't generate these unless an executable stack is explicitly requested.
- more ELF loading goo - sets whether we're a compat task or not (TIF_32BIT) based on compat.h - for compat reasons (pre-GNU_STACK) checks if the READ_IMPLIES_EXEC flag should be set for ancient toolchains
Here's our second problem, we test if read_implies_exec based on stk != EXSTACK_DISABLE_X, which is true since stk == EXSTACK_DEFAULT.
So we set current->personality |= READ_IMPLIES_EXEC like a broken legacy toolchain would want.
- Now we call setup_arg_pages to set up the stack...
fs/exec.c:setup_arg_pages() - lots of magic happens here - vm_flags gets initialized to VM_STACK_FLAGS
Here's our third problem, VM_STACK_FLAGS on arm64 is VM_DEFAULT_DATA_FLAG which tests READ_IMPLIES_EXEC and sets VM_EXEC if it's true. So we end up with an executable stack mapping, since we don't have executable_stack set (it's still EXSTACK_DEFAULT at this point) to unset it anywhere.
Bang. execstack AVC when the program starts running.
The easiest way I can see to fix this is to test if we're a legacy task and fix it up there. But that's not as simple as it sounds, because the 32-bit ABI depends on what revision of the CPU we've enabled (not that it matters since we're ARMv8...) Regardless, in the compat case, set READ_IMPLIES_EXEC if we've found a GNU_STACK header which explicitly requested it as in arch/arm/kernel/elf.c:arm_elf_read_implies_exec().
Signed-off-by: Kyle McMartin kmcmarti@redhat.com Signed-off-by: Donald Dutile ddutile@redhat.com --- arch/arm64/include/asm/elf.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h index 1f65be3..c0f89a0 100644 --- a/arch/arm64/include/asm/elf.h +++ b/arch/arm64/include/asm/elf.h @@ -114,7 +114,8 @@ typedef struct user_fpsimd_state elf_fpregset_t; */ #define elf_check_arch(x) ((x)->e_machine == EM_AARCH64)
-#define elf_read_implies_exec(ex,stk) (stk != EXSTACK_DISABLE_X) +#define elf_read_implies_exec(ex,stk) (test_thread_flag(TIF_32BIT) \ + ? (stk == EXSTACK_ENABLE_X) : 0)
#define CORE_DUMP_USE_REGSET #define ELF_EXEC_PAGESIZE PAGE_SIZE