Skip to content

Commit

Permalink
cr-restore: rseq: dynamically handle *libc with rseq
Browse files Browse the repository at this point in the history
Before this patch we assumed that CRIU is compiled against
the same GLibc as it runs with. But as we see from real
world examples like #1935 it's not always true.

The idea of this patch is to detect rseq configuration
for the main CRIU process and use it to unregister
rseq for all further child processes. It's correct,
because we restore pstree using clone*() syscalls,
don't use exec*() (!) syscalls, so rseq gets inherited
in the kernel and rseq configuration remains the same
for all children processes.

This will prevent issues like this:
#1935

Suggested-by: Florian Weimer <[email protected]>
Signed-off-by: Alexander Mikhalitsyn <[email protected]>
  • Loading branch information
mihalicyn authored and avagin committed Aug 8, 2022
1 parent ce1b705 commit f0b0a64
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 10 deletions.
16 changes: 8 additions & 8 deletions criu/cr-restore.c
Original file line number Diff line number Diff line change
Expand Up @@ -3103,14 +3103,14 @@ static void prep_libc_rseq_info(struct rst_rseq_param *rseq)
#else
static void prep_libc_rseq_info(struct rst_rseq_param *rseq)
{
/*
* TODO: handle built-in rseq on other libc'ies like musl
* We can do that using get_rseq_conf kernel feature.
*
* For now we just assume that other libc libraries are
* not registering rseq by default.
*/
rseq->rseq_abi_pointer = 0;
if (!kdat.has_rseq || !kdat.has_ptrace_get_rseq_conf) {
rseq->rseq_abi_pointer = 0;
return;
}

rseq->rseq_abi_pointer = kdat.libc_rseq_conf.rseq_abi_pointer;
rseq->rseq_abi_size = kdat.libc_rseq_conf.rseq_abi_size;
rseq->signature = kdat.libc_rseq_conf.signature;
}
#endif

Expand Down
2 changes: 2 additions & 0 deletions criu/include/kerndat.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "asm/kerndat.h"
#include "util-vdso.h"
#include "hugetlb.h"
#include <compel/ptrace.h>

struct stat;

Expand Down Expand Up @@ -82,6 +83,7 @@ struct kerndat_s {
bool has_openat2;
bool has_rseq;
bool has_ptrace_get_rseq_conf;
struct __ptrace_rseq_configuration libc_rseq_conf;
};

extern struct kerndat_s kdat;
Expand Down
25 changes: 23 additions & 2 deletions criu/kerndat.c
Original file line number Diff line number Diff line change
Expand Up @@ -923,13 +923,17 @@ static int kerndat_has_ptrace_get_rseq_conf(void)
pid_t pid;
int len;
struct __ptrace_rseq_configuration rseq;
int ret = 0;

pid = fork_and_ptrace_attach(NULL);
if (pid < 0)
return -1;

len = ptrace(PTRACE_GET_RSEQ_CONFIGURATION, pid, sizeof(rseq), &rseq);
if (len != sizeof(rseq)) {
if (kdat.has_ptrace_get_rseq_conf)
ret = 1; /* we should update kdat */

kdat.has_ptrace_get_rseq_conf = false;
pr_info("ptrace(PTRACE_GET_RSEQ_CONFIGURATION) is not supported\n");
goto out;
Expand All @@ -940,16 +944,27 @@ static int kerndat_has_ptrace_get_rseq_conf(void)
* we need to pay attention to that and, possibly, make changes on the CRIU side.
*/
if (rseq.flags != 0) {
if (kdat.has_ptrace_get_rseq_conf)
ret = 1; /* we should update kdat */

kdat.has_ptrace_get_rseq_conf = false;
pr_err("ptrace(PTRACE_GET_RSEQ_CONFIGURATION): rseq.flags != 0\n");
} else {
if (!kdat.has_ptrace_get_rseq_conf)
ret = 1; /* we should update kdat */

kdat.has_ptrace_get_rseq_conf = true;

if (memcmp(&kdat.libc_rseq_conf, &rseq, sizeof(rseq)))
ret = 1; /* we should update kdat */

kdat.libc_rseq_conf = rseq;
}

out:
kill(pid, SIGKILL);
waitpid(pid, NULL, 0);
return 0;
return ret;
}

int kerndat_sockopt_buf_lock(void)
Expand Down Expand Up @@ -1472,6 +1487,12 @@ int kerndat_try_load_new(void)
if (ret < 0)
return ret;

ret = kerndat_has_ptrace_get_rseq_conf();
if (ret < 0) {
pr_err("kerndat_has_ptrace_get_rseq_conf failed when initializing kerndat.\n");
return ret;
}

/* New information is found, we need to save to the cache */
if (ret)
kerndat_save_cache();
Expand Down Expand Up @@ -1657,7 +1678,7 @@ int kerndat_init(void)
pr_err("kerndat_has_rseq failed when initializing kerndat.\n");
ret = -1;
}
if (!ret && kerndat_has_ptrace_get_rseq_conf()) {
if (!ret && (kerndat_has_ptrace_get_rseq_conf() < 0)) {
pr_err("kerndat_has_ptrace_get_rseq_conf failed when initializing kerndat.\n");
ret = -1;
}
Expand Down

0 comments on commit f0b0a64

Please sign in to comment.