summaryrefslogtreecommitdiff
path: root/arch/um/kernel/skas/stub.c
diff options
context:
space:
mode:
authorBenjamin Berg <benjamin@sipsolutions.net>2024-07-03 15:45:28 +0200
committerJohannes Berg <johannes.berg@intel.com>2024-07-03 17:09:49 +0200
commit76ed9158e1d474e963fc59da7a461b27a2212c5a (patch)
tree815dd1fd2568cdcc27d75178249cc809027ca80b /arch/um/kernel/skas/stub.c
parent542dc79f6ea601788704a79ff54283c2bea265e9 (diff)
downloadlinux-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.c80
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();
+}