1*76ed9158SBenjamin Berg // SPDX-License-Identifier: GPL-2.0 2*76ed9158SBenjamin Berg /* 3*76ed9158SBenjamin Berg * Copyright (C) 2021 Benjamin Berg <benjamin@sipsolutions.net> 4*76ed9158SBenjamin Berg */ 5*76ed9158SBenjamin Berg 6*76ed9158SBenjamin Berg #include <sysdep/stub.h> 7*76ed9158SBenjamin Berg 8*76ed9158SBenjamin Berg static __always_inline int syscall_handler(struct stub_data *d) 9*76ed9158SBenjamin Berg { 10*76ed9158SBenjamin Berg int i; 11*76ed9158SBenjamin Berg unsigned long res; 12*76ed9158SBenjamin Berg 13*76ed9158SBenjamin Berg for (i = 0; i < d->syscall_data_len; i++) { 14*76ed9158SBenjamin Berg struct stub_syscall *sc = &d->syscall_data[i]; 15*76ed9158SBenjamin Berg 16*76ed9158SBenjamin Berg switch (sc->syscall) { 17*76ed9158SBenjamin Berg case STUB_SYSCALL_MMAP: 18*76ed9158SBenjamin Berg res = stub_syscall6(STUB_MMAP_NR, 19*76ed9158SBenjamin Berg sc->mem.addr, sc->mem.length, 20*76ed9158SBenjamin Berg sc->mem.prot, 21*76ed9158SBenjamin Berg MAP_SHARED | MAP_FIXED, 22*76ed9158SBenjamin Berg sc->mem.fd, sc->mem.offset); 23*76ed9158SBenjamin Berg if (res != sc->mem.addr) { 24*76ed9158SBenjamin Berg d->err = res; 25*76ed9158SBenjamin Berg d->syscall_data_len = i; 26*76ed9158SBenjamin Berg return -1; 27*76ed9158SBenjamin Berg } 28*76ed9158SBenjamin Berg break; 29*76ed9158SBenjamin Berg case STUB_SYSCALL_MUNMAP: 30*76ed9158SBenjamin Berg res = stub_syscall2(__NR_munmap, 31*76ed9158SBenjamin Berg sc->mem.addr, sc->mem.length); 32*76ed9158SBenjamin Berg if (res) { 33*76ed9158SBenjamin Berg d->err = res; 34*76ed9158SBenjamin Berg d->syscall_data_len = i; 35*76ed9158SBenjamin Berg return -1; 36*76ed9158SBenjamin Berg } 37*76ed9158SBenjamin Berg break; 38*76ed9158SBenjamin Berg case STUB_SYSCALL_MPROTECT: 39*76ed9158SBenjamin Berg res = stub_syscall3(__NR_mprotect, 40*76ed9158SBenjamin Berg sc->mem.addr, sc->mem.length, 41*76ed9158SBenjamin Berg sc->mem.prot); 42*76ed9158SBenjamin Berg if (res) { 43*76ed9158SBenjamin Berg d->err = res; 44*76ed9158SBenjamin Berg d->syscall_data_len = i; 45*76ed9158SBenjamin Berg return -1; 46*76ed9158SBenjamin Berg } 47*76ed9158SBenjamin Berg break; 48*76ed9158SBenjamin Berg case STUB_SYSCALL_LDT: 49*76ed9158SBenjamin Berg res = stub_syscall3(__NR_modify_ldt, sc->ldt.func, 50*76ed9158SBenjamin Berg (unsigned long) &sc->ldt.desc, 51*76ed9158SBenjamin Berg sizeof(sc->ldt.desc)); 52*76ed9158SBenjamin Berg /* We only write, so the expected result is zero */ 53*76ed9158SBenjamin Berg if (res) { 54*76ed9158SBenjamin Berg d->err = res; 55*76ed9158SBenjamin Berg d->syscall_data_len = i; 56*76ed9158SBenjamin Berg return -1; 57*76ed9158SBenjamin Berg } 58*76ed9158SBenjamin Berg break; 59*76ed9158SBenjamin Berg default: 60*76ed9158SBenjamin Berg d->err = -95; /* EOPNOTSUPP */ 61*76ed9158SBenjamin Berg d->syscall_data_len = i; 62*76ed9158SBenjamin Berg return -1; 63*76ed9158SBenjamin Berg } 64*76ed9158SBenjamin Berg } 65*76ed9158SBenjamin Berg 66*76ed9158SBenjamin Berg d->err = 0; 67*76ed9158SBenjamin Berg d->syscall_data_len = 0; 68*76ed9158SBenjamin Berg 69*76ed9158SBenjamin Berg return 0; 70*76ed9158SBenjamin Berg } 71*76ed9158SBenjamin Berg 72*76ed9158SBenjamin Berg void __section(".__syscall_stub") 73*76ed9158SBenjamin Berg stub_syscall_handler(void) 74*76ed9158SBenjamin Berg { 75*76ed9158SBenjamin Berg struct stub_data *d = get_stub_data(); 76*76ed9158SBenjamin Berg 77*76ed9158SBenjamin Berg syscall_handler(d); 78*76ed9158SBenjamin Berg 79*76ed9158SBenjamin Berg trap_myself(); 80*76ed9158SBenjamin Berg } 81