linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 14(16] pramfs: memory protection
@ 2010-10-10 16:36 Marco Stornelli
  2010-10-10 16:46 ` Andi Kleen
  0 siblings, 1 reply; 7+ messages in thread
From: Marco Stornelli @ 2010-10-10 16:36 UTC (permalink / raw)
  To: Linux Kernel; +Cc: Linux Embedded, Linux FS Devel, Tim Bird, linux-mm

From: Marco Stornelli <marco.stornelli@gmail.com>

Memory write protection.

Signed-off-by: Marco Stornelli <marco.stornelli@gmail.com>
---
diff -Nurp linux-2.6.36-orig/fs/pramfs/wprotect.c linux-2.6.36/fs/pramfs/wprotect.c
--- linux-2.6.36-orig/fs/pramfs/wprotect.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.36/fs/pramfs/wprotect.c	2010-09-26 18:04:07.000000000 +0200
@@ -0,0 +1,31 @@
+/*
+ * FILE NAME fs/pramfs/wprotect.c
+ *
+ * BRIEF DESCRIPTION
+ *
+ * Write protection for the filesystem pages.
+ *
+ * Copyright 2009-2010 Marco Stornelli <marco.stornelli@gmail.com>
+ * Copyright 2003 Sony Corporation
+ * Copyright 2003 Matsushita Electric Industrial Co., Ltd.
+ * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/io.h>
+#include "pram.h"
+
+void pram_writeable(void *vaddr, unsigned long size, int rw)
+{
+	int ret = 0;
+
+	ret = rw ? write_on_kernel_pte_range((unsigned long)vaddr, size) :
+		    write_off_kernel_pte_range((unsigned long)vaddr, size);
+
+	BUG_ON(ret);
+}
diff -Nurp linux-2.6.36-orig/include/linux/mm.h linux-2.6.36/include/linux/mm.h
--- linux-2.6.36-orig/include/linux/mm.h	2010-09-13 01:07:37.000000000 +0200
+++ linux-2.6.36/include/linux/mm.h	2010-09-14 18:49:52.000000000 +0200
@@ -811,6 +811,11 @@ int follow_phys(struct vm_area_struct *v
 		unsigned int flags, unsigned long *prot, resource_size_t *phys);
 int generic_access_phys(struct vm_area_struct *vma, unsigned long addr,
 			void *buf, int len, int write);
+int writeable_kernel_pte_range(unsigned long address, unsigned long size,
+				unsigned int rw);
+
+#define write_on_kernel_pte_range(addr, size) writeable_kernel_pte_range(addr, size, 1)
+#define write_off_kernel_pte_range(addr, size) writeable_kernel_pte_range(addr, size, 0)
  static inline void unmap_shared_mapping_range(struct address_space *mapping,
 		loff_t const holebegin, loff_t const holelen)
diff -Nurp linux-2.6.36-orig/mm/memory.c linux-2.6.36/mm/memory.c
--- linux-2.6.36-orig/mm/memory.c	2010-09-13 01:07:37.000000000 +0200
+++ linux-2.6.36/mm/memory.c	2010-09-14 18:49:52.000000000 +0200
@@ -3587,3 +3587,49 @@ void might_fault(void)
 }
 EXPORT_SYMBOL(might_fault);
 #endif
+
+int writeable_kernel_pte_range(unsigned long address, unsigned long size,
+							      unsigned int rw)
+{
+
+	unsigned long addr = address & PAGE_MASK;
+	unsigned long end = address + size;
+	unsigned long start = addr;
+	int ret = -EINVAL;
+	pgd_t *pgd;
+	pud_t *pud;
+	pmd_t *pmd;
+	pte_t *ptep, pte;
+
+	spin_lock_irq(&init_mm.page_table_lock);
+
+	do {
+		pgd = pgd_offset(&init_mm, address);
+		if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
+			goto out;
+
+		pud = pud_offset(pgd, address);
+		if (pud_none(*pud) || unlikely(pud_bad(*pud)))
+			goto out;
+
+		pmd = pmd_offset(pud, address);
+		if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
+			goto out;
+
+		ptep = pte_offset_kernel(pmd, addr);
+		pte = *ptep;
+		if (pte_present(pte)) {
+			  pte = rw ? pte_mkwrite(pte) : pte_wrprotect(pte);
+			  *ptep = pte;
+		}
+		addr += PAGE_SIZE;
+	} while (addr && (addr < end));
+
+	ret = 0;
+
+out:
+	flush_tlb_kernel_range(start, end);
+	spin_unlock_irq(&init_mm.page_table_lock);
+	return ret;
+}
+EXPORT_SYMBOL(writeable_kernel_pte_range);
 

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 14(16] pramfs: memory protection
  2010-10-10 16:36 [PATCH 14(16] pramfs: memory protection Marco Stornelli
@ 2010-10-10 16:46 ` Andi Kleen
  2010-10-11  6:57   ` Marco Stornelli
  2010-10-11 17:32   ` Marco Stornelli
  0 siblings, 2 replies; 7+ messages in thread
From: Andi Kleen @ 2010-10-10 16:46 UTC (permalink / raw)
  To: Marco Stornelli
  Cc: Linux Kernel, Linux Embedded, Linux FS Devel, Tim Bird, linux-mm

Marco Stornelli <marco.stornelli@gmail.com> writes:
> +
> +	do {
> +		pgd = pgd_offset(&init_mm, address);
> +		if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
> +			goto out;
> +
> +		pud = pud_offset(pgd, address);
> +		if (pud_none(*pud) || unlikely(pud_bad(*pud)))
> +			goto out;
> +
> +		pmd = pmd_offset(pud, address);
> +		if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
> +			goto out;
> +
> +		ptep = pte_offset_kernel(pmd, addr);
> +		pte = *ptep;
> +		if (pte_present(pte)) {

This won't work at all on x86 because you don't handle large 
pages.

And it doesn't work on x86-64 because the first 2GB are double
mapped (direct and kernel text mapping)

Thirdly I expect it won't either on architectures that map
the direct mapping with special registers (like IA64 or MIPS)

I'm not sure this is very useful anyways. It doesn't protect
against stray DMA and it doesn't protect against writes through
broken user PTEs.

-Andi

-- 
ak@linux.intel.com -- Speaking for myself only.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 14(16] pramfs: memory protection
  2010-10-10 16:46 ` Andi Kleen
@ 2010-10-11  6:57   ` Marco Stornelli
  2010-10-11 17:32   ` Marco Stornelli
  1 sibling, 0 replies; 7+ messages in thread
From: Marco Stornelli @ 2010-10-11  6:57 UTC (permalink / raw)
  To: Andi Kleen
  Cc: Linux Kernel, Linux Embedded, Linux FS Devel, Tim Bird, linux-mm

2010/10/10 Andi Kleen <andi@firstfloor.org>:
> Marco Stornelli <marco.stornelli@gmail.com> writes:
>> +
>> +     do {
>> +             pgd = pgd_offset(&init_mm, address);
>> +             if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
>> +                     goto out;
>> +
>> +             pud = pud_offset(pgd, address);
>> +             if (pud_none(*pud) || unlikely(pud_bad(*pud)))
>> +                     goto out;
>> +
>> +             pmd = pmd_offset(pud, address);
>> +             if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
>> +                     goto out;
>> +
>> +             ptep = pte_offset_kernel(pmd, addr);
>> +             pte = *ptep;
>> +             if (pte_present(pte)) {
>
> This won't work at all on x86 because you don't handle large
> pages.

On x86 works because I tested. Maybe there's a particular
configuration with large pages. Sincerly I'm only an "user", so if
you/Linus or others want to change it or rewrite it, for me it's ok.
The pte manipulation are a bit out of scope for a fs, so I let the
things to the mm experts.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 14(16] pramfs: memory protection
  2010-10-10 16:46 ` Andi Kleen
  2010-10-11  6:57   ` Marco Stornelli
@ 2010-10-11 17:32   ` Marco Stornelli
  2010-10-12  7:45     ` Andi Kleen
  1 sibling, 1 reply; 7+ messages in thread
From: Marco Stornelli @ 2010-10-11 17:32 UTC (permalink / raw)
  To: Andi Kleen
  Cc: Linux Kernel, Linux Embedded, Linux FS Devel, Tim Bird, linux-mm

Il 10/10/2010 18:46, Andi Kleen ha scritto:
> This won't work at all on x86 because you don't handle large 
> pages.
> 
> And it doesn't work on x86-64 because the first 2GB are double
> mapped (direct and kernel text mapping)
> 
> Thirdly I expect it won't either on architectures that map
> the direct mapping with special registers (like IA64 or MIPS)

Andi, what do you think to use the already implemented follow_pte
instead? 

int writeable_kernel_pte_range(unsigned long address, unsigned long size,
							      unsigned int rw)
{

	unsigned long addr = address & PAGE_MASK;
	unsigned long end = address + size;
	unsigned long start = addr;
	int ret = -EINVAL;
	pte_t *ptep, pte;
	spinlock_t *lock = &init_mm.page_table_lock;

	do {
		ret = follow_pte(&init_mm, addr, &ptep, &lock);
		if (ret)
			goto out;
		pte = *ptep;
		if (pte_present(pte)) {
			  pte = rw ? pte_mkwrite(pte) : pte_wrprotect(pte);
			  *ptep = pte;
		}
		pte_unmap_unlock(ptep, lock);
		addr += PAGE_SIZE;
	} while (addr && (addr < end));

	ret = 0;

out:
	flush_tlb_kernel_range(start, end);
	return ret;
}


> 
> I'm not sure this is very useful anyways. It doesn't protect
> against stray DMA and it doesn't protect against writes through
> broken user PTEs.
> 
> -Andi
> 

It's a way to have more protection against kernel bug, for a 
in-memory fs can be important. However this option can be 
enabled/disabled at fs level.

Marco

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 14(16] pramfs: memory protection
  2010-10-11 17:32   ` Marco Stornelli
@ 2010-10-12  7:45     ` Andi Kleen
  2010-10-12 10:47       ` Marco Stornelli
  0 siblings, 1 reply; 7+ messages in thread
From: Andi Kleen @ 2010-10-12  7:45 UTC (permalink / raw)
  To: Marco Stornelli
  Cc: Andi Kleen, Linux Kernel, Linux Embedded, Linux FS Devel,
	Tim Bird, linux-mm

On Mon, Oct 11, 2010 at 07:32:10PM +0200, Marco Stornelli wrote:
> Il 10/10/2010 18:46, Andi Kleen ha scritto:
> > This won't work at all on x86 because you don't handle large 
> > pages.
> > 
> > And it doesn't work on x86-64 because the first 2GB are double
> > mapped (direct and kernel text mapping)
> > 
> > Thirdly I expect it won't either on architectures that map
> > the direct mapping with special registers (like IA64 or MIPS)
> 
> Andi, what do you think to use the already implemented follow_pte
> instead? 

Has all the same problems. Really you need an per architecture
function. Perhaps some architectures could use a common helper,
but certainly not all.

x86 already has some infrastructure for this, but it currently
has serious problems too (like not merging mappings on unmap) 
and is generally overdesigned ugly code.

-Andi

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 14(16] pramfs: memory protection
  2010-10-12  7:45     ` Andi Kleen
@ 2010-10-12 10:47       ` Marco Stornelli
  2010-10-12 11:56         ` Andi Kleen
  0 siblings, 1 reply; 7+ messages in thread
From: Marco Stornelli @ 2010-10-12 10:47 UTC (permalink / raw)
  To: Andi Kleen
  Cc: Linux Kernel, Linux Embedded, Linux FS Devel, Tim Bird, linux-mm

2010/10/12 Andi Kleen <andi@firstfloor.org>:
> On Mon, Oct 11, 2010 at 07:32:10PM +0200, Marco Stornelli wrote:
>> Il 10/10/2010 18:46, Andi Kleen ha scritto:
>> > This won't work at all on x86 because you don't handle large
>> > pages.
>> >
>> > And it doesn't work on x86-64 because the first 2GB are double
>> > mapped (direct and kernel text mapping)
>> >
>> > Thirdly I expect it won't either on architectures that map
>> > the direct mapping with special registers (like IA64 or MIPS)
>>
>> Andi, what do you think to use the already implemented follow_pte
>> instead?
>
> Has all the same problems. Really you need an per architecture
> function. Perhaps some architectures could use a common helper,
> but certainly not all.
>

per-arch?! Wow. Mmm...maybe I have to change something at fs level to
avoid that. An alternative could be to use the follow_pte solution but
avoid the protection via Kconfig if the fs is used on some archs (ia64
or MIPS), with large pages and so on. An help of the kernel community
to know all these particular cases is welcome.

Regards,

Marco

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 14(16] pramfs: memory protection
  2010-10-12 10:47       ` Marco Stornelli
@ 2010-10-12 11:56         ` Andi Kleen
  0 siblings, 0 replies; 7+ messages in thread
From: Andi Kleen @ 2010-10-12 11:56 UTC (permalink / raw)
  To: Marco Stornelli
  Cc: Andi Kleen, Linux Kernel, Linux Embedded, Linux FS Devel,
	Tim Bird, linux-mm

> per-arch?! Wow. Mmm...maybe I have to change something at fs level to
> avoid that. An alternative could be to use the follow_pte solution but
> avoid the protection via Kconfig if the fs is used on some archs (ia64
> or MIPS), with large pages and so on. An help of the kernel community
> to know all these particular cases is welcome.

It depends if the protection is a fundamental part of your design
(but if it is I would argue that's broken because it's really not very good
protection): If it's just an optional nice to have you can stub
it out on architectures that don't support it.

-Andi
-- 
ak@linux.intel.com -- Speaking for myself only.

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2010-10-12 11:56 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-10-10 16:36 [PATCH 14(16] pramfs: memory protection Marco Stornelli
2010-10-10 16:46 ` Andi Kleen
2010-10-11  6:57   ` Marco Stornelli
2010-10-11 17:32   ` Marco Stornelli
2010-10-12  7:45     ` Andi Kleen
2010-10-12 10:47       ` Marco Stornelli
2010-10-12 11:56         ` Andi Kleen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).