xref: /openbmc/linux/arch/arm64/mm/mmap.c (revision 1151f838cb626005f4d69bf675dacaaa5ea909d6)
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