Commit 41d5e5d7 authored by Nick Piggin's avatar Nick Piggin Committed by Tony Luck

[IA64] permon use-after-free fix

Perfmon associates vmalloc()ed memory with a file descriptor, and installs
a vma mapping that memory.  Unfortunately, the vm_file field is not filled
in, so processes with mappings to that memory do not prevent the file from
being closed and the memory freed.  This results in use-after-free bugs and
multiple freeing of pages, etc.

I saw this bug on an Altix on SLES9.  Haven't reproduced upstream but it
looks like the same issue is there.
Signed-off-by: default avatarNick Piggin <npiggin@suse.de>
Cc: Stephane Eranian <eranian@hpl.hp.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarTony Luck <tony.luck@intel.com>
parent 50157b09
...@@ -2299,7 +2299,7 @@ pfm_remap_buffer(struct vm_area_struct *vma, unsigned long buf, unsigned long ad ...@@ -2299,7 +2299,7 @@ pfm_remap_buffer(struct vm_area_struct *vma, unsigned long buf, unsigned long ad
* allocate a sampling buffer and remaps it into the user address space of the task * allocate a sampling buffer and remaps it into the user address space of the task
*/ */
static int static int
pfm_smpl_buffer_alloc(struct task_struct *task, pfm_context_t *ctx, unsigned long rsize, void **user_vaddr) pfm_smpl_buffer_alloc(struct task_struct *task, struct file *filp, pfm_context_t *ctx, unsigned long rsize, void **user_vaddr)
{ {
struct mm_struct *mm = task->mm; struct mm_struct *mm = task->mm;
struct vm_area_struct *vma = NULL; struct vm_area_struct *vma = NULL;
...@@ -2349,6 +2349,7 @@ pfm_smpl_buffer_alloc(struct task_struct *task, pfm_context_t *ctx, unsigned lon ...@@ -2349,6 +2349,7 @@ pfm_smpl_buffer_alloc(struct task_struct *task, pfm_context_t *ctx, unsigned lon
* partially initialize the vma for the sampling buffer * partially initialize the vma for the sampling buffer
*/ */
vma->vm_mm = mm; vma->vm_mm = mm;
vma->vm_file = filp;
vma->vm_flags = VM_READ| VM_MAYREAD |VM_RESERVED; vma->vm_flags = VM_READ| VM_MAYREAD |VM_RESERVED;
vma->vm_page_prot = PAGE_READONLY; /* XXX may need to change */ vma->vm_page_prot = PAGE_READONLY; /* XXX may need to change */
...@@ -2387,6 +2388,8 @@ pfm_smpl_buffer_alloc(struct task_struct *task, pfm_context_t *ctx, unsigned lon ...@@ -2387,6 +2388,8 @@ pfm_smpl_buffer_alloc(struct task_struct *task, pfm_context_t *ctx, unsigned lon
goto error; goto error;
} }
get_file(filp);
/* /*
* now insert the vma in the vm list for the process, must be * now insert the vma in the vm list for the process, must be
* done with mmap lock held * done with mmap lock held
...@@ -2464,7 +2467,7 @@ pfarg_is_sane(struct task_struct *task, pfarg_context_t *pfx) ...@@ -2464,7 +2467,7 @@ pfarg_is_sane(struct task_struct *task, pfarg_context_t *pfx)
} }
static int static int
pfm_setup_buffer_fmt(struct task_struct *task, pfm_context_t *ctx, unsigned int ctx_flags, pfm_setup_buffer_fmt(struct task_struct *task, struct file *filp, pfm_context_t *ctx, unsigned int ctx_flags,
unsigned int cpu, pfarg_context_t *arg) unsigned int cpu, pfarg_context_t *arg)
{ {
pfm_buffer_fmt_t *fmt = NULL; pfm_buffer_fmt_t *fmt = NULL;
...@@ -2505,7 +2508,7 @@ pfm_setup_buffer_fmt(struct task_struct *task, pfm_context_t *ctx, unsigned int ...@@ -2505,7 +2508,7 @@ pfm_setup_buffer_fmt(struct task_struct *task, pfm_context_t *ctx, unsigned int
/* /*
* buffer is always remapped into the caller's address space * buffer is always remapped into the caller's address space
*/ */
ret = pfm_smpl_buffer_alloc(current, ctx, size, &uaddr); ret = pfm_smpl_buffer_alloc(current, filp, ctx, size, &uaddr);
if (ret) goto error; if (ret) goto error;
/* keep track of user address of buffer */ /* keep track of user address of buffer */
...@@ -2716,7 +2719,7 @@ pfm_context_create(pfm_context_t *ctx, void *arg, int count, struct pt_regs *reg ...@@ -2716,7 +2719,7 @@ pfm_context_create(pfm_context_t *ctx, void *arg, int count, struct pt_regs *reg
* does the user want to sample? * does the user want to sample?
*/ */
if (pfm_uuid_cmp(req->ctx_smpl_buf_id, pfm_null_uuid)) { if (pfm_uuid_cmp(req->ctx_smpl_buf_id, pfm_null_uuid)) {
ret = pfm_setup_buffer_fmt(current, ctx, ctx_flags, 0, req); ret = pfm_setup_buffer_fmt(current, filp, ctx, ctx_flags, 0, req);
if (ret) goto buffer_error; if (ret) goto buffer_error;
} }
......
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