[CRIU] [PATCH 7/7] exec: Implement basic remote syscall execution
Pavel Emelyanov
xemul at parallels.com
Mon Dec 17 15:31:32 EST 2012
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: Pavel Emelyanov <xemul at parallels.com>
---
Makefile | 2 +-
arch/x86/Makefile | 12 ++++-
arch/x86/syscalls-x86-64.sh | 14 +++++
cr-exec.c | 120 ++++++++++++++++++++++++++++++++++++++++++-
4 files changed, 145 insertions(+), 3 deletions(-)
diff --git a/Makefile b/Makefile
index 95580eb..8d60ec0 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 5896efe..c0108a1 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 809967c..39616b2 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(", $3, ",", $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 b32099a..dee160c 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_size == 0) {
+ 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_info("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;
}
--
1.7.1
More information about the CRIU
mailing list