Commit eb4f6fb9 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] Fix statically declare FIXMAPs

From: Anton Blanchard <anton@samba.org>, 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
parent 3ab88352
...@@ -76,22 +76,6 @@ int task_statm(struct mm_struct *mm, int *shared, int *text, ...@@ -76,22 +76,6 @@ int task_statm(struct mm_struct *mm, int *shared, int *text,
return size; 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) static int show_map(struct seq_file *m, void *v)
{ {
struct vm_area_struct *map = v; struct vm_area_struct *map = v;
...@@ -146,15 +130,16 @@ static void *m_start(struct seq_file *m, loff_t *pos) ...@@ -146,15 +130,16 @@ static void *m_start(struct seq_file *m, loff_t *pos)
up_read(&mm->mmap_sem); up_read(&mm->mmap_sem);
mmput(mm); mmput(mm);
if (l == -1) if (l == -1)
map = gate_map(); map = get_gate_vma(task);
} }
return map; return map;
} }
static void m_stop(struct seq_file *m, void *v) static void m_stop(struct seq_file *m, void *v)
{ {
struct task_struct *task = m->private;
struct vm_area_struct *map = v; 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; struct mm_struct *mm = map->vm_mm;
up_read(&mm->mmap_sem); up_read(&mm->mmap_sem);
mmput(mm); mmput(mm);
...@@ -163,13 +148,14 @@ static void m_stop(struct seq_file *m, void *v) ...@@ -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) 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; struct vm_area_struct *map = v;
(*pos)++; (*pos)++;
if (map->vm_next) if (map->vm_next)
return map->vm_next; return map->vm_next;
m_stop(m, v); m_stop(m, v);
if (map != gate_map()) if (map != get_gate_vma(task))
return gate_map(); return get_gate_vma(task);
return NULL; return NULL;
} }
......
...@@ -642,5 +642,33 @@ kernel_map_pages(struct page *page, int numpages, int enable) ...@@ -642,5 +642,33 @@ kernel_map_pages(struct page *page, int numpages, int enable)
} }
#endif #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 /* __KERNEL__ */
#endif /* _LINUX_MM_H */ #endif /* _LINUX_MM_H */
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/rmap-locking.h> #include <linux/rmap-locking.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h>
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
#include <asm/rmap.h> #include <asm/rmap.h>
...@@ -704,25 +705,13 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, ...@@ -704,25 +705,13 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
struct vm_area_struct * vma; struct vm_area_struct * vma;
vma = find_extend_vma(mm, start); vma = find_extend_vma(mm, start);
if (!vma && in_gate_area(tsk, 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,
};
unsigned long pg = start & PAGE_MASK; unsigned long pg = start & PAGE_MASK;
struct vm_area_struct *gate_vma = get_gate_vma(tsk);
pgd_t *pgd; pgd_t *pgd;
pmd_t *pmd; pmd_t *pmd;
pte_t *pte; pte_t *pte;
if (write) /* user fixmap pages are read-only */ if (write) /* user gate pages are read-only */
return i ? : -EFAULT; return i ? : -EFAULT;
pgd = pgd_offset_k(pg); pgd = pgd_offset_k(pg);
if (!pgd) if (!pgd)
...@@ -738,13 +727,12 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, ...@@ -738,13 +727,12 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
get_page(pages[i]); get_page(pages[i]);
} }
if (vmas) if (vmas)
vmas[i] = &fixmap_vma; vmas[i] = gate_vma;
i++; i++;
start += PAGE_SIZE; start += PAGE_SIZE;
len--; len--;
continue; continue;
} }
#endif
if (!vma || (pages && (vma->vm_flags & VM_IO)) if (!vma || (pages && (vma->vm_flags & VM_IO))
|| !(flags & vma->vm_flags)) || !(flags & vma->vm_flags))
...@@ -1699,3 +1687,18 @@ struct page * vmalloc_to_page(void * vmalloc_addr) ...@@ -1699,3 +1687,18 @@ struct page * vmalloc_to_page(void * vmalloc_addr)
} }
EXPORT_SYMBOL(vmalloc_to_page); 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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment