[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