Compare commits
No commits in common. "fb5508e36954194c9924ef5a255b07ad1da2b5ac" and "b2cf446e9dd5593c388c1f244c527741070f7a26" have entirely different histories.
fb5508e369
...
b2cf446e9d
@ -1,7 +1,7 @@
|
|||||||
cmake_minimum_required(VERSION 3.17.0)
|
cmake_minimum_required(VERSION 3.17.0)
|
||||||
|
|
||||||
# Start Project
|
# Start Project
|
||||||
project(runtime)
|
project(trampoline)
|
||||||
|
|
||||||
# Headers
|
# Headers
|
||||||
add_library(trampoline-headers INTERFACE)
|
add_library(trampoline-headers INTERFACE)
|
||||||
@ -11,23 +11,21 @@ target_include_directories(trampoline-headers INTERFACE include)
|
|||||||
if(NOT TRAMPOLINE_HEADERS_ONLY)
|
if(NOT TRAMPOLINE_HEADERS_ONLY)
|
||||||
# Check Architecture
|
# Check Architecture
|
||||||
include(CheckSymbolExists)
|
include(CheckSymbolExists)
|
||||||
check_symbol_exists("__aarch64__" "" USE_NATIVE_RUNTIME)
|
check_symbol_exists("__aarch64__" "" USE_NATIVE_TRAMPOLINE)
|
||||||
check_symbol_exists("__x86_64__" "" USE_QEMU_RUNTIME)
|
check_symbol_exists("__x86_64__" "" USE_QEMU_TRAMPOLINE)
|
||||||
|
|
||||||
# Include Correct Sub-Project
|
# Include Correct Sub-Project
|
||||||
set(RUNTIME_RPATH "$ORIGIN/../lib/native")
|
if(USE_NATIVE_TRAMPOLINE)
|
||||||
set(RUNTIME_EXTRA_LINK_FLAG "--disable-new-dtags")
|
|
||||||
target_compile_definitions(trampoline-headers INTERFACE MCPI_BUILD_RUNTIME)
|
|
||||||
if(USE_NATIVE_RUNTIME)
|
|
||||||
add_subdirectory(native)
|
add_subdirectory(native)
|
||||||
elseif(USE_QEMU_RUNTIME)
|
target_compile_definitions(trampoline-headers INTERFACE MCPI_USE_NATIVE_TRAMPOLINE)
|
||||||
|
elseif(USE_QEMU_TRAMPOLINE)
|
||||||
add_subdirectory(qemu)
|
add_subdirectory(qemu)
|
||||||
target_compile_definitions(trampoline-headers INTERFACE MCPI_RUNTIME_IS_QEMU)
|
target_compile_definitions(trampoline-headers INTERFACE MCPI_USE_QEMU)
|
||||||
else()
|
else()
|
||||||
message(FATAL_ERROR "Unsupported Architecture")
|
message(FATAL_ERROR "Unsupported Architecture")
|
||||||
endif()
|
endif()
|
||||||
else()
|
else()
|
||||||
# No-Op Install Function
|
# No-Op Install Function
|
||||||
function(install_runtime)
|
function(install_trampoline)
|
||||||
endfunction()
|
endfunction()
|
||||||
endif()
|
endif()
|
19
README.md
19
README.md
@ -1,19 +0,0 @@
|
|||||||
# MCPI Runtime
|
|
||||||
**Fact:** MCPI is a 32-bit ARM binary.
|
|
||||||
|
|
||||||
**Another fact:** Most modern computers do not use 32-bit ARM and therefore cannot run MCPI natively.
|
|
||||||
|
|
||||||
**Solution:** This project allows MCPI to run on modern computers.
|
|
||||||
|
|
||||||
## How
|
|
||||||
This project works differently depending on the host system's architecture.
|
|
||||||
|
|
||||||
### 64-Bit x86 Host
|
|
||||||
On this platform, a patched version of QEMU is used.
|
|
||||||
|
|
||||||
QEMU emulates ARM code so MCPI can run on x86 hardware. And the patch adds a system-call which allows MCPI to run graphics code on the host. This prevents the need for emulated GPU drivers.
|
|
||||||
|
|
||||||
### 64-Bit ARM Host
|
|
||||||
QEMU is not necessary on this platform because it can already run 32-bit ARM code natively.
|
|
||||||
|
|
||||||
Instead, the runtime is implemented as two processes: a parent and a child. The child becomes MCPI and can send graphics commands to the parent. And because the parent is 64-bit, 32-bit drivers are not needed.
|
|
@ -2,21 +2,26 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
// Maximum Arguments Length
|
// Switch Between Pipe?PTrace Mode
|
||||||
#define MAX_TRAMPOLINE_ARGS_SIZE 2097152 // 2 MiB
|
#ifdef MCPI_USE_NATIVE_TRAMPOLINE
|
||||||
|
#define TRAMPOLINE_USE_PTRACE_ENV "_MCPI_TRAMPOLINE_USE_PTRACE"
|
||||||
|
#endif
|
||||||
|
|
||||||
// System Call Constants
|
// System Call Constants
|
||||||
|
#define MAX_TRAMPOLINE_ARGS_SIZE 2097152 // 2 MiB
|
||||||
#define TRAMPOLINE_SYSCALL 0x1337
|
#define TRAMPOLINE_SYSCALL 0x1337
|
||||||
|
|
||||||
// Pipe Constants
|
// Pipe Constants
|
||||||
|
#ifdef MCPI_USE_NATIVE_TRAMPOLINE
|
||||||
#define TRAMPOLINE_ARGUMENTS_PIPE_ENV "_MCPI_TRAMPOLINE_ARGUMENTS"
|
#define TRAMPOLINE_ARGUMENTS_PIPE_ENV "_MCPI_TRAMPOLINE_ARGUMENTS"
|
||||||
#define TRAMPOLINE_RETURN_VALUE_PIPE_ENV "_MCPI_TRAMPOLINE_RETURN_VALUE"
|
#define TRAMPOLINE_RETURN_VALUE_PIPE_ENV "_MCPI_TRAMPOLINE_RETURN_VALUE"
|
||||||
struct trampoline_pipe_arguments {
|
struct trampoline_pipe_arguments {
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
uint32_t allow_early_return;
|
|
||||||
uint32_t length;
|
uint32_t length;
|
||||||
|
uint32_t args_addr;
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
// Function Types
|
// Function Types
|
||||||
typedef void (*trampoline_writer_t)(uint32_t guest_addr, const void *data, uint32_t size);
|
typedef void (*trampoline_writer_t)(uint32_t guest_addr, void *data, uint32_t size);
|
||||||
typedef uint32_t (*trampoline_t)(trampoline_writer_t writer, uint32_t id, const unsigned char *args);
|
typedef uint32_t (*trampoline_t)(trampoline_writer_t writer, uint32_t id, const unsigned char *args);
|
@ -1,25 +1,27 @@
|
|||||||
project(native-runtime)
|
project(native-trampoline)
|
||||||
|
|
||||||
# Build
|
# Build
|
||||||
add_executable(runtime
|
add_executable(trampoline
|
||||||
src/memory.cpp
|
src/memory.cpp
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
src/trampoline.cpp
|
src/trampoline.cpp
|
||||||
src/pipe.cpp
|
src/ptrace/loop.cpp
|
||||||
|
src/ptrace/init.cpp
|
||||||
|
src/pipe/pipe.cpp
|
||||||
src/signals.cpp
|
src/signals.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
# Warnings
|
# Warnings
|
||||||
target_compile_options(runtime PRIVATE -Wall -Wextra -Werror -Wpointer-arith -Wshadow -Wnull-dereference)
|
target_compile_options(trampoline PRIVATE -Wall -Wextra -Werror -Wpointer-arith -Wshadow -Wnull-dereference)
|
||||||
|
|
||||||
# Link
|
# Link
|
||||||
target_link_libraries(runtime dl rt trampoline-headers)
|
target_link_libraries(trampoline dl trampoline-headers)
|
||||||
|
|
||||||
# RPath
|
# RPath
|
||||||
set_target_properties(runtime PROPERTIES INSTALL_RPATH "${RUNTIME_RPATH}")
|
set_target_properties(trampoline PROPERTIES INSTALL_RPATH "$ORIGIN/../lib/native")
|
||||||
target_link_options(runtime PRIVATE "LINKER:${RUNTIME_EXTRA_LINK_FLAG}")
|
target_link_options(trampoline PRIVATE "LINKER:--disable-new-dtags")
|
||||||
|
|
||||||
# Install
|
# Install
|
||||||
function(install_runtime bin_dir)
|
function(install_trampoline bin_dir)
|
||||||
install(TARGETS runtime DESTINATION "${bin_dir}")
|
install(TARGETS trampoline DESTINATION "${bin_dir}")
|
||||||
endfunction()
|
endfunction()
|
||||||
|
@ -5,6 +5,6 @@
|
|||||||
|
|
||||||
#define ERR(format, ...) \
|
#define ERR(format, ...) \
|
||||||
{ \
|
{ \
|
||||||
fprintf(stderr, "RUNTIME ERROR: " format "\n", ##__VA_ARGS__); \
|
fprintf(stderr, "TRAMPOLINE ERROR: " format "\n", ##__VA_ARGS__); \
|
||||||
exit(EXIT_FAILURE); \
|
exit(EXIT_FAILURE); \
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,12 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <sys/prctl.h>
|
|
||||||
|
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "trampoline.h"
|
#include "trampoline.h"
|
||||||
#include "pipe.h"
|
#include "ptrace/ptrace.h"
|
||||||
|
#include "pipe/pipe.h"
|
||||||
#include "signals.h"
|
#include "signals.h"
|
||||||
|
|
||||||
// Main
|
// Main
|
||||||
@ -16,8 +16,11 @@ int main(__attribute__((unused)) int argc, char *argv[]) {
|
|||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
ERR("Invalid Arguments");
|
ERR("Invalid Arguments");
|
||||||
}
|
}
|
||||||
|
bool use_ptrace = getenv(TRAMPOLINE_USE_PTRACE_ENV) != nullptr;
|
||||||
// Setup
|
// Setup
|
||||||
init_pipe_common();
|
if (!use_ptrace) {
|
||||||
|
init_pipe_common();
|
||||||
|
}
|
||||||
// Fork
|
// Fork
|
||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
if (pid == -1) {
|
if (pid == -1) {
|
||||||
@ -25,9 +28,11 @@ int main(__attribute__((unused)) int argc, char *argv[]) {
|
|||||||
} else if (pid == 0) {
|
} else if (pid == 0) {
|
||||||
// Setup
|
// Setup
|
||||||
setpgid(0, 0);
|
setpgid(0, 0);
|
||||||
init_pipe_guest();
|
if (use_ptrace) {
|
||||||
// Kill Child If Parent Exits First
|
init_ptrace_guest();
|
||||||
prctl(PR_SET_PDEATHSIG, SIGKILL);
|
} else {
|
||||||
|
init_pipe_guest();
|
||||||
|
}
|
||||||
// Execute Program
|
// Execute Program
|
||||||
execvp(argv[1], (char *const *) &argv[1]);
|
execvp(argv[1], (char *const *) &argv[1]);
|
||||||
ERR("Unable To Execute Program: %s: %s", argv[1], strerror(errno));
|
ERR("Unable To Execute Program: %s: %s", argv[1], strerror(errno));
|
||||||
@ -39,7 +44,11 @@ int main(__attribute__((unused)) int argc, char *argv[]) {
|
|||||||
init_memory(pid);
|
init_memory(pid);
|
||||||
init_trampoline();
|
init_trampoline();
|
||||||
|
|
||||||
// Start Pipes
|
// Start PTrace
|
||||||
init_pipe_host(pid);
|
if (use_ptrace) {
|
||||||
|
init_ptrace_host(pid);
|
||||||
|
} else {
|
||||||
|
init_pipe_host(pid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,19 +5,38 @@
|
|||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
// Read/Write Memory
|
// Store PID
|
||||||
static pid_t guest_pid;
|
static pid_t guest_pid;
|
||||||
void init_memory(pid_t pid) {
|
void init_memory(pid_t pid) {
|
||||||
guest_pid = pid;
|
guest_pid = pid;
|
||||||
}
|
}
|
||||||
void memory_writer(uint32_t guest_addr, const void *data, uint32_t size) {
|
|
||||||
|
// Read Memory
|
||||||
|
void memory_reader(uint32_t guest_addr, void *data, uint32_t size) {
|
||||||
|
if (size == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
iovec local[1];
|
iovec local[1];
|
||||||
local[0].iov_base = (void *) data;
|
local[0].iov_base = data;
|
||||||
local[0].iov_len = size;
|
local[0].iov_len = size;
|
||||||
iovec remote[1];
|
iovec remote[1];
|
||||||
remote[0].iov_base = (void *) (uint64_t) guest_addr;
|
remote[0].iov_base = (void *) (uint64_t) guest_addr;
|
||||||
remote[0].iov_len = size;
|
remote[0].iov_len = size;
|
||||||
const ssize_t ret = process_vm_writev(guest_pid, local, 1, remote, 1, 0);
|
ssize_t ret = process_vm_readv(guest_pid, local, 1, remote, 1, 0);
|
||||||
|
if (ret != size) {
|
||||||
|
ERR("Unable To Read Data: %s", strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write Memory
|
||||||
|
void memory_writer(uint32_t guest_addr, void *data, uint32_t size) {
|
||||||
|
iovec local[1];
|
||||||
|
local[0].iov_base = data;
|
||||||
|
local[0].iov_len = size;
|
||||||
|
iovec remote[1];
|
||||||
|
remote[0].iov_base = (void *) (uint64_t) guest_addr;
|
||||||
|
remote[0].iov_len = size;
|
||||||
|
ssize_t ret = process_vm_writev(guest_pid, local, 1, remote, 1, 0);
|
||||||
if (ret != size) {
|
if (ret != size) {
|
||||||
ERR("Unable To Write Data: %s", strerror(errno));
|
ERR("Unable To Write Data: %s", strerror(errno));
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,6 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
// Read External Memory
|
void memory_reader(uint32_t guest_addr, void *data, uint32_t size);
|
||||||
void memory_writer(uint32_t guest_addr, const void *data, uint32_t size);
|
void memory_writer(uint32_t guest_addr, void *data, uint32_t size);
|
||||||
void init_memory(pid_t guest_pid);
|
void init_memory(pid_t guest_pid);
|
@ -8,9 +8,9 @@
|
|||||||
|
|
||||||
#include "pipe.h"
|
#include "pipe.h"
|
||||||
|
|
||||||
#include "log.h"
|
#include "../log.h"
|
||||||
#include "trampoline.h"
|
#include "../trampoline.h"
|
||||||
#include "memory.h"
|
#include "../memory.h"
|
||||||
|
|
||||||
// Setup Pipes
|
// Setup Pipes
|
||||||
#define PIPE_READ 0
|
#define PIPE_READ 0
|
||||||
@ -47,26 +47,15 @@ void init_pipe_host(pid_t guest_pid) {
|
|||||||
trampoline_pipe_arguments cmd = {};
|
trampoline_pipe_arguments cmd = {};
|
||||||
while (read(arguments_pipe[PIPE_READ], &cmd, sizeof(trampoline_pipe_arguments)) > 0) {
|
while (read(arguments_pipe[PIPE_READ], &cmd, sizeof(trampoline_pipe_arguments)) > 0) {
|
||||||
static unsigned char args[MAX_TRAMPOLINE_ARGS_SIZE];
|
static unsigned char args[MAX_TRAMPOLINE_ARGS_SIZE];
|
||||||
size_t position = 0;
|
memory_reader(cmd.args_addr, args, cmd.length);
|
||||||
while (position < cmd.length) {
|
|
||||||
ssize_t ret = read(arguments_pipe[PIPE_READ], args + position, cmd.length - position);
|
|
||||||
if (ret == -1) {
|
|
||||||
ERR("Unable To Read Trampoline Arguments");
|
|
||||||
} else {
|
|
||||||
position += ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
uint32_t ret = trampoline(cmd.id, args);
|
uint32_t ret = trampoline(cmd.id, args);
|
||||||
if (!cmd.allow_early_return) {
|
write(return_value_pipe[PIPE_WRITE], &ret, sizeof(uint32_t));
|
||||||
write(return_value_pipe[PIPE_WRITE], &ret, sizeof(uint32_t));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Reap Child
|
// Reap Child
|
||||||
int status;
|
int status;
|
||||||
if (waitpid(guest_pid, &status, 0) == -1) {
|
if (waitpid(guest_pid, &status, 0) == -1) {
|
||||||
ERR("Unable To Reap Child: %s", strerror(errno));
|
ERR("Unable To Reap Child: %s", strerror(errno));
|
||||||
}
|
}
|
||||||
// Exit
|
|
||||||
if (WIFEXITED(status)) {
|
if (WIFEXITED(status)) {
|
||||||
exit(WEXITSTATUS(status));
|
exit(WEXITSTATUS(status));
|
||||||
} else {
|
} else {
|
46
native/src/ptrace/init.cpp
Normal file
46
native/src/ptrace/init.cpp
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#include <linux/seccomp.h>
|
||||||
|
#include <linux/filter.h>
|
||||||
|
#include <sys/prctl.h>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cerrno>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include <trampoline/types.h>
|
||||||
|
|
||||||
|
#include "ptrace.h"
|
||||||
|
#include "../log.h"
|
||||||
|
|
||||||
|
// Init
|
||||||
|
void init_ptrace_host(pid_t guest_pid) {
|
||||||
|
// Wait For PTrace
|
||||||
|
safe_wait(guest_pid, nullptr);
|
||||||
|
// Configure PTrace
|
||||||
|
safe_ptrace(PTRACE_SETOPTIONS, guest_pid, nullptr, (void *) (PTRACE_O_EXITKILL | PTRACE_O_TRACESECCOMP));
|
||||||
|
// Start Loop
|
||||||
|
loop_ptrace(guest_pid);
|
||||||
|
}
|
||||||
|
void init_ptrace_guest() {
|
||||||
|
// seccomp Filter
|
||||||
|
sock_filter filter[] = {
|
||||||
|
// Load Syscall Number To Accumulator
|
||||||
|
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(seccomp_data, nr)),
|
||||||
|
// If Syscall Does Not Match The Trampoline, Then Skip The Next Instruction
|
||||||
|
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, TRAMPOLINE_SYSCALL, 0, 1),
|
||||||
|
// Trigger PTrace And End Filter
|
||||||
|
BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_TRACE),
|
||||||
|
// Allow Syscall And End Filter
|
||||||
|
BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW)
|
||||||
|
};
|
||||||
|
sock_fprog prog = {
|
||||||
|
.len = (unsigned short) (sizeof(filter) / sizeof(filter[0])),
|
||||||
|
.filter = filter
|
||||||
|
};
|
||||||
|
// Setup PTrace
|
||||||
|
safe_ptrace(PTRACE_TRACEME, 0, nullptr, nullptr);
|
||||||
|
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) {
|
||||||
|
ERR("Unable To Prepare Process For Seccomp: %s", strerror(errno));
|
||||||
|
}
|
||||||
|
if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) == -1) {
|
||||||
|
ERR("Unable To Set Seccomp Filter: %s", strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
117
native/src/ptrace/loop.cpp
Normal file
117
native/src/ptrace/loop.cpp
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
#include <sys/wait.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cerrno>
|
||||||
|
#include <elf.h>
|
||||||
|
|
||||||
|
#ifndef __aarch64__
|
||||||
|
#error "Unsupported Host Architecture"
|
||||||
|
#endif
|
||||||
|
#include <asm/ptrace.h>
|
||||||
|
|
||||||
|
#include "ptrace.h"
|
||||||
|
#include "../log.h"
|
||||||
|
#include "../trampoline.h"
|
||||||
|
#include "../memory.h"
|
||||||
|
|
||||||
|
// Helper Functions
|
||||||
|
void safe_ptrace(__ptrace_request request, pid_t pid, void *addr, void *data) {
|
||||||
|
if (ptrace(request, pid, addr, data) == -1) {
|
||||||
|
ERR("PTrace Error: %s", strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void safe_wait(pid_t guest_pid, int *status) {
|
||||||
|
int real_status;
|
||||||
|
if (waitpid(guest_pid, &real_status, 0) == -1) {
|
||||||
|
ERR("Unable To Wait For Guest");
|
||||||
|
}
|
||||||
|
if (WIFEXITED(real_status)) {
|
||||||
|
// Process Exited
|
||||||
|
exit(WEXITSTATUS(real_status));
|
||||||
|
}
|
||||||
|
if (status != nullptr) {
|
||||||
|
*status = real_status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void ptrace_wait_syscall(pid_t guest_pid) {
|
||||||
|
while (true) {
|
||||||
|
safe_ptrace(PTRACE_CONT, guest_pid, nullptr, nullptr);
|
||||||
|
int status;
|
||||||
|
safe_wait(guest_pid, &status);
|
||||||
|
if ((status >> 8) == (SIGTRAP | (PTRACE_EVENT_SECCOMP << 8))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Registers
|
||||||
|
struct arm32_pt_regs {
|
||||||
|
uint32_t regs[18];
|
||||||
|
};
|
||||||
|
static bool check_syscall(pid_t guest_pid, arm32_pt_regs *out) {
|
||||||
|
// Read Registers
|
||||||
|
arm32_pt_regs regs = {};
|
||||||
|
iovec io = {
|
||||||
|
.iov_base = ®s,
|
||||||
|
.iov_len = sizeof(regs)
|
||||||
|
};
|
||||||
|
safe_ptrace(PTRACE_GETREGSET, guest_pid, (void *) NT_PRSTATUS, &io);
|
||||||
|
if (io.iov_len != sizeof(regs)) {
|
||||||
|
ERR("Guest Must Be 32-Bit");
|
||||||
|
}
|
||||||
|
// Check Syscall
|
||||||
|
if (regs.regs[7] != TRAMPOLINE_SYSCALL) {
|
||||||
|
// Not Trampoline
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Block Syscall
|
||||||
|
int new_syscall = -1;
|
||||||
|
iovec syscall_io = {
|
||||||
|
.iov_base = &new_syscall,
|
||||||
|
.iov_len = sizeof(int),
|
||||||
|
};
|
||||||
|
safe_ptrace(PTRACE_SETREGSET, guest_pid, (void *) NT_ARM_SYSTEM_CALL, &syscall_io);
|
||||||
|
// Export Registers
|
||||||
|
*out = regs;
|
||||||
|
// Return
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
static void get_arguments(arm32_pt_regs *regs, uint32_t *arg1, uint32_t *arg2, uint32_t *arg3) {
|
||||||
|
*arg1 = regs->regs[0];
|
||||||
|
*arg2 = regs->regs[1];
|
||||||
|
*arg3 = regs->regs[2];
|
||||||
|
}
|
||||||
|
static void set_syscall_return(pid_t guest_pid, arm32_pt_regs *regs) {
|
||||||
|
regs->regs[0] = 0;
|
||||||
|
iovec io = {
|
||||||
|
.iov_base = regs,
|
||||||
|
.iov_len = sizeof(arm32_pt_regs)
|
||||||
|
};
|
||||||
|
safe_ptrace(PTRACE_SETREGSET, guest_pid, (void *) NT_PRSTATUS, &io);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main Loop
|
||||||
|
void loop_ptrace(pid_t guest_pid) {
|
||||||
|
while (true) {
|
||||||
|
// Wait For Syscall
|
||||||
|
ptrace_wait_syscall(guest_pid);
|
||||||
|
|
||||||
|
// Handle Syscall
|
||||||
|
arm32_pt_regs regs = {};
|
||||||
|
bool is_trampoline = check_syscall(guest_pid, ®s);
|
||||||
|
if (is_trampoline) {
|
||||||
|
// Get Arguments
|
||||||
|
uint32_t id;
|
||||||
|
uint32_t length;
|
||||||
|
uint32_t args_addr;
|
||||||
|
get_arguments(®s, &id, &length, &args_addr);
|
||||||
|
static unsigned char args[MAX_TRAMPOLINE_ARGS_SIZE];
|
||||||
|
memory_reader(args_addr, args, length);
|
||||||
|
// Run Trampoline
|
||||||
|
uint32_t ret = trampoline(id, args);
|
||||||
|
memory_writer(args_addr, &ret, sizeof(uint32_t));
|
||||||
|
// Set Syscall Return
|
||||||
|
set_syscall_return(guest_pid, ®s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
native/src/ptrace/ptrace.h
Normal file
10
native/src/ptrace/ptrace.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/ptrace.h>
|
||||||
|
|
||||||
|
void safe_ptrace(__ptrace_request request, pid_t pid, void *addr, void *data);
|
||||||
|
void safe_wait(pid_t guest_pid, int *status);
|
||||||
|
void init_ptrace_host(pid_t guest_pid);
|
||||||
|
void init_ptrace_guest();
|
||||||
|
void loop_ptrace(pid_t guest_pid);
|
@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
#include "signals.h"
|
#include "signals.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cerrno>
|
||||||
|
|
||||||
// Signal Handlers
|
// Signal Handlers
|
||||||
static pid_t guest_pid = -1;
|
static pid_t guest_pid = -1;
|
||||||
static void exit_handler(__attribute__((unused)) int signal_id) {
|
static void exit_handler(__attribute__((unused)) int signal_id) {
|
||||||
|
@ -6,7 +6,7 @@ if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.24.0)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Archive
|
# Archive
|
||||||
if(NOT DEFINED RUNTIME_QEMU_ARCHIVE)
|
if(NOT DEFINED TRAMPOLINE_QEMU_ARCHIVE)
|
||||||
message(FATAL_ERROR "Missing QEMU Archive")
|
message(FATAL_ERROR "Missing QEMU Archive")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ if(DEFINED ENV{PKG_CONFIG_LIBDIR})
|
|||||||
endif()
|
endif()
|
||||||
set(EXTRA_C_FLAGS "-s -I${CMAKE_CURRENT_SOURCE_DIR}/../include")
|
set(EXTRA_C_FLAGS "-s -I${CMAKE_CURRENT_SOURCE_DIR}/../include")
|
||||||
ExternalProject_Add(qemu
|
ExternalProject_Add(qemu
|
||||||
URL "${RUNTIME_QEMU_ARCHIVE}"
|
URL "${TRAMPOLINE_QEMU_ARCHIVE}"
|
||||||
# Configure Build
|
# Configure Build
|
||||||
CONFIGURE_COMMAND
|
CONFIGURE_COMMAND
|
||||||
"${CMAKE_COMMAND}" "-E" "env"
|
"${CMAKE_COMMAND}" "-E" "env"
|
||||||
@ -36,7 +36,7 @@ ExternalProject_Add(qemu
|
|||||||
"--cross-prefix="
|
"--cross-prefix="
|
||||||
"--cc=${CMAKE_C_COMPILER}"
|
"--cc=${CMAKE_C_COMPILER}"
|
||||||
"--cxx=${CMAKE_CXX_COMPILER}"
|
"--cxx=${CMAKE_CXX_COMPILER}"
|
||||||
"--extra-ldflags=-ldl -Wl,-rpath=${RUNTIME_RPATH} -Wl,${RUNTIME_EXTRA_LINK_FLAG}"
|
"--extra-ldflags=-ldl -Wl,-rpath=$ORIGIN/../lib/native -Wl,--disable-new-dtags"
|
||||||
"--disable-debug-info"
|
"--disable-debug-info"
|
||||||
"--target-list=arm-linux-user"
|
"--target-list=arm-linux-user"
|
||||||
"--without-default-features"
|
"--without-default-features"
|
||||||
@ -54,9 +54,9 @@ ExternalProject_Add(qemu
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Install
|
# Install
|
||||||
function(install_runtime bin_dir legal_dir)
|
function(install_trampoline bin_dir legal_dir)
|
||||||
ExternalProject_Get_property(qemu BINARY_DIR)
|
ExternalProject_Get_property(qemu BINARY_DIR)
|
||||||
install(PROGRAMS "${BINARY_DIR}/qemu-arm" DESTINATION "${bin_dir}" RENAME "runtime")
|
install(PROGRAMS "${BINARY_DIR}/qemu-arm" DESTINATION "${bin_dir}" RENAME "trampoline")
|
||||||
# License
|
# License
|
||||||
ExternalProject_Get_property(qemu SOURCE_DIR)
|
ExternalProject_Get_property(qemu SOURCE_DIR)
|
||||||
install(FILES "${SOURCE_DIR}/COPYING" DESTINATION "${legal_dir}/qemu")
|
install(FILES "${SOURCE_DIR}/COPYING" DESTINATION "${legal_dir}/qemu")
|
||||||
|
Loading…
Reference in New Issue
Block a user