#include <linux/init.h>
#include <linux/highuid.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/compiler.h>
#include <linux/highmem.h>
#include <linux/pagemap.h>
#include <linux/syscalls.h>
#include <linux/random.h>
#include <linux/elf.h>
+#include <linux/utsname.h>
#include <asm/uaccess.h>
#include <asm/param.h>
#include <asm/page.h>
static int load_elf_library(struct file *);
static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, int, int);
-#ifndef elf_addr_t
-#define elf_addr_t unsigned long
-#endif
-
/*
* If we don't support core dumping, then supply a NULL so we
* don't even try.
*/
#if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE)
-static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file);
+static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit);
#else
#define elf_core_dump NULL
#endif
.load_binary = load_elf_binary,
.load_shlib = load_elf_library,
.core_dump = elf_core_dump,
- .min_coredump = ELF_EXEC_PAGESIZE
+ .min_coredump = ELF_EXEC_PAGESIZE,
+ .hasvdso = 1
};
#define BAD_ADDR(x) ((unsigned long)(x) >= TASK_SIZE)
elf_addr_t *elf_info;
int ei_index = 0;
struct task_struct *tsk = current;
+ struct vm_area_struct *vma;
+
+ /*
+ * In some cases (e.g. Hyper-Threading), we want to avoid L1
+ * evictions by the processes running on the same package. One
+ * thing we can do is to shuffle the initial stack for them.
+ */
+
+ p = arch_align_stack(p);
/*
* If this architecture has a platform capability string, copy it
if (k_platform) {
size_t len = strlen(k_platform) + 1;
- /*
- * In some cases (e.g. Hyper-Threading), we want to avoid L1
- * evictions by the processes running on the same package. One
- * thing we can do is to shuffle the initial stack for them.
- */
-
- p = arch_align_stack(p);
-
u_platform = (elf_addr_t __user *)STACK_ALLOC(p, len);
if (__copy_to_user(u_platform, k_platform, len))
return -EFAULT;
/* Create the ELF interpreter info */
elf_info = (elf_addr_t *)current->mm->saved_auxv;
+ /* update AT_VECTOR_SIZE_BASE if the number of NEW_AUX_ENT() changes */
#define NEW_AUX_ENT(id, val) \
do { \
elf_info[ei_index++] = id; \
/*
* ARCH_DLINFO must come first so PPC can do its special alignment of
* AUXV.
+ * update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT() in
+ * ARCH_DLINFO changes
*/
ARCH_DLINFO;
#endif
sp = (elf_addr_t __user *)bprm->p;
#endif
+
+ /*
+ * Grow the stack manually; some architectures have a limit on how
+ * far ahead a user-space access may be in order to grow the stack.
+ */
+ vma = find_extend_vma(current->mm, bprm->p);
+ if (!vma)
+ return -EFAULT;
+
/* Now, let's put argc (and argv, envp if appropriate) on the stack */
if (__put_user(argc, sp++))
return -EFAULT;
if (interp_aout) {
argv = sp + 2;
envp = argv + argc + 1;
- __put_user((elf_addr_t)(unsigned long)argv, sp++);
- __put_user((elf_addr_t)(unsigned long)envp, sp++);
+ if (__put_user((elf_addr_t)(unsigned long)argv, sp++) ||
+ __put_user((elf_addr_t)(unsigned long)envp, sp++))
+ return -EFAULT;
} else {
argv = sp;
envp = argv + argc + 1;
p = current->mm->arg_end = current->mm->arg_start;
while (argc-- > 0) {
size_t len;
- __put_user((elf_addr_t)p, argv++);
- len = strnlen_user((void __user *)p, PAGE_SIZE*MAX_ARG_PAGES);
- if (!len || len > PAGE_SIZE*MAX_ARG_PAGES)
+ if (__put_user((elf_addr_t)p, argv++))
+ return -EFAULT;
+ len = strnlen_user((void __user *)p, MAX_ARG_STRLEN);
+ if (!len || len > MAX_ARG_STRLEN)
return 0;
p += len;
}
current->mm->arg_end = current->mm->env_start = p;
while (envc-- > 0) {
size_t len;
- __put_user((elf_addr_t)p, envp++);
- len = strnlen_user((void __user *)p, PAGE_SIZE*MAX_ARG_PAGES);
- if (!len || len > PAGE_SIZE*MAX_ARG_PAGES)
+ if (__put_user((elf_addr_t)p, envp++))
+ return -EFAULT;
+ len = strnlen_user((void __user *)p, MAX_ARG_STRLEN);
+ if (!len || len > MAX_ARG_STRLEN)
return 0;
p += len;
}
#define INTERPRETER_ELF 2
#ifndef STACK_RND_MASK
-#define STACK_RND_MASK 0x7ff /* with 4K pages 8MB of VA */
+#define STACK_RND_MASK (0x7ff >> (PAGE_SHIFT - 12)) /* 8MB of VA */
#endif
static unsigned long randomize_stack_top(unsigned long stack_top)
unsigned long reloc_func_desc = 0;
char passed_fileno[6];
struct files_struct *files;
- int have_pt_gnu_stack, executable_stack = EXSTACK_DEFAULT;
+ int executable_stack = EXSTACK_DEFAULT;
unsigned long def_flags = 0;
struct {
struct elfhdr elf_ex;
retval = PTR_ERR(interpreter);
if (IS_ERR(interpreter))
goto out_free_interp;
+
+ /*
+ * If the binary is not readable then enforce
+ * mm->dumpable = 0 regardless of the interpreter's
+ * permissions.
+ */
+ if (file_permission(interpreter, MAY_READ) < 0)
+ bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP;
+
retval = kernel_read(interpreter, 0, bprm->buf,
BINPRM_BUF_SIZE);
if (retval != BINPRM_BUF_SIZE) {
executable_stack = EXSTACK_DISABLE_X;
break;
}
- have_pt_gnu_stack = (i < loc->elf_ex.e_phnum);
/* Some simple consistency checks for the interpreter */
if (elf_interpreter) {
+ static int warn;
interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
/* Now figure out which format our binary is */
if (memcmp(loc->interp_elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
interpreter_type &= ~INTERPRETER_ELF;
+ if (interpreter_type == INTERPRETER_AOUT && warn < 10) {
+ printk(KERN_WARNING "a.out ELF interpreter %s is "
+ "deprecated and will not be supported "
+ "after Linux 2.6.25\n", elf_interpreter);
+ warn++;
+ }
+
retval = -ELIBBAD;
if (!interpreter_type)
goto out_free_dentry;
}
/* OK, This is the point of no return */
- current->mm->start_data = 0;
- current->mm->end_data = 0;
- current->mm->end_code = 0;
- current->mm->mmap = NULL;
current->flags &= ~PF_FORKNOEXEC;
current->mm->def_flags = def_flags;
* default mmap base, as well as whatever program they
* might try to exec. This is because the brk will
* follow the loader, and is not movable. */
- if (current->flags & PF_RANDOMIZE)
- load_bias = randomize_range(0x10000,
- ELF_ET_DYN_BASE,
- 0);
- else
- load_bias = ELF_ET_DYN_BASE;
- load_bias = ELF_PAGESTART(load_bias - vaddr);
+ load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr);
}
error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt,
elf_prot, elf_flags);
if (BAD_ADDR(error)) {
send_sig(SIGKILL, current, 0);
+ retval = IS_ERR((void *)error) ?
+ PTR_ERR((void*)error) : -EINVAL;
goto out_free_dentry;
}
TASK_SIZE - elf_ppnt->p_memsz < k) {
/* set_brk can never work. Avoid overflows. */
send_sig(SIGKILL, current, 0);
+ retval = -EINVAL;
goto out_free_dentry;
}
compute_creds(bprm);
current->flags &= ~PF_FORKNOEXEC;
- create_elf_tables(bprm, &loc->elf_ex,
+ retval = create_elf_tables(bprm, &loc->elf_ex,
(interpreter_type == INTERPRETER_AOUT),
load_addr, interp_load_addr);
+ if (retval < 0) {
+ send_sig(SIGKILL, current, 0);
+ goto out;
+ }
/* N.B. passed_fileno might not be initialized? */
if (interpreter_type == INTERPRETER_AOUT)
current->mm->arg_start += strlen(passed_fileno) + 1;
}
/*
- * Decide whether a segment is worth dumping; default is yes to be
- * sure (missing info is worse than too much; etc).
- * Personally I'd include everything, and use the coredump limit...
- *
- * I think we should skip something. But I am not sure how. H.J.
+ * Decide what to dump of a segment, part, all or none.
*/
-static int maydump(struct vm_area_struct *vma)
+static unsigned long vma_dump_size(struct vm_area_struct *vma,
+ unsigned long mm_flags)
{
+ /* The vma can be set up to tell us the answer directly. */
+ if (vma->vm_flags & VM_ALWAYSDUMP)
+ goto whole;
+
/* Do not dump I/O mapped devices or special mappings */
if (vma->vm_flags & (VM_IO | VM_RESERVED))
return 0;
- /* Dump shared memory only if mapped from an anonymous file. */
- if (vma->vm_flags & VM_SHARED)
- return vma->vm_file->f_dentry->d_inode->i_nlink == 0;
+#define FILTER(type) (mm_flags & (1UL << MMF_DUMP_##type))
+
+ /* By default, dump shared memory if mapped from an anonymous file. */
+ if (vma->vm_flags & VM_SHARED) {
+ if (vma->vm_file->f_path.dentry->d_inode->i_nlink == 0 ?
+ FILTER(ANON_SHARED) : FILTER(MAPPED_SHARED))
+ goto whole;
+ return 0;
+ }
- /* If it hasn't been written to, don't write it out */
- if (!vma->anon_vma)
+ /* Dump segments that have been written to. */
+ if (vma->anon_vma && FILTER(ANON_PRIVATE))
+ goto whole;
+ if (vma->vm_file == NULL)
return 0;
- return 1;
+ if (FILTER(MAPPED_PRIVATE))
+ goto whole;
+
+ /*
+ * If this looks like the beginning of a DSO or executable mapping,
+ * check for an ELF header. If we find one, dump the first page to
+ * aid in determining what was mapped here.
+ */
+ if (FILTER(ELF_HEADERS) && vma->vm_file != NULL && vma->vm_pgoff == 0) {
+ u32 __user *header = (u32 __user *) vma->vm_start;
+ u32 word;
+ /*
+ * Doing it this way gets the constant folded by GCC.
+ */
+ union {
+ u32 cmp;
+ char elfmag[SELFMAG];
+ } magic;
+ BUILD_BUG_ON(SELFMAG != sizeof word);
+ magic.elfmag[EI_MAG0] = ELFMAG0;
+ magic.elfmag[EI_MAG1] = ELFMAG1;
+ magic.elfmag[EI_MAG2] = ELFMAG2;
+ magic.elfmag[EI_MAG3] = ELFMAG3;
+ if (get_user(word, header) == 0 && word == magic.cmp)
+ return PAGE_SIZE;
+ }
+
+#undef FILTER
+
+ return 0;
+
+whole:
+ return vma->vm_end - vma->vm_start;
}
/* An ELF note in memory */
prstatus->pr_pid = p->pid;
prstatus->pr_ppid = p->parent->pid;
prstatus->pr_pgrp = process_group(p);
- prstatus->pr_sid = p->signal->session;
+ prstatus->pr_sid = process_session(p);
if (thread_group_leader(p)) {
/*
* This is the record for the group leader. Add in the
psinfo->pr_pid = p->pid;
psinfo->pr_ppid = p->parent->pid;
psinfo->pr_pgrp = process_group(p);
- psinfo->pr_sid = p->signal->session;
+ psinfo->pr_sid = process_session(p);
i = p->state ? ffz(~p->state) + 1 : 0;
psinfo->pr_state = i;
elf_fpregset_t fpu; /* NT_PRFPREG */
struct task_struct *thread;
#ifdef ELF_CORE_COPY_XFPREGS
- elf_fpxregset_t xfpu; /* NT_PRXFPREG */
+ elf_fpxregset_t xfpu; /* ELF_CORE_XFPREG_TYPE */
#endif
struct memelfnote notes[3];
int num_notes;
#ifdef ELF_CORE_COPY_XFPREGS
if (elf_core_copy_task_xfpregs(p, &t->xfpu)) {
- fill_note(&t->notes[2], "LINUX", NT_PRXFPREG, sizeof(t->xfpu),
- &t->xfpu);
+ fill_note(&t->notes[2], "LINUX", ELF_CORE_XFPREG_TYPE,
+ sizeof(t->xfpu), &t->xfpu);
t->num_notes++;
sz += notesize(&t->notes[2]);
}
return sz;
}
+static struct vm_area_struct *first_vma(struct task_struct *tsk,
+ struct vm_area_struct *gate_vma)
+{
+ struct vm_area_struct *ret = tsk->mm->mmap;
+
+ if (ret)
+ return ret;
+ return gate_vma;
+}
+/*
+ * Helper function for iterating across a vma list. It ensures that the caller
+ * will visit `gate_vma' prior to terminating the search.
+ */
+static struct vm_area_struct *next_vma(struct vm_area_struct *this_vma,
+ struct vm_area_struct *gate_vma)
+{
+ struct vm_area_struct *ret;
+
+ ret = this_vma->vm_next;
+ if (ret)
+ return ret;
+ if (this_vma == gate_vma)
+ return NULL;
+ return gate_vma;
+}
+
/*
* Actual dumper
*
* and then they are actually written out. If we run out of core limit
* we just truncate.
*/
-static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
+static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit)
{
#define NUM_NOTES 6
int has_dumped = 0;
int segs;
size_t size = 0;
int i;
- struct vm_area_struct *vma;
+ struct vm_area_struct *vma, *gate_vma;
struct elfhdr *elf = NULL;
loff_t offset = 0, dataoff, foffset;
- unsigned long limit = current->signal->rlim[RLIMIT_CORE].rlim_cur;
int numnote;
struct memelfnote *notes = NULL;
struct elf_prstatus *prstatus = NULL; /* NT_PRSTATUS */
#endif
int thread_status_size = 0;
elf_addr_t *auxv;
+ unsigned long mm_flags;
/*
* We no longer stop all VM operations.
segs += ELF_CORE_EXTRA_PHDRS;
#endif
+ gate_vma = get_gate_vma(current);
+ if (gate_vma != NULL)
+ segs++;
+
/* Set up header */
fill_elf_header(elf, segs + 1); /* including notes section */
#ifdef ELF_CORE_COPY_XFPREGS
if (elf_core_copy_task_xfpregs(current, xfpu))
fill_note(notes + numnote++,
- "LINUX", NT_PRXFPREG, sizeof(*xfpu), xfpu);
+ "LINUX", ELF_CORE_XFPREG_TYPE, sizeof(*xfpu), xfpu);
#endif
fs = get_fs();
sz += thread_status_size;
-#ifdef ELF_CORE_WRITE_EXTRA_NOTES
- sz += ELF_CORE_EXTRA_NOTES_SIZE;
-#endif
+ sz += elf_coredump_extra_notes_size();
fill_elf_note_phdr(&phdr, sz, offset);
offset += sz;
dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
+ /*
+ * We must use the same mm->flags while dumping core to avoid
+ * inconsistency between the program headers and bodies, otherwise an
+ * unusable core file can be generated.
+ */
+ mm_flags = current->mm->flags;
+
/* Write program headers for segments dump */
- for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
+ for (vma = first_vma(current, gate_vma); vma != NULL;
+ vma = next_vma(vma, gate_vma)) {
struct elf_phdr phdr;
- size_t sz;
-
- sz = vma->vm_end - vma->vm_start;
phdr.p_type = PT_LOAD;
phdr.p_offset = offset;
phdr.p_vaddr = vma->vm_start;
phdr.p_paddr = 0;
- phdr.p_filesz = maydump(vma) ? sz : 0;
- phdr.p_memsz = sz;
+ phdr.p_filesz = vma_dump_size(vma, mm_flags);
+ phdr.p_memsz = vma->vm_end - vma->vm_start;
offset += phdr.p_filesz;
phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0;
if (vma->vm_flags & VM_WRITE)
if (!writenote(notes + i, file, &foffset))
goto end_coredump;
-#ifdef ELF_CORE_WRITE_EXTRA_NOTES
- ELF_CORE_WRITE_EXTRA_NOTES;
-#endif
+ if (elf_coredump_extra_notes_write(file, &foffset))
+ goto end_coredump;
/* write out the thread status notes section */
list_for_each(t, &thread_list) {
/* Align to page */
DUMP_SEEK(dataoff - foffset);
- for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
+ for (vma = first_vma(current, gate_vma); vma != NULL;
+ vma = next_vma(vma, gate_vma)) {
unsigned long addr;
+ unsigned long end;
- if (!maydump(vma))
- continue;
+ end = vma->vm_start + vma_dump_size(vma, mm_flags);
- for (addr = vma->vm_start;
- addr < vma->vm_end;
- addr += PAGE_SIZE) {
+ for (addr = vma->vm_start; addr < end; addr += PAGE_SIZE) {
struct page *page;
struct vm_area_struct *vma;
&page, &vma) <= 0) {
DUMP_SEEK(PAGE_SIZE);
} else {
- if (page == ZERO_PAGE(addr)) {
- DUMP_SEEK(PAGE_SIZE);
+ if (page == ZERO_PAGE(0)) {
+ if (!dump_seek(file, PAGE_SIZE)) {
+ page_cache_release(page);
+ goto end_coredump;
+ }
} else {
void *kaddr;
flush_cache_page(vma, addr,