lkml.org 
[lkml]   [2004]   [Mar]   [23]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    SubjectNon-Exec stack patches
    Hi,

    find attached 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 meainwhile support for marking the binaries with a
    PT_GNU_STACK section with ot without 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.

    I believe this part should be merged into official mainstream kernels.
    Ingo, what do you think?

    Regards,
    --
    Kurt Garloff <garloff@suse.de> Cologne, DE
    SUSE LINUX AG, Nuernberg, DE SUSE Labs (Head)
    diff -uNrp linux-2.6.4.EXSTACK/arch/ia64/ia32/binfmt_elf32.c linux-2.6.4.noexec/arch/ia64/ia32/binfmt_elf32.c
    --- linux-2.6.4.EXSTACK/arch/ia64/ia32/binfmt_elf32.c 2004-03-23 21:18:35.000000000 +0100
    +++ linux-2.6.4.noexec/arch/ia64/ia32/binfmt_elf32.c 2004-03-23 22:48:31.000000000 +0100
    @@ -35,7 +35,7 @@ extern void ia64_elf32_init (struct pt_r

    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
    @@ -152,7 +152,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;
    @@ -181,8 +181,14 @@ ia32_setup_arg_pages (struct linux_binpr
    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 > 0)
    + mpnt->vm_flags = VM_STACK_FLAGS | VM_EXEC;
    + else if (executable_stack < 0)
    + 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 = mpnt->vm_start >> PAGE_SHIFT;
    mpnt->vm_file = NULL;
    @@ -197,7 +203,7 @@ ia32_setup_arg_pages (struct linux_binpr
    struct page *page = bprm->page[i];
    if (page) {
    bprm->page[i] = NULL;
    - put_dirty_page(current, page, stack_base, PAGE_COPY, mpnt);
    + put_dirty_page(current, page, stack_base, mpnt->vm_page_prot, mpnt);
    }
    stack_base += PAGE_SIZE;
    }
    diff -uNrp linux-2.6.4.EXSTACK/arch/ia64/ia32/ia32priv.h linux-2.6.4.noexec/arch/ia64/ia32/ia32priv.h
    --- linux-2.6.4.EXSTACK/arch/ia64/ia32/ia32priv.h 2004-03-11 03:55:51.000000000 +0100
    +++ linux-2.6.4.noexec/arch/ia64/ia32/ia32priv.h 2004-03-23 22:56:20.000000000 +0100
    @@ -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);

    diff -uNrp linux-2.6.4.EXSTACK/arch/mips/kernel/irixelf.c linux-2.6.4.noexec/arch/mips/kernel/irixelf.c
    --- linux-2.6.4.EXSTACK/arch/mips/kernel/irixelf.c 2004-03-11 03:56:03.000000000 +0100
    +++ linux-2.6.4.noexec/arch/mips/kernel/irixelf.c 2004-03-23 22:56:42.000000000 +0100
    @@ -688,7 +688,7 @@ static int load_irix_binary(struct linux
    * change some of these later.
    */
    current->mm->rss = 0;
    - setup_arg_pages(bprm);
    + setup_arg_pages(bprm, 0);
    current->mm->start_stack = bprm->p;

    /* At this point, we assume that the image should be loaded at
    diff -uNrp linux-2.6.4.EXSTACK/arch/s390/kernel/binfmt_elf32.c linux-2.6.4.noexec/arch/s390/kernel/binfmt_elf32.c
    --- linux-2.6.4.EXSTACK/arch/s390/kernel/binfmt_elf32.c 2004-03-11 03:55:44.000000000 +0100
    +++ linux-2.6.4.noexec/arch/s390/kernel/binfmt_elf32.c 2004-03-23 22:51:25.000000000 +0100
    @@ -114,7 +114,7 @@ typedef s390_regs32 elf_gregset_t;
    #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
    @@ -165,7 +165,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,"
    diff -uNrp linux-2.6.4.EXSTACK/arch/s390/kernel/compat_exec.c linux-2.6.4.noexec/arch/s390/kernel/compat_exec.c
    --- linux-2.6.4.EXSTACK/arch/s390/kernel/compat_exec.c 2004-03-23 21:18:35.000000000 +0100
    +++ linux-2.6.4.noexec/arch/s390/kernel/compat_exec.c 2004-03-23 22:58:15.000000000 +0100
    @@ -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_binpr
    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;
    diff -uNrp linux-2.6.4.EXSTACK/arch/sparc64/kernel/binfmt_aout32.c linux-2.6.4.noexec/arch/sparc64/kernel/binfmt_aout32.c
    --- linux-2.6.4.EXSTACK/arch/sparc64/kernel/binfmt_aout32.c 2004-03-11 03:55:27.000000000 +0100
    +++ linux-2.6.4.noexec/arch/sparc64/kernel/binfmt_aout32.c 2004-03-23 22:49:50.000000000 +0100
    @@ -310,7 +310,7 @@ beyond_if:
    orig_thr_flags = current_thread_info()->flags;
    current_thread_info()->flags |= _TIF_32BIT;

    - retval = setup_arg_pages(bprm);
    + retval = setup_arg_pages(bprm, 0);
    if (retval < 0) {
    current_thread_info()->flags = orig_thr_flags;

    diff -uNrp linux-2.6.4.EXSTACK/arch/x86_64/ia32/ia32_aout.c linux-2.6.4.noexec/arch/x86_64/ia32/ia32_aout.c
    --- linux-2.6.4.EXSTACK/arch/x86_64/ia32/ia32_aout.c 2004-03-11 03:55:54.000000000 +0100
    +++ linux-2.6.4.noexec/arch/x86_64/ia32/ia32_aout.c 2004-03-23 22:59:47.000000000 +0100
    @@ -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 @@ beyond_if:

    set_brk(current->mm->start_brk, current->mm->brk);

    - retval = ia32_setup_arg_pages(bprm);
    + retval = ia32_setup_arg_pages(bprm, 0);
    if (retval < 0) {
    /* Someone check-me: is this error path enough? */
    send_sig(SIGKILL, current, 0);
    diff -uNrp linux-2.6.4.EXSTACK/arch/x86_64/ia32/ia32_binfmt.c linux-2.6.4.noexec/arch/x86_64/ia32/ia32_binfmt.c
    --- linux-2.6.4.EXSTACK/arch/x86_64/ia32/ia32_binfmt.c 2004-03-23 22:42:31.000000000 +0100
    +++ linux-2.6.4.noexec/arch/x86_64/ia32/ia32_binfmt.c 2004-03-23 21:18:35.000000000 +0100
    @@ -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 *r
    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
    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 > 0)
    + mpnt->vm_flags = vm_stack_flags32 | VM_EXEC;
    + else if (executable_stack < 0)
    + 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;
    @@ -373,7 +378,7 @@ int setup_arg_pages(struct linux_binprm
    struct page *page = bprm->page[i];
    if (page) {
    bprm->page[i] = NULL;
    - put_dirty_page(current,page,stack_base,PAGE_COPY_EXEC, mpnt);
    + put_dirty_page(current,page,stack_base,mpnt->vm_page_prot,mpnt);
    }
    stack_base += PAGE_SIZE;
    }
    diff -uNrp linux-2.6.4.EXSTACK/fs/binfmt_aout.c linux-2.6.4.noexec/fs/binfmt_aout.c
    --- linux-2.6.4.EXSTACK/fs/binfmt_aout.c 2004-03-23 22:42:31.000000000 +0100
    +++ linux-2.6.4.noexec/fs/binfmt_aout.c 2004-03-23 21:18:35.000000000 +0100
    @@ -413,7 +413,7 @@ beyond_if:

    set_brk(current->mm->start_brk, current->mm->brk);

    - retval = setup_arg_pages(bprm);
    + retval = setup_arg_pages(bprm, 0);
    if (retval < 0) {
    /* Someone check-me: is this error path enough? */
    send_sig(SIGKILL, current, 0);
    diff -uNrp linux-2.6.4.EXSTACK/fs/binfmt_elf.c linux-2.6.4.noexec/fs/binfmt_elf.c
    --- linux-2.6.4.EXSTACK/fs/binfmt_elf.c 2004-03-23 22:42:31.000000000 +0100
    +++ linux-2.6.4.noexec/fs/binfmt_elf.c 2004-03-23 21:18:35.000000000 +0100
    @@ -476,6 +476,7 @@ static int load_elf_binary(struct linux_
    struct exec interp_ex;
    char passed_fileno[6];
    struct files_struct *files;
    + int executable_stack = 0; /* Don't touch */

    /* Get the exec-header */
    elf_ex = *((struct elfhdr *) bprm->buf);
    @@ -599,6 +600,15 @@ static int load_elf_binary(struct linux_
    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 = 1;
    + else
    + executable_stack = -1;
    + }
    +
    /* 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_
    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;
    diff -uNrp linux-2.6.4.EXSTACK/fs/binfmt_som.c linux-2.6.4.noexec/fs/binfmt_som.c
    --- linux-2.6.4.EXSTACK/fs/binfmt_som.c 2004-03-23 22:42:31.000000000 +0100
    +++ linux-2.6.4.noexec/fs/binfmt_som.c 2004-03-23 21:18:35.000000000 +0100
    @@ -254,7 +254,7 @@ load_som_binary(struct linux_binprm * bp

    set_binfmt(&som_format);
    compute_creds(bprm);
    - setup_arg_pages(bprm);
    + setup_arg_pages(bprm, 0);

    create_som_tables(bprm);

    diff -uNrp linux-2.6.4.EXSTACK/fs/exec.c linux-2.6.4.noexec/fs/exec.c
    --- linux-2.6.4.EXSTACK/fs/exec.c 2004-03-23 22:42:31.000000000 +0100
    +++ linux-2.6.4.noexec/fs/exec.c 2004-03-23 21:18:35.000000000 +0100
    @@ -342,7 +342,7 @@ out_sig:
    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,13 @@ int setup_arg_pages(struct linux_binprm
    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;
    + if (executable_stack > 0)
    + mpnt->vm_flags = VM_STACK_FLAGS | VM_EXEC;
    + else if (executable_stack < 0)
    + 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 = mpnt->vm_start >> PAGE_SHIFT;
    mpnt->vm_file = NULL;
    diff -uNrp linux-2.6.4.EXSTACK/include/linux/binfmts.h linux-2.6.4.noexec/include/linux/binfmts.h
    --- linux-2.6.4.EXSTACK/include/linux/binfmts.h 2004-03-23 22:42:31.000000000 +0100
    +++ linux-2.6.4.noexec/include/linux/binfmts.h 2004-03-23 21:18:35.000000000 +0100
    @@ -58,7 +58,7 @@ extern int prepare_binprm(struct linux_b
    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);
    +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);
    diff -uNrp linux-2.6.4.EXSTACK/include/linux/elf.h linux-2.6.4.noexec/include/linux/elf.h
    --- linux-2.6.4.EXSTACK/include/linux/elf.h 2004-03-23 22:42:31.000000000 +0100
    +++ linux-2.6.4.noexec/include/linux/elf.h 2004-03-23 21:18:35.000000000 +0100
    @@ -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[unhandled content-type:application/pgp-signature]
    \
     
     \ /
      Last update: 2005-03-22 14:01    [W:0.039 / U:59.220 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site