2017-03-04 21:42:51 -08:00
|
|
|
#include <compel/plugins/std.h>
|
2016-11-16 18:06:50 +03:00
|
|
|
|
|
|
|
#include "common/scm.h"
|
2016-10-31 18:05:56 +03:00
|
|
|
#include "common/compiler.h"
|
|
|
|
#include "common/lock.h"
|
2018-05-10 19:14:44 +01:00
|
|
|
#include "common/page.h"
|
2016-10-31 18:05:56 +03:00
|
|
|
|
2021-07-19 07:28:38 +00:00
|
|
|
#define pr_err(fmt, ...) print_on_level(1, fmt, ##__VA_ARGS__)
|
|
|
|
#define pr_info(fmt, ...) print_on_level(3, fmt, ##__VA_ARGS__)
|
|
|
|
#define pr_debug(fmt, ...) print_on_level(4, fmt, ##__VA_ARGS__)
|
2016-11-16 18:06:50 +03:00
|
|
|
|
2016-10-31 18:05:56 +03:00
|
|
|
#include "common/bug.h"
|
2016-11-16 18:06:50 +03:00
|
|
|
|
|
|
|
#include "uapi/compel/asm/sigframe.h"
|
|
|
|
#include "uapi/compel/infect-rpc.h"
|
|
|
|
|
|
|
|
#include "rpc-pie-priv.h"
|
2016-10-31 18:05:56 +03:00
|
|
|
|
2022-05-15 19:58:04 +03:00
|
|
|
#ifndef ARCH_RT_SIGRETURN_DUMP
|
|
|
|
#define ARCH_RT_SIGRETURN_DUMP ARCH_RT_SIGRETURN
|
|
|
|
#endif
|
|
|
|
|
2016-10-31 18:05:56 +03:00
|
|
|
static int tsock = -1;
|
|
|
|
|
|
|
|
static struct rt_sigframe *sigframe;
|
|
|
|
|
2018-05-10 19:14:44 +01:00
|
|
|
#ifdef ARCH_HAS_LONG_PAGES
|
|
|
|
/*
|
|
|
|
* XXX: Make it compel's std plugin global variable. Drop parasite_size().
|
|
|
|
* Hint: compel on aarch64 shall learn relocs for that.
|
|
|
|
*/
|
|
|
|
static unsigned __page_size;
|
|
|
|
|
2023-06-20 13:23:24 +04:00
|
|
|
unsigned long __attribute((weak)) page_size(void)
|
2018-05-10 19:14:44 +01:00
|
|
|
{
|
|
|
|
return __page_size;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-10-31 18:05:56 +03:00
|
|
|
int parasite_get_rpc_sock(void)
|
|
|
|
{
|
|
|
|
return tsock;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* RPC helpers */
|
|
|
|
static int __parasite_daemon_reply_ack(unsigned int cmd, int err)
|
|
|
|
{
|
|
|
|
struct ctl_msg m;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
m = ctl_msg_ack(cmd, err);
|
|
|
|
ret = sys_sendto(tsock, &m, sizeof(m), 0, NULL, 0);
|
|
|
|
if (ret != sizeof(m)) {
|
|
|
|
pr_err("Sent only %d bytes while %zu expected\n", ret, sizeof(m));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2021-07-19 07:28:38 +00:00
|
|
|
pr_debug("__sent ack msg: %d %d %d\n", m.cmd, m.ack, m.err);
|
2016-10-31 18:05:56 +03:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int __parasite_daemon_wait_msg(struct ctl_msg *m)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
pr_debug("Daemon waits for command\n");
|
|
|
|
|
|
|
|
while (1) {
|
2021-07-19 07:28:38 +00:00
|
|
|
*m = (struct ctl_msg){};
|
2016-10-31 18:05:56 +03:00
|
|
|
ret = sys_recvfrom(tsock, m, sizeof(*m), MSG_WAITALL, NULL, 0);
|
|
|
|
if (ret != sizeof(*m)) {
|
2021-07-19 07:28:38 +00:00
|
|
|
pr_err("Trimmed message received (%d/%d)\n", (int)sizeof(*m), ret);
|
2016-10-31 18:05:56 +03:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2021-07-19 07:28:38 +00:00
|
|
|
pr_debug("__fetched msg: %d %d %d\n", m->cmd, m->ack, m->err);
|
2016-10-31 18:05:56 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Core infect code */
|
|
|
|
|
2022-05-15 19:58:04 +03:00
|
|
|
static noinline unsigned long fini_sigreturn(unsigned long new_sp)
|
2016-10-31 18:05:56 +03:00
|
|
|
{
|
2022-05-15 19:58:04 +03:00
|
|
|
ARCH_RT_SIGRETURN_DUMP(new_sp, sigframe);
|
|
|
|
return new_sp;
|
2016-10-31 18:05:56 +03:00
|
|
|
}
|
|
|
|
|
2022-05-15 19:58:04 +03:00
|
|
|
static unsigned long fini(void)
|
2016-10-31 18:05:56 +03:00
|
|
|
{
|
|
|
|
unsigned long new_sp;
|
|
|
|
|
|
|
|
parasite_cleanup();
|
|
|
|
|
|
|
|
new_sp = (long)sigframe + RT_SIGFRAME_OFFSET(sigframe);
|
2021-07-19 07:28:38 +00:00
|
|
|
pr_debug("%ld: new_sp=%lx ip %lx\n", sys_gettid(), new_sp, RT_SIGFRAME_REGIP(sigframe));
|
2016-10-31 18:05:56 +03:00
|
|
|
|
|
|
|
sys_close(tsock);
|
2016-11-16 18:06:48 +03:00
|
|
|
std_log_set_fd(-1);
|
2016-10-31 18:05:56 +03:00
|
|
|
|
2022-05-15 19:58:04 +03:00
|
|
|
return fini_sigreturn(new_sp);
|
2016-10-31 18:05:56 +03:00
|
|
|
|
|
|
|
BUG();
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2022-05-15 19:58:04 +03:00
|
|
|
static noinline __used unsigned long parasite_daemon(void *args)
|
2016-10-31 18:05:56 +03:00
|
|
|
{
|
|
|
|
struct ctl_msg m;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
pr_debug("Running daemon thread leader\n");
|
|
|
|
|
|
|
|
/* Reply we're alive */
|
|
|
|
if (__parasite_daemon_reply_ack(PARASITE_CMD_INIT_DAEMON, 0))
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
if (__parasite_daemon_wait_msg(&m))
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (ret && m.cmd != PARASITE_CMD_FINI) {
|
|
|
|
pr_err("Command rejected\n");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m.cmd == PARASITE_CMD_FINI)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
ret = parasite_daemon_cmd(m.cmd, args);
|
|
|
|
|
|
|
|
if (__parasite_daemon_reply_ack(m.cmd, ret))
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
pr_err("Close the control socket for writing\n");
|
|
|
|
sys_shutdown(tsock, SHUT_WR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
2022-05-15 19:58:04 +03:00
|
|
|
return fini();
|
2016-10-31 18:05:56 +03:00
|
|
|
}
|
|
|
|
|
2022-05-15 19:58:04 +03:00
|
|
|
static noinline __used unsigned long parasite_init_daemon(void *data)
|
2016-10-31 18:05:56 +03:00
|
|
|
{
|
|
|
|
struct parasite_init_args *args = data;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
args->sigreturn_addr = (uint64_t)(uintptr_t)fini_sigreturn;
|
2021-07-19 07:28:38 +00:00
|
|
|
sigframe = (void *)(uintptr_t)args->sigframe;
|
2018-05-10 19:14:44 +01:00
|
|
|
#ifdef ARCH_HAS_LONG_PAGES
|
|
|
|
__page_size = args->page_size;
|
|
|
|
#endif
|
2016-10-31 18:05:56 +03:00
|
|
|
|
|
|
|
ret = tsock = sys_socket(PF_UNIX, SOCK_SEQPACKET, 0);
|
|
|
|
if (tsock < 0) {
|
|
|
|
pr_err("Can't create socket: %d\n", tsock);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = sys_connect(tsock, (struct sockaddr *)&args->h_addr, args->h_addr_len);
|
|
|
|
if (ret < 0) {
|
|
|
|
pr_err("Can't connect the control socket\n");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
futex_set_and_wake(&args->daemon_connected, 1);
|
|
|
|
|
|
|
|
ret = recv_fd(tsock);
|
|
|
|
if (ret >= 0) {
|
2016-11-16 18:06:48 +03:00
|
|
|
std_log_set_fd(ret);
|
|
|
|
std_log_set_loglevel(args->log_level);
|
2016-10-31 18:05:56 +03:00
|
|
|
ret = 0;
|
|
|
|
} else
|
|
|
|
goto err;
|
|
|
|
|
2022-05-15 19:58:04 +03:00
|
|
|
return parasite_daemon(data);
|
2016-10-31 18:05:56 +03:00
|
|
|
|
|
|
|
err:
|
|
|
|
futex_set_and_wake(&args->daemon_connected, ret);
|
2022-05-15 19:58:04 +03:00
|
|
|
return fini();
|
2016-10-31 18:05:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef __parasite_entry
|
2021-07-19 07:28:38 +00:00
|
|
|
#define __parasite_entry
|
2016-10-31 18:05:56 +03:00
|
|
|
#endif
|
|
|
|
|
2020-07-16 23:14:35 +00:00
|
|
|
/*
|
|
|
|
* __export_parasite_service_{cmd,args} serve as arguments to the
|
|
|
|
* parasite_service() function. We use these global variables to make it
|
|
|
|
* easier to pass arguments when invoking from ptrace.
|
|
|
|
*
|
|
|
|
* We need the linker to allocate these variables. Hence the dummy
|
|
|
|
* initialization. Otherwise, we end up with COMMON symbols.
|
|
|
|
*/
|
|
|
|
unsigned int __export_parasite_service_cmd = 0;
|
2021-07-19 07:28:38 +00:00
|
|
|
void *__export_parasite_service_args_ptr = NULL;
|
2020-07-16 23:14:35 +00:00
|
|
|
|
2022-05-15 19:58:04 +03:00
|
|
|
unsigned long __used __parasite_entry parasite_service(void)
|
2016-10-31 18:05:56 +03:00
|
|
|
{
|
2020-07-16 23:14:35 +00:00
|
|
|
unsigned int cmd = __export_parasite_service_cmd;
|
|
|
|
void *args = __export_parasite_service_args_ptr;
|
|
|
|
|
2016-10-31 18:05:56 +03:00
|
|
|
pr_info("Parasite cmd %d/%x process\n", cmd, cmd);
|
|
|
|
|
compel: kill self-unmap in parasite
Why should we have self-unmapping code in parasite?
It looks like, we can drop this code using simple sys_unmap()
injection (like that I did for `criu exec` action and for cases where we
failed to insert parasite by some reason, but still need to unmap remotes).
It's an RFC, so just a suggestion - maybe I miss something you have in
mind - please, describe that/those things.
My motivation is:
- less code, defined commands for PIE, one BUG() less, one jump to PIE less
- I'm making one 64-bit parasite on x86 instead of two 32 and 64 bit.
It works (branch 32-one-parasite) with long-jump in the beginning to
64-bit code from 32-bit task.
On parasite curing it sig-returns from 64-bit parasite to 32-bit task,
this point we're trapping in CRIU. After that we command parasite to
unmap itself, so it long-jumps again to parasite 64-bit code, unmaps,
we caught task after sys_unmap and the task is with 64-bit CS.
We can't set 32-bit registers after this - kernel checks that
registers set is the same on PTRACE_SETREGSET:
> > static int ptrace_regset(struct task_struct *task, int req, unsigned int type,
> > struct iovec *kiov)
...
> > if (!regset || (kiov->iov_len % regset->size) != 0)
> > return -EINVAL;
So, to return again to 32-bit task I need sigreturn() again or add
long-jump with 32-bit CS.
I've disable that for 32-bit testing with (in compel_cure_remote):
- if (ctl->addr_cmd) {
+ if (ctl->addr_cmd && user_regs_native(&ctl->orig.regs)) {
And it works. It also works for native tasks, so why should we keep it?
travis-ci: success for compel: kill self-unmap in parasite
Cc: Cyrill Gorcunov <gorcunov@openvz.org>
Cc: Pavel Emelyanov <xemul@virtuozzo.com>
Cc: Andrei Vagin <avagin@virtuozzo.com>
Signed-off-by: Dmitry Safonov <dsafonov@virtuozzo.com>
Acked-by: Andrei Vagin <avagin@virtuozzo.com>
Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2016-11-25 15:51:00 +03:00
|
|
|
if (cmd == PARASITE_CMD_INIT_DAEMON)
|
2016-10-31 18:05:56 +03:00
|
|
|
return parasite_init_daemon(args);
|
|
|
|
|
|
|
|
return parasite_trap_cmd(cmd, args);
|
|
|
|
}
|