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 -puN fs/proc/task_mmu.c~proc-pid-maps-gate-fixes fs/proc/task_mmu.c --- 25/fs/proc/task_mmu.c~proc-pid-maps-gate-fixes 2004-01-11 22:41:33.000000000 -0800 +++ 25-akpm/fs/proc/task_mmu.c 2004-01-11 22:41:33.000000000 -0800 @@ -76,22 +76,6 @@ int task_statm(struct mm_struct *mm, int 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, 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, 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 -puN include/linux/mm.h~proc-pid-maps-gate-fixes include/linux/mm.h --- 25/include/linux/mm.h~proc-pid-maps-gate-fixes 2004-01-11 22:41:33.000000000 -0800 +++ 25-akpm/include/linux/mm.h 2004-01-11 23:31:11.000000000 -0800 @@ -642,5 +642,33 @@ kernel_map_pages(struct page *page, int } #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 -puN mm/memory.c~proc-pid-maps-gate-fixes mm/memory.c --- 25/mm/memory.c~proc-pid-maps-gate-fixes 2004-01-11 22:41:33.000000000 -0800 +++ 25-akpm/mm/memory.c 2004-01-12 02:46:43.000000000 -0800 @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -705,25 +706,13 @@ int get_user_pages(struct task_struct *t 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) @@ -739,13 +728,12 @@ int get_user_pages(struct task_struct *t get_page(pages[i]); } if (vmas) - vmas[i] = &fixmap_vma; + vmas[i] = gate_vma; i++; start += PAGE_SIZE; len--; continue; } -#endif if (!vma) return i ? : -EFAULT; @@ -1713,3 +1701,18 @@ struct page * vmalloc_to_page(void * vma } 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 _