summaryrefslogtreecommitdiff
path: root/arch/um/kernel
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2021-01-13 22:09:44 +0100
committerRichard Weinberger <richard@nod.at>2021-02-12 21:37:38 +0100
commitbfc58e2b98e99737409cd9f4d86a79677c5b887c (patch)
treee73fa8fa0c10f6129ed4b80028cba003dc5d69c5 /arch/um/kernel
parent9f0b4807a44ff81cf59421c8a86641efec586610 (diff)
um: remove process stub VMA
This mostly reverts the old commit 3963333fe676 ("uml: cover stubs with a VMA") which had added a VMA to the existing PTEs. However, there's no real reason to have the PTEs in the first place and the VMA cannot be 'fixed' in place, which leads to bugs that userspace could try to unmap them and be forcefully killed, or such. Also, there's a bit of an ugly hole in userspace's address space. Simplify all this: just install the stub code/page at the top of the (inner) address space, i.e. put it just above TASK_SIZE. The pages are simply hard-coded to be mapped in the userspace process we use to implement an mm context, and they're out of reach of the inner mmap/munmap/mprotect etc. since they're above TASK_SIZE. Getting rid of the VMA also makes vma_merge() no longer hit one of the VM_WARN_ON()s there because we installed a VMA while the code assumes the stack VMA is the first one. It also removes a lockdep warning about mmap_sem usage since we no longer have uml_setup_stubs() and thus no longer need to do any manipulation that would require mmap_sem in activate_mm(). Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Richard Weinberger <richard@nod.at>
Diffstat (limited to 'arch/um/kernel')
-rw-r--r--arch/um/kernel/exec.c4
-rw-r--r--arch/um/kernel/skas/mmu.c87
-rw-r--r--arch/um/kernel/tlb.c15
-rw-r--r--arch/um/kernel/um_arch.c5
4 files changed, 6 insertions, 105 deletions
diff --git a/arch/um/kernel/exec.c b/arch/um/kernel/exec.c
index e8fd5d540b05..4d8498100341 100644
--- a/arch/um/kernel/exec.c
+++ b/arch/um/kernel/exec.c
@@ -26,9 +26,7 @@ void flush_thread(void)
arch_flush_thread(&current->thread.arch);
- ret = unmap(&current->mm->context.id, 0, STUB_START, 0, &data);
- ret = ret || unmap(&current->mm->context.id, STUB_END,
- host_task_size - STUB_END, 1, &data);
+ ret = unmap(&current->mm->context.id, 0, TASK_SIZE, 1, &data);
if (ret) {
printk(KERN_ERR "flush_thread - clearing address space failed, "
"err = %d\n", ret);
diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c
index d9961163da66..125df465e8ea 100644
--- a/arch/um/kernel/skas/mmu.c
+++ b/arch/um/kernel/skas/mmu.c
@@ -14,47 +14,6 @@
#include <os.h>
#include <skas.h>
-static int init_stub_pte(struct mm_struct *mm, unsigned long proc,
- unsigned long kernel)
-{
- pgd_t *pgd;
- p4d_t *p4d;
- pud_t *pud;
- pmd_t *pmd;
- pte_t *pte;
-
- pgd = pgd_offset(mm, proc);
-
- p4d = p4d_alloc(mm, pgd, proc);
- if (!p4d)
- goto out;
-
- pud = pud_alloc(mm, p4d, proc);
- if (!pud)
- goto out_pud;
-
- pmd = pmd_alloc(mm, pud, proc);
- if (!pmd)
- goto out_pmd;
-
- pte = pte_alloc_map(mm, pmd, proc);
- if (!pte)
- goto out_pte;
-
- *pte = mk_pte(virt_to_page(kernel), __pgprot(_PAGE_PRESENT));
- *pte = pte_mkread(*pte);
- return 0;
-
- out_pte:
- pmd_free(mm, pmd);
- out_pmd:
- pud_free(mm, pud);
- out_pud:
- p4d_free(mm, p4d);
- out:
- return -ENOMEM;
-}
-
int init_new_context(struct task_struct *task, struct mm_struct *mm)
{
struct mm_context *from_mm = NULL;
@@ -98,52 +57,6 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm)
return ret;
}
-void uml_setup_stubs(struct mm_struct *mm)
-{
- int err, ret;
-
- ret = init_stub_pte(mm, STUB_CODE,
- (unsigned long) __syscall_stub_start);
- if (ret)
- goto out;
-
- ret = init_stub_pte(mm, STUB_DATA, mm->context.id.stack);
- if (ret)
- goto out;
-
- mm->context.stub_pages[0] = virt_to_page(__syscall_stub_start);
- mm->context.stub_pages[1] = virt_to_page(mm->context.id.stack);
-
- /* dup_mmap already holds mmap_lock */
- err = install_special_mapping(mm, STUB_START, STUB_END - STUB_START,
- VM_READ | VM_MAYREAD | VM_EXEC |
- VM_MAYEXEC | VM_DONTCOPY | VM_PFNMAP,
- mm->context.stub_pages);
- if (err) {
- printk(KERN_ERR "install_special_mapping returned %d\n", err);
- goto out;
- }
- return;
-
-out:
- force_sigsegv(SIGSEGV);
-}
-
-void arch_exit_mmap(struct mm_struct *mm)
-{
- pte_t *pte;
-
- pte = virt_to_pte(mm, STUB_CODE);
- if (pte != NULL)
- pte_clear(mm, STUB_CODE, pte);
-
- pte = virt_to_pte(mm, STUB_DATA);
- if (pte == NULL)
- return;
-
- pte_clear(mm, STUB_DATA, pte);
-}
-
void destroy_context(struct mm_struct *mm)
{
struct mm_context *mmu = &mm->context;
diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c
index 5be1b0da9f3b..bc38f79ca3a3 100644
--- a/arch/um/kernel/tlb.c
+++ b/arch/um/kernel/tlb.c
@@ -125,9 +125,6 @@ static int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
struct host_vm_op *last;
int fd = -1, ret = 0;
- if (virt + len > STUB_START && virt < STUB_END)
- return -EINVAL;
-
if (hvc->userspace)
fd = phys_mapping(phys, &offset);
else
@@ -165,9 +162,6 @@ static int add_munmap(unsigned long addr, unsigned long len,
struct host_vm_op *last;
int ret = 0;
- if (addr + len > STUB_START && addr < STUB_END)
- return -EINVAL;
-
if (hvc->index != 0) {
last = &hvc->ops[hvc->index - 1];
if ((last->type == MUNMAP) &&
@@ -195,9 +189,6 @@ static int add_mprotect(unsigned long addr, unsigned long len,
struct host_vm_op *last;
int ret = 0;
- if (addr + len > STUB_START && addr < STUB_END)
- return -EINVAL;
-
if (hvc->index != 0) {
last = &hvc->ops[hvc->index - 1];
if ((last->type == MPROTECT) &&
@@ -232,9 +223,6 @@ static inline int update_pte_range(pmd_t *pmd, unsigned long addr,
pte = pte_offset_kernel(pmd, addr);
do {
- if ((addr >= STUB_START) && (addr < STUB_END))
- continue;
-
r = pte_read(*pte);
w = pte_write(*pte);
x = pte_exec(*pte);
@@ -478,9 +466,6 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
address &= PAGE_MASK;
- if (address >= STUB_START && address < STUB_END)
- goto kill;
-
pgd = pgd_offset(mm, address);
if (!pgd_present(*pgd))
goto kill;
diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
index 80e2660782a0..74e07e748a9b 100644
--- a/arch/um/kernel/um_arch.c
+++ b/arch/um/kernel/um_arch.c
@@ -249,6 +249,7 @@ void uml_finishsetup(void)
}
/* Set during early boot */
+unsigned long stub_start;
unsigned long task_size;
EXPORT_SYMBOL(task_size);
@@ -283,6 +284,10 @@ int __init linux_main(int argc, char **argv)
add_arg(DEFAULT_COMMAND_LINE_CONSOLE);
host_task_size = os_get_top_address();
+ /* reserve two pages for the stubs */
+ host_task_size -= 2 * PAGE_SIZE;
+ stub_start = host_task_size;
+
/*
* TASK_SIZE needs to be PGDIR_SIZE aligned or else exit_mmap craps
* out