diff options
author | Nick Piggin <npiggin@suse.de> | 2007-03-06 05:34:25 -0500 |
---|---|---|
committer | Tony Luck <tony.luck@intel.com> | 2007-03-06 17:49:52 -0500 |
commit | 41d5e5d73ecef4ef56b7b4cde962929a712689b4 (patch) | |
tree | 51cb9289609c639d86a768ff92340291a4d1b452 /arch | |
parent | 50157b09b33c2ec3637d3b317b06a7235c57c7f2 (diff) |
[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: Nick Piggin <npiggin@suse.de>
Cc: Stephane Eranian <eranian@hpl.hp.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Tony Luck <tony.luck@intel.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/ia64/kernel/perfmon.c | 11 |
1 files changed, 7 insertions, 4 deletions
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c index 9ddf896a137a..abc7ad035886 100644 --- a/arch/ia64/kernel/perfmon.c +++ b/arch/ia64/kernel/perfmon.c | |||
@@ -2299,7 +2299,7 @@ pfm_remap_buffer(struct vm_area_struct *vma, unsigned long buf, unsigned long ad | |||
2299 | * allocate a sampling buffer and remaps it into the user address space of the task | 2299 | * allocate a sampling buffer and remaps it into the user address space of the task |
2300 | */ | 2300 | */ |
2301 | static int | 2301 | static int |
2302 | pfm_smpl_buffer_alloc(struct task_struct *task, pfm_context_t *ctx, unsigned long rsize, void **user_vaddr) | 2302 | pfm_smpl_buffer_alloc(struct task_struct *task, struct file *filp, pfm_context_t *ctx, unsigned long rsize, void **user_vaddr) |
2303 | { | 2303 | { |
2304 | struct mm_struct *mm = task->mm; | 2304 | struct mm_struct *mm = task->mm; |
2305 | struct vm_area_struct *vma = NULL; | 2305 | 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 | * partially initialize the vma for the sampling buffer | 2349 | * partially initialize the vma for the sampling buffer |
2350 | */ | 2350 | */ |
2351 | vma->vm_mm = mm; | 2351 | vma->vm_mm = mm; |
2352 | vma->vm_file = filp; | ||
2352 | vma->vm_flags = VM_READ| VM_MAYREAD |VM_RESERVED; | 2353 | vma->vm_flags = VM_READ| VM_MAYREAD |VM_RESERVED; |
2353 | vma->vm_page_prot = PAGE_READONLY; /* XXX may need to change */ | 2354 | vma->vm_page_prot = PAGE_READONLY; /* XXX may need to change */ |
2354 | 2355 | ||
@@ -2387,6 +2388,8 @@ pfm_smpl_buffer_alloc(struct task_struct *task, pfm_context_t *ctx, unsigned lon | |||
2387 | goto error; | 2388 | goto error; |
2388 | } | 2389 | } |
2389 | 2390 | ||
2391 | get_file(filp); | ||
2392 | |||
2390 | /* | 2393 | /* |
2391 | * now insert the vma in the vm list for the process, must be | 2394 | * now insert the vma in the vm list for the process, must be |
2392 | * done with mmap lock held | 2395 | * done with mmap lock held |
@@ -2464,7 +2467,7 @@ pfarg_is_sane(struct task_struct *task, pfarg_context_t *pfx) | |||
2464 | } | 2467 | } |
2465 | 2468 | ||
2466 | static int | 2469 | static int |
2467 | pfm_setup_buffer_fmt(struct task_struct *task, pfm_context_t *ctx, unsigned int ctx_flags, | 2470 | pfm_setup_buffer_fmt(struct task_struct *task, struct file *filp, pfm_context_t *ctx, unsigned int ctx_flags, |
2468 | unsigned int cpu, pfarg_context_t *arg) | 2471 | unsigned int cpu, pfarg_context_t *arg) |
2469 | { | 2472 | { |
2470 | pfm_buffer_fmt_t *fmt = NULL; | 2473 | 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 | /* | 2508 | /* |
2506 | * buffer is always remapped into the caller's address space | 2509 | * buffer is always remapped into the caller's address space |
2507 | */ | 2510 | */ |
2508 | ret = pfm_smpl_buffer_alloc(current, ctx, size, &uaddr); | 2511 | ret = pfm_smpl_buffer_alloc(current, filp, ctx, size, &uaddr); |
2509 | if (ret) goto error; | 2512 | if (ret) goto error; |
2510 | 2513 | ||
2511 | /* keep track of user address of buffer */ | 2514 | /* 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 | * does the user want to sample? | 2719 | * does the user want to sample? |
2717 | */ | 2720 | */ |
2718 | if (pfm_uuid_cmp(req->ctx_smpl_buf_id, pfm_null_uuid)) { | 2721 | if (pfm_uuid_cmp(req->ctx_smpl_buf_id, pfm_null_uuid)) { |
2719 | ret = pfm_setup_buffer_fmt(current, ctx, ctx_flags, 0, req); | 2722 | ret = pfm_setup_buffer_fmt(current, filp, ctx, ctx_flags, 0, req); |
2720 | if (ret) goto buffer_error; | 2723 | if (ret) goto buffer_error; |
2721 | } | 2724 | } |
2722 | 2725 | ||