11d18c47cSCatalin Marinas /* 21d18c47cSCatalin Marinas * Based on arch/arm/mm/mmap.c 31d18c47cSCatalin Marinas * 41d18c47cSCatalin Marinas * Copyright (C) 2012 ARM Ltd. 51d18c47cSCatalin Marinas * 61d18c47cSCatalin Marinas * This program is free software; you can redistribute it and/or modify 71d18c47cSCatalin Marinas * it under the terms of the GNU General Public License version 2 as 81d18c47cSCatalin Marinas * published by the Free Software Foundation. 91d18c47cSCatalin Marinas * 101d18c47cSCatalin Marinas * This program is distributed in the hope that it will be useful, 111d18c47cSCatalin Marinas * but WITHOUT ANY WARRANTY; without even the implied warranty of 121d18c47cSCatalin Marinas * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 131d18c47cSCatalin Marinas * GNU General Public License for more details. 141d18c47cSCatalin Marinas * 151d18c47cSCatalin Marinas * You should have received a copy of the GNU General Public License 161d18c47cSCatalin Marinas * along with this program. If not, see <http://www.gnu.org/licenses/>. 171d18c47cSCatalin Marinas */ 181d18c47cSCatalin Marinas 191d18c47cSCatalin Marinas #include <linux/elf.h> 201d18c47cSCatalin Marinas #include <linux/fs.h> 21*1151f838SArd Biesheuvel #include <linux/memblock.h> 221d18c47cSCatalin Marinas #include <linux/mm.h> 231d18c47cSCatalin Marinas #include <linux/mman.h> 241d18c47cSCatalin Marinas #include <linux/export.h> 251d18c47cSCatalin Marinas #include <linux/shm.h> 263f07c014SIngo Molnar #include <linux/sched/signal.h> 2701042607SIngo Molnar #include <linux/sched/mm.h> 281d18c47cSCatalin Marinas #include <linux/io.h> 291d18c47cSCatalin Marinas #include <linux/personality.h> 301d18c47cSCatalin Marinas #include <linux/random.h> 311d18c47cSCatalin Marinas 321d18c47cSCatalin Marinas #include <asm/cputype.h> 331d18c47cSCatalin Marinas 341d18c47cSCatalin Marinas /* 351d18c47cSCatalin Marinas * Leave enough space between the mmap area and the stack to honour ulimit in 361d18c47cSCatalin Marinas * the face of randomisation. 371d18c47cSCatalin Marinas */ 381d18c47cSCatalin Marinas #define MIN_GAP (SZ_128M + ((STACK_RND_MASK << PAGE_SHIFT) + 1)) 391d18c47cSCatalin Marinas #define MAX_GAP (STACK_TOP/6*5) 401d18c47cSCatalin Marinas 411d18c47cSCatalin Marinas static int mmap_is_legacy(void) 421d18c47cSCatalin Marinas { 431d18c47cSCatalin Marinas if (current->personality & ADDR_COMPAT_LAYOUT) 441d18c47cSCatalin Marinas return 1; 451d18c47cSCatalin Marinas 461d18c47cSCatalin Marinas if (rlimit(RLIMIT_STACK) == RLIM_INFINITY) 471d18c47cSCatalin Marinas return 1; 481d18c47cSCatalin Marinas 491d18c47cSCatalin Marinas return sysctl_legacy_va_layout; 501d18c47cSCatalin Marinas } 511d18c47cSCatalin Marinas 522b68f6caSKees Cook unsigned long arch_mmap_rnd(void) 531d18c47cSCatalin Marinas { 54dd04cff1SKees Cook unsigned long rnd; 551d18c47cSCatalin Marinas 568f0d3aa9SDaniel Cashman #ifdef CONFIG_COMPAT 578f0d3aa9SDaniel Cashman if (test_thread_flag(TIF_32BIT)) 585ef11c35SDaniel Cashman rnd = get_random_long() & ((1UL << mmap_rnd_compat_bits) - 1); 598f0d3aa9SDaniel Cashman else 608f0d3aa9SDaniel Cashman #endif 615ef11c35SDaniel Cashman rnd = get_random_long() & ((1UL << mmap_rnd_bits) - 1); 62d6c763afSYann Droneaud return rnd << PAGE_SHIFT; 631d18c47cSCatalin Marinas } 641d18c47cSCatalin Marinas 65dd04cff1SKees Cook static unsigned long mmap_base(unsigned long rnd) 661d18c47cSCatalin Marinas { 671d18c47cSCatalin Marinas unsigned long gap = rlimit(RLIMIT_STACK); 681d18c47cSCatalin Marinas 691d18c47cSCatalin Marinas if (gap < MIN_GAP) 701d18c47cSCatalin Marinas gap = MIN_GAP; 711d18c47cSCatalin Marinas else if (gap > MAX_GAP) 721d18c47cSCatalin Marinas gap = MAX_GAP; 731d18c47cSCatalin Marinas 74dd04cff1SKees Cook return PAGE_ALIGN(STACK_TOP - gap - rnd); 751d18c47cSCatalin Marinas } 761d18c47cSCatalin Marinas 771d18c47cSCatalin Marinas /* 781d18c47cSCatalin Marinas * This function, called very early during the creation of a new process VM 791d18c47cSCatalin Marinas * image, sets up which VM layout function to use: 801d18c47cSCatalin Marinas */ 811d18c47cSCatalin Marinas void arch_pick_mmap_layout(struct mm_struct *mm) 821d18c47cSCatalin Marinas { 83dd04cff1SKees Cook unsigned long random_factor = 0UL; 84dd04cff1SKees Cook 85dd04cff1SKees Cook if (current->flags & PF_RANDOMIZE) 862b68f6caSKees Cook random_factor = arch_mmap_rnd(); 87dd04cff1SKees Cook 881d18c47cSCatalin Marinas /* 891d18c47cSCatalin Marinas * Fall back to the standard layout if the personality bit is set, or 901d18c47cSCatalin Marinas * if the expected stack growth is unlimited: 911d18c47cSCatalin Marinas */ 921d18c47cSCatalin Marinas if (mmap_is_legacy()) { 93dd04cff1SKees Cook mm->mmap_base = TASK_UNMAPPED_BASE + random_factor; 941d18c47cSCatalin Marinas mm->get_unmapped_area = arch_get_unmapped_area; 951d18c47cSCatalin Marinas } else { 96dd04cff1SKees Cook mm->mmap_base = mmap_base(random_factor); 971d18c47cSCatalin Marinas mm->get_unmapped_area = arch_get_unmapped_area_topdown; 981d18c47cSCatalin Marinas } 991d18c47cSCatalin Marinas } 1001d18c47cSCatalin Marinas 1011d18c47cSCatalin Marinas /* 1021d18c47cSCatalin Marinas * You really shouldn't be using read() or write() on /dev/mem. This might go 1031d18c47cSCatalin Marinas * away in the future. 1041d18c47cSCatalin Marinas */ 105097cbd8dSMin-Hua Chen int valid_phys_addr_range(phys_addr_t addr, size_t size) 1061d18c47cSCatalin Marinas { 107*1151f838SArd Biesheuvel /* 108*1151f838SArd Biesheuvel * Check whether addr is covered by a memory region without the 109*1151f838SArd Biesheuvel * MEMBLOCK_NOMAP attribute, and whether that region covers the 110*1151f838SArd Biesheuvel * entire range. In theory, this could lead to false negatives 111*1151f838SArd Biesheuvel * if the range is covered by distinct but adjacent memory regions 112*1151f838SArd Biesheuvel * that only differ in other attributes. However, few of such 113*1151f838SArd Biesheuvel * attributes have been defined, and it is debatable whether it 114*1151f838SArd Biesheuvel * follows that /dev/mem read() calls should be able traverse 115*1151f838SArd Biesheuvel * such boundaries. 116*1151f838SArd Biesheuvel */ 117*1151f838SArd Biesheuvel return memblock_is_region_memory(addr, size) && 118*1151f838SArd Biesheuvel memblock_is_map_memory(addr); 1191d18c47cSCatalin Marinas } 1201d18c47cSCatalin Marinas 1211d18c47cSCatalin Marinas /* 1221d18c47cSCatalin Marinas * Do not allow /dev/mem mappings beyond the supported physical range. 1231d18c47cSCatalin Marinas */ 1241d18c47cSCatalin Marinas int valid_mmap_phys_addr_range(unsigned long pfn, size_t size) 1251d18c47cSCatalin Marinas { 1261d18c47cSCatalin Marinas return !(((pfn << PAGE_SHIFT) + size) & ~PHYS_MASK); 1271d18c47cSCatalin Marinas } 1281d18c47cSCatalin Marinas 1291d18c47cSCatalin Marinas #ifdef CONFIG_STRICT_DEVMEM 1301d18c47cSCatalin Marinas 1311d18c47cSCatalin Marinas #include <linux/ioport.h> 1321d18c47cSCatalin Marinas 1331d18c47cSCatalin Marinas /* 1341d18c47cSCatalin Marinas * devmem_is_allowed() checks to see if /dev/mem access to a certain address 1351d18c47cSCatalin Marinas * is valid. The argument is a physical page number. We mimic x86 here by 1361d18c47cSCatalin Marinas * disallowing access to system RAM as well as device-exclusive MMIO regions. 1371d18c47cSCatalin Marinas * This effectively disable read()/write() on /dev/mem. 1381d18c47cSCatalin Marinas */ 1391d18c47cSCatalin Marinas int devmem_is_allowed(unsigned long pfn) 1401d18c47cSCatalin Marinas { 1411d18c47cSCatalin Marinas if (iomem_is_exclusive(pfn << PAGE_SHIFT)) 1421d18c47cSCatalin Marinas return 0; 1431d18c47cSCatalin Marinas if (!page_is_ram(pfn)) 1441d18c47cSCatalin Marinas return 1; 1451d18c47cSCatalin Marinas return 0; 1461d18c47cSCatalin Marinas } 1471d18c47cSCatalin Marinas 1481d18c47cSCatalin Marinas #endif 149