#include <linux/time.h>
#include <linux/mm.h>
#include <linux/mman.h>
-#include <linux/a.out.h>
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/binfmts.h>
return 0;
}
-/* Let's use some macros to make this stack manipulation a litle clearer */
+/* Let's use some macros to make this stack manipulation a little clearer */
#ifdef CONFIG_STACK_GROWSUP
#define STACK_ADD(sp, items) ((elf_addr_t __user *)(sp) + (items))
#define STACK_ROUND(sp, items) \
#define STACK_ALLOC(sp, len) ({ sp -= len ; sp; })
#endif
+#ifndef ELF_BASE_PLATFORM
+/*
+ * AT_BASE_PLATFORM indicates the "real" hardware/microarchitecture.
+ * If the arch defines ELF_BASE_PLATFORM (in asm/elf.h), the value
+ * will be copied to the user stack in the same manner as AT_PLATFORM.
+ */
+#define ELF_BASE_PLATFORM NULL
+#endif
+
static int
create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
- int interp_aout, unsigned long load_addr,
- unsigned long interp_load_addr)
+ unsigned long load_addr, unsigned long interp_load_addr)
{
unsigned long p = bprm->p;
int argc = bprm->argc;
elf_addr_t __user *envp;
elf_addr_t __user *sp;
elf_addr_t __user *u_platform;
+ elf_addr_t __user *u_base_platform;
const char *k_platform = ELF_PLATFORM;
+ const char *k_base_platform = ELF_BASE_PLATFORM;
int items;
elf_addr_t *elf_info;
int ei_index = 0;
return -EFAULT;
}
+ /*
+ * If this architecture has a "base" platform capability
+ * string, copy it to userspace.
+ */
+ u_base_platform = NULL;
+ if (k_base_platform) {
+ size_t len = strlen(k_base_platform) + 1;
+
+ u_base_platform = (elf_addr_t __user *)STACK_ALLOC(p, len);
+ if (__copy_to_user(u_base_platform, k_base_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 */
NEW_AUX_ENT(AT_GID, tsk->gid);
NEW_AUX_ENT(AT_EGID, tsk->egid);
NEW_AUX_ENT(AT_SECURE, security_bprm_secureexec(bprm));
+ NEW_AUX_ENT(AT_EXECFN, bprm->exec);
if (k_platform) {
NEW_AUX_ENT(AT_PLATFORM,
(elf_addr_t)(unsigned long)u_platform);
}
+ if (k_base_platform) {
+ NEW_AUX_ENT(AT_BASE_PLATFORM,
+ (elf_addr_t)(unsigned long)u_base_platform);
+ }
if (bprm->interp_flags & BINPRM_FLAGS_EXECFD) {
NEW_AUX_ENT(AT_EXECFD, bprm->interp_data);
}
sp = STACK_ADD(p, ei_index);
- items = (argc + 1) + (envc + 1);
- if (interp_aout) {
- items += 3; /* a.out interpreters require argv & envp too */
- } else {
- items += 1; /* ELF interpreters only put argc on the stack */
- }
+ items = (argc + 1) + (envc + 1) + 1;
bprm->p = STACK_ROUND(sp, items);
/* Point sp at the lowest address on the stack */
/* 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;
- 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;
- }
+ argv = sp;
+ envp = argv + argc + 1;
/* Populate argv and envp */
p = current->mm->arg_end = current->mm->arg_start;
return -EFAULT;
len = strnlen_user((void __user *)p, MAX_ARG_STRLEN);
if (!len || len > MAX_ARG_STRLEN)
- return 0;
+ return -EINVAL;
p += len;
}
if (__put_user(0, argv))
return -EFAULT;
len = strnlen_user((void __user *)p, MAX_ARG_STRLEN);
if (!len || len > MAX_ARG_STRLEN)
- return 0;
+ return -EINVAL;
p += len;
}
if (__put_user(0, envp))
return error;
}
-static unsigned long load_aout_interp(struct exec *interp_ex,
- struct file *interpreter)
-{
- unsigned long text_data, elf_entry = ~0UL;
- char __user * addr;
- loff_t offset;
-
- current->mm->end_code = interp_ex->a_text;
- text_data = interp_ex->a_text + interp_ex->a_data;
- current->mm->end_data = text_data;
- current->mm->brk = interp_ex->a_bss + text_data;
-
- switch (N_MAGIC(*interp_ex)) {
- case OMAGIC:
- offset = 32;
- addr = (char __user *)0;
- break;
- case ZMAGIC:
- case QMAGIC:
- offset = N_TXTOFF(*interp_ex);
- addr = (char __user *)N_TXTADDR(*interp_ex);
- break;
- default:
- goto out;
- }
-
- down_write(¤t->mm->mmap_sem);
- do_brk(0, text_data);
- up_write(¤t->mm->mmap_sem);
- if (!interpreter->f_op || !interpreter->f_op->read)
- goto out;
- if (interpreter->f_op->read(interpreter, addr, text_data, &offset) < 0)
- goto out;
- flush_icache_range((unsigned long)addr,
- (unsigned long)addr + text_data);
-
- down_write(¤t->mm->mmap_sem);
- do_brk(ELF_PAGESTART(text_data + ELF_MIN_ALIGN - 1),
- interp_ex->a_bss);
- up_write(¤t->mm->mmap_sem);
- elf_entry = interp_ex->a_entry;
-
-out:
- return elf_entry;
-}
-
/*
* These are the functions used to load ELF style executables and shared
* libraries. There is no binary dependent code anywhere else.
*/
#define INTERPRETER_NONE 0
-#define INTERPRETER_AOUT 1
#define INTERPRETER_ELF 2
#ifndef STACK_RND_MASK
unsigned long load_addr = 0, load_bias = 0;
int load_addr_set = 0;
char * elf_interpreter = NULL;
- unsigned int interpreter_type = INTERPRETER_NONE;
- unsigned char ibcs2_interpreter = 0;
unsigned long error;
struct elf_phdr *elf_ppnt, *elf_phdata;
unsigned long elf_bss, elf_brk;
unsigned long interp_load_addr = 0;
unsigned long start_code, end_code, start_data, end_data;
unsigned long reloc_func_desc = 0;
- char passed_fileno[6];
- struct files_struct *files;
int executable_stack = EXSTACK_DEFAULT;
unsigned long def_flags = 0;
struct {
struct elfhdr elf_ex;
struct elfhdr interp_elf_ex;
- struct exec interp_ex;
} *loc;
loc = kmalloc(sizeof(*loc), GFP_KERNEL);
goto out_free_ph;
}
- files = current->files; /* Refcounted so ok */
- retval = unshare_files();
- if (retval < 0)
- goto out_free_ph;
- if (files == current->files) {
- put_files_struct(files);
- files = NULL;
- }
-
- /* exec will make our files private anyway, but for the a.out
- loader stuff we need to do it earlier */
retval = get_unused_fd();
if (retval < 0)
- goto out_free_fh;
+ goto out_free_ph;
get_file(bprm->file);
fd_install(elf_exec_fileno = retval, bprm->file);
if (elf_interpreter[elf_ppnt->p_filesz - 1] != '\0')
goto out_free_interp;
- /* If the program interpreter is one of these two,
- * then assume an iBCS2 image. Otherwise assume
- * a native linux image.
- */
- if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
- strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0)
- ibcs2_interpreter = 1;
-
/*
* The early SET_PERSONALITY here is so that the lookup
* for the interpreter happens in the namespace of the
* switch really is going to happen - do this in
* flush_thread(). - akpm
*/
- SET_PERSONALITY(loc->elf_ex, ibcs2_interpreter);
+ SET_PERSONALITY(loc->elf_ex, 0);
interpreter = open_exec(elf_interpreter);
retval = PTR_ERR(interpreter);
}
/* Get the exec headers */
- loc->interp_ex = *((struct exec *)bprm->buf);
loc->interp_elf_ex = *((struct elfhdr *)bprm->buf);
break;
}
/* 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 ((N_MAGIC(loc->interp_ex) != OMAGIC) &&
- (N_MAGIC(loc->interp_ex) != ZMAGIC) &&
- (N_MAGIC(loc->interp_ex) != QMAGIC))
- interpreter_type = INTERPRETER_ELF;
-
- 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)
+ /* Not an ELF interpreter */
+ if (memcmp(loc->interp_elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
goto out_free_dentry;
-
- /* Make sure only one type was selected */
- if ((interpreter_type & INTERPRETER_ELF) &&
- interpreter_type != INTERPRETER_ELF) {
- // FIXME - ratelimit this before re-enabling
- // printk(KERN_WARNING "ELF: Ambiguous type, using ELF\n");
- interpreter_type = INTERPRETER_ELF;
- }
/* Verify the interpreter has a valid arch */
- if ((interpreter_type == INTERPRETER_ELF) &&
- !elf_check_arch(&loc->interp_elf_ex))
+ if (!elf_check_arch(&loc->interp_elf_ex))
goto out_free_dentry;
} else {
/* Executables without an interpreter also need a personality */
- SET_PERSONALITY(loc->elf_ex, ibcs2_interpreter);
- }
-
- /* OK, we are done with that, now set up the arg stuff,
- and then start this sucker up */
- if ((!bprm->sh_bang) && (interpreter_type == INTERPRETER_AOUT)) {
- char *passed_p = passed_fileno;
- sprintf(passed_fileno, "%d", elf_exec_fileno);
-
- if (elf_interpreter) {
- retval = copy_strings_kernel(1, &passed_p, bprm);
- if (retval)
- goto out_free_dentry;
- bprm->argc++;
- }
+ SET_PERSONALITY(loc->elf_ex, 0);
}
/* Flush all traces of the currently running executable */
if (retval)
goto out_free_dentry;
- /* Discard our unneeded old files struct */
- if (files) {
- put_files_struct(files);
- files = NULL;
- }
-
/* OK, This is the point of no return */
current->flags &= ~PF_FORKNOEXEC;
current->mm->def_flags = def_flags;
/* Do this immediately, since STACK_TOP as used in setup_arg_pages
may depend on the personality. */
- SET_PERSONALITY(loc->elf_ex, ibcs2_interpreter);
+ SET_PERSONALITY(loc->elf_ex, 0);
if (elf_read_implies_exec(loc->elf_ex, executable_stack))
current->personality |= READ_IMPLIES_EXEC;
}
if (elf_interpreter) {
- if (interpreter_type == INTERPRETER_AOUT) {
- elf_entry = load_aout_interp(&loc->interp_ex,
- interpreter);
- } else {
- unsigned long uninitialized_var(interp_map_addr);
-
- elf_entry = load_elf_interp(&loc->interp_elf_ex,
- interpreter,
- &interp_map_addr,
- load_bias);
- if (!IS_ERR((void *)elf_entry)) {
- /*
- * load_elf_interp() returns relocation
- * adjustment
- */
- interp_load_addr = elf_entry;
- elf_entry += loc->interp_elf_ex.e_entry;
- }
+ unsigned long uninitialized_var(interp_map_addr);
+
+ elf_entry = load_elf_interp(&loc->interp_elf_ex,
+ interpreter,
+ &interp_map_addr,
+ load_bias);
+ if (!IS_ERR((void *)elf_entry)) {
+ /*
+ * load_elf_interp() returns relocation
+ * adjustment
+ */
+ interp_load_addr = elf_entry;
+ elf_entry += loc->interp_elf_ex.e_entry;
}
if (BAD_ADDR(elf_entry)) {
force_sig(SIGSEGV, current);
kfree(elf_phdata);
- if (interpreter_type != INTERPRETER_AOUT)
- sys_close(elf_exec_fileno);
+ sys_close(elf_exec_fileno);
set_binfmt(&elf_format);
compute_creds(bprm);
current->flags &= ~PF_FORKNOEXEC;
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;
current->mm->end_code = end_code;
current->mm->start_code = start_code;
current->mm->start_data = start_data;
current->mm->start_stack = bprm->p;
#ifdef arch_randomize_brk
- if (current->flags & PF_RANDOMIZE)
+ if ((current->flags & PF_RANDOMIZE) && (randomize_va_space > 1))
current->mm->brk = current->mm->start_brk =
arch_randomize_brk(current->mm);
#endif
#endif
start_thread(regs, elf_entry, bprm->p);
- if (unlikely(current->ptrace & PT_PTRACED)) {
- if (current->ptrace & PT_TRACE_EXEC)
- ptrace_notify ((PTRACE_EVENT_EXEC << 8) | SIGTRAP);
- else
- send_sig(SIGTRAP, current, 0);
- }
retval = 0;
out:
kfree(loc);
kfree(elf_interpreter);
out_free_file:
sys_close(elf_exec_fileno);
-out_free_fh:
- if (files)
- reset_files_struct(current, files);
out_free_ph:
kfree(elf_phdata);
goto out;
static void fill_elf_header(struct elfhdr *elf, int segs,
u16 machine, u32 flags, u8 osabi)
{
+ memset(elf, 0, sizeof(*elf));
+
memcpy(elf->e_ident, ELFMAG, SELFMAG);
elf->e_ident[EI_CLASS] = ELF_CLASS;
elf->e_ident[EI_DATA] = ELF_DATA;
elf->e_ident[EI_VERSION] = EV_CURRENT;
elf->e_ident[EI_OSABI] = ELF_OSABI;
- memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
elf->e_type = ET_CORE;
elf->e_machine = machine;
elf->e_version = EV_CURRENT;
- elf->e_entry = 0;
elf->e_phoff = sizeof(struct elfhdr);
- elf->e_shoff = 0;
elf->e_flags = flags;
elf->e_ehsize = sizeof(struct elfhdr);
elf->e_phentsize = sizeof(struct elf_phdr);
elf->e_phnum = segs;
- elf->e_shentsize = 0;
- elf->e_shnum = 0;
- elf->e_shstrndx = 0;
+
return;
}
fill_note(note, "CORE", NT_AUXV, i * sizeof(elf_addr_t), auxv);
}
+#ifdef CORE_DUMP_USE_REGSET
+#include <linux/regset.h>
+
+struct elf_thread_core_info {
+ struct elf_thread_core_info *next;
+ struct task_struct *task;
+ struct elf_prstatus prstatus;
+ struct memelfnote notes[0];
+};
+
+struct elf_note_info {
+ struct elf_thread_core_info *thread;
+ struct memelfnote psinfo;
+ struct memelfnote auxv;
+ size_t size;
+ int thread_notes;
+};
+
+/*
+ * When a regset has a writeback hook, we call it on each thread before
+ * dumping user memory. On register window machines, this makes sure the
+ * user memory backing the register data is up to date before we read it.
+ */
+static void do_thread_regset_writeback(struct task_struct *task,
+ const struct user_regset *regset)
+{
+ if (regset->writeback)
+ regset->writeback(task, regset, 1);
+}
+
+static int fill_thread_core_info(struct elf_thread_core_info *t,
+ const struct user_regset_view *view,
+ long signr, size_t *total)
+{
+ unsigned int i;
+
+ /*
+ * NT_PRSTATUS is the one special case, because the regset data
+ * goes into the pr_reg field inside the note contents, rather
+ * than being the whole note contents. We fill the reset in here.
+ * We assume that regset 0 is NT_PRSTATUS.
+ */
+ fill_prstatus(&t->prstatus, t->task, signr);
+ (void) view->regsets[0].get(t->task, &view->regsets[0],
+ 0, sizeof(t->prstatus.pr_reg),
+ &t->prstatus.pr_reg, NULL);
+
+ fill_note(&t->notes[0], "CORE", NT_PRSTATUS,
+ sizeof(t->prstatus), &t->prstatus);
+ *total += notesize(&t->notes[0]);
+
+ do_thread_regset_writeback(t->task, &view->regsets[0]);
+
+ /*
+ * Each other regset might generate a note too. For each regset
+ * that has no core_note_type or is inactive, we leave t->notes[i]
+ * all zero and we'll know to skip writing it later.
+ */
+ for (i = 1; i < view->n; ++i) {
+ const struct user_regset *regset = &view->regsets[i];
+ do_thread_regset_writeback(t->task, regset);
+ if (regset->core_note_type &&
+ (!regset->active || regset->active(t->task, regset))) {
+ int ret;
+ size_t size = regset->n * regset->size;
+ void *data = kmalloc(size, GFP_KERNEL);
+ if (unlikely(!data))
+ return 0;
+ ret = regset->get(t->task, regset,
+ 0, size, data, NULL);
+ if (unlikely(ret))
+ kfree(data);
+ else {
+ if (regset->core_note_type != NT_PRFPREG)
+ fill_note(&t->notes[i], "LINUX",
+ regset->core_note_type,
+ size, data);
+ else {
+ t->prstatus.pr_fpvalid = 1;
+ fill_note(&t->notes[i], "CORE",
+ NT_PRFPREG, size, data);
+ }
+ *total += notesize(&t->notes[i]);
+ }
+ }
+ }
+
+ return 1;
+}
+
+static int fill_note_info(struct elfhdr *elf, int phdrs,
+ struct elf_note_info *info,
+ long signr, struct pt_regs *regs)
+{
+ struct task_struct *dump_task = current;
+ const struct user_regset_view *view = task_user_regset_view(dump_task);
+ struct elf_thread_core_info *t;
+ struct elf_prpsinfo *psinfo;
+ struct core_thread *ct;
+ unsigned int i;
+
+ info->size = 0;
+ info->thread = NULL;
+
+ psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL);
+ fill_note(&info->psinfo, "CORE", NT_PRPSINFO, sizeof(*psinfo), psinfo);
+
+ if (psinfo == NULL)
+ return 0;
+
+ /*
+ * Figure out how many notes we're going to need for each thread.
+ */
+ info->thread_notes = 0;
+ for (i = 0; i < view->n; ++i)
+ if (view->regsets[i].core_note_type != 0)
+ ++info->thread_notes;
+
+ /*
+ * Sanity check. We rely on regset 0 being in NT_PRSTATUS,
+ * since it is our one special case.
+ */
+ if (unlikely(info->thread_notes == 0) ||
+ unlikely(view->regsets[0].core_note_type != NT_PRSTATUS)) {
+ WARN_ON(1);
+ return 0;
+ }
+
+ /*
+ * Initialize the ELF file header.
+ */
+ fill_elf_header(elf, phdrs,
+ view->e_machine, view->e_flags, view->ei_osabi);
+
+ /*
+ * Allocate a structure for each thread.
+ */
+ for (ct = &dump_task->mm->core_state->dumper; ct; ct = ct->next) {
+ t = kzalloc(offsetof(struct elf_thread_core_info,
+ notes[info->thread_notes]),
+ GFP_KERNEL);
+ if (unlikely(!t))
+ return 0;
+
+ t->task = ct->task;
+ if (ct->task == dump_task || !info->thread) {
+ t->next = info->thread;
+ info->thread = t;
+ } else {
+ /*
+ * Make sure to keep the original task at
+ * the head of the list.
+ */
+ t->next = info->thread->next;
+ info->thread->next = t;
+ }
+ }
+
+ /*
+ * Now fill in each thread's information.
+ */
+ for (t = info->thread; t != NULL; t = t->next)
+ if (!fill_thread_core_info(t, view, signr, &info->size))
+ return 0;
+
+ /*
+ * Fill in the two process-wide notes.
+ */
+ fill_psinfo(psinfo, dump_task->group_leader, dump_task->mm);
+ info->size += notesize(&info->psinfo);
+
+ fill_auxv_note(&info->auxv, current->mm);
+ info->size += notesize(&info->auxv);
+
+ return 1;
+}
+
+static size_t get_note_info_size(struct elf_note_info *info)
+{
+ return info->size;
+}
+
+/*
+ * Write all the notes for each thread. When writing the first thread, the
+ * process-wide notes are interleaved after the first thread-specific note.
+ */
+static int write_note_info(struct elf_note_info *info,
+ struct file *file, loff_t *foffset)
+{
+ bool first = 1;
+ struct elf_thread_core_info *t = info->thread;
+
+ do {
+ int i;
+
+ if (!writenote(&t->notes[0], file, foffset))
+ return 0;
+
+ if (first && !writenote(&info->psinfo, file, foffset))
+ return 0;
+ if (first && !writenote(&info->auxv, file, foffset))
+ return 0;
+
+ for (i = 1; i < info->thread_notes; ++i)
+ if (t->notes[i].data &&
+ !writenote(&t->notes[i], file, foffset))
+ return 0;
+
+ first = 0;
+ t = t->next;
+ } while (t);
+
+ return 1;
+}
+
+static void free_note_info(struct elf_note_info *info)
+{
+ struct elf_thread_core_info *threads = info->thread;
+ while (threads) {
+ unsigned int i;
+ struct elf_thread_core_info *t = threads;
+ threads = t->next;
+ WARN_ON(t->notes[0].data && t->notes[0].data != &t->prstatus);
+ for (i = 1; i < info->thread_notes; ++i)
+ kfree(t->notes[i].data);
+ kfree(t);
+ }
+ kfree(info->psinfo.data);
+}
+
+#else
+
/* Here is the structure in which status of each thread is captured. */
struct elf_thread_status
{
{
#define NUM_NOTES 6
struct list_head *t;
- struct task_struct *g, *p;
info->notes = NULL;
info->prstatus = NULL;
info->thread_status_size = 0;
if (signr) {
- struct elf_thread_status *tmp;
- rcu_read_lock();
- do_each_thread(g, p)
- if (current->mm == p->mm && current != p) {
- tmp = kzalloc(sizeof(*tmp), GFP_ATOMIC);
- if (!tmp) {
- rcu_read_unlock();
- return 0;
- }
- tmp->thread = p;
- list_add(&tmp->list, &info->thread_list);
- }
- while_each_thread(g, p);
- rcu_read_unlock();
+ struct core_thread *ct;
+ struct elf_thread_status *ets;
+
+ for (ct = current->mm->core_state->dumper.next;
+ ct; ct = ct->next) {
+ ets = kzalloc(sizeof(*ets), GFP_KERNEL);
+ if (!ets)
+ return 0;
+
+ ets->thread = ct->task;
+ list_add(&ets->list, &info->thread_list);
+ }
+
list_for_each(t, &info->thread_list) {
- struct elf_thread_status *tmp;
int sz;
- tmp = list_entry(t, struct elf_thread_status, list);
- sz = elf_dump_thread_status(signr, tmp);
+ ets = list_entry(t, struct elf_thread_status, list);
+ sz = elf_dump_thread_status(signr, ets);
info->thread_status_size += sz;
}
}
#endif
}
+#endif
+
static struct vm_area_struct *first_vma(struct task_struct *tsk,
struct vm_area_struct *gate_vma)
{
/* alloc memory for large data structures: too large to be on stack */
elf = kmalloc(sizeof(*elf), GFP_KERNEL);
if (!elf)
- goto cleanup;
+ goto out;
segs = current->mm->map_count;
#ifdef ELF_CORE_EXTRA_PHDRS
for (addr = vma->vm_start; addr < end; addr += PAGE_SIZE) {
struct page *page;
- struct vm_area_struct *vma;
+ struct vm_area_struct *tmp_vma;
if (get_user_pages(current, current->mm, addr, 1, 0, 1,
- &page, &vma) <= 0) {
+ &page, &tmp_vma) <= 0) {
DUMP_SEEK(PAGE_SIZE);
} else {
if (page == ZERO_PAGE(0)) {
}
} else {
void *kaddr;
- flush_cache_page(vma, addr,
+ flush_cache_page(tmp_vma, addr,
page_to_pfn(page));
kaddr = kmap(page);
if ((size += PAGE_SIZE) > limit ||
set_fs(fs);
cleanup:
- kfree(elf);
free_note_info(&info);
+ kfree(elf);
+out:
return has_dumped;
}