Commit 01cc53b2 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] Non-Exec stack support

From: Kurt Garloff <garloff@suse.de>

A patch to parse the elf binaries for a PT_GNU_STACK section to set the stack
non-executable if possible.  Most parts have been shamelessly stolen from
Ingo Molnar's more ambitious stackshield
http://people.redhat.com/mingo/exec-shield/exec-shield-2.6.4-C9

The toolchain has meanwhile support for marking the binaries with a
PT_GNU_STACK section wwithout x bit as needed.

If no such section is found, we leave the stack to whatever the arch defaults
to.  If there is one, we explicitly disabled the VM_EXEC bit if no x bit is
found, otherwise explicitly enable.
parent 492361a6
......@@ -35,7 +35,7 @@ extern void ia64_elf32_init (struct pt_regs *regs);
static void elf32_set_personality (void);
#define setup_arg_pages(bprm) ia32_setup_arg_pages(bprm)
#define setup_arg_pages(bprm,exec) ia32_setup_arg_pages(bprm,exec)
#define elf_map elf32_map
#undef SET_PERSONALITY
......@@ -149,7 +149,7 @@ ia64_elf32_init (struct pt_regs *regs)
}
int
ia32_setup_arg_pages (struct linux_binprm *bprm)
ia32_setup_arg_pages (struct linux_binprm *bprm, int executable_stack)
{
unsigned long stack_base;
struct vm_area_struct *mpnt;
......@@ -178,8 +178,14 @@ ia32_setup_arg_pages (struct linux_binprm *bprm)
mpnt->vm_mm = current->mm;
mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
mpnt->vm_end = IA32_STACK_TOP;
mpnt->vm_page_prot = PAGE_COPY;
mpnt->vm_flags = VM_STACK_FLAGS;
if (executable_stack == EXSTACK_ENABLE_X)
mpnt->vm_flags = VM_STACK_FLAGS | VM_EXEC;
else if (executable_stack == EXSTACK_DISABLE_X)
mpnt->vm_flags = VM_STACK_FLAGS & ~VM_EXEC;
else
mpnt->vm_flags = VM_STACK_FLAGS;
mpnt->vm_page_prot = (mpnt->vm_flags & VM_EXEC)?
PAGE_COPY_EXEC: PAGE_COPY;
mpnt->vm_ops = NULL;
mpnt->vm_pgoff = 0;
mpnt->vm_file = NULL;
......@@ -192,7 +198,7 @@ ia32_setup_arg_pages (struct linux_binprm *bprm)
struct page *page = bprm->page[i];
if (page) {
bprm->page[i] = NULL;
put_dirty_page(current, page, stack_base, PAGE_COPY);
put_dirty_page(current, page, stack_base, mpnt->vm_page_prot);
}
stack_base += PAGE_SIZE;
}
......
......@@ -494,7 +494,7 @@ struct ia32_user_desc {
struct linux_binprm;
extern void ia32_init_addr_space (struct pt_regs *regs);
extern int ia32_setup_arg_pages (struct linux_binprm *bprm);
extern int ia32_setup_arg_pages (struct linux_binprm *bprm, int exec_stack);
extern unsigned long ia32_do_mmap (struct file *, unsigned long, unsigned long, int, int, loff_t);
extern void ia32_load_segment_descriptors (struct task_struct *task);
......
......@@ -688,7 +688,7 @@ static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs)
* change some of these later.
*/
current->mm->rss = 0;
setup_arg_pages(bprm);
setup_arg_pages(bprm, EXSTACK_DEFAULT);
current->mm->start_stack = bprm->p;
/* At this point, we assume that the image should be loaded at
......
......@@ -115,7 +115,7 @@ static inline int dump_regs32(struct pt_regs *ptregs, elf_gregset_t *regs)
#include <linux/binfmts.h>
#include <linux/compat.h>
int setup_arg_pages32(struct linux_binprm *bprm);
int setup_arg_pages32(struct linux_binprm *bprm, int executable_stack);
#define elf_prstatus elf_prstatus32
struct elf_prstatus32
......@@ -166,7 +166,7 @@ struct elf_prpsinfo32
#undef start_thread
#define start_thread start_thread31
#define setup_arg_pages(bprm) setup_arg_pages32(bprm)
#define setup_arg_pages(bprm, exec) setup_arg_pages32(bprm, exec)
#define elf_map elf_map32
MODULE_DESCRIPTION("Binary format loader for compatibility with 32bit Linux for S390 binaries,"
......
......@@ -37,7 +37,7 @@
#undef STACK_TOP
#define STACK_TOP TASK31_SIZE
int setup_arg_pages32(struct linux_binprm *bprm)
int setup_arg_pages32(struct linux_binprm *bprm, int executable_stack)
{
unsigned long stack_base;
struct vm_area_struct *mpnt;
......@@ -66,6 +66,7 @@ int setup_arg_pages32(struct linux_binprm *bprm)
mpnt->vm_mm = mm;
mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
mpnt->vm_end = STACK_TOP;
/* executable stack setting would be applied here */
mpnt->vm_page_prot = PAGE_COPY;
mpnt->vm_flags = VM_STACK_FLAGS;
mpnt->vm_ops = NULL;
......
......@@ -310,7 +310,7 @@ static int load_aout32_binary(struct linux_binprm * bprm, struct pt_regs * regs)
orig_thr_flags = current_thread_info()->flags;
current_thread_info()->flags |= _TIF_32BIT;
retval = setup_arg_pages(bprm);
retval = setup_arg_pages(bprm, EXSTACK_DEFAULT);
if (retval < 0) {
current_thread_info()->flags = orig_thr_flags;
......
......@@ -35,7 +35,7 @@
#undef WARN_OLD
#undef CORE_DUMP /* probably broken */
extern int ia32_setup_arg_pages(struct linux_binprm *bprm);
extern int ia32_setup_arg_pages(struct linux_binprm *bprm, int exec_stack);
static int load_aout_binary(struct linux_binprm *, struct pt_regs * regs);
static int load_aout_library(struct file*);
......@@ -395,7 +395,7 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
set_brk(current->mm->start_brk, current->mm->brk);
retval = ia32_setup_arg_pages(bprm);
retval = ia32_setup_arg_pages(bprm, EXSTACK_DEFAULT);
if (retval < 0) {
/* Someone check-me: is this error path enough? */
send_sig(SIGKILL, current, 0);
......
......@@ -272,8 +272,8 @@ do { \
#define load_elf_binary load_elf32_binary
#define ELF_PLAT_INIT(r, load_addr) elf32_init(r)
#define setup_arg_pages(bprm) ia32_setup_arg_pages(bprm)
int ia32_setup_arg_pages(struct linux_binprm *bprm);
#define setup_arg_pages(bprm, exec_stack) ia32_setup_arg_pages(bprm, exec_stack)
int ia32_setup_arg_pages(struct linux_binprm *bprm, int executable_stack);
#undef start_thread
#define start_thread(regs,new_rip,new_rsp) do { \
......@@ -325,7 +325,7 @@ static void elf32_init(struct pt_regs *regs)
me->thread.es = __USER_DS;
}
int setup_arg_pages(struct linux_binprm *bprm)
int setup_arg_pages(struct linux_binprm *bprm, int executable_stack)
{
unsigned long stack_base;
struct vm_area_struct *mpnt;
......@@ -354,7 +354,12 @@ int setup_arg_pages(struct linux_binprm *bprm)
mpnt->vm_mm = mm;
mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
mpnt->vm_end = IA32_STACK_TOP;
mpnt->vm_flags = vm_stack_flags32;
if (executable_stack == EXSTACK_ENABLE_X)
mpnt->vm_flags = vm_stack_flags32 | VM_EXEC;
else if (executable_stack == EXSTACK_DISABLE_X)
mpnt->vm_flags = vm_stack_flags32 & ~VM_EXEC;
else
mpnt->vm_flags = vm_stack_flags32;
mpnt->vm_page_prot = (mpnt->vm_flags & VM_EXEC) ?
PAGE_COPY_EXEC : PAGE_COPY;
mpnt->vm_ops = NULL;
......@@ -370,7 +375,7 @@ int setup_arg_pages(struct linux_binprm *bprm)
struct page *page = bprm->page[i];
if (page) {
bprm->page[i] = NULL;
put_dirty_page(current,page,stack_base,PAGE_COPY_EXEC);
put_dirty_page(current,page,stack_base,mpnt->vm_page_prot);
}
stack_base += PAGE_SIZE;
}
......
......@@ -413,7 +413,7 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
set_brk(current->mm->start_brk, current->mm->brk);
retval = setup_arg_pages(bprm);
retval = setup_arg_pages(bprm, EXSTACK_DEFAULT);
if (retval < 0) {
/* Someone check-me: is this error path enough? */
send_sig(SIGKILL, current, 0);
......
......@@ -476,6 +476,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
struct exec interp_ex;
char passed_fileno[6];
struct files_struct *files;
int executable_stack = EXSTACK_DEFAULT;
/* Get the exec-header */
elf_ex = *((struct elfhdr *) bprm->buf);
......@@ -599,6 +600,15 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
elf_ppnt++;
}
elf_ppnt = elf_phdata;
for (i = 0; i < elf_ex.e_phnum; i++, elf_ppnt++)
if (elf_ppnt->p_type == PT_GNU_STACK) {
if (elf_ppnt->p_flags & PF_X)
executable_stack = EXSTACK_ENABLE_X;
else
executable_stack = EXSTACK_DISABLE_X;
}
/* Some simple consistency checks for the interpreter */
if (elf_interpreter) {
interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
......@@ -674,7 +684,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
change some of these later */
current->mm->rss = 0;
current->mm->free_area_cache = TASK_UNMAPPED_BASE;
retval = setup_arg_pages(bprm);
retval = setup_arg_pages(bprm, executable_stack);
if (retval < 0) {
send_sig(SIGKILL, current, 0);
goto out_free_dentry;
......
......@@ -254,7 +254,7 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs)
set_binfmt(&som_format);
compute_creds(bprm);
setup_arg_pages(bprm);
setup_arg_pages(bprm, EXSTACK_DEFAULT);
create_som_tables(bprm);
......
......@@ -342,7 +342,7 @@ void put_dirty_page(struct task_struct *tsk, struct page *page,
return;
}
int setup_arg_pages(struct linux_binprm *bprm)
int setup_arg_pages(struct linux_binprm *bprm, int executable_stack)
{
unsigned long stack_base;
struct vm_area_struct *mpnt;
......@@ -425,8 +425,16 @@ int setup_arg_pages(struct linux_binprm *bprm)
mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
mpnt->vm_end = STACK_TOP;
#endif
mpnt->vm_page_prot = protection_map[VM_STACK_FLAGS & 0x7];
mpnt->vm_flags = VM_STACK_FLAGS;
/* Adjust stack execute permissions; explicitly enable
* for EXSTACK_ENABLE_X, disable for EXSTACK_DISABLE_X
* and leave alone (arch default) otherwise. */
if (unlikely(executable_stack == EXSTACK_ENABLE_X))
mpnt->vm_flags = VM_STACK_FLAGS | VM_EXEC;
else if (executable_stack == EXSTACK_DISABLE_X)
mpnt->vm_flags = VM_STACK_FLAGS & ~VM_EXEC;
else
mpnt->vm_flags = VM_STACK_FLAGS;
mpnt->vm_page_prot = protection_map[mpnt->vm_flags & 0x7];
mpnt->vm_ops = NULL;
mpnt->vm_pgoff = 0;
mpnt->vm_file = NULL;
......
......@@ -119,7 +119,8 @@
#define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_A)
#define PAGE_SHARED __pgprot(__ACCESS_BITS | _PAGE_PL_3 | _PAGE_AR_RW)
#define PAGE_READONLY __pgprot(__ACCESS_BITS | _PAGE_PL_3 | _PAGE_AR_R)
#define PAGE_COPY __pgprot(__ACCESS_BITS | _PAGE_PL_3 | _PAGE_AR_RX)
#define PAGE_COPY __pgprot(__ACCESS_BITS | _PAGE_PL_3 | _PAGE_AR_R)
#define PAGE_COPY_EXEC __pgprot(__ACCESS_BITS | _PAGE_PL_3 | _PAGE_AR_RX)
#define PAGE_GATE __pgprot(__ACCESS_BITS | _PAGE_PL_0 | _PAGE_AR_X_RX)
#define PAGE_KERNEL __pgprot(__DIRTY_BITS | _PAGE_PL_0 | _PAGE_AR_RWX)
#define PAGE_KERNELRX __pgprot(__ACCESS_BITS | _PAGE_PL_0 | _PAGE_AR_RX)
......
......@@ -58,7 +58,13 @@ extern int prepare_binprm(struct linux_binprm *);
extern void remove_arg_zero(struct linux_binprm *);
extern int search_binary_handler(struct linux_binprm *,struct pt_regs *);
extern int flush_old_exec(struct linux_binprm * bprm);
extern int setup_arg_pages(struct linux_binprm * bprm);
/* Stack area protections */
#define EXSTACK_DEFAULT 0 /* Whatever the arch defaults to */
#define EXSTACK_DISABLE_X 1 /* Disable executable stacks */
#define EXSTACK_ENABLE_X 2 /* Enable executable stacks */
extern int setup_arg_pages(struct linux_binprm * bprm, int executable_stack);
extern int copy_strings(int argc,char __user * __user * argv,struct linux_binprm *bprm);
extern int copy_strings_kernel(int argc,char ** argv,struct linux_binprm *bprm);
extern void compute_creds(struct linux_binprm *binprm);
......
......@@ -35,6 +35,8 @@ typedef __s64 Elf64_Sxword;
#define PT_HIPROC 0x7fffffff
#define PT_GNU_EH_FRAME 0x6474e550
#define PT_GNU_STACK (PT_LOOS + 0x474e551)
/* These constants define the different elf file types */
#define ET_NONE 0
#define ET_REL 1
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment