aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArjan van de Ven <arjan@linux.intel.com>2008-04-24 17:40:47 -0400
committerIngo Molnar <mingo@elte.hu>2008-04-24 17:40:47 -0400
commitae531c26c5c2a28ca1b35a75b39b3b256850f2c8 (patch)
treee4c2f3ec25bdb0e2e5f7f15f79a60c3175f03718
parent94bc891b00e40cbec375feb4568780af183fd7f4 (diff)
x86: introduce /dev/mem restrictions with a config option
This patch introduces a restriction on /dev/mem: Only non-memory can be read or written unless the newly introduced config option is set. The X server needs access to /dev/mem for the PCI space, but it doesn't need access to memory; both the file permissions and SELinux permissions of /dev/mem just make X effectively super-super powerful. With the exception of the BIOS area, there's just no valid app that uses /dev/mem on actual memory. Other popular users of /dev/mem are rootkits and the like. (note: mmap access of memory via /dev/mem was already not allowed since a really long time) People who want to use /dev/mem for kernel debugging can enable the config option. The restrictions of this patch have been in the Fedora and RHEL kernels for at least 4 years without any problems. Signed-off-by: Arjan van de Ven <arjan@linux.intel.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--arch/x86/Kconfig.debug12
-rw-r--r--arch/x86/mm/init_32.c19
-rw-r--r--arch/x86/mm/init_64.c20
-rw-r--r--drivers/char/mem.c28
-rw-r--r--include/asm-x86/page.h1
5 files changed, 80 insertions, 0 deletions
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index 610aaecc19f8..0c1890c41279 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -5,6 +5,18 @@ config TRACE_IRQFLAGS_SUPPORT
5 5
6source "lib/Kconfig.debug" 6source "lib/Kconfig.debug"
7 7
8config NONPROMISC_DEVMEM
9 bool "Disable promiscuous /dev/mem"
10 default y
11 help
12 The /dev/mem file by default only allows userspace access to PCI
13 space and the BIOS code and data regions. This is sufficient for
14 dosemu and X and all common users of /dev/mem. With this config
15 option, you allow userspace access to all of memory, including
16 kernel and userspace memory. Accidental access to this is
17 obviously disasterous, but specific access can be used by people
18 debugging the kernel.
19
8config EARLY_PRINTK 20config EARLY_PRINTK
9 bool "Early printk" if EMBEDDED 21 bool "Early printk" if EMBEDDED
10 default y 22 default y
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c
index 9ec62da85fd7..39852d539018 100644
--- a/arch/x86/mm/init_32.c
+++ b/arch/x86/mm/init_32.c
@@ -227,6 +227,25 @@ static inline int page_kills_ppro(unsigned long pagenr)
227 return 0; 227 return 0;
228} 228}
229 229
230/*
231 * devmem_is_allowed() checks to see if /dev/mem access to a certain address
232 * is valid. The argument is a physical page number.
233 *
234 *
235 * On x86, access has to be given to the first megabyte of ram because that area
236 * contains bios code and data regions used by X and dosemu and similar apps.
237 * Access has to be given to non-kernel-ram areas as well, these contain the PCI
238 * mmio resources as well as potential bios/acpi data regions.
239 */
240int devmem_is_allowed(unsigned long pagenr)
241{
242 if (pagenr <= 256)
243 return 1;
244 if (!page_is_ram(pagenr))
245 return 1;
246 return 0;
247}
248
230#ifdef CONFIG_HIGHMEM 249#ifdef CONFIG_HIGHMEM
231pte_t *kmap_pte; 250pte_t *kmap_pte;
232pgprot_t kmap_prot; 251pgprot_t kmap_prot;
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index 1ff7906a9a4d..49c274ee2fba 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -664,6 +664,26 @@ EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
664 664
665#endif /* CONFIG_MEMORY_HOTPLUG */ 665#endif /* CONFIG_MEMORY_HOTPLUG */
666 666
667/*
668 * devmem_is_allowed() checks to see if /dev/mem access to a certain address
669 * is valid. The argument is a physical page number.
670 *
671 *
672 * On x86, access has to be given to the first megabyte of ram because that area
673 * contains bios code and data regions used by X and dosemu and similar apps.
674 * Access has to be given to non-kernel-ram areas as well, these contain the PCI
675 * mmio resources as well as potential bios/acpi data regions.
676 */
677int devmem_is_allowed(unsigned long pagenr)
678{
679 if (pagenr <= 256)
680 return 1;
681 if (!page_is_ram(pagenr))
682 return 1;
683 return 0;
684}
685
686
667static struct kcore_list kcore_mem, kcore_vmalloc, kcore_kernel, 687static struct kcore_list kcore_mem, kcore_vmalloc, kcore_kernel,
668 kcore_modules, kcore_vsyscall; 688 kcore_modules, kcore_vsyscall;
669 689
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 20070b7c573d..dcf6e31970a1 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -108,6 +108,30 @@ static inline int valid_mmap_phys_addr_range(unsigned long pfn, size_t size)
108} 108}
109#endif 109#endif
110 110
111#ifdef CONFIG_NONPROMISC_DEVMEM
112static inline int range_is_allowed(unsigned long from, unsigned long to)
113{
114 unsigned long cursor;
115
116 cursor = from >> PAGE_SHIFT;
117 while ((cursor << PAGE_SHIFT) < to) {
118 if (!devmem_is_allowed(cursor)) {
119 printk(KERN_INFO "Program %s tried to read /dev/mem "
120 "between %lx->%lx.\n",
121 current->comm, from, to);
122 return 0;
123 }
124 cursor++;
125 }
126 return 1;
127}
128#else
129static inline int range_is_allowed(unsigned long from, unsigned long to)
130{
131 return 1;
132}
133#endif
134
111/* 135/*
112 * This funcion reads the *physical* memory. The f_pos points directly to the 136 * This funcion reads the *physical* memory. The f_pos points directly to the
113 * memory location. 137 * memory location.
@@ -157,6 +181,8 @@ static ssize_t read_mem(struct file * file, char __user * buf,
157 */ 181 */
158 ptr = xlate_dev_mem_ptr(p); 182 ptr = xlate_dev_mem_ptr(p);
159 183
184 if (!range_is_allowed(p, p+count))
185 return -EPERM;
160 if (copy_to_user(buf, ptr, sz)) 186 if (copy_to_user(buf, ptr, sz))
161 return -EFAULT; 187 return -EFAULT;
162 buf += sz; 188 buf += sz;
@@ -214,6 +240,8 @@ static ssize_t write_mem(struct file * file, const char __user * buf,
214 */ 240 */
215 ptr = xlate_dev_mem_ptr(p); 241 ptr = xlate_dev_mem_ptr(p);
216 242
243 if (!range_is_allowed(p, p+sz))
244 return -EPERM;
217 copied = copy_from_user(ptr, buf, sz); 245 copied = copy_from_user(ptr, buf, sz);
218 if (copied) { 246 if (copied) {
219 written += sz - copied; 247 written += sz - copied;
diff --git a/include/asm-x86/page.h b/include/asm-x86/page.h
index 6724a4bc6b7a..b381f4a5a0bd 100644
--- a/include/asm-x86/page.h
+++ b/include/asm-x86/page.h
@@ -47,6 +47,7 @@
47#ifndef __ASSEMBLY__ 47#ifndef __ASSEMBLY__
48 48
49extern int page_is_ram(unsigned long pagenr); 49extern int page_is_ram(unsigned long pagenr);
50extern int devmem_is_allowed(unsigned long pagenr);
50 51
51extern unsigned long max_pfn_mapped; 52extern unsigned long max_pfn_mapped;
52 53