Commit cbcfb20c authored by Aurelien Jarno's avatar Aurelien Jarno

[mips] Correctly bounds check virt_addr_valid (Closes: #929366)

parent 3b44df14
......@@ -20,6 +20,9 @@ linux (4.19.37-4) UNRELEASED; urgency=medium
* Bluetooth: hidp: fix buffer overflow (CVE-2019-11884)
[ Aurelien Jarno ]
* [mips] Correctly bounds check virt_addr_valid (Closes: #929366)
-- Ben Hutchings <> Sun, 19 May 2019 00:04:16 +0100
linux (4.19.37-3) unstable; urgency=medium
From: Paul Burton <>
Date: Tue, 28 May 2019 17:05:03 +0000
Subject: MIPS: Bounds check virt_addr_valid
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
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 ca219452c6b8
("arm64: Correctly bounds check virt_addr_valid").
This fixes fallout when hardened usercopy is enabled caused by the
related commit 517e1fbeb65f ("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
Signed-off-by: Paul Burton <>
References: ca219452c6b8 ("arm64: Correctly bounds check virt_addr_valid")
References: 517e1fbeb65f ("mm/usercopy: Drop extra is_vmalloc_or_module() check")
Reported-by: Julien Cristau <>
Reviewed-by: Philippe Mathieu-Daudé <>
Tested-by: YunQiang Su <>
Cc: # v4.12+
Cc: Yunqiang Su <>
arch/mips/mm/mmap.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/arch/mips/mm/mmap.c b/arch/mips/mm/mmap.c
index 2f616ebeb7e0..7755a1fad05a 100644
--- a/arch/mips/mm/mmap.c
+++ b/arch/mips/mm/mmap.c
@@ -203,6 +203,11 @@ unsigned long arch_randomize_brk(struct mm_struct *mm)
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)));
......@@ -82,6 +82,7 @@ bugfix/arm64/arm64-dts-allwinner-a64-Enable-A64-timer-workaround.patch
# Arch features
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