[ARM] Improve non-executable support
Add support for detecting non-executable stack binaries, and adjust permissions to prevent execution from data and stack areas. Also, ensure that READ_IMPLIES_EXEC is enabled for older CPUs where that is true, and for any executable-stack binary. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
committed by
Russell King
parent
5ec9407dd1
commit
8ec53663d2
@@ -18,9 +18,32 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG];
|
|||||||
typedef struct user_fp elf_fpregset_t;
|
typedef struct user_fp elf_fpregset_t;
|
||||||
|
|
||||||
#define EM_ARM 40
|
#define EM_ARM 40
|
||||||
#define EF_ARM_APCS26 0x08
|
|
||||||
#define EF_ARM_SOFT_FLOAT 0x200
|
#define EF_ARM_EABI_MASK 0xff000000
|
||||||
#define EF_ARM_EABI_MASK 0xFF000000
|
#define EF_ARM_EABI_UNKNOWN 0x00000000
|
||||||
|
#define EF_ARM_EABI_VER1 0x01000000
|
||||||
|
#define EF_ARM_EABI_VER2 0x02000000
|
||||||
|
#define EF_ARM_EABI_VER3 0x03000000
|
||||||
|
#define EF_ARM_EABI_VER4 0x04000000
|
||||||
|
#define EF_ARM_EABI_VER5 0x05000000
|
||||||
|
|
||||||
|
#define EF_ARM_BE8 0x00800000 /* ABI 4,5 */
|
||||||
|
#define EF_ARM_LE8 0x00400000 /* ABI 4,5 */
|
||||||
|
#define EF_ARM_MAVERICK_FLOAT 0x00000800 /* ABI 0 */
|
||||||
|
#define EF_ARM_VFP_FLOAT 0x00000400 /* ABI 0 */
|
||||||
|
#define EF_ARM_SOFT_FLOAT 0x00000200 /* ABI 0 */
|
||||||
|
#define EF_ARM_OLD_ABI 0x00000100 /* ABI 0 */
|
||||||
|
#define EF_ARM_NEW_ABI 0x00000080 /* ABI 0 */
|
||||||
|
#define EF_ARM_ALIGN8 0x00000040 /* ABI 0 */
|
||||||
|
#define EF_ARM_PIC 0x00000020 /* ABI 0 */
|
||||||
|
#define EF_ARM_MAPSYMSFIRST 0x00000010 /* ABI 2 */
|
||||||
|
#define EF_ARM_APCS_FLOAT 0x00000010 /* ABI 0, floats in fp regs */
|
||||||
|
#define EF_ARM_DYNSYMSUSESEGIDX 0x00000008 /* ABI 2 */
|
||||||
|
#define EF_ARM_APCS_26 0x00000008 /* ABI 0 */
|
||||||
|
#define EF_ARM_SYMSARESORTED 0x00000004 /* ABI 1,2 */
|
||||||
|
#define EF_ARM_INTERWORK 0x00000004 /* ABI 0 */
|
||||||
|
#define EF_ARM_HASENTRY 0x00000002 /* All */
|
||||||
|
#define EF_ARM_RELEXEC 0x00000001 /* All */
|
||||||
|
|
||||||
#define R_ARM_NONE 0
|
#define R_ARM_NONE 0
|
||||||
#define R_ARM_PC24 1
|
#define R_ARM_PC24 1
|
||||||
@@ -57,23 +80,16 @@ typedef struct user_fp elf_fpregset_t;
|
|||||||
|
|
||||||
extern char elf_platform[];
|
extern char elf_platform[];
|
||||||
|
|
||||||
|
struct elf32_hdr;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is used to ensure we don't load something for the wrong architecture.
|
* This is used to ensure we don't load something for the wrong architecture.
|
||||||
*/
|
*/
|
||||||
#define elf_check_arch(x) ((x)->e_machine == EM_ARM && ELF_PROC_OK(x))
|
extern int elf_check_arch(const struct elf32_hdr *);
|
||||||
|
#define elf_check_arch elf_check_arch
|
||||||
|
|
||||||
/*
|
extern int arm_elf_read_implies_exec(const struct elf32_hdr *, int);
|
||||||
* 32-bit code is always OK. Some cpus can do 26-bit, some can't.
|
#define elf_read_implies_exec(ex,stk) arm_elf_read_implies_exec(&(ex), stk)
|
||||||
*/
|
|
||||||
#define ELF_PROC_OK(x) (ELF_THUMB_OK(x) && ELF_26BIT_OK(x))
|
|
||||||
|
|
||||||
#define ELF_THUMB_OK(x) \
|
|
||||||
((elf_hwcap & HWCAP_THUMB && ((x)->e_entry & 1) == 1) || \
|
|
||||||
((x)->e_entry & 3) == 0)
|
|
||||||
|
|
||||||
#define ELF_26BIT_OK(x) \
|
|
||||||
((elf_hwcap & HWCAP_26BIT && (x)->e_flags & EF_ARM_APCS26) || \
|
|
||||||
((x)->e_flags & EF_ARM_APCS26) == 0)
|
|
||||||
|
|
||||||
#define USE_ELF_CORE_DUMP
|
#define USE_ELF_CORE_DUMP
|
||||||
#define ELF_EXEC_PAGESIZE 4096
|
#define ELF_EXEC_PAGESIZE 4096
|
||||||
@@ -90,23 +106,7 @@ extern char elf_platform[];
|
|||||||
have no such handler. */
|
have no such handler. */
|
||||||
#define ELF_PLAT_INIT(_r, load_addr) (_r)->ARM_r0 = 0
|
#define ELF_PLAT_INIT(_r, load_addr) (_r)->ARM_r0 = 0
|
||||||
|
|
||||||
/*
|
extern void elf_set_personality(const struct elf32_hdr *);
|
||||||
* Since the FPA coprocessor uses CP1 and CP2, and iWMMXt uses CP0
|
#define SET_PERSONALITY(ex, ibcs2) elf_set_personality(&(ex))
|
||||||
* and CP1, we only enable access to the iWMMXt coprocessor if the
|
|
||||||
* binary is EABI or softfloat (and thus, guaranteed not to use
|
|
||||||
* FPA instructions.)
|
|
||||||
*/
|
|
||||||
#define SET_PERSONALITY(ex, ibcs2) \
|
|
||||||
do { \
|
|
||||||
if ((ex).e_flags & EF_ARM_APCS26) { \
|
|
||||||
set_personality(PER_LINUX); \
|
|
||||||
} else { \
|
|
||||||
set_personality(PER_LINUX_32BIT); \
|
|
||||||
if (elf_hwcap & HWCAP_IWMMXT && (ex).e_flags & (EF_ARM_EABI_MASK | EF_ARM_SOFT_FLOAT)) \
|
|
||||||
set_thread_flag(TIF_USING_IWMMXT); \
|
|
||||||
else \
|
|
||||||
clear_thread_flag(TIF_USING_IWMMXT); \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -184,8 +184,9 @@ typedef struct page *pgtable_t;
|
|||||||
|
|
||||||
#endif /* !__ASSEMBLY__ */
|
#endif /* !__ASSEMBLY__ */
|
||||||
|
|
||||||
#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \
|
#define VM_DATA_DEFAULT_FLAGS \
|
||||||
VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
|
(((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0) | \
|
||||||
|
VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* With EABI on ARMv5 and above we must have 64-bit aligned slab pointers.
|
* With EABI on ARMv5 and above we must have 64-bit aligned slab pointers.
|
||||||
|
@@ -197,22 +197,29 @@ extern void __pgd_error(const char *file, int line, unsigned long val);
|
|||||||
* shared mapping bits.
|
* shared mapping bits.
|
||||||
*/
|
*/
|
||||||
#define _L_PTE_DEFAULT L_PTE_PRESENT | L_PTE_YOUNG
|
#define _L_PTE_DEFAULT L_PTE_PRESENT | L_PTE_YOUNG
|
||||||
#define _L_PTE_READ L_PTE_USER | L_PTE_EXEC
|
|
||||||
|
|
||||||
extern pgprot_t pgprot_user;
|
extern pgprot_t pgprot_user;
|
||||||
extern pgprot_t pgprot_kernel;
|
extern pgprot_t pgprot_kernel;
|
||||||
|
|
||||||
|
#define _MOD_PROT(p, b) __pgprot(pgprot_val(p) | (b))
|
||||||
|
|
||||||
#define PAGE_NONE pgprot_user
|
#define PAGE_NONE pgprot_user
|
||||||
#define PAGE_COPY __pgprot(pgprot_val(pgprot_user) | _L_PTE_READ)
|
#define PAGE_SHARED _MOD_PROT(pgprot_user, L_PTE_USER | L_PTE_WRITE)
|
||||||
#define PAGE_SHARED __pgprot(pgprot_val(pgprot_user) | _L_PTE_READ | \
|
#define PAGE_SHARED_EXEC _MOD_PROT(pgprot_user, L_PTE_USER | L_PTE_WRITE | L_PTE_EXEC)
|
||||||
L_PTE_WRITE)
|
#define PAGE_COPY _MOD_PROT(pgprot_user, L_PTE_USER)
|
||||||
#define PAGE_READONLY __pgprot(pgprot_val(pgprot_user) | _L_PTE_READ)
|
#define PAGE_COPY_EXEC _MOD_PROT(pgprot_user, L_PTE_USER | L_PTE_EXEC)
|
||||||
|
#define PAGE_READONLY _MOD_PROT(pgprot_user, L_PTE_USER)
|
||||||
|
#define PAGE_READONLY_EXEC _MOD_PROT(pgprot_user, L_PTE_USER | L_PTE_EXEC)
|
||||||
#define PAGE_KERNEL pgprot_kernel
|
#define PAGE_KERNEL pgprot_kernel
|
||||||
|
#define PAGE_KERNEL_EXEC _MOD_PROT(pgprot_kernel, L_PTE_EXEC)
|
||||||
|
|
||||||
#define __PAGE_NONE __pgprot(_L_PTE_DEFAULT)
|
#define __PAGE_NONE __pgprot(_L_PTE_DEFAULT)
|
||||||
#define __PAGE_COPY __pgprot(_L_PTE_DEFAULT | _L_PTE_READ)
|
#define __PAGE_SHARED __pgprot(_L_PTE_DEFAULT | L_PTE_USER | L_PTE_WRITE)
|
||||||
#define __PAGE_SHARED __pgprot(_L_PTE_DEFAULT | _L_PTE_READ | L_PTE_WRITE)
|
#define __PAGE_SHARED_EXEC __pgprot(_L_PTE_DEFAULT | L_PTE_USER | L_PTE_WRITE | L_PTE_EXEC)
|
||||||
#define __PAGE_READONLY __pgprot(_L_PTE_DEFAULT | _L_PTE_READ)
|
#define __PAGE_COPY __pgprot(_L_PTE_DEFAULT | L_PTE_USER)
|
||||||
|
#define __PAGE_COPY_EXEC __pgprot(_L_PTE_DEFAULT | L_PTE_USER | L_PTE_EXEC)
|
||||||
|
#define __PAGE_READONLY __pgprot(_L_PTE_DEFAULT | L_PTE_USER)
|
||||||
|
#define __PAGE_READONLY_EXEC __pgprot(_L_PTE_DEFAULT | L_PTE_USER | L_PTE_EXEC)
|
||||||
|
|
||||||
#endif /* __ASSEMBLY__ */
|
#endif /* __ASSEMBLY__ */
|
||||||
|
|
||||||
@@ -228,19 +235,19 @@ extern pgprot_t pgprot_kernel;
|
|||||||
#define __P001 __PAGE_READONLY
|
#define __P001 __PAGE_READONLY
|
||||||
#define __P010 __PAGE_COPY
|
#define __P010 __PAGE_COPY
|
||||||
#define __P011 __PAGE_COPY
|
#define __P011 __PAGE_COPY
|
||||||
#define __P100 __PAGE_READONLY
|
#define __P100 __PAGE_READONLY_EXEC
|
||||||
#define __P101 __PAGE_READONLY
|
#define __P101 __PAGE_READONLY_EXEC
|
||||||
#define __P110 __PAGE_COPY
|
#define __P110 __PAGE_COPY_EXEC
|
||||||
#define __P111 __PAGE_COPY
|
#define __P111 __PAGE_COPY_EXEC
|
||||||
|
|
||||||
#define __S000 __PAGE_NONE
|
#define __S000 __PAGE_NONE
|
||||||
#define __S001 __PAGE_READONLY
|
#define __S001 __PAGE_READONLY
|
||||||
#define __S010 __PAGE_SHARED
|
#define __S010 __PAGE_SHARED
|
||||||
#define __S011 __PAGE_SHARED
|
#define __S011 __PAGE_SHARED
|
||||||
#define __S100 __PAGE_READONLY
|
#define __S100 __PAGE_READONLY_EXEC
|
||||||
#define __S101 __PAGE_READONLY
|
#define __S101 __PAGE_READONLY_EXEC
|
||||||
#define __S110 __PAGE_SHARED
|
#define __S110 __PAGE_SHARED_EXEC
|
||||||
#define __S111 __PAGE_SHARED
|
#define __S111 __PAGE_SHARED_EXEC
|
||||||
|
|
||||||
#ifndef __ASSEMBLY__
|
#ifndef __ASSEMBLY__
|
||||||
/*
|
/*
|
||||||
|
@@ -10,7 +10,7 @@ endif
|
|||||||
|
|
||||||
# Object file lists.
|
# Object file lists.
|
||||||
|
|
||||||
obj-y := compat.o entry-armv.o entry-common.o irq.o \
|
obj-y := compat.o elf.o entry-armv.o entry-common.o irq.o \
|
||||||
process.o ptrace.o setup.o signal.o \
|
process.o ptrace.o setup.o signal.o \
|
||||||
sys_arm.o stacktrace.o time.o traps.o
|
sys_arm.o stacktrace.o time.o traps.o
|
||||||
|
|
||||||
|
79
arch/arm/kernel/elf.c
Normal file
79
arch/arm/kernel/elf.c
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/personality.h>
|
||||||
|
#include <linux/binfmts.h>
|
||||||
|
#include <linux/elf.h>
|
||||||
|
|
||||||
|
int elf_check_arch(const struct elf32_hdr *x)
|
||||||
|
{
|
||||||
|
unsigned int eflags;
|
||||||
|
|
||||||
|
/* Make sure it's an ARM executable */
|
||||||
|
if (x->e_machine != EM_ARM)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Make sure the entry address is reasonable */
|
||||||
|
if (x->e_entry & 1) {
|
||||||
|
if (!(elf_hwcap & HWCAP_THUMB))
|
||||||
|
return 0;
|
||||||
|
} else if (x->e_entry & 3)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
eflags = x->e_flags;
|
||||||
|
if ((eflags & EF_ARM_EABI_MASK) == EF_ARM_EABI_UNKNOWN) {
|
||||||
|
/* APCS26 is only allowed if the CPU supports it */
|
||||||
|
if ((eflags & EF_ARM_APCS_26) && !(elf_hwcap & HWCAP_26BIT))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* VFP requires the supporting code */
|
||||||
|
if ((eflags & EF_ARM_VFP_FLOAT) && !(elf_hwcap & HWCAP_VFP))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(elf_check_arch);
|
||||||
|
|
||||||
|
void elf_set_personality(const struct elf32_hdr *x)
|
||||||
|
{
|
||||||
|
unsigned int eflags = x->e_flags;
|
||||||
|
unsigned int personality = PER_LINUX_32BIT;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* APCS-26 is only valid for OABI executables
|
||||||
|
*/
|
||||||
|
if ((eflags & EF_ARM_EABI_MASK) == EF_ARM_EABI_UNKNOWN) {
|
||||||
|
if (eflags & EF_ARM_APCS_26)
|
||||||
|
personality = PER_LINUX;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_personality(personality);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Since the FPA coprocessor uses CP1 and CP2, and iWMMXt uses CP0
|
||||||
|
* and CP1, we only enable access to the iWMMXt coprocessor if the
|
||||||
|
* binary is EABI or softfloat (and thus, guaranteed not to use
|
||||||
|
* FPA instructions.)
|
||||||
|
*/
|
||||||
|
if (elf_hwcap & HWCAP_IWMMXT &&
|
||||||
|
eflags & (EF_ARM_EABI_MASK | EF_ARM_SOFT_FLOAT)) {
|
||||||
|
set_thread_flag(TIF_USING_IWMMXT);
|
||||||
|
} else {
|
||||||
|
clear_thread_flag(TIF_USING_IWMMXT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(elf_set_personality);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set READ_IMPLIES_EXEC if:
|
||||||
|
* - the binary requires an executable stack
|
||||||
|
* - we're running on a CPU which doesn't support NX.
|
||||||
|
*/
|
||||||
|
int arm_elf_read_implies_exec(const struct elf32_hdr *x, int executable_stack)
|
||||||
|
{
|
||||||
|
if (executable_stack != EXSTACK_ENABLE_X)
|
||||||
|
return 1;
|
||||||
|
if (cpu_architecture() <= CPU_ARCH_ARMv6)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(arm_elf_read_implies_exec);
|
@@ -47,7 +47,7 @@ void *module_alloc(unsigned long size)
|
|||||||
if (!area)
|
if (!area)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return __vmalloc_area(area, GFP_KERNEL, PAGE_KERNEL);
|
return __vmalloc_area(area, GFP_KERNEL, PAGE_KERNEL_EXEC);
|
||||||
}
|
}
|
||||||
#else /* CONFIG_MMU */
|
#else /* CONFIG_MMU */
|
||||||
void *module_alloc(unsigned long size)
|
void *module_alloc(unsigned long size)
|
||||||
|
Reference in New Issue
Block a user