Pipes!
This commit is contained in:
parent
4d09fd9396
commit
b2cf446e9d
@ -17,6 +17,7 @@ if(NOT TRAMPOLINE_HEADERS_ONLY)
|
||||
# Include Correct Sub-Project
|
||||
if(USE_NATIVE_TRAMPOLINE)
|
||||
add_subdirectory(native)
|
||||
target_compile_definitions(trampoline-headers INTERFACE MCPI_USE_NATIVE_TRAMPOLINE)
|
||||
elseif(USE_QEMU_TRAMPOLINE)
|
||||
add_subdirectory(qemu)
|
||||
target_compile_definitions(trampoline-headers INTERFACE MCPI_USE_QEMU)
|
||||
|
@ -2,10 +2,26 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// Constants
|
||||
// Switch Between Pipe?PTrace Mode
|
||||
#ifdef MCPI_USE_NATIVE_TRAMPOLINE
|
||||
#define TRAMPOLINE_USE_PTRACE_ENV "_MCPI_TRAMPOLINE_USE_PTRACE"
|
||||
#endif
|
||||
|
||||
// System Call Constants
|
||||
#define MAX_TRAMPOLINE_ARGS_SIZE 2097152 // 2 MiB
|
||||
#define TRAMPOLINE_SYSCALL 0x1337
|
||||
|
||||
// Pipe Constants
|
||||
#ifdef MCPI_USE_NATIVE_TRAMPOLINE
|
||||
#define TRAMPOLINE_ARGUMENTS_PIPE_ENV "_MCPI_TRAMPOLINE_ARGUMENTS"
|
||||
#define TRAMPOLINE_RETURN_VALUE_PIPE_ENV "_MCPI_TRAMPOLINE_RETURN_VALUE"
|
||||
struct trampoline_pipe_arguments {
|
||||
uint32_t id;
|
||||
uint32_t length;
|
||||
uint32_t args_addr;
|
||||
};
|
||||
#endif
|
||||
|
||||
// Function Types
|
||||
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);
|
@ -1,7 +1,15 @@
|
||||
project(native-trampoline)
|
||||
|
||||
# Build
|
||||
add_executable(trampoline src/memory.cpp src/main.cpp src/trampoline.cpp src/ptrace.cpp)
|
||||
add_executable(trampoline
|
||||
src/memory.cpp
|
||||
src/main.cpp
|
||||
src/trampoline.cpp
|
||||
src/ptrace/loop.cpp
|
||||
src/ptrace/init.cpp
|
||||
src/pipe/pipe.cpp
|
||||
src/signals.cpp
|
||||
)
|
||||
|
||||
# Warnings
|
||||
target_compile_options(trampoline PRIVATE -Wall -Wextra -Werror -Wpointer-arith -Wshadow -Wnull-dereference)
|
||||
|
@ -1,49 +1,37 @@
|
||||
#include <unistd.h>
|
||||
#include <cstring>
|
||||
#include <cerrno>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/wait.h>
|
||||
#include <linux/seccomp.h>
|
||||
#include <linux/filter.h>
|
||||
#include <cstddef>
|
||||
#include <sys/prctl.h>
|
||||
|
||||
#include <trampoline/types.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "memory.h"
|
||||
#include "trampoline.h"
|
||||
#include "ptrace.h"
|
||||
#include "ptrace/ptrace.h"
|
||||
#include "pipe/pipe.h"
|
||||
#include "signals.h"
|
||||
|
||||
// Main
|
||||
int main(__attribute__((unused)) int argc, char *argv[]) {
|
||||
// Check Arguments
|
||||
if (argc < 2) {
|
||||
ERR("Invalid Arguments");
|
||||
}
|
||||
bool use_ptrace = getenv(TRAMPOLINE_USE_PTRACE_ENV) != nullptr;
|
||||
// Setup
|
||||
if (!use_ptrace) {
|
||||
init_pipe_common();
|
||||
}
|
||||
// Fork
|
||||
pid_t pid = fork();
|
||||
if (pid == -1) {
|
||||
ERR("Unable To Fork Process: %s", strerror(errno));
|
||||
} else if (pid == 0) {
|
||||
// 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
|
||||
ptrace(PTRACE_TRACEME, 0, 0, 0);
|
||||
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));
|
||||
// Setup
|
||||
setpgid(0, 0);
|
||||
if (use_ptrace) {
|
||||
init_ptrace_guest();
|
||||
} else {
|
||||
init_pipe_guest();
|
||||
}
|
||||
// Execute Program
|
||||
execvp(argv[1], (char *const *) &argv[1]);
|
||||
@ -51,16 +39,16 @@ int main(__attribute__((unused)) int argc, char *argv[]) {
|
||||
} else {
|
||||
// Parent
|
||||
|
||||
// Wait For PTrace
|
||||
waitpid(pid, nullptr, 0);
|
||||
// Configure PTrace
|
||||
ptrace(PTRACE_SETOPTIONS, pid, 0, PTRACE_O_EXITKILL | PTRACE_O_TRACESECCOMP);
|
||||
|
||||
// Setup Trampoline
|
||||
init_signals(pid);
|
||||
init_memory(pid);
|
||||
init_trampoline();
|
||||
|
||||
// Start PTrace Loop
|
||||
loop_ptrace(pid);
|
||||
// Start PTrace
|
||||
if (use_ptrace) {
|
||||
init_ptrace_host(pid);
|
||||
} else {
|
||||
init_pipe_host(pid);
|
||||
}
|
||||
}
|
||||
}
|
64
native/src/pipe/pipe.cpp
Normal file
64
native/src/pipe/pipe.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
#include <unistd.h>
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <trampoline/types.h>
|
||||
|
||||
#include "pipe.h"
|
||||
|
||||
#include "../log.h"
|
||||
#include "../trampoline.h"
|
||||
#include "../memory.h"
|
||||
|
||||
// Setup Pipes
|
||||
#define PIPE_READ 0
|
||||
#define PIPE_WRITE 1
|
||||
static int arguments_pipe[2];
|
||||
static int return_value_pipe[2];
|
||||
static void safe_pipe(int *out) {
|
||||
int ret = pipe(out);
|
||||
if (ret != 0) {
|
||||
ERR("Unable To Create Pipe: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
void init_pipe_common() {
|
||||
safe_pipe(arguments_pipe);
|
||||
safe_pipe(return_value_pipe);
|
||||
}
|
||||
|
||||
// Guest
|
||||
void init_pipe_guest() {
|
||||
// Close Unneeded Pipes
|
||||
close(arguments_pipe[PIPE_READ]);
|
||||
close(return_value_pipe[PIPE_WRITE]);
|
||||
// Setup Environment
|
||||
setenv(TRAMPOLINE_ARGUMENTS_PIPE_ENV, std::to_string(arguments_pipe[PIPE_WRITE]).c_str(), true);
|
||||
setenv(TRAMPOLINE_RETURN_VALUE_PIPE_ENV, std::to_string(return_value_pipe[PIPE_READ]).c_str(), true);
|
||||
}
|
||||
|
||||
// Host
|
||||
void init_pipe_host(pid_t guest_pid) {
|
||||
// Close Unneeded Pipes
|
||||
close(arguments_pipe[PIPE_WRITE]);
|
||||
close(return_value_pipe[PIPE_READ]);
|
||||
// Wait For Commands
|
||||
trampoline_pipe_arguments cmd = {};
|
||||
while (read(arguments_pipe[PIPE_READ], &cmd, sizeof(trampoline_pipe_arguments)) > 0) {
|
||||
static unsigned char args[MAX_TRAMPOLINE_ARGS_SIZE];
|
||||
memory_reader(cmd.args_addr, args, cmd.length);
|
||||
uint32_t ret = trampoline(cmd.id, args);
|
||||
write(return_value_pipe[PIPE_WRITE], &ret, sizeof(uint32_t));
|
||||
}
|
||||
// Reap Child
|
||||
int status;
|
||||
if (waitpid(guest_pid, &status, 0) == -1) {
|
||||
ERR("Unable To Reap Child: %s", strerror(errno));
|
||||
}
|
||||
if (WIFEXITED(status)) {
|
||||
exit(WEXITSTATUS(status));
|
||||
} else {
|
||||
ERR("Unable To Determine Exit Code");
|
||||
}
|
||||
}
|
7
native/src/pipe/pipe.h
Normal file
7
native/src/pipe/pipe.h
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
void init_pipe_common();
|
||||
void init_pipe_host(pid_t guest_pid);
|
||||
void init_pipe_guest();
|
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));
|
||||
}
|
||||
}
|
@ -1,4 +1,3 @@
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/uio.h>
|
||||
#include <cstring>
|
||||
@ -11,23 +10,27 @@
|
||||
#include <asm/ptrace.h>
|
||||
|
||||
#include "ptrace.h"
|
||||
#include "log.h"
|
||||
#include "trampoline.h"
|
||||
#include "memory.h"
|
||||
#include "../log.h"
|
||||
#include "../trampoline.h"
|
||||
#include "../memory.h"
|
||||
|
||||
// Helper Functions
|
||||
static void safe_ptrace(__ptrace_request request, pid_t pid, void *addr, void *data) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
static void safe_wait(pid_t guest_pid, int *status) {
|
||||
if (waitpid(guest_pid, status, 0) == -1) {
|
||||
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(*status)) {
|
||||
if (WIFEXITED(real_status)) {
|
||||
// Process Exited
|
||||
exit(WEXITSTATUS(*status));
|
||||
exit(WEXITSTATUS(real_status));
|
||||
}
|
||||
if (status != nullptr) {
|
||||
*status = real_status;
|
||||
}
|
||||
}
|
||||
static void ptrace_wait_syscall(pid_t guest_pid) {
|
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);
|
28
native/src/signals.cpp
Normal file
28
native/src/signals.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "signals.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <cerrno>
|
||||
|
||||
// Signal Handlers
|
||||
static pid_t guest_pid = -1;
|
||||
static void exit_handler(__attribute__((unused)) int signal_id) {
|
||||
// Stop Child
|
||||
kill(guest_pid, SIGTERM);
|
||||
}
|
||||
|
||||
// Init
|
||||
void init_signals(pid_t pid) {
|
||||
guest_pid = pid;
|
||||
// Install Signal Handlers
|
||||
struct sigaction act_sigint = {};
|
||||
act_sigint.sa_flags = SA_RESTART;
|
||||
act_sigint.sa_handler = &exit_handler;
|
||||
sigaction(SIGINT, &act_sigint, nullptr);
|
||||
struct sigaction act_sigterm = {};
|
||||
act_sigterm.sa_flags = SA_RESTART;
|
||||
act_sigterm.sa_handler = &exit_handler;
|
||||
sigaction(SIGTERM, &act_sigterm, nullptr);
|
||||
}
|
@ -2,4 +2,4 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
void loop_ptrace(pid_t guest_pid);
|
||||
void init_signals(pid_t guest_pid);
|
@ -2,6 +2,5 @@
|
||||
|
||||
#include <trampoline/types.h>
|
||||
|
||||
#define MAX_TRAMPOLINE_ARGS_SIZE 2097152 // See media-layer/trampoline/src/guest/guest.h
|
||||
uint32_t trampoline(uint32_t id, const unsigned char *args);
|
||||
void init_trampoline();
|
Loading…
Reference in New Issue
Block a user