mirror of
https://github.com/checkpoint-restore/criu.git
synced 2026-07-25 19:14:04 +00:00
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: Pavel Emelyanov <xemul@parallels.com>
This commit is contained in:
parent
4bb4ece76e
commit
15901c2d76
4 changed files with 145 additions and 3 deletions
2
Makefile
2
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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
120
cr-exec.c
120
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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue