mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
arm64: mm: validate /dev/mem mmap ranges without overflow
An arm64 syzkaller reproducer creates a FUSE character device with
major:minor 1:1, so opening it uses the /dev/mem file operations. It
maps one page from offset 0xfffffffffffff000 at user address zero.
The next openat() with a NULL pathname triggers a synchronous external
abort (SEA, ESR 0x96000010) in strncpy_from_user() via do_getname(),
panicking the kernel.
valid_mmap_phys_addr_range() checks the exclusive end by adding the
mapping size to the starting address. For this offset, the sum wraps
to zero and passes the PHYS_MASK test, allowing an out-of-range PFN to
reach remap_pfn_range(). The inclusive-end overflow check in
mmap_mem_prepare() does not catch it because the end is ULONG_MAX.
Reject starting PFNs outside PHYS_MASK and compare the inclusive length
against the remaining physical range without overflowing. This also
allows mappings that end exactly at PHYS_MASK, which the old check
incorrectly rejects.
Fixes: 1d18c47c73 ("arm64: MMU fault handling and page table management")
Cc: stable@vger.kernel.org
Signed-off-by: Zhao Gongyi <zhaogongyi@bytedance.com>
[catalin.marinas@arm.com: changed the check to look more like __access_ok()]
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
This commit is contained in:
parent
beeec04046
commit
b0958b1397
|
|
@ -61,7 +61,9 @@ int valid_phys_addr_range(phys_addr_t addr, size_t size)
|
|||
*/
|
||||
int valid_mmap_phys_addr_range(unsigned long pfn, size_t size)
|
||||
{
|
||||
return !(((pfn << PAGE_SHIFT) + size) & ~PHYS_MASK);
|
||||
const phys_addr_t limit = PHYS_MASK + 1;
|
||||
|
||||
return size <= limit && pfn <= (limit - size) >> PAGE_SHIFT;
|
||||
}
|
||||
|
||||
static int __init adjust_protection_map(void)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user