// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2021 Benjamin Berg */ #include 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(); }