Commit 76ed9158 authored by Benjamin Berg's avatar Benjamin Berg Committed by Johannes Berg

um: Rework syscall handling

Rework syscall handling to be platform independent. Also create a clean
split between queueing of syscalls and flushing them out, removing the
need to keep state in the code that triggers the syscalls.

The code adds syscall_data_len to the global mm_id structure. This will
be used later to allow surrounding code to track whether syscalls still
need to run and if errors occurred.
Signed-off-by: default avatarBenjamin Berg <benjamin@sipsolutions.net>
Link: https://patch.msgid.link/20240703134536.1161108-5-benjamin@sipsolutions.netSigned-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 542dc79f
...@@ -272,19 +272,15 @@ extern long long os_persistent_clock_emulation(void); ...@@ -272,19 +272,15 @@ extern long long os_persistent_clock_emulation(void);
extern long long os_nsecs(void); extern long long os_nsecs(void);
/* skas/mem.c */ /* skas/mem.c */
extern long run_syscall_stub(struct mm_id * mm_idp, int syscall_stub_flush(struct mm_id *mm_idp);
int syscall, unsigned long *args, long expected, struct stub_syscall *syscall_stub_alloc(struct mm_id *mm_idp);
void **addr, int done);
extern long syscall_stub_data(struct mm_id * mm_idp, void map(struct mm_id *mm_idp, unsigned long virt,
unsigned long *data, int data_count, unsigned long len, int prot, int phys_fd,
void **addr, void **stub_addr); unsigned long long offset);
extern int map(struct mm_id * mm_idp, unsigned long virt, void unmap(struct mm_id *mm_idp, unsigned long addr, unsigned long len);
unsigned long len, int prot, int phys_fd, void protect(struct mm_id *mm_idp, unsigned long addr,
unsigned long long offset, int done, void **data); unsigned long len, unsigned int prot);
extern int unmap(struct mm_id * mm_idp, unsigned long addr, unsigned long len,
int done, void **data);
extern int protect(struct mm_id * mm_idp, unsigned long addr,
unsigned long len, unsigned int prot, int done, void **data);
/* skas/process.c */ /* skas/process.c */
extern int is_skas_winch(int pid, int fd, void *data); extern int is_skas_winch(int pid, int fd, void *data);
......
...@@ -13,6 +13,7 @@ struct mm_id { ...@@ -13,6 +13,7 @@ struct mm_id {
} u; } u;
unsigned long stack; unsigned long stack;
int kill; int kill;
int syscall_data_len;
}; };
void __switch_mm(struct mm_id *mm_idp); void __switch_mm(struct mm_id *mm_idp);
......
...@@ -10,14 +10,45 @@ ...@@ -10,14 +10,45 @@
#include <linux/compiler_types.h> #include <linux/compiler_types.h>
#include <as-layout.h> #include <as-layout.h>
#include <sysdep/tls.h>
#define STUB_NEXT_SYSCALL(s) \
((struct stub_syscall *) (((unsigned long) s) + (s)->cmd_len))
enum stub_syscall_type {
STUB_SYSCALL_UNSET = 0,
STUB_SYSCALL_MMAP,
STUB_SYSCALL_MUNMAP,
STUB_SYSCALL_MPROTECT,
STUB_SYSCALL_LDT,
};
struct stub_syscall {
union {
struct {
unsigned long addr;
unsigned long length;
unsigned long offset;
int fd;
int prot;
} mem;
struct {
user_desc_t desc;
int func;
} ldt;
};
enum stub_syscall_type syscall;
};
struct stub_data { struct stub_data {
unsigned long offset; unsigned long offset;
int fd; int fd;
long parent_err, child_err; long err, child_err;
int syscall_data_len;
/* 128 leaves enough room for additional fields in the struct */ /* 128 leaves enough room for additional fields in the struct */
unsigned char syscall_data[UM_KERN_PAGE_SIZE - 128] __aligned(16); struct stub_syscall syscall_data[(UM_KERN_PAGE_SIZE - 128) / sizeof(struct stub_syscall)] __aligned(16);
/* Stack for our signal handlers and for calling into . */ /* Stack for our signal handlers and for calling into . */
unsigned char sigstack[UM_KERN_PAGE_SIZE] __aligned(UM_KERN_PAGE_SIZE); unsigned char sigstack[UM_KERN_PAGE_SIZE] __aligned(UM_KERN_PAGE_SIZE);
......
...@@ -42,11 +42,19 @@ extern void panic(const char *fmt, ...) ...@@ -42,11 +42,19 @@ extern void panic(const char *fmt, ...)
#define printk(...) _printk(__VA_ARGS__) #define printk(...) _printk(__VA_ARGS__)
extern int _printk(const char *fmt, ...) extern int _printk(const char *fmt, ...)
__attribute__ ((format (printf, 1, 2))); __attribute__ ((format (printf, 1, 2)));
extern void print_hex_dump(const char *level, const char *prefix_str,
int prefix_type, int rowsize, int groupsize,
const void *buf, size_t len, _Bool ascii);
#else #else
static inline int printk(const char *fmt, ...) static inline int printk(const char *fmt, ...)
{ {
return 0; return 0;
} }
static inline void print_hex_dump(const char *level, const char *prefix_str,
int prefix_type, int rowsize, int groupsize,
const void *buf, size_t len, _Bool ascii)
{
}
#endif #endif
extern int in_aton(char *str); extern int in_aton(char *str);
......
...@@ -22,15 +22,11 @@ ...@@ -22,15 +22,11 @@
void flush_thread(void) void flush_thread(void)
{ {
void *data = NULL;
int ret;
arch_flush_thread(&current->thread.arch); arch_flush_thread(&current->thread.arch);
ret = unmap(&current->mm->context.id, 0, TASK_SIZE, 1, &data); unmap(&current->mm->context.id, 0, TASK_SIZE);
if (ret) { if (syscall_stub_flush(&current->mm->context.id) < 0) {
printk(KERN_ERR "%s - clearing address space failed, err = %d\n", printk(KERN_ERR "%s - clearing address space failed", __func__);
__func__, ret);
force_sig(SIGKILL); force_sig(SIGKILL);
} }
get_safe_registers(current_pt_regs()->regs.gp, get_safe_registers(current_pt_regs()->regs.gp,
......
...@@ -3,14 +3,15 @@ ...@@ -3,14 +3,15 @@
# Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) # 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 -> # GCC hardened also auto-enables -fpic, but we need %ebx so it can't work ->
# disable it # disable it
CFLAGS_clone.o := $(CFLAGS_NO_HARDENING) 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 KCOV_INSTRUMENT := n
......
...@@ -33,7 +33,7 @@ stub_clone_handler(void) ...@@ -33,7 +33,7 @@ stub_clone_handler(void)
sizeof(data->syscall_data) / 2 - sizeof(data->syscall_data) / 2 -
sizeof(void *)); sizeof(void *));
if (err) { if (err) {
data->parent_err = err; data->err = err;
goto done; goto done;
} }
......
// 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();
}
...@@ -71,21 +71,19 @@ static int do_ops(struct host_vm_change *hvc, int end, ...@@ -71,21 +71,19 @@ static int do_ops(struct host_vm_change *hvc, int end,
switch (op->type) { switch (op->type) {
case MMAP: case MMAP:
if (hvc->userspace) if (hvc->userspace)
ret = map(&hvc->mm->context.id, op->u.mmap.addr, map(&hvc->mm->context.id, op->u.mmap.addr,
op->u.mmap.len, op->u.mmap.prot, op->u.mmap.len, op->u.mmap.prot,
op->u.mmap.fd, op->u.mmap.fd,
op->u.mmap.offset, finished, op->u.mmap.offset);
&hvc->data);
else else
map_memory(op->u.mmap.addr, op->u.mmap.offset, map_memory(op->u.mmap.addr, op->u.mmap.offset,
op->u.mmap.len, 1, 1, 1); op->u.mmap.len, 1, 1, 1);
break; break;
case MUNMAP: case MUNMAP:
if (hvc->userspace) if (hvc->userspace)
ret = unmap(&hvc->mm->context.id, unmap(&hvc->mm->context.id,
op->u.munmap.addr, op->u.munmap.addr,
op->u.munmap.len, finished, op->u.munmap.len);
&hvc->data);
else else
ret = os_unmap_memory( ret = os_unmap_memory(
(void *) op->u.munmap.addr, (void *) op->u.munmap.addr,
...@@ -94,11 +92,10 @@ static int do_ops(struct host_vm_change *hvc, int end, ...@@ -94,11 +92,10 @@ static int do_ops(struct host_vm_change *hvc, int end,
break; break;
case MPROTECT: case MPROTECT:
if (hvc->userspace) if (hvc->userspace)
ret = protect(&hvc->mm->context.id, protect(&hvc->mm->context.id,
op->u.mprotect.addr, op->u.mprotect.addr,
op->u.mprotect.len, op->u.mprotect.len,
op->u.mprotect.prot, op->u.mprotect.prot);
finished, &hvc->data);
else else
ret = os_protect_memory( ret = os_protect_memory(
(void *) op->u.mprotect.addr, (void *) op->u.mprotect.addr,
...@@ -113,6 +110,9 @@ static int do_ops(struct host_vm_change *hvc, int end, ...@@ -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) if (ret == -ENOMEM)
report_enomem(); report_enomem();
...@@ -461,7 +461,6 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long address) ...@@ -461,7 +461,6 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
pmd_t *pmd; pmd_t *pmd;
pte_t *pte; pte_t *pte;
struct mm_struct *mm = vma->vm_mm; struct mm_struct *mm = vma->vm_mm;
void *flush = NULL;
int r, w, x, prot, err = 0; int r, w, x, prot, err = 0;
struct mm_id *mm_id; struct mm_id *mm_id;
...@@ -504,14 +503,13 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long address) ...@@ -504,14 +503,13 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
int fd; int fd;
fd = phys_mapping(pte_val(*pte) & PAGE_MASK, &offset); fd = phys_mapping(pte_val(*pte) & PAGE_MASK, &offset);
err = map(mm_id, address, PAGE_SIZE, prot, fd, offset, map(mm_id, address, PAGE_SIZE, prot, fd, offset);
1, &flush); } else
} unmap(mm_id, address, PAGE_SIZE);
else err = unmap(mm_id, address, PAGE_SIZE, 1, &flush); } else if (pte_newprot(*pte))
} protect(mm_id, address, PAGE_SIZE, prot);
else if (pte_newprot(*pte))
err = protect(mm_id, address, PAGE_SIZE, prot, 1, &flush);
err = syscall_stub_flush(mm_id);
if (err) { if (err) {
if (err == -ENOMEM) if (err == -ENOMEM)
report_enomem(); report_enomem();
......
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
/* /*
* Copyright (C) 2021 Benjamin Berg <benjamin@sipsolutions.net>
* Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
*/ */
...@@ -19,7 +20,7 @@ ...@@ -19,7 +20,7 @@
#include <sysdep/stub.h> #include <sysdep/stub.h>
#include "../internal.h" #include "../internal.h"
extern char batch_syscall_stub[], __syscall_stub_start[]; extern char __syscall_stub_start[];
static inline unsigned long *check_init_stack(struct mm_id * mm_idp, static inline unsigned long *check_init_stack(struct mm_id * mm_idp,
unsigned long *stack) unsigned long *stack)
...@@ -36,22 +37,24 @@ static unsigned long syscall_regs[MAX_REG_NR]; ...@@ -36,22 +37,24 @@ static unsigned long syscall_regs[MAX_REG_NR];
static int __init init_syscall_regs(void) static int __init init_syscall_regs(void)
{ {
get_safe_registers(syscall_regs, NULL); get_safe_registers(syscall_regs, NULL);
syscall_regs[REGS_IP_INDEX] = STUB_CODE + syscall_regs[REGS_IP_INDEX] = STUB_CODE +
((unsigned long) batch_syscall_stub - ((unsigned long) stub_syscall_handler -
(unsigned long) __syscall_stub_start); (unsigned long) __syscall_stub_start);
syscall_regs[REGS_SP_INDEX] = STUB_DATA; syscall_regs[REGS_SP_INDEX] = STUB_DATA +
offsetof(struct stub_data, sigstack) +
sizeof(((struct stub_data *) 0)->sigstack) -
sizeof(void *);
return 0; return 0;
} }
__initcall(init_syscall_regs); __initcall(init_syscall_regs);
static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr) static inline long do_syscall_stub(struct mm_id *mm_idp)
{ {
struct stub_data *proc_data = (void *)mm_idp->stack;
int n, i; int n, i;
long ret, offset;
unsigned long * data;
unsigned long * syscall;
int err, pid = mm_idp->u.pid; int err, pid = mm_idp->u.pid;
n = ptrace_setregs(pid, syscall_regs); n = ptrace_setregs(pid, syscall_regs);
...@@ -63,6 +66,9 @@ static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr) ...@@ -63,6 +66,9 @@ static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr)
__func__, -n); __func__, -n);
} }
/* Inform process how much we have filled in. */
proc_data->syscall_data_len = mm_idp->syscall_data_len;
err = ptrace(PTRACE_CONT, pid, 0, 0); err = ptrace(PTRACE_CONT, pid, 0, 0);
if (err) if (err)
panic("Failed to continue stub, pid = %d, errno = %d\n", pid, panic("Failed to continue stub, pid = %d, errno = %d\n", pid,
...@@ -71,135 +77,113 @@ static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr) ...@@ -71,135 +77,113 @@ static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr)
wait_stub_done(pid); wait_stub_done(pid);
/* /*
* When the stub stops, we find the following values on the * proc_data->err will be non-zero if there was an (unexpected) error.
* beginning of the stack: * In that case, syscall_data_len points to the last executed syscall,
* (long )return_value * otherwise it will be zero (but we do not need to rely on that).
* (long )offset to failed sycall-data (0, if no error)
*/ */
ret = *((unsigned long *) mm_idp->stack); if (proc_data->err < 0) {
offset = *((unsigned long *) mm_idp->stack + 1); struct stub_syscall *sc;
if (offset) {
data = (unsigned long *)(mm_idp->stack + offset - STUB_DATA); if (proc_data->syscall_data_len < 0 ||
printk(UM_KERN_ERR "%s : ret = %ld, offset = %ld, data = %p\n", proc_data->syscall_data_len >= ARRAY_SIZE(proc_data->syscall_data))
__func__, ret, offset, data); panic("Syscall data was corrupted by stub (len is: %d, expected maximum: %d)!",
syscall = (unsigned long *)((unsigned long)data + data[0]); proc_data->syscall_data_len,
printk(UM_KERN_ERR "%s: syscall %ld failed, return value = 0x%lx, expected return value = 0x%lx\n", mm_idp->syscall_data_len);
__func__, syscall[0], ret, syscall[7]);
printk(UM_KERN_ERR " syscall parameters: 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n", sc = &proc_data->syscall_data[proc_data->syscall_data_len];
syscall[1], syscall[2], syscall[3],
syscall[4], syscall[5], syscall[6]); printk(UM_KERN_ERR "%s : length = %d, last offset = %d",
for (n = 1; n < data[0]/sizeof(long); n++) { __func__, mm_idp->syscall_data_len,
if (n == 1) proc_data->syscall_data_len);
printk(UM_KERN_ERR " additional syscall data:"); printk(UM_KERN_ERR "%s : stub syscall type %d failed, return value = 0x%lx\n",
if (n % 4 == 1) __func__, sc->syscall, proc_data->err);
printk("\n" UM_KERN_ERR " ");
printk(" 0x%lx", data[n]); print_hex_dump(UM_KERN_ERR,
} " syscall data: ", 0,
if (n > 1) 16, 4, sc, sizeof(*sc), 0);
printk("\n");
mm_idp->syscall_data_len = proc_data->err;
} else {
mm_idp->syscall_data_len = 0;
} }
else ret = 0;
*addr = check_init_stack(mm_idp, NULL);
return ret; return mm_idp->syscall_data_len;
} }
long run_syscall_stub(struct mm_id * mm_idp, int syscall, int syscall_stub_flush(struct mm_id *mm_idp)
unsigned long *args, long expected, void **addr,
int done)
{ {
unsigned long *stack = check_init_stack(mm_idp, *addr); int res;
*stack += sizeof(long); if (mm_idp->syscall_data_len == 0)
stack += *stack / sizeof(long);
*stack++ = syscall;
*stack++ = args[0];
*stack++ = args[1];
*stack++ = args[2];
*stack++ = args[3];
*stack++ = args[4];
*stack++ = args[5];
*stack++ = expected;
*stack = 0;
if (!done && ((((unsigned long) stack) & ~UM_KERN_PAGE_MASK) <
UM_KERN_PAGE_SIZE - 10 * sizeof(long))) {
*addr = stack;
return 0; return 0;
/* If an error happened already, report it and reset the state. */
if (mm_idp->syscall_data_len < 0) {
res = mm_idp->syscall_data_len;
mm_idp->syscall_data_len = 0;
return res;
} }
return do_syscall_stub(mm_idp, addr); res = do_syscall_stub(mm_idp);
mm_idp->syscall_data_len = 0;
return res;
} }
long syscall_stub_data(struct mm_id * mm_idp, struct stub_syscall *syscall_stub_alloc(struct mm_id *mm_idp)
unsigned long *data, int data_count,
void **addr, void **stub_addr)
{ {
unsigned long *stack; struct stub_syscall *sc;
int ret = 0; struct stub_data *proc_data = (struct stub_data *) mm_idp->stack;
/* if (mm_idp->syscall_data_len > 0 &&
* If *addr still is uninitialized, it *must* contain NULL. mm_idp->syscall_data_len == ARRAY_SIZE(proc_data->syscall_data))
* Thus in this case do_syscall_stub correctly won't be called. do_syscall_stub(mm_idp);
*/
if ((((unsigned long) *addr) & ~UM_KERN_PAGE_MASK) >= if (mm_idp->syscall_data_len < 0) {
UM_KERN_PAGE_SIZE - (10 + data_count) * sizeof(long)) { /* Return dummy to retain error state. */
ret = do_syscall_stub(mm_idp, addr); sc = &proc_data->syscall_data[0];
/* in case of error, don't overwrite data on stack */ } else {
if (ret) sc = &proc_data->syscall_data[mm_idp->syscall_data_len];
return ret; mm_idp->syscall_data_len += 1;
} }
memset(sc, 0, sizeof(*sc));
stack = check_init_stack(mm_idp, *addr); return sc;
*addr = stack;
*stack = data_count * sizeof(long);
memcpy(stack + 1, data, data_count * sizeof(long));
*stub_addr = (void *)(((unsigned long)(stack + 1) &
~UM_KERN_PAGE_MASK) + STUB_DATA);
return 0;
} }
int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len, int prot,
int phys_fd, unsigned long long offset, int done, void **data)
{
int ret;
unsigned long args[] = { virt, len, prot,
MAP_SHARED | MAP_FIXED, phys_fd,
MMAP_OFFSET(offset) };
ret = run_syscall_stub(mm_idp, STUB_MMAP_NR, args, virt, void map(struct mm_id *mm_idp, unsigned long virt, unsigned long len, int prot,
data, done); int phys_fd, unsigned long long offset)
{
return ret; struct stub_syscall *sc;
sc = syscall_stub_alloc(mm_idp);
sc->syscall = STUB_SYSCALL_MMAP;
sc->mem.addr = virt;
sc->mem.length = len;
sc->mem.prot = prot;
sc->mem.fd = phys_fd;
sc->mem.offset = MMAP_OFFSET(offset);
} }
int unmap(struct mm_id * mm_idp, unsigned long addr, unsigned long len, void unmap(struct mm_id *mm_idp, unsigned long addr, unsigned long len)
int done, void **data)
{ {
int ret; struct stub_syscall *sc;
unsigned long args[] = { (unsigned long) addr, len, 0, 0, 0,
0 };
ret = run_syscall_stub(mm_idp, __NR_munmap, args, 0, sc = syscall_stub_alloc(mm_idp);
data, done); sc->syscall = STUB_SYSCALL_MUNMAP;
sc->mem.addr = addr;
return ret; sc->mem.length = len;
} }
int protect(struct mm_id * mm_idp, unsigned long addr, unsigned long len, void protect(struct mm_id *mm_idp, unsigned long addr, unsigned long len,
unsigned int prot, int done, void **data) unsigned int prot)
{ {
int ret; struct stub_syscall *sc;
unsigned long args[] = { addr, len, prot, 0, 0, 0 };
ret = run_syscall_stub(mm_idp, __NR_mprotect, args, 0,
data, done);
return ret; sc = syscall_stub_alloc(mm_idp);
sc->syscall = STUB_SYSCALL_MPROTECT;
sc->mem.addr = addr;
sc->mem.length = len;
sc->mem.prot = prot;
} }
...@@ -501,7 +501,7 @@ int copy_context_skas0(unsigned long new_stack, int pid) ...@@ -501,7 +501,7 @@ int copy_context_skas0(unsigned long new_stack, int pid)
*data = ((struct stub_data) { *data = ((struct stub_data) {
.offset = MMAP_OFFSET(new_offset), .offset = MMAP_OFFSET(new_offset),
.fd = new_fd, .fd = new_fd,
.parent_err = -ESRCH, .err = -ESRCH,
.child_err = 0, .child_err = 0,
}); });
...@@ -538,7 +538,7 @@ int copy_context_skas0(unsigned long new_stack, int pid) ...@@ -538,7 +538,7 @@ int copy_context_skas0(unsigned long new_stack, int pid)
wait_stub_done(pid); wait_stub_done(pid);
pid = data->parent_err; pid = data->err;
if (pid < 0) { if (pid < 0) {
printk(UM_KERN_ERR "%s - stub-parent reports error %d\n", printk(UM_KERN_ERR "%s - stub-parent reports error %d\n",
__func__, -pid); __func__, -pid);
......
...@@ -11,7 +11,7 @@ endif ...@@ -11,7 +11,7 @@ endif
obj-y = bugs_$(BITS).o delay.o fault.o ldt.o \ obj-y = bugs_$(BITS).o delay.o fault.o ldt.o \
ptrace_$(BITS).o ptrace_user.o setjmp_$(BITS).o signal.o \ ptrace_$(BITS).o ptrace_user.o setjmp_$(BITS).o signal.o \
stub_$(BITS).o stub_segv.o \ stub_segv.o \
sys_call_table_$(BITS).o sysrq_$(BITS).o tls_$(BITS).o \ sys_call_table_$(BITS).o sysrq_$(BITS).o tls_$(BITS).o \
mem_$(BITS).o subarch.o os-Linux/ mem_$(BITS).o subarch.o os-Linux/
......
...@@ -12,33 +12,22 @@ ...@@ -12,33 +12,22 @@
#include <os.h> #include <os.h>
#include <skas.h> #include <skas.h>
#include <sysdep/tls.h> #include <sysdep/tls.h>
#include <stub-data.h>
static inline int modify_ldt (int func, void *ptr, unsigned long bytecount) static inline int modify_ldt (int func, void *ptr, unsigned long bytecount)
{ {
return syscall(__NR_modify_ldt, func, ptr, bytecount); return syscall(__NR_modify_ldt, func, ptr, bytecount);
} }
static long write_ldt_entry(struct mm_id *mm_idp, int func, static void write_ldt_entry(struct mm_id *mm_idp, int func,
struct user_desc *desc, void **addr, int done) struct user_desc *desc)
{ {
long res; struct stub_syscall *sc;
void *stub_addr;
BUILD_BUG_ON(sizeof(*desc) % sizeof(long));
res = syscall_stub_data(mm_idp, (unsigned long *)desc,
sizeof(*desc) / sizeof(long),
addr, &stub_addr);
if (!res) {
unsigned long args[] = { func,
(unsigned long)stub_addr,
sizeof(*desc),
0, 0, 0 };
res = run_syscall_stub(mm_idp, __NR_modify_ldt, args,
0, addr, done);
}
return res; sc = syscall_stub_alloc(mm_idp);
sc->syscall = STUB_SYSCALL_LDT;
sc->ldt.func = func;
memcpy(&sc->ldt.desc, desc, sizeof(*desc));
} }
/* /*
...@@ -127,7 +116,6 @@ static int write_ldt(void __user * ptr, unsigned long bytecount, int func) ...@@ -127,7 +116,6 @@ static int write_ldt(void __user * ptr, unsigned long bytecount, int func)
int i, err; int i, err;
struct user_desc ldt_info; struct user_desc ldt_info;
struct ldt_entry entry0, *ldt_p; struct ldt_entry entry0, *ldt_p;
void *addr = NULL;
err = -EINVAL; err = -EINVAL;
if (bytecount != sizeof(ldt_info)) if (bytecount != sizeof(ldt_info))
...@@ -148,7 +136,8 @@ static int write_ldt(void __user * ptr, unsigned long bytecount, int func) ...@@ -148,7 +136,8 @@ static int write_ldt(void __user * ptr, unsigned long bytecount, int func)
mutex_lock(&ldt->lock); mutex_lock(&ldt->lock);
err = write_ldt_entry(mm_idp, func, &ldt_info, &addr, 1); write_ldt_entry(mm_idp, func, &ldt_info);
err = syscall_stub_flush(mm_idp);
if (err) if (err)
goto out_unlock; goto out_unlock;
...@@ -166,7 +155,8 @@ static int write_ldt(void __user * ptr, unsigned long bytecount, int func) ...@@ -166,7 +155,8 @@ static int write_ldt(void __user * ptr, unsigned long bytecount, int func)
err = -ENOMEM; err = -ENOMEM;
/* Undo the change in host */ /* Undo the change in host */
memset(&ldt_info, 0, sizeof(ldt_info)); memset(&ldt_info, 0, sizeof(ldt_info));
write_ldt_entry(mm_idp, 1, &ldt_info, &addr, 1); write_ldt_entry(mm_idp, 1, &ldt_info);
err = syscall_stub_flush(mm_idp);
goto out_unlock; goto out_unlock;
} }
if (i == 0) { if (i == 0) {
...@@ -303,7 +293,6 @@ long init_new_ldt(struct mm_context *new_mm, struct mm_context *from_mm) ...@@ -303,7 +293,6 @@ long init_new_ldt(struct mm_context *new_mm, struct mm_context *from_mm)
short * num_p; short * num_p;
int i; int i;
long page, err=0; long page, err=0;
void *addr = NULL;
mutex_init(&new_mm->arch.ldt.lock); mutex_init(&new_mm->arch.ldt.lock);
...@@ -318,11 +307,9 @@ long init_new_ldt(struct mm_context *new_mm, struct mm_context *from_mm) ...@@ -318,11 +307,9 @@ long init_new_ldt(struct mm_context *new_mm, struct mm_context *from_mm)
ldt_get_host_info(); ldt_get_host_info();
for (num_p=host_ldt_entries; *num_p != -1; num_p++) { for (num_p=host_ldt_entries; *num_p != -1; num_p++) {
desc.entry_number = *num_p; desc.entry_number = *num_p;
err = write_ldt_entry(&new_mm->id, 1, &desc, write_ldt_entry(&new_mm->id, 1, &desc);
&addr, *(num_p + 1) == -1);
if (err)
break;
} }
err = syscall_stub_flush(&new_mm->id);
new_mm->arch.ldt.entry_count = 0; new_mm->arch.ldt.entry_count = 0;
goto out; goto out;
......
...@@ -12,4 +12,5 @@ ...@@ -12,4 +12,5 @@
#endif #endif
extern void stub_segv_handler(int, siginfo_t *, void *); extern void stub_segv_handler(int, siginfo_t *, void *);
extern void stub_syscall_handler(void);
extern void stub_clone_handler(void); extern void stub_clone_handler(void);
/* SPDX-License-Identifier: GPL-2.0 */
#include <as-layout.h>
.section .__syscall_stub, "ax"
.globl batch_syscall_stub
batch_syscall_stub:
/* %esp comes in as "top of page" */
mov %esp, %ecx
/* %esp has pointer to first operation */
add $8, %esp
again:
/* load length of additional data */
mov 0x0(%esp), %eax
/* if(length == 0) : end of list */
/* write possible 0 to header */
mov %eax, 0x4(%ecx)
cmpl $0, %eax
jz done
/* save current pointer */
mov %esp, 0x4(%ecx)
/* skip additional data */
add %eax, %esp
/* load syscall-# */
pop %eax
/* load syscall params */
pop %ebx
pop %ecx
pop %edx
pop %esi
pop %edi
pop %ebp
/* execute syscall */
int $0x80
/* restore top of page pointer in %ecx */
mov %esp, %ecx
andl $(~UM_KERN_PAGE_SIZE) + 1, %ecx
/* check return value */
pop %ebx
cmp %ebx, %eax
je again
done:
/* save return value */
mov %eax, (%ecx)
/* stop */
int3
/* SPDX-License-Identifier: GPL-2.0 */
#include <as-layout.h>
.section .__syscall_stub, "ax"
.globl batch_syscall_stub
batch_syscall_stub:
/* %rsp has the pointer to first operation */
mov %rsp, %rbx
add $0x10, %rsp
again:
/* load length of additional data */
mov 0x0(%rsp), %rax
/* if(length == 0) : end of list */
/* write possible 0 to header */
mov %rax, 8(%rbx)
cmp $0, %rax
jz done
/* save current pointer */
mov %rsp, 8(%rbx)
/* skip additional data */
add %rax, %rsp
/* load syscall-# */
pop %rax
/* load syscall params */
pop %rdi
pop %rsi
pop %rdx
pop %r10
pop %r8
pop %r9
/* execute syscall */
syscall
/* check return value */
pop %rcx
cmp %rcx, %rax
je again
done:
/* save return value */
mov %rax, (%rbx)
/* stop */
int3
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