[PATCH 1/11] oprofile: add check_user_page_readable()

From: Greg Banks
Date: Tue Nov 09 2004 - 05:45:35 EST



--
Greg Banks, R&D Software Engineer, SGI Australian Software Group.
I don't speak for SGI.

Add check_user_page_readable() for kernel modules which need
to follow user space addresses but can't use get_user().

Signed-off-by: John Levon <levon@xxxxxxxxxxxxxxxxx>
Signed-off-by: Greg Banks <gnb@xxxxxxxxxxxxxxxxx>
---

include/linux/mm.h | 1 +
mm/memory.c | 20 ++++++++++++++++++--
2 files changed, 19 insertions(+), 2 deletions(-)

Index: linux/include/linux/mm.h
===================================================================
--- linux.orig/include/linux/mm.h 2004-11-06 01:12:07.%N +1100
+++ linux/include/linux/mm.h 2004-11-07 17:59:40.%N +1100
@@ -789,6 +789,7 @@ extern struct page * vmalloc_to_page(voi
extern unsigned long vmalloc_to_pfn(void *addr);
extern struct page * follow_page(struct mm_struct *mm, unsigned long address,
int write);
+extern int check_user_page_readable(struct mm_struct *mm, unsigned long address);
int remap_pfn_range(struct vm_area_struct *, unsigned long,
unsigned long, unsigned long, pgprot_t);

Index: linux/mm/memory.c
===================================================================
--- linux.orig/mm/memory.c 2004-11-06 01:11:57.%N +1100
+++ linux/mm/memory.c 2004-11-07 17:59:40.%N +1100
@@ -746,8 +746,8 @@ void zap_page_range(struct vm_area_struc
* Do a quick page-table lookup for a single page.
* mm->page_table_lock must be held.
*/
-struct page *
-follow_page(struct mm_struct *mm, unsigned long address, int write)
+static struct page *
+__follow_page(struct mm_struct *mm, unsigned long address, int read, int write)
{
pml4_t *pml4;
pgd_t *pgd;
@@ -790,6 +790,8 @@ follow_page(struct mm_struct *mm, unsign
if (pte_present(pte)) {
if (write && !pte_write(pte))
goto out;
+ if (read && !pte_read(pte))
+ goto out;
pfn = pte_pfn(pte);
if (pfn_valid(pfn)) {
page = pfn_to_page(pfn);
@@ -804,6 +806,20 @@ out:
return NULL;
}

+struct page *
+follow_page(struct mm_struct *mm, unsigned long address, int write)
+{
+ return __follow_page(mm, address, /*read*/0, write);
+}
+
+int
+check_user_page_readable(struct mm_struct *mm, unsigned long address)
+{
+ return __follow_page(mm, address, /*read*/1, /*write*/0) != NULL;
+}
+
+EXPORT_SYMBOL(check_user_page_readable);
+
/*
* Given a physical address, is there a useful struct page pointing to
* it? This may become more complex in the future if we start dealing