diff --git a/Makefile b/Makefile index 95580eb18..8d60ec058 100644 --- a/Makefile +++ b/Makefile @@ -42,7 +42,7 @@ endif SRC_DIR ?= $(shell pwd) -CFLAGS = -I$(SRC_DIR)/include -I$(SRC_DIR)/pie -fno-strict-aliasing +CFLAGS = -I$(SRC_DIR)/include -I$(SRC_DIR)/pie -I$(SRC_DIR)/arch/$(ARCH)/ -fno-strict-aliasing LIBS := -lrt -lpthread -lprotobuf-c diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 5896efeef..c0108a1f9 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -10,6 +10,8 @@ SYS-GEN := syscalls-x86-64.sh SYS-OBJ := syscalls.o +SYS-EXEC-TBL := sys-exec-tbl.c + CFLAGS += -c -fpie -Wstrict-prototypes -Wa,--noexecstack -D__ASSEMBLY__ -nostdlib -fomit-frame-pointer -I$(shell pwd) .DEFAULT_GOAL := x86 @@ -25,11 +27,18 @@ $(SYS-ASM): $(SYS-GEN) $(SYS-DEF) $(SYS-ASM-COMMON) $(SYS-TYPES) $(SYS-ASM-COMMON) \ $(SYS-TYPES) +$(SYS-EXEC-TBL): $(SYS-GEN) $(SYS-DEF) + $(E) " GEN " $@ + $(Q) $(SH) \ + $(SYS-GEN) --exec \ + $(SYS-DEF) \ + $(SYS-EXEC-TBL) + %.o: %.S $(E) " CC " $@ $(Q) $(CC) $(CFLAGS) $^ -o $@ -x86: $(SYS-OBJ) +x86: $(SYS-OBJ) $(SYS-EXEC-TBL) clean: $(E) " CLEAN SYSCALLS" @@ -37,5 +46,6 @@ clean: $(Q) $(RM) -f $(SYS-CODES) $(Q) $(RM) -f $(SYS-PROTO) $(Q) $(RM) -f $(SYS-OBJ) + $(Q) $(RM) -f $(SYS-EXEC-TBL) .PHONY: clean x86 diff --git a/arch/x86/syscalls-x86-64.sh b/arch/x86/syscalls-x86-64.sh index 809967c44..dd24471f6 100644 --- a/arch/x86/syscalls-x86-64.sh +++ b/arch/x86/syscalls-x86-64.sh @@ -33,7 +33,21 @@ function gen_asm() { echo "#endif /* $protosdef */" >> $protosout } +function gen_exec() { + in=$1 + codecout=$2 + + echo "/* Autogenerated, don't edit */" > $codecout + + cat $in | egrep -v '^#' | sed -e 's/\t\{1,\}/|/g' | awk -F '|' '{print "SYSCALL(", substr($3, 5), ",", $2, ")"}' >> $codecout +} + if [ "$1" = "--asm" ]; then shift gen_asm $@ fi + +if [ "$1" = "--exec" ]; then + shift + gen_exec $@ +fi diff --git a/cr-exec.c b/cr-exec.c index b32099a93..4bdd72e71 100644 --- a/cr-exec.c +++ b/cr-exec.c @@ -4,7 +4,125 @@ #include "ptrace.h" #include "parasite-syscall.h" +struct syscall_exec_desc { + char *name; + unsigned nr; +}; + +static struct syscall_exec_desc sc_exec_table[] = { +#define SYSCALL(__name, __nr) { .name = #__name, .nr = __nr, }, +#include "sys-exec-tbl.c" +#undef SYSCALL + { }, /* terminator */ +}; + +static struct syscall_exec_desc *find_syscall(char *name) +{ + int i; + + for (i = 0; sc_exec_table[i].name != NULL; i++) + if (!strcmp(sc_exec_table[i].name, name)) + return &sc_exec_table[i]; + + return NULL; +} + +#define MAX_ARGS 6 + +static int execute_syscall(struct parasite_ctl *ctl, + struct syscall_exec_desc *scd, char **opt) +{ + int i, err; + unsigned long args[MAX_ARGS] = {}, ret, r_mem_size = 0; + void *r_mem = NULL; + + for (i = 0; i < MAX_ARGS; i++) { + if (opt[i] == NULL) + break; + + if (opt[i][0] == '&') { + int len; + + if (!r_mem) { + err = parasite_map_exchange(ctl, PAGE_SIZE); + if (err) + return err; + + r_mem_size = PAGE_SIZE; + r_mem = ctl->local_map; + } + + len = strlen(opt[i]); + if (r_mem_size < len) { + pr_err("Arg size overflow\n"); + return -1; + } + + memcpy(r_mem, opt[i] + 1, len); + args[i] = (unsigned long)ctl->remote_map + (r_mem - ctl->local_map); + pr_info("Pushing mem arg [%s]\n", (char *)r_mem); + r_mem_size -= len; + r_mem += len; + } else + args[i] = strtol(opt[i], NULL, 0); + } + + pr_info("Calling %d with %lu %lu %lu %lu %lu %lu\n", scd->nr, + args[0], args[1], args[2], args[3], args[4], args[5]); + + err = syscall_seized(ctl, scd->nr, &ret, + args[0], args[1], args[2], args[3], args[4], args[5]); + if (err) + return err; + + pr_msg("Syscall returned %lx(%d)\n", ret, (int)ret); + return 0; +} + int cr_exec(int pid, char **opt) { - return -1; + char *sys_name = opt[0]; + struct syscall_exec_desc *si; + struct parasite_ctl *ctl; + LIST_HEAD(vma_area_list); + int ret = -1, prev_state; + + if (!sys_name) { + pr_err("Syscall name required\n"); + goto out; + } + + si = find_syscall(sys_name); + if (!si) { + pr_err("Unknown syscall [%s]\n", sys_name); + goto out; + } + + prev_state = ret = seize_task(pid, -1, NULL, NULL); + if (ret < 0) { + pr_err("Can't seize task %d\n", pid); + goto out; + } + + ret = collect_mappings(pid, &vma_area_list); + if (ret) { + pr_err("Can't collect vmas for %d\n", pid); + goto out_unseize; + } + + ctl = parasite_prep_ctl(pid, &vma_area_list); + if (!ctl) { + pr_err("Can't prep ctl %d\n", pid); + goto out_unseize; + } + + ret = execute_syscall(ctl, si, opt + 1); + if (ret < 0) + pr_err("Can't execure syscall remotely\n"); + + parasite_cure_seized(ctl, NULL); +out_unseize: + unseize_task(pid, prev_state); +out: + return ret; }