Commit f1b519a3 authored by Andi Kleen's avatar Andi Kleen Committed by Linus Torvalds

[PATCH] x86_64: make in_gate_vma() safer

x86-64 in_gate_vma would take a read lock on the VMA when the passed
address was inside the 32bit vsyscall page.

This would be called by get_user_pages, which already holds the mmap_sem.

Unfortunately some callers of get_user_pages hold the mmap_sem for writing,
which could in theory cause a deadlock.

I think it can currently not happen because the only users who hold it for
write before calling gup() are coredump and AIO in the ring setup, and both
should not ever access the vsyscall page. 

But not taking the semaphore is safer and avoid this here.
Signed-off-by: default avatarAndi Kleen <ak@suse.de>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 0a6fd29e
......@@ -30,16 +30,20 @@ extern int sysctl_vsyscall32;
char *syscall32_page;
static int use_sysenter __initdata = -1;
/* RED-PEN: This knows too much about high level VM */
/* Alternative would be to generate a vma with appropriate backing options
and let it be handled by generic VM */
int map_syscall32(struct mm_struct *mm, unsigned long address)
/*
* Map the 32bit vsyscall page on demand.
*
* RED-PEN: This knows too much about high level VM.
*
* Alternative would be to generate a vma with appropriate backing options
* and let it be handled by generic VM.
*/
int __map_syscall32(struct mm_struct *mm, unsigned long address)
{
pte_t *pte;
pmd_t *pmd;
int err = 0;
down_read(&mm->mmap_sem);
spin_lock(&mm->page_table_lock);
pmd = pmd_alloc(mm, pgd_offset(mm, address), address);
if (pmd && (pte = pte_alloc_map(mm, pmd, address)) != NULL) {
......@@ -54,6 +58,14 @@ int map_syscall32(struct mm_struct *mm, unsigned long address)
} else
err = -ENOMEM;
spin_unlock(&mm->page_table_lock);
return err;
}
int map_syscall32(struct mm_struct *mm, unsigned long address)
{
int err;
down_read(&mm->mmap_sem);
err = __map_syscall32(mm, address);
up_read(&mm->mmap_sem);
return err;
}
......
......@@ -609,7 +609,7 @@ struct vm_area_struct *get_gate_vma(struct task_struct *tsk)
if (test_tsk_thread_flag(tsk, TIF_IA32)) {
/* lookup code assumes the pages are present. set them up
now */
if (map_syscall32(tsk->mm, 0xfffe000) < 0)
if (__map_syscall32(tsk->mm, 0xfffe000) < 0)
return NULL;
return &gate32_vma;
}
......
......@@ -70,6 +70,7 @@ extern void __show_regs(struct pt_regs * regs);
extern void show_regs(struct pt_regs * regs);
extern int map_syscall32(struct mm_struct *mm, unsigned long address);
extern int __map_syscall32(struct mm_struct *mm, unsigned long address);
extern char *syscall32_page;
extern void syscall32_cpu_init(void);
......
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