mirror of
https://github.com/torvalds/linux.git
synced 2024-11-25 21:51:40 +00:00
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: Benjamin Berg <benjamin@sipsolutions.net> Link: https://patch.msgid.link/20240703134536.1161108-5-benjamin@sipsolutions.net Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
542dc79f6e
commit
76ed9158e1
@ -272,19 +272,15 @@ extern long long os_persistent_clock_emulation(void);
|
||||
extern long long os_nsecs(void);
|
||||
|
||||
/* skas/mem.c */
|
||||
extern long run_syscall_stub(struct mm_id * mm_idp,
|
||||
int syscall, unsigned long *args, long expected,
|
||||
void **addr, int done);
|
||||
extern long syscall_stub_data(struct mm_id * mm_idp,
|
||||
unsigned long *data, int data_count,
|
||||
void **addr, void **stub_addr);
|
||||
extern 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);
|
||||
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);
|
||||
int syscall_stub_flush(struct mm_id *mm_idp);
|
||||
struct stub_syscall *syscall_stub_alloc(struct mm_id *mm_idp);
|
||||
|
||||
void map(struct mm_id *mm_idp, unsigned long virt,
|
||||
unsigned long len, int prot, int phys_fd,
|
||||
unsigned long long offset);
|
||||
void unmap(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);
|
||||
|
||||
/* skas/process.c */
|
||||
extern int is_skas_winch(int pid, int fd, void *data);
|
||||
|
@ -13,6 +13,7 @@ struct mm_id {
|
||||
} u;
|
||||
unsigned long stack;
|
||||
int kill;
|
||||
int syscall_data_len;
|
||||
};
|
||||
|
||||
void __switch_mm(struct mm_id *mm_idp);
|
||||
|
@ -10,14 +10,45 @@
|
||||
|
||||
#include <linux/compiler_types.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 {
|
||||
unsigned long offset;
|
||||
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 */
|
||||
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 . */
|
||||
unsigned char sigstack[UM_KERN_PAGE_SIZE] __aligned(UM_KERN_PAGE_SIZE);
|
||||
|
@ -42,11 +42,19 @@ extern void panic(const char *fmt, ...)
|
||||
#define printk(...) _printk(__VA_ARGS__)
|
||||
extern int _printk(const char *fmt, ...)
|
||||
__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
|
||||
static inline int printk(const char *fmt, ...)
|
||||
{
|
||||
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
|
||||
|
||||
extern int in_aton(char *str);
|
||||
|
@ -22,15 +22,11 @@
|
||||
|
||||
void flush_thread(void)
|
||||
{
|
||||
void *data = NULL;
|
||||
int ret;
|
||||
|
||||
arch_flush_thread(¤t->thread.arch);
|
||||
|
||||
ret = unmap(¤t->mm->context.id, 0, TASK_SIZE, 1, &data);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "%s - clearing address space failed, err = %d\n",
|
||||
__func__, ret);
|
||||
unmap(¤t->mm->context.id, 0, TASK_SIZE);
|
||||
if (syscall_stub_flush(¤t->mm->context.id) < 0) {
|
||||
printk(KERN_ERR "%s - clearing address space failed", __func__);
|
||||
force_sig(SIGKILL);
|
||||
}
|
||||
get_safe_registers(current_pt_regs()->regs.gp,
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
80
arch/um/kernel/skas/stub.c
Normal file
80
arch/um/kernel/skas/stub.c
Normal file
@ -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();
|
||||
}
|
@ -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();
|
||||
|
@ -1,5 +1,6 @@
|
||||
// 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)
|
||||
*/
|
||||
|
||||
@ -19,7 +20,7 @@
|
||||
#include <sysdep/stub.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,
|
||||
unsigned long *stack)
|
||||
@ -36,22 +37,24 @@ static unsigned long syscall_regs[MAX_REG_NR];
|
||||
static int __init init_syscall_regs(void)
|
||||
{
|
||||
get_safe_registers(syscall_regs, NULL);
|
||||
|
||||
syscall_regs[REGS_IP_INDEX] = STUB_CODE +
|
||||
((unsigned long) batch_syscall_stub -
|
||||
((unsigned long) stub_syscall_handler -
|
||||
(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;
|
||||
}
|
||||
|
||||
__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;
|
||||
long ret, offset;
|
||||
unsigned long * data;
|
||||
unsigned long * syscall;
|
||||
int err, pid = mm_idp->u.pid;
|
||||
|
||||
n = ptrace_setregs(pid, syscall_regs);
|
||||
@ -63,6 +66,9 @@ static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr)
|
||||
__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);
|
||||
if (err)
|
||||
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)
|
||||
wait_stub_done(pid);
|
||||
|
||||
/*
|
||||
* When the stub stops, we find the following values on the
|
||||
* beginning of the stack:
|
||||
* (long )return_value
|
||||
* (long )offset to failed sycall-data (0, if no error)
|
||||
* proc_data->err will be non-zero if there was an (unexpected) error.
|
||||
* In that case, syscall_data_len points to the last executed syscall,
|
||||
* otherwise it will be zero (but we do not need to rely on that).
|
||||
*/
|
||||
ret = *((unsigned long *) mm_idp->stack);
|
||||
offset = *((unsigned long *) mm_idp->stack + 1);
|
||||
if (offset) {
|
||||
data = (unsigned long *)(mm_idp->stack + offset - STUB_DATA);
|
||||
printk(UM_KERN_ERR "%s : ret = %ld, offset = %ld, data = %p\n",
|
||||
__func__, ret, offset, data);
|
||||
syscall = (unsigned long *)((unsigned long)data + data[0]);
|
||||
printk(UM_KERN_ERR "%s: syscall %ld failed, return value = 0x%lx, expected return value = 0x%lx\n",
|
||||
__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",
|
||||
syscall[1], syscall[2], syscall[3],
|
||||
syscall[4], syscall[5], syscall[6]);
|
||||
for (n = 1; n < data[0]/sizeof(long); n++) {
|
||||
if (n == 1)
|
||||
printk(UM_KERN_ERR " additional syscall data:");
|
||||
if (n % 4 == 1)
|
||||
printk("\n" UM_KERN_ERR " ");
|
||||
printk(" 0x%lx", data[n]);
|
||||
}
|
||||
if (n > 1)
|
||||
printk("\n");
|
||||
if (proc_data->err < 0) {
|
||||
struct stub_syscall *sc;
|
||||
|
||||
if (proc_data->syscall_data_len < 0 ||
|
||||
proc_data->syscall_data_len >= ARRAY_SIZE(proc_data->syscall_data))
|
||||
panic("Syscall data was corrupted by stub (len is: %d, expected maximum: %d)!",
|
||||
proc_data->syscall_data_len,
|
||||
mm_idp->syscall_data_len);
|
||||
|
||||
sc = &proc_data->syscall_data[proc_data->syscall_data_len];
|
||||
|
||||
printk(UM_KERN_ERR "%s : length = %d, last offset = %d",
|
||||
__func__, mm_idp->syscall_data_len,
|
||||
proc_data->syscall_data_len);
|
||||
printk(UM_KERN_ERR "%s : stub syscall type %d failed, return value = 0x%lx\n",
|
||||
__func__, sc->syscall, proc_data->err);
|
||||
|
||||
print_hex_dump(UM_KERN_ERR,
|
||||
" syscall data: ", 0,
|
||||
16, 4, sc, sizeof(*sc), 0);
|
||||
|
||||
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,
|
||||
unsigned long *args, long expected, void **addr,
|
||||
int done)
|
||||
int syscall_stub_flush(struct mm_id *mm_idp)
|
||||
{
|
||||
unsigned long *stack = check_init_stack(mm_idp, *addr);
|
||||
int res;
|
||||
|
||||
*stack += sizeof(long);
|
||||
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;
|
||||
if (mm_idp->syscall_data_len == 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,
|
||||
unsigned long *data, int data_count,
|
||||
void **addr, void **stub_addr)
|
||||
struct stub_syscall *syscall_stub_alloc(struct mm_id *mm_idp)
|
||||
{
|
||||
unsigned long *stack;
|
||||
int ret = 0;
|
||||
struct stub_syscall *sc;
|
||||
struct stub_data *proc_data = (struct stub_data *) mm_idp->stack;
|
||||
|
||||
/*
|
||||
* If *addr still is uninitialized, it *must* contain NULL.
|
||||
* Thus in this case do_syscall_stub correctly won't be called.
|
||||
*/
|
||||
if ((((unsigned long) *addr) & ~UM_KERN_PAGE_MASK) >=
|
||||
UM_KERN_PAGE_SIZE - (10 + data_count) * sizeof(long)) {
|
||||
ret = do_syscall_stub(mm_idp, addr);
|
||||
/* in case of error, don't overwrite data on stack */
|
||||
if (ret)
|
||||
return ret;
|
||||
if (mm_idp->syscall_data_len > 0 &&
|
||||
mm_idp->syscall_data_len == ARRAY_SIZE(proc_data->syscall_data))
|
||||
do_syscall_stub(mm_idp);
|
||||
|
||||
if (mm_idp->syscall_data_len < 0) {
|
||||
/* Return dummy to retain error state. */
|
||||
sc = &proc_data->syscall_data[0];
|
||||
} else {
|
||||
sc = &proc_data->syscall_data[mm_idp->syscall_data_len];
|
||||
mm_idp->syscall_data_len += 1;
|
||||
}
|
||||
memset(sc, 0, sizeof(*sc));
|
||||
|
||||
stack = check_init_stack(mm_idp, *addr);
|
||||
*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;
|
||||
return sc;
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
void map(struct mm_id *mm_idp, unsigned long virt, unsigned long len, int prot,
|
||||
int phys_fd, unsigned long long offset)
|
||||
{
|
||||
int ret;
|
||||
unsigned long args[] = { virt, len, prot,
|
||||
MAP_SHARED | MAP_FIXED, phys_fd,
|
||||
MMAP_OFFSET(offset) };
|
||||
struct stub_syscall *sc;
|
||||
|
||||
ret = run_syscall_stub(mm_idp, STUB_MMAP_NR, args, virt,
|
||||
data, done);
|
||||
|
||||
return ret;
|
||||
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,
|
||||
int done, void **data)
|
||||
void unmap(struct mm_id *mm_idp, unsigned long addr, unsigned long len)
|
||||
{
|
||||
int ret;
|
||||
unsigned long args[] = { (unsigned long) addr, len, 0, 0, 0,
|
||||
0 };
|
||||
struct stub_syscall *sc;
|
||||
|
||||
ret = run_syscall_stub(mm_idp, __NR_munmap, args, 0,
|
||||
data, done);
|
||||
|
||||
return ret;
|
||||
sc = syscall_stub_alloc(mm_idp);
|
||||
sc->syscall = STUB_SYSCALL_MUNMAP;
|
||||
sc->mem.addr = addr;
|
||||
sc->mem.length = len;
|
||||
}
|
||||
|
||||
int protect(struct mm_id * mm_idp, unsigned long addr, unsigned long len,
|
||||
unsigned int prot, int done, void **data)
|
||||
void protect(struct mm_id *mm_idp, unsigned long addr, unsigned long len,
|
||||
unsigned int prot)
|
||||
{
|
||||
int ret;
|
||||
unsigned long args[] = { addr, len, prot, 0, 0, 0 };
|
||||
struct stub_syscall *sc;
|
||||
|
||||
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)
|
||||
*data = ((struct stub_data) {
|
||||
.offset = MMAP_OFFSET(new_offset),
|
||||
.fd = new_fd,
|
||||
.parent_err = -ESRCH,
|
||||
.err = -ESRCH,
|
||||
.child_err = 0,
|
||||
});
|
||||
|
||||
@ -538,7 +538,7 @@ int copy_context_skas0(unsigned long new_stack, int pid)
|
||||
|
||||
wait_stub_done(pid);
|
||||
|
||||
pid = data->parent_err;
|
||||
pid = data->err;
|
||||
if (pid < 0) {
|
||||
printk(UM_KERN_ERR "%s - stub-parent reports error %d\n",
|
||||
__func__, -pid);
|
||||
|
@ -11,7 +11,7 @@ endif
|
||||
|
||||
obj-y = bugs_$(BITS).o delay.o fault.o ldt.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 \
|
||||
mem_$(BITS).o subarch.o os-Linux/
|
||||
|
||||
|
@ -12,33 +12,22 @@
|
||||
#include <os.h>
|
||||
#include <skas.h>
|
||||
#include <sysdep/tls.h>
|
||||
#include <stub-data.h>
|
||||
|
||||
static inline int modify_ldt (int func, void *ptr, unsigned long bytecount)
|
||||
{
|
||||
return syscall(__NR_modify_ldt, func, ptr, bytecount);
|
||||
}
|
||||
|
||||
static long write_ldt_entry(struct mm_id *mm_idp, int func,
|
||||
struct user_desc *desc, void **addr, int done)
|
||||
static void write_ldt_entry(struct mm_id *mm_idp, int func,
|
||||
struct user_desc *desc)
|
||||
{
|
||||
long res;
|
||||
void *stub_addr;
|
||||
struct stub_syscall *sc;
|
||||
|
||||
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)
|
||||
int i, err;
|
||||
struct user_desc ldt_info;
|
||||
struct ldt_entry entry0, *ldt_p;
|
||||
void *addr = NULL;
|
||||
|
||||
err = -EINVAL;
|
||||
if (bytecount != sizeof(ldt_info))
|
||||
@ -148,7 +136,8 @@ static int write_ldt(void __user * ptr, unsigned long bytecount, int func)
|
||||
|
||||
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)
|
||||
goto out_unlock;
|
||||
|
||||
@ -166,7 +155,8 @@ static int write_ldt(void __user * ptr, unsigned long bytecount, int func)
|
||||
err = -ENOMEM;
|
||||
/* Undo the change in host */
|
||||
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;
|
||||
}
|
||||
if (i == 0) {
|
||||
@ -303,7 +293,6 @@ long init_new_ldt(struct mm_context *new_mm, struct mm_context *from_mm)
|
||||
short * num_p;
|
||||
int i;
|
||||
long page, err=0;
|
||||
void *addr = NULL;
|
||||
|
||||
|
||||
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)
|
||||
ldt_get_host_info();
|
||||
for (num_p=host_ldt_entries; *num_p != -1; num_p++) {
|
||||
desc.entry_number = *num_p;
|
||||
err = write_ldt_entry(&new_mm->id, 1, &desc,
|
||||
&addr, *(num_p + 1) == -1);
|
||||
if (err)
|
||||
break;
|
||||
write_ldt_entry(&new_mm->id, 1, &desc);
|
||||
}
|
||||
err = syscall_stub_flush(&new_mm->id);
|
||||
new_mm->arch.ldt.entry_count = 0;
|
||||
|
||||
goto out;
|
||||
|
@ -12,4 +12,5 @@
|
||||
#endif
|
||||
|
||||
extern void stub_segv_handler(int, siginfo_t *, void *);
|
||||
extern void stub_syscall_handler(void);
|
||||
extern void stub_clone_handler(void);
|
||||
|
@ -1,56 +0,0 @@
|
||||
/* 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
|
@ -1,50 +0,0 @@
|
||||
/* 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
|
Loading…
Reference in New Issue
Block a user