[PATCH] read_zero_pagealigned() locking fix
Ramiro Voicu hits the BUG_ON(!pte_none(*pte)) in zeromap_pte_range: kernel bugzilla 7645. Right: read_zero_pagealigned uses down_read of mmap_sem, but another thread's racing read of /dev/zero, or a normal fault, can easily set that pte again, in between zap_page_range and zeromap_page_range getting there. It's been wrong ever since 2.4.3. The simple fix is to use down_write instead, but that would serialize reads of /dev/zero more than at present: perhaps some app would be badly affected. So instead let zeromap_page_range return the error instead of BUG_ON, and read_zero_pagealigned break to the slower clear_user loop in that case - there's no need to optimize for it. Use -EEXIST for when a pte is found: BUG_ON in mmap_zero (the other user of zeromap_page_range), though it really isn't interesting there. And since mmap_zero wants -EAGAIN for out-of-memory, the zeromaps better return that than -ENOMEM. Signed-off-by: Hugh Dickins <hugh@veritas.com> Cc: Ramiro Voicu: <Ramiro.Voicu@cern.ch> Cc: <stable@kernel.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
committed by
Linus Torvalds
parent
347a00fb4a
commit
5fcf7bb73f
@@ -646,7 +646,8 @@ static inline size_t read_zero_pagealigned(char __user * buf, size_t size)
|
||||
count = size;
|
||||
|
||||
zap_page_range(vma, addr, count, NULL);
|
||||
zeromap_page_range(vma, addr, count, PAGE_COPY);
|
||||
if (zeromap_page_range(vma, addr, count, PAGE_COPY))
|
||||
break;
|
||||
|
||||
size -= count;
|
||||
buf += count;
|
||||
@@ -713,11 +714,14 @@ out:
|
||||
|
||||
static int mmap_zero(struct file * file, struct vm_area_struct * vma)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (vma->vm_flags & VM_SHARED)
|
||||
return shmem_zero_setup(vma);
|
||||
if (zeromap_page_range(vma, vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot))
|
||||
return -EAGAIN;
|
||||
return 0;
|
||||
err = zeromap_page_range(vma, vma->vm_start,
|
||||
vma->vm_end - vma->vm_start, vma->vm_page_prot);
|
||||
BUG_ON(err == -EEXIST);
|
||||
return err;
|
||||
}
|
||||
#else /* CONFIG_MMU */
|
||||
static ssize_t read_zero(struct file * file, char * buf,
|
||||
|
Reference in New Issue
Block a user