From eb4f6fb91be878c1acd727d62abb600b77b631fd Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 19 Jan 2004 05:12:38 -0800 Subject: [PATCH] [PATCH] Fix statically declare FIXMAPs From: Anton Blanchard , me. Two uses of the FIXADDR_USER_START/END things are problematic: a) ppc64 wants the FIXADDR area to be at a different location on 32bit and 64bit tasks. On 32bit we want it just below 4GB but that gets in the way on 64bit. By putting both right at -(some small amount) we can also use some ppc tricks to get there real quickly (single instruction branches). b) We assume that FIXADDR_USER_START and FIXADDR_USER_END are constants. This breaks the UML build. Fixes: - Call it all gate. We currently have half the stuff called fixmap and the other gate, lets be consistent. - Create in_gate_area(), get_gate_vma() and use it in both places - Provide defaults for in_gate_area/get_gate_vma, allowing an arch to override it. (I used CONFIG_* but am open to better suggestions here) - The /proc/pid/maps vma wasnt marked readable but the get_user vma was. That sounds suspicious to me, they are now both the same VMA and so have the same (read,exec) permissions --- fs/proc/task_mmu.c | 26 ++++++-------------------- include/linux/mm.h | 28 ++++++++++++++++++++++++++++ mm/memory.c | 37 ++++++++++++++++++++----------------- 3 files changed, 54 insertions(+), 37 deletions(-) diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 739ca9f198e90..1a7440ae3902c 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -76,22 +76,6 @@ int task_statm(struct mm_struct *mm, int *shared, int *text, return size; } -#ifdef AT_SYSINFO_EHDR - -static struct vm_area_struct gate_vmarea = { - /* Do _not_ mark this area as readable, cuz not the entire range may be readable - (e.g., due to execute-only pages or holes) and the tools that read - /proc/PID/maps should read the interesting bits from the gate-DSO file - instead. */ - .vm_start = FIXADDR_USER_START, - .vm_end = FIXADDR_USER_END -}; - -# define gate_map() &gate_vmarea -#else -# define gate_map() NULL -#endif - static int show_map(struct seq_file *m, void *v) { struct vm_area_struct *map = v; @@ -146,15 +130,16 @@ static void *m_start(struct seq_file *m, loff_t *pos) up_read(&mm->mmap_sem); mmput(mm); if (l == -1) - map = gate_map(); + map = get_gate_vma(task); } return map; } static void m_stop(struct seq_file *m, void *v) { + struct task_struct *task = m->private; struct vm_area_struct *map = v; - if (map && map != gate_map()) { + if (map && map != get_gate_vma(task)) { struct mm_struct *mm = map->vm_mm; up_read(&mm->mmap_sem); mmput(mm); @@ -163,13 +148,14 @@ static void m_stop(struct seq_file *m, void *v) static void *m_next(struct seq_file *m, void *v, loff_t *pos) { + struct task_struct *task = m->private; struct vm_area_struct *map = v; (*pos)++; if (map->vm_next) return map->vm_next; m_stop(m, v); - if (map != gate_map()) - return gate_map(); + if (map != get_gate_vma(task)) + return get_gate_vma(task); return NULL; } diff --git a/include/linux/mm.h b/include/linux/mm.h index 42f5c2df91d1b..3ecd3d633c5f7 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -642,5 +642,33 @@ kernel_map_pages(struct page *page, int numpages, int enable) } #endif +#ifndef CONFIG_ARCH_GATE_AREA +#ifdef AT_SYSINFO_EHDR +static inline int in_gate_area(struct task_struct *task, unsigned long addr) +{ + if ((addr >= FIXADDR_USER_START) && (addr < FIXADDR_USER_END)) + return 1; + else + return 0; +} + +extern struct vm_area_struct gate_vma; +static inline struct vm_area_struct *get_gate_vma(struct task_struct *tsk) +{ + return &gate_vma; +} +#else +static inline int in_gate_area(struct task_struct *task, unsigned long addr) +{ + return 0; +} + +static inline struct vm_area_struct *get_gate_vma(struct task_struct *tsk) +{ + return NULL; +} +#endif +#endif + #endif /* __KERNEL__ */ #endif /* _LINUX_MM_H */ diff --git a/mm/memory.c b/mm/memory.c index f1c49a218663d..d0c834a8ce976 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -704,25 +705,13 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, struct vm_area_struct * vma; vma = find_extend_vma(mm, start); - -#ifdef FIXADDR_USER_START - if (!vma && - start >= FIXADDR_USER_START && start < FIXADDR_USER_END) { - static struct vm_area_struct fixmap_vma = { - /* Catch users - if there are any valid - ones, we can make this be "&init_mm" or - something. */ - .vm_mm = NULL, - .vm_start = FIXADDR_USER_START, - .vm_end = FIXADDR_USER_END, - .vm_page_prot = PAGE_READONLY, - .vm_flags = VM_READ | VM_EXEC, - }; + if (!vma && in_gate_area(tsk, start)) { unsigned long pg = start & PAGE_MASK; + struct vm_area_struct *gate_vma = get_gate_vma(tsk); pgd_t *pgd; pmd_t *pmd; pte_t *pte; - if (write) /* user fixmap pages are read-only */ + if (write) /* user gate pages are read-only */ return i ? : -EFAULT; pgd = pgd_offset_k(pg); if (!pgd) @@ -738,13 +727,12 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, get_page(pages[i]); } if (vmas) - vmas[i] = &fixmap_vma; + vmas[i] = gate_vma; i++; start += PAGE_SIZE; len--; continue; } -#endif if (!vma || (pages && (vma->vm_flags & VM_IO)) || !(flags & vma->vm_flags)) @@ -1699,3 +1687,18 @@ struct page * vmalloc_to_page(void * vmalloc_addr) } EXPORT_SYMBOL(vmalloc_to_page); + +#if !defined(CONFIG_ARCH_GATE_AREA) && defined(AT_SYSINFO_EHDR) +struct vm_area_struct gate_vma; + +static int __init gate_vma_init(void) +{ + gate_vma.vm_mm = NULL; + gate_vma.vm_start = FIXADDR_USER_START; + gate_vma.vm_end = FIXADDR_USER_END; + gate_vma.vm_page_prot = PAGE_READONLY; + gate_vma.vm_flags = 0; + return 0; +} +__initcall(gate_vma_init); +#endif -- 2.53.0