From: Greg Banks 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 Signed-off-by: Greg Banks Signed-off-by: Andrew Morton --- 25-akpm/include/linux/mm.h | 1 + 25-akpm/mm/memory.c | 20 ++++++++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff -puN include/linux/mm.h~oprofile-add-check_user_page_readable include/linux/mm.h --- 25/include/linux/mm.h~oprofile-add-check_user_page_readable 2004-12-03 20:56:07.705588760 -0800 +++ 25-akpm/include/linux/mm.h 2004-12-03 20:56:07.711587848 -0800 @@ -823,6 +823,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); diff -puN mm/memory.c~oprofile-add-check_user_page_readable mm/memory.c --- 25/mm/memory.c~oprofile-add-check_user_page_readable 2004-12-03 20:56:07.707588456 -0800 +++ 25-akpm/mm/memory.c 2004-12-03 20:56:07.713587544 -0800 @@ -747,8 +747,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; @@ -791,6 +791,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); @@ -805,6 +807,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 _