From 1d54cf2b973a6265789b382b7d305771321b9b57 Mon Sep 17 00:00:00 2001 From: "sukadev@linux.vnet.ibm.com" Date: Tue, 30 Aug 2011 09:19:17 +0000 Subject: powerpc: Implement CONFIG_STRICT_DEVMEM As described in the help text in the patch, this token restricts general access to /dev/mem as a way of increasing the security. Specifically, access to exclusive IOMEM and kernel RAM is denied unless CONFIG_STRICT_DEVMEM is set to 'n'. Implement the 'devmem_is_allowed()' interface for Powerpc. It will be called from range_is_allowed() when userpsace attempts to access /dev/mem. This patch is based on an earlier patch from Steve Best and with input from Paul Mackerras and Scott Wood. [BenH] Fixed a typo or two and removed the generic change which should be submitted as a separate patch Signed-off-by: Sukadev Bhattiprolu Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/mm/mem.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'arch/powerpc/mm/mem.c') diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index 2dd6bdd31fe1..22563b9664c3 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -585,3 +585,21 @@ static int add_system_ram_resources(void) return 0; } subsys_initcall(add_system_ram_resources); + +#ifdef CONFIG_STRICT_DEVMEM +/* + * devmem_is_allowed(): check to see if /dev/mem access to a certain address + * is valid. The argument is a physical page number. + * + * Access has to be given to non-kernel-ram areas as well, these contain the + * PCI mmio resources as well as potential bios/acpi data regions. + */ +int devmem_is_allowed(unsigned long pfn) +{ + if (iomem_is_exclusive(pfn << PAGE_SHIFT)) + return 0; + if (!page_is_ram(pfn)) + return 1; + return 0; +} +#endif /* CONFIG_STRICT_DEVMEM */ -- cgit v1.2.3 From d93e4d7d72037d8c9405e8d404ecb2ee162adc25 Mon Sep 17 00:00:00 2001 From: Becky Bruce Date: Mon, 28 Nov 2011 14:43:33 +0000 Subject: powerpc/book3e: Change hugetlb preload to take vma argument This avoids an extra find_vma() and is less error-prone. Signed-off-by: Becky Bruce Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/hugetlb.h | 3 ++- arch/powerpc/mm/hugetlbpage-book3e.c | 8 ++++++-- arch/powerpc/mm/mem.c | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) (limited to 'arch/powerpc/mm/mem.c') diff --git a/arch/powerpc/include/asm/hugetlb.h b/arch/powerpc/include/asm/hugetlb.h index 555044c310b2..863f49d5ea35 100644 --- a/arch/powerpc/include/asm/hugetlb.h +++ b/arch/powerpc/include/asm/hugetlb.h @@ -52,7 +52,8 @@ static inline int is_hugepage_only_range(struct mm_struct *mm, } #endif -void book3e_hugetlb_preload(struct mm_struct *mm, unsigned long ea, pte_t pte); +void book3e_hugetlb_preload(struct vm_area_struct *vma, unsigned long ea, + pte_t pte); void flush_hugetlb_page(struct vm_area_struct *vma, unsigned long vmaddr); void hugetlb_free_pgd_range(struct mmu_gather *tlb, unsigned long addr, diff --git a/arch/powerpc/mm/hugetlbpage-book3e.c b/arch/powerpc/mm/hugetlbpage-book3e.c index 4d6d849a3e54..3bc700655fc8 100644 --- a/arch/powerpc/mm/hugetlbpage-book3e.c +++ b/arch/powerpc/mm/hugetlbpage-book3e.c @@ -37,12 +37,14 @@ static inline int book3e_tlb_exists(unsigned long ea, unsigned long pid) return found; } -void book3e_hugetlb_preload(struct mm_struct *mm, unsigned long ea, pte_t pte) +void book3e_hugetlb_preload(struct vm_area_struct *vma, unsigned long ea, + pte_t pte) { unsigned long mas1, mas2; u64 mas7_3; unsigned long psize, tsize, shift; unsigned long flags; + struct mm_struct *mm; #ifdef CONFIG_PPC_FSL_BOOK3E int index, ncams; @@ -51,12 +53,14 @@ void book3e_hugetlb_preload(struct mm_struct *mm, unsigned long ea, pte_t pte) if (unlikely(is_kernel_addr(ea))) return; + mm = vma->vm_mm; + #ifdef CONFIG_PPC_MM_SLICES psize = get_slice_psize(mm, ea); tsize = mmu_get_tsize(psize); shift = mmu_psize_defs[psize].shift; #else - psize = vma_mmu_pagesize(find_vma(mm, ea)); + psize = vma_mmu_pagesize(vma); shift = __ilog2(psize); tsize = shift - 10; #endif diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index 22563b9664c3..83d819f30864 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -553,7 +553,7 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, #if (defined(CONFIG_PPC_BOOK3E_64) || defined(CONFIG_PPC_FSL_BOOK3E)) \ && defined(CONFIG_HUGETLB_PAGE) if (is_vm_hugetlb_page(vma)) - book3e_hugetlb_preload(vma->vm_mm, address, *ptep); + book3e_hugetlb_preload(vma, address, *ptep); #endif } -- cgit v1.2.3 From 8a3e3d31d13ece3003e8f750178a7db02c5cd123 Mon Sep 17 00:00:00 2001 From: "sukadev@linux.vnet.ibm.com" Date: Fri, 2 Dec 2011 12:26:23 +0000 Subject: powerpc: Punch a hole in /dev/mem for librtas With CONFIG_STRICT_DEVMEM=y, user space cannot read any part of /dev/mem. Since this breaks librtas, punch a hole in /dev/mem to allow access to the rmo_buffer that librtas needs. Anton Blanchard reported the problem and helped with the fix. A quick test for this patch: # cat /proc/rtas/rmo_buffer 000000000f190000 10000 # python -c "print 0x000000000f190000 / 0x10000" 3865 # dd if=/dev/mem of=/tmp/foo count=1 bs=64k skip=3865 1+0 records in 1+0 records out 65536 bytes (66 kB) copied, 0.000205235 s, 319 MB/s # dd if=/dev/mem of=/tmp/foo dd: reading `/dev/mem': Operation not permitted 0+0 records in 0+0 records out 0 bytes (0 B) copied, 0.00022519 s, 0.0 kB/s Signed-off-by: Sukadev Bhattiprolu Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/rtas.h | 12 ++++++++++++ arch/powerpc/mm/mem.c | 3 +++ 2 files changed, 15 insertions(+) (limited to 'arch/powerpc/mm/mem.c') diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h index 1646b76bd3d2..01c143bb77ae 100644 --- a/arch/powerpc/include/asm/rtas.h +++ b/arch/powerpc/include/asm/rtas.h @@ -313,5 +313,17 @@ static inline u32 rtas_config_addr(int busno, int devfn, int reg) extern void __cpuinit rtas_give_timebase(void); extern void __cpuinit rtas_take_timebase(void); +#ifdef CONFIG_PPC_RTAS +static inline int page_is_rtas_user_buf(unsigned long pfn) +{ + unsigned long paddr = (pfn << PAGE_SHIFT); + if (paddr >= rtas_rmo_buf && paddr < (rtas_rmo_buf + RTAS_RMOBUF_MAX)) + return 1; + return 0; +} +#else +static inline int page_is_rtas_user_buf(unsigned long pfn) { return 0;} +#endif + #endif /* __KERNEL__ */ #endif /* _POWERPC_RTAS_H */ diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index 83d819f30864..395f42d5f785 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -51,6 +51,7 @@ #include #include #include +#include #include "mmu_decl.h" @@ -600,6 +601,8 @@ int devmem_is_allowed(unsigned long pfn) return 0; if (!page_is_ram(pfn)) return 1; + if (page_is_rtas_user_buf(pfn)) + return 1; return 0; } #endif /* CONFIG_STRICT_DEVMEM */ -- cgit v1.2.3 From 1d7cfe18ec2eb2d0480a9b29465af66b61291202 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 8 Dec 2011 10:22:08 -0800 Subject: powerpc: Use HAVE_MEMBLOCK_NODE_MAP powerpc doesn't access early_node_map[] directly and enabling HAVE_MEMBLOCK_NODE_MAP is trivial - replacing add_active_range() calls with memblock_set_node() and selecting HAVE_MEMBLOCK_NODE_MAP is enough. Signed-off-by: Tejun Heo Cc: Benjamin Herrenschmidt Cc: Yinghai Lu --- arch/powerpc/Kconfig | 1 + arch/powerpc/mm/mem.c | 2 +- arch/powerpc/mm/numa.c | 10 ++++------ 3 files changed, 6 insertions(+), 7 deletions(-) (limited to 'arch/powerpc/mm/mem.c') diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 951e18f5335b..8516477c4dc5 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -117,6 +117,7 @@ config PPC select HAVE_KRETPROBES select HAVE_ARCH_TRACEHOOK select HAVE_MEMBLOCK + select HAVE_MEMBLOCK_NODE_MAP select HAVE_DMA_ATTRS select HAVE_DMA_API_DEBUG select USE_GENERIC_SMP_HELPERS if SMP diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index 2dd6bdd31fe1..8e2eb6611b0b 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -199,7 +199,7 @@ void __init do_init_bootmem(void) unsigned long start_pfn, end_pfn; start_pfn = memblock_region_memory_base_pfn(reg); end_pfn = memblock_region_memory_end_pfn(reg); - add_active_range(0, start_pfn, end_pfn); + memblock_set_node(0, (phys_addr_t)ULLONG_MAX, 0); } /* Add all physical memory to the bootmem map, mark each area diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index 261adbd3b55a..e6eea0ac80c8 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -690,9 +690,7 @@ static void __init parse_drconf_memory(struct device_node *memory) node_set_online(nid); sz = numa_enforce_memory_limit(base, size); if (sz) - add_active_range(nid, base >> PAGE_SHIFT, - (base >> PAGE_SHIFT) - + (sz >> PAGE_SHIFT)); + memblock_set_node(base, sz, nid); } while (--ranges); } } @@ -782,8 +780,7 @@ new_range: continue; } - add_active_range(nid, start >> PAGE_SHIFT, - (start >> PAGE_SHIFT) + (size >> PAGE_SHIFT)); + memblock_set_node(start, size, nid); if (--ranges) goto new_range; @@ -819,7 +816,8 @@ static void __init setup_nonnuma(void) end_pfn = memblock_region_memory_end_pfn(reg); fake_numa_create_new_node(end_pfn, &nid); - add_active_range(nid, start_pfn, end_pfn); + memblock_set_node(PFN_PHYS(start_pfn), + PFN_PHYS(end_pfn - start_pfn), nid); node_set_online(nid); } } -- cgit v1.2.3