summaryrefslogtreecommitdiff
path: root/arch/um/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/um/kernel')
-rw-r--r--arch/um/kernel/exec.c10
-rw-r--r--arch/um/kernel/skas/Makefile7
-rw-r--r--arch/um/kernel/skas/clone.c2
-rw-r--r--arch/um/kernel/skas/stub.c80
-rw-r--r--arch/um/kernel/tlb.c42
5 files changed, 108 insertions, 33 deletions
diff --git a/arch/um/kernel/exec.c b/arch/um/kernel/exec.c
index 827a0d3fa589..5c8836b012e9 100644
--- a/arch/um/kernel/exec.c
+++ b/arch/um/kernel/exec.c
@@ -22,15 +22,11 @@
void flush_thread(void)
{
- void *data = NULL;
- int ret;
-
arch_flush_thread(&current->thread.arch);
- ret = unmap(&current->mm->context.id, 0, TASK_SIZE, 1, &data);
- if (ret) {
- printk(KERN_ERR "%s - clearing address space failed, err = %d\n",
- __func__, ret);
+ unmap(&current->mm->context.id, 0, TASK_SIZE);
+ if (syscall_stub_flush(&current->mm->context.id) < 0) {
+ printk(KERN_ERR "%s - clearing address space failed", __func__);
force_sig(SIGKILL);
}
get_safe_registers(current_pt_regs()->regs.gp,
diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile
index f93972a25765..dd8bc2167e36 100644
--- a/arch/um/kernel/skas/Makefile
+++ b/arch/um/kernel/skas/Makefile
@@ -3,14 +3,15 @@
# Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
#
-obj-y := clone.o mmu.o process.o syscall.o uaccess.o
+obj-y := clone.o stub.o mmu.o process.o syscall.o uaccess.o
-# clone.o is in the stub, so it can't be built with profiling
+# clone.o and stub.o are in the stub, so it can't be built with profiling
# GCC hardened also auto-enables -fpic, but we need %ebx so it can't work ->
# disable it
CFLAGS_clone.o := $(CFLAGS_NO_HARDENING)
-UNPROFILE_OBJS := clone.o
+CFLAGS_stub.o := $(CFLAGS_NO_HARDENING)
+UNPROFILE_OBJS := clone.o stub.o
KCOV_INSTRUMENT := n
diff --git a/arch/um/kernel/skas/clone.c b/arch/um/kernel/skas/clone.c
index 906f7454887c..b59fa43d68ce 100644
--- a/arch/um/kernel/skas/clone.c
+++ b/arch/um/kernel/skas/clone.c
@@ -33,7 +33,7 @@ stub_clone_handler(void)
sizeof(data->syscall_data) / 2 -
sizeof(void *));
if (err) {
- data->parent_err = err;
+ data->err = err;
goto done;
}
diff --git a/arch/um/kernel/skas/stub.c b/arch/um/kernel/skas/stub.c
new file mode 100644
index 000000000000..8773529b5048
--- /dev/null
+++ b/arch/um/kernel/skas/stub.c
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 Benjamin Berg <benjamin@sipsolutions.net>
+ */
+
+#include <sysdep/stub.h>
+
+static __always_inline int syscall_handler(struct stub_data *d)
+{
+ int i;
+ unsigned long res;
+
+ for (i = 0; i < d->syscall_data_len; i++) {
+ struct stub_syscall *sc = &d->syscall_data[i];
+
+ switch (sc->syscall) {
+ case STUB_SYSCALL_MMAP:
+ res = stub_syscall6(STUB_MMAP_NR,
+ sc->mem.addr, sc->mem.length,
+ sc->mem.prot,
+ MAP_SHARED | MAP_FIXED,
+ sc->mem.fd, sc->mem.offset);
+ if (res != sc->mem.addr) {
+ d->err = res;
+ d->syscall_data_len = i;
+ return -1;
+ }
+ break;
+ case STUB_SYSCALL_MUNMAP:
+ res = stub_syscall2(__NR_munmap,
+ sc->mem.addr, sc->mem.length);
+ if (res) {
+ d->err = res;
+ d->syscall_data_len = i;
+ return -1;
+ }
+ break;
+ case STUB_SYSCALL_MPROTECT:
+ res = stub_syscall3(__NR_mprotect,
+ sc->mem.addr, sc->mem.length,
+ sc->mem.prot);
+ if (res) {
+ d->err = res;
+ d->syscall_data_len = i;
+ return -1;
+ }
+ break;
+ case STUB_SYSCALL_LDT:
+ res = stub_syscall3(__NR_modify_ldt, sc->ldt.func,
+ (unsigned long) &sc->ldt.desc,
+ sizeof(sc->ldt.desc));
+ /* We only write, so the expected result is zero */
+ if (res) {
+ d->err = res;
+ d->syscall_data_len = i;
+ return -1;
+ }
+ break;
+ default:
+ d->err = -95; /* EOPNOTSUPP */
+ d->syscall_data_len = i;
+ return -1;
+ }
+ }
+
+ d->err = 0;
+ d->syscall_data_len = 0;
+
+ return 0;
+}
+
+void __section(".__syscall_stub")
+stub_syscall_handler(void)
+{
+ struct stub_data *d = get_stub_data();
+
+ syscall_handler(d);
+
+ trap_myself();
+}
diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c
index 8784f03fa4a6..a89e2886485f 100644
--- a/arch/um/kernel/tlb.c
+++ b/arch/um/kernel/tlb.c
@@ -71,21 +71,19 @@ static int do_ops(struct host_vm_change *hvc, int end,
switch (op->type) {
case MMAP:
if (hvc->userspace)
- ret = map(&hvc->mm->context.id, op->u.mmap.addr,
- op->u.mmap.len, op->u.mmap.prot,
- op->u.mmap.fd,
- op->u.mmap.offset, finished,
- &hvc->data);
+ map(&hvc->mm->context.id, op->u.mmap.addr,
+ op->u.mmap.len, op->u.mmap.prot,
+ op->u.mmap.fd,
+ op->u.mmap.offset);
else
map_memory(op->u.mmap.addr, op->u.mmap.offset,
op->u.mmap.len, 1, 1, 1);
break;
case MUNMAP:
if (hvc->userspace)
- ret = unmap(&hvc->mm->context.id,
- op->u.munmap.addr,
- op->u.munmap.len, finished,
- &hvc->data);
+ unmap(&hvc->mm->context.id,
+ op->u.munmap.addr,
+ op->u.munmap.len);
else
ret = os_unmap_memory(
(void *) op->u.munmap.addr,
@@ -94,11 +92,10 @@ static int do_ops(struct host_vm_change *hvc, int end,
break;
case MPROTECT:
if (hvc->userspace)
- ret = protect(&hvc->mm->context.id,
- op->u.mprotect.addr,
- op->u.mprotect.len,
- op->u.mprotect.prot,
- finished, &hvc->data);
+ protect(&hvc->mm->context.id,
+ op->u.mprotect.addr,
+ op->u.mprotect.len,
+ op->u.mprotect.prot);
else
ret = os_protect_memory(
(void *) op->u.mprotect.addr,
@@ -113,6 +110,9 @@ static int do_ops(struct host_vm_change *hvc, int end,
}
}
+ if (hvc->userspace && finished)
+ ret = syscall_stub_flush(&hvc->mm->context.id);
+
if (ret == -ENOMEM)
report_enomem();
@@ -461,7 +461,6 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
pmd_t *pmd;
pte_t *pte;
struct mm_struct *mm = vma->vm_mm;
- void *flush = NULL;
int r, w, x, prot, err = 0;
struct mm_id *mm_id;
@@ -504,14 +503,13 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
int fd;
fd = phys_mapping(pte_val(*pte) & PAGE_MASK, &offset);
- err = map(mm_id, address, PAGE_SIZE, prot, fd, offset,
- 1, &flush);
- }
- else err = unmap(mm_id, address, PAGE_SIZE, 1, &flush);
- }
- else if (pte_newprot(*pte))
- err = protect(mm_id, address, PAGE_SIZE, prot, 1, &flush);
+ map(mm_id, address, PAGE_SIZE, prot, fd, offset);
+ } else
+ unmap(mm_id, address, PAGE_SIZE);
+ } else if (pte_newprot(*pte))
+ protect(mm_id, address, PAGE_SIZE, prot);
+ err = syscall_stub_flush(mm_id);
if (err) {
if (err == -ENOMEM)
report_enomem();