Commit 074a1e11 authored by Paul Burton's avatar Paul Burton

MIPS: Bounds check virt_addr_valid

The virt_addr_valid() function is meant to return true iff
virt_to_page() will return a valid struct page reference. This is true
iff the address provided is found within the unmapped address range
between PAGE_OFFSET & MAP_BASE, but we don't currently check for that
condition. Instead we simply mask the address to obtain what will be a
physical address if the virtual address is indeed in the desired range,
shift it to form a PFN & then call pfn_valid(). This can incorrectly
return true if called with a virtual address which, after masking,
happens to form a physical address corresponding to a valid PFN.

For example we may vmalloc an address in the kernel mapped region
starting a MAP_BASE & obtain the virtual address:

  addr = 0xc000000000002000

When masked by virt_to_phys(), which uses __pa() & in turn CPHYSADDR(),
we obtain the following (bogus) physical address:

  addr = 0x2000

In a common system with PHYS_OFFSET=0 this will correspond to a valid
struct page which should really be accessed by virtual address
PAGE_OFFSET+0x2000, causing virt_addr_valid() to incorrectly return 1
indicating that the original address corresponds to a struct page.

This is equivalent to the ARM64 change made in commit ca219452
("arm64: Correctly bounds check virt_addr_valid").

This fixes fallout when hardened usercopy is enabled caused by the
related commit 517e1fbe ("mm/usercopy: Drop extra
is_vmalloc_or_module() check") which removed a check for the vmalloc
range that was present from the introduction of the hardened usercopy
feature.
Signed-off-by: default avatarPaul Burton <paul.burton@mips.com>
References: ca219452 ("arm64: Correctly bounds check virt_addr_valid")
References: 517e1fbe ("mm/usercopy: Drop extra is_vmalloc_or_module() check")
Reported-by: default avatarJulien Cristau <jcristau@debian.org>
Reviewed-by: default avatarPhilippe Mathieu-Daudé <f4bug@amsat.org>
Tested-by: default avatarYunQiang Su <ysu@wavecomp.com>
URL: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=929366
Cc: stable@vger.kernel.org # v4.12+
Cc: linux-mips@vger.kernel.org
Cc: Yunqiang Su <ysu@wavecomp.com>
parent c5eac1f5
...@@ -203,6 +203,11 @@ unsigned long arch_randomize_brk(struct mm_struct *mm) ...@@ -203,6 +203,11 @@ unsigned long arch_randomize_brk(struct mm_struct *mm)
int __virt_addr_valid(const volatile void *kaddr) int __virt_addr_valid(const volatile void *kaddr)
{ {
unsigned long vaddr = (unsigned long)vaddr;
if ((vaddr < PAGE_OFFSET) || (vaddr >= MAP_BASE))
return 0;
return pfn_valid(PFN_DOWN(virt_to_phys(kaddr))); return pfn_valid(PFN_DOWN(virt_to_phys(kaddr)));
} }
EXPORT_SYMBOL_GPL(__virt_addr_valid); EXPORT_SYMBOL_GPL(__virt_addr_valid);
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