Commit 15901c2d authored by Pavel Emelyanov's avatar Pavel Emelyanov

exec: Implement basic remote syscall execution

Syntax is

crtools exec -t <pid> <syscall_name> [<arguments>]

Two types of arguments are supported -- plain, treated
as number, passed as is to the syscall. Buffer, started
with '&' -- the rest of the string is pushed to the tgt
task's memory and pointer to one is passed as syscall
argument.
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent 4bb4ece7
......@@ -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
......
......@@ -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
......@@ -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
......@@ -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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment