diff options
author | Benjamin Berg <benjamin@sipsolutions.net> | 2024-07-03 15:45:28 +0200 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2024-07-03 17:09:49 +0200 |
commit | 76ed9158e1d474e963fc59da7a461b27a2212c5a (patch) | |
tree | 815dd1fd2568cdcc27d75178249cc809027ca80b /arch/um/kernel/skas/stub.c | |
parent | 542dc79f6ea601788704a79ff54283c2bea265e9 (diff) | |
download | linux-76ed9158e1d474e963fc59da7a461b27a2212c5a.tar.gz linux-76ed9158e1d474e963fc59da7a461b27a2212c5a.tar.bz2 linux-76ed9158e1d474e963fc59da7a461b27a2212c5a.zip |
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>
Diffstat (limited to 'arch/um/kernel/skas/stub.c')
-rw-r--r-- | arch/um/kernel/skas/stub.c | 80 |
1 files changed, 80 insertions, 0 deletions
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(); +} |