struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, struct vm_area_list *vma_area_list, struct parasite_drain_fd *dfds) { int ret; struct parasite_ctl *ctl; ctl = parasite_prep_ctl(pid, vma_area_list); if (!ctl) return NULL; /* * Inject a parasite engine. Ie allocate memory inside alien * space and copy engine code there. Then re-map the engine * locally, so we will get an easy way to access engine memory * without using ptrace at all. */ ctl->args_size = parasite_args_size(vma_area_list, dfds); ret = parasite_map_exchange(ctl, parasite_size + ctl->args_size); if (ret) goto err_restore; pr_info("Putting parasite blob into %p->%p\n", ctl->local_map, ctl->remote_map); memcpy(ctl->local_map, parasite_blob, sizeof(parasite_blob)); /* Setup the rest of a control block */ ctl->parasite_ip = (unsigned long)parasite_sym(ctl->remote_map, __export_parasite_head_start); ctl->addr_cmd = parasite_sym(ctl->local_map, __export_parasite_cmd); ctl->addr_args = parasite_sym(ctl->local_map, __export_parasite_args); ret = parasite_init(ctl, pid, item->nr_threads); if (ret) { pr_err("%d: Can't create a transport socket\n", pid); goto err_restore; } ctl->signals_blocked = 1; ret = parasite_set_logfd(ctl, pid); if (ret) { pr_err("%d: Can't set a logging descriptor\n", pid); goto err_restore; } ret = parasite_init_threads_seized(ctl, item); if (ret) goto err_restore; return ctl; err_restore: parasite_cure_seized(ctl, item); return NULL; }
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; unsigned int ret_args[MAX_ARGS] = {}; void *r_mem = NULL; for (i = 0; i < MAX_ARGS; i++) { if (opt[i] == NULL) break; /* * &foo -- argument string "foo" * @<size> -- ret-arg of size <size> */ if ((opt[i][0] == '&') || (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; } if (opt[i][0] == '&') { len = strlen(opt[i]); if (r_mem_size < len) { pr_err("Arg size overflow\n"); return -1; } memcpy(r_mem, opt[i] + 1, len); } else { len = strtol(opt[i] + 1, NULL, 0); if (!len || (r_mem_size < len)) { pr_err("Bad argument size %d\n", len); return -1; } ret_args[i] = len; } args[i] = (unsigned long)ctl->remote_map + (r_mem - ctl->local_map); pr_info("Pushing %c mem arg [%s]\n", opt[i][0], (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); for (i = 0; i < MAX_ARGS; i++) { unsigned long addr; if (!ret_args[i]) continue; pr_msg("Argument %d returns:\n", i); addr = (unsigned long)ctl->local_map + (args[i] - (unsigned long)ctl->remote_map); print_data(0, (unsigned char *)addr, ret_args[i]); } return 0; }