Add riscv64 to ExclusiveArch
This commit is contained in:
commit
1bf1b71e49
941
compel-handle-rseq-in-generic-compel-code.patch
Normal file
941
compel-handle-rseq-in-generic-compel-code.patch
Normal file
@ -0,0 +1,941 @@
|
||||
diff --git a/Documentation/compel.txt b/Documentation/compel.txt
|
||||
index 506228f592..cdca1e6229 100644
|
||||
--- a/Documentation/compel.txt
|
||||
+++ b/Documentation/compel.txt
|
||||
@@ -93,7 +93,7 @@ The parasitic code is compiled and converted to a header using *compel*, and inc
|
||||
Following steps are performed to infect the victim process:
|
||||
|
||||
- stop the task: *int compel_stop_task(int pid);*
|
||||
- - prepare infection handler: *struct parasite_ctl *compel_prepare(int pid);*
|
||||
+ - prepare infection handler: *struct parasite_ctl *compel_prepare(int pid, bool handle_rseq);*
|
||||
- execute system call: *int compel_syscall(ctl, int syscall_nr, long *ret, int arg ...);*
|
||||
- infect victim: *int compel_infect(ctl, nr_thread, size_of_args_area);*
|
||||
- cure the victim: *int compel_cure(ctl);* //ctl pointer is freed by this call
|
||||
diff --git a/compel/include/uapi/infect.h b/compel/include/uapi/infect.h
|
||||
index 4bbf57c4db..f88d91b1e0 100644
|
||||
--- a/compel/include/uapi/infect.h
|
||||
+++ b/compel/include/uapi/infect.h
|
||||
@@ -47,12 +47,12 @@ extern int compel_resume_task_sig(pid_t pid, int orig_state, int state, int stop
|
||||
struct parasite_ctl;
|
||||
struct parasite_thread_ctl;
|
||||
|
||||
-extern struct parasite_ctl __must_check *compel_prepare(int pid);
|
||||
-extern struct parasite_ctl __must_check *compel_prepare_noctx(int pid);
|
||||
+extern struct parasite_ctl __must_check *compel_prepare(int pid, bool handle_rseq);
|
||||
+extern struct parasite_ctl __must_check *compel_prepare_noctx(int pid, bool handle_rseq);
|
||||
extern int __must_check compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned long args_size);
|
||||
extern int __must_check compel_infect_no_daemon(struct parasite_ctl *ctl, unsigned long nr_threads,
|
||||
unsigned long args_size);
|
||||
-extern struct parasite_thread_ctl __must_check *compel_prepare_thread(struct parasite_ctl *ctl, int pid);
|
||||
+extern struct parasite_thread_ctl __must_check *compel_prepare_thread(struct parasite_ctl *ctl, int pid, bool handle_rseq);
|
||||
extern void compel_release_thread(struct parasite_thread_ctl *);
|
||||
|
||||
extern int __must_check compel_start_daemon(struct parasite_ctl *ctl);
|
||||
diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c
|
||||
index 8f44dbfc3e..b4764ce836 100644
|
||||
--- a/compel/src/lib/infect.c
|
||||
+++ b/compel/src/lib/infect.c
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "common/xmalloc.h"
|
||||
#include "common/lock.h"
|
||||
#include "common/page.h"
|
||||
+#include "linux/rseq.h"
|
||||
|
||||
#include <compel/plugins/std/syscall-codes.h>
|
||||
#include <compel/plugins/std/asm/syscall-types.h>
|
||||
@@ -42,7 +43,7 @@
|
||||
#define SECCOMP_MODE_DISABLED 0
|
||||
#endif
|
||||
|
||||
-static int prepare_thread(int pid, struct thread_ctx *ctx);
|
||||
+static int prepare_thread(int pid, struct thread_ctx *ctx, bool handle_rseq);
|
||||
|
||||
static inline void close_safe(int *pfd)
|
||||
{
|
||||
@@ -1111,13 +1112,13 @@ int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned l
|
||||
return 0;
|
||||
}
|
||||
|
||||
-struct parasite_thread_ctl *compel_prepare_thread(struct parasite_ctl *ctl, int pid)
|
||||
+struct parasite_thread_ctl *compel_prepare_thread(struct parasite_ctl *ctl, int pid, bool handle_rseq)
|
||||
{
|
||||
struct parasite_thread_ctl *tctl;
|
||||
|
||||
tctl = xmalloc(sizeof(*tctl));
|
||||
if (tctl) {
|
||||
- if (prepare_thread(pid, &tctl->th)) {
|
||||
+ if (prepare_thread(pid, &tctl->th, handle_rseq)) {
|
||||
xfree(tctl);
|
||||
tctl = NULL;
|
||||
} else {
|
||||
@@ -1129,7 +1130,117 @@ struct parasite_thread_ctl *compel_prepare_thread(struct parasite_ctl *ctl, int
|
||||
return tctl;
|
||||
}
|
||||
|
||||
-static int prepare_thread(int pid, struct thread_ctx *ctx)
|
||||
+#define decode_pointer(x) ((void *)(unsigned long)(x))
|
||||
+
|
||||
+static bool task_in_rseq(struct criu_rseq_cs *rseq_cs, uint64_t addr)
|
||||
+{
|
||||
+ return addr - rseq_cs->start_ip < rseq_cs->post_commit_offset;
|
||||
+}
|
||||
+
|
||||
+static int read_rseq_cs(pid_t tid, struct __ptrace_rseq_configuration *rseqc, struct criu_rseq_cs *rseq_cs,
|
||||
+ struct criu_rseq *rseq)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ if (!rseqc->rseq_abi_pointer)
|
||||
+ return 0;
|
||||
+
|
||||
+ ret = ptrace_peek_area(tid, rseq,
|
||||
+ decode_pointer(rseqc->rseq_abi_pointer),
|
||||
+ sizeof(struct criu_rseq));
|
||||
+ if (ret) {
|
||||
+ pr_err("ptrace_peek_area(%d, %lx, %lx, %lx): fail to read rseq struct\n",
|
||||
+ tid, (unsigned long)rseq, (unsigned long)rseqc->rseq_abi_pointer,
|
||||
+ (unsigned long)sizeof(struct criu_rseq));
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ if (!rseq->rseq_cs)
|
||||
+ return 0;
|
||||
+
|
||||
+ ret = ptrace_peek_area(tid, rseq_cs,
|
||||
+ decode_pointer(rseq->rseq_cs),
|
||||
+ sizeof(struct criu_rseq_cs));
|
||||
+ if (ret) {
|
||||
+ pr_err("ptrace_peek_area(%d, %lx, %lx, %lx): fail to read rseq_cs struct\n",
|
||||
+ tid, (unsigned long)rseq_cs, (unsigned long)rseq->rseq_cs,
|
||||
+ (unsigned long)sizeof(struct criu_rseq_cs));
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * parasite_thread_rseq checks if the victim process is in an rseq critical
|
||||
+ * section and, if so, aborts it.
|
||||
+ */
|
||||
+static int parasite_thread_rseq(int pid, struct thread_ctx *ctx)
|
||||
+{
|
||||
+ struct criu_rseq_cs _rseq_cs = {}, *rseq_cs = &_rseq_cs;
|
||||
+ struct __ptrace_rseq_configuration rseqc;
|
||||
+ int ret;
|
||||
+ struct criu_rseq rseq = {};
|
||||
+
|
||||
+ ret = ptrace(PTRACE_GET_RSEQ_CONFIGURATION, pid, sizeof(rseqc), &rseqc);
|
||||
+ if (ret < 0) {
|
||||
+ pr_perror("ptrace(PTRACE_GET_RSEQ_CONFIGURATION, %d) = %d", pid, ret);
|
||||
+ return -1;
|
||||
+ } else if (ret != sizeof(rseqc)) {
|
||||
+ pr_err("ptrace(PTRACE_GET_RSEQ_CONFIGURATION, %d) returned unexpected size %d\n", pid, ret);
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ if (rseqc.flags != 0) {
|
||||
+ pr_err("something wrong with ptrace(PTRACE_GET_RSEQ_CONFIGURATION, %d) flags = 0x%x\n", pid,
|
||||
+ rseqc.flags);
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ pr_debug("rseq of %d: ptr = 0x%lx sign = 0x%x\n", pid, (unsigned long)rseqc.rseq_abi_pointer,
|
||||
+ rseqc.signature);
|
||||
+
|
||||
+ if (read_rseq_cs(pid, &rseqc, rseq_cs, &rseq))
|
||||
+ return -1;
|
||||
+
|
||||
+ if (rseq.rseq_cs) {
|
||||
+ uint64_t zero_addr = 0;
|
||||
+
|
||||
+ pr_debug(
|
||||
+ "fixup_thread_rseq for %d: rseq_cs start_ip = %llx abort_ip = %llx post_commit_offset = %llx flags = %x version = %x; IP = %lx\n",
|
||||
+ pid, rseq_cs->start_ip, rseq_cs->abort_ip, rseq_cs->post_commit_offset, rseq_cs->flags,
|
||||
+ rseq_cs->version, (unsigned long)REG_IP(ctx->regs));
|
||||
+
|
||||
+ if (rseq_cs->version != 0) {
|
||||
+ pr_err("unsupported RSEQ ABI version = %d\n", rseq_cs->version);
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ if (rseq.flags || rseq_cs->flags)
|
||||
+ pr_warn("deprecated rseq flags are ignored for %d: rseq.flags = %#x rseq_cs.flags = %#x\n",
|
||||
+ pid, rseq.flags, rseq_cs->flags);
|
||||
+
|
||||
+ if (task_in_rseq(rseq_cs, REG_IP(ctx->regs))) {
|
||||
+ SET_REG_IP(ctx->regs, rseq_cs->abort_ip);
|
||||
+ if (ptrace_set_regs(pid, &ctx->regs)) {
|
||||
+ pr_perror("Can't apply rseq abort registers (pid: %d)", pid);
|
||||
+ return -1;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (ptrace_poke_area(pid, &zero_addr,
|
||||
+ decode_pointer(rseqc.rseq_abi_pointer) +
|
||||
+ offsetof(struct criu_rseq, rseq_cs),
|
||||
+ sizeof(zero_addr))) {
|
||||
+ pr_err("ptrace_poke_area(%d) failed to zero out rseq_cs\n", pid);
|
||||
+ return -1;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int prepare_thread(int pid, struct thread_ctx *ctx, bool handle_rseq)
|
||||
{
|
||||
if (ptrace(PTRACE_GETSIGMASK, pid, sizeof(k_rtsigset_t), &ctx->sigmask)) {
|
||||
pr_perror("can't get signal blocking mask for %d", pid);
|
||||
@@ -1141,6 +1252,11 @@ static int prepare_thread(int pid, struct thread_ctx *ctx)
|
||||
return -1;
|
||||
}
|
||||
|
||||
+ if (handle_rseq && parasite_thread_rseq(pid, ctx)) {
|
||||
+ pr_err("Can't handle rseq (pid: %d)\n", pid);
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1153,7 +1269,7 @@ void compel_release_thread(struct parasite_thread_ctl *tctl)
|
||||
xfree(tctl);
|
||||
}
|
||||
|
||||
-struct parasite_ctl *compel_prepare_noctx(int pid)
|
||||
+struct parasite_ctl *compel_prepare_noctx(int pid, bool handle_rseq)
|
||||
{
|
||||
struct parasite_ctl *ctl = NULL;
|
||||
|
||||
@@ -1170,7 +1286,7 @@ struct parasite_ctl *compel_prepare_noctx(int pid)
|
||||
ctl->tsock = -1;
|
||||
ctl->ictx.log_fd = -1;
|
||||
|
||||
- if (prepare_thread(pid, &ctl->orig))
|
||||
+ if (prepare_thread(pid, &ctl->orig, handle_rseq))
|
||||
goto err;
|
||||
|
||||
ctl->rpid = pid;
|
||||
@@ -1346,12 +1462,12 @@ static int make_sigframe_plain(void *from, struct rt_sigframe *f, struct rt_sigf
|
||||
return 0;
|
||||
}
|
||||
|
||||
-struct parasite_ctl *compel_prepare(int pid)
|
||||
+struct parasite_ctl *compel_prepare(int pid, bool handle_rseq)
|
||||
{
|
||||
struct parasite_ctl *ctl;
|
||||
struct infect_ctx *ictx;
|
||||
|
||||
- ctl = compel_prepare_noctx(pid);
|
||||
+ ctl = compel_prepare_noctx(pid, handle_rseq);
|
||||
if (ctl == NULL)
|
||||
goto out;
|
||||
|
||||
diff --git a/compel/test/fdspy/spy.c b/compel/test/fdspy/spy.c
|
||||
index 41de99e200..35a6805715 100644
|
||||
--- a/compel/test/fdspy/spy.c
|
||||
+++ b/compel/test/fdspy/spy.c
|
||||
@@ -39,7 +39,7 @@ static int do_infection(int pid, int *stolen_fd)
|
||||
err_and_ret("Can't stop task");
|
||||
|
||||
printf("Preparing parasite ctl\n");
|
||||
- ctl = compel_prepare(pid);
|
||||
+ ctl = compel_prepare(pid, false);
|
||||
if (!ctl)
|
||||
err_and_ret("Can't prepare for infection");
|
||||
|
||||
diff --git a/compel/test/infect/spy.c b/compel/test/infect/spy.c
|
||||
index 143946941e..da9b2d729a 100644
|
||||
--- a/compel/test/infect/spy.c
|
||||
+++ b/compel/test/infect/spy.c
|
||||
@@ -38,7 +38,7 @@ static int do_infection(int pid)
|
||||
err_and_ret("Can't stop task");
|
||||
|
||||
printf("Preparing parasite ctl\n");
|
||||
- ctl = compel_prepare(pid);
|
||||
+ ctl = compel_prepare(pid, false);
|
||||
if (!ctl)
|
||||
err_and_ret("Can't prepare for infection");
|
||||
|
||||
diff --git a/compel/test/rsys/spy.c b/compel/test/rsys/spy.c
|
||||
index 4a6fcef29c..ca5630332f 100644
|
||||
--- a/compel/test/rsys/spy.c
|
||||
+++ b/compel/test/rsys/spy.c
|
||||
@@ -33,7 +33,7 @@ static int do_rsetsid(int pid)
|
||||
err_and_ret("Can't stop task");
|
||||
|
||||
printf("Preparing parasite ctl\n");
|
||||
- ctl = compel_prepare(pid);
|
||||
+ ctl = compel_prepare(pid, false);
|
||||
if (!ctl)
|
||||
err_and_ret("Can't prepare for infection");
|
||||
|
||||
diff --git a/compel/test/stack/spy.c b/compel/test/stack/spy.c
|
||||
index 184c8ab318..d0ac16e718 100644
|
||||
--- a/compel/test/stack/spy.c
|
||||
+++ b/compel/test/stack/spy.c
|
||||
@@ -123,7 +123,7 @@ static int do_infection(int pid)
|
||||
err_and_ret("Can't stop task\n");
|
||||
|
||||
printf("Preparing parasite ctl\n");
|
||||
- ctl = compel_prepare(pid);
|
||||
+ ctl = compel_prepare(pid, false);
|
||||
if (!ctl)
|
||||
err_and_ret("Can't prepare for infection\n");
|
||||
|
||||
diff --git a/criu/cr-dump.c b/criu/cr-dump.c
|
||||
index 6fe7c42e4e..fe3a3edd38 100644
|
||||
--- a/criu/cr-dump.c
|
||||
+++ b/criu/cr-dump.c
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "images/siginfo.pb-c.h"
|
||||
|
||||
#include "common/list.h"
|
||||
+#include "linux/rseq.h"
|
||||
#include "imgset.h"
|
||||
#include "file-ids.h"
|
||||
#include "kcmp-ids.h"
|
||||
@@ -908,72 +909,6 @@ static int collect_file_locks(void)
|
||||
return parse_file_locks();
|
||||
}
|
||||
|
||||
-static bool task_in_rseq(struct criu_rseq_cs *rseq_cs, uint64_t addr)
|
||||
-{
|
||||
- return addr >= rseq_cs->start_ip && addr < rseq_cs->start_ip + rseq_cs->post_commit_offset;
|
||||
-}
|
||||
-
|
||||
-static int fixup_thread_rseq(const struct pstree_item *item, int i)
|
||||
-{
|
||||
- CoreEntry *core = item->core[i];
|
||||
- struct criu_rseq_cs *rseq_cs = &dmpi(item)->thread_rseq_cs[i];
|
||||
- pid_t tid = item->threads[i].real;
|
||||
-
|
||||
- if (!kdat.has_ptrace_get_rseq_conf)
|
||||
- return 0;
|
||||
-
|
||||
- /* equivalent to (struct rseq)->rseq_cs is NULL */
|
||||
- if (!rseq_cs->start_ip)
|
||||
- return 0;
|
||||
-
|
||||
- pr_debug(
|
||||
- "fixup_thread_rseq for %d: rseq_cs start_ip = %llx abort_ip = %llx post_commit_offset = %llx flags = %x version = %x; IP = %lx\n",
|
||||
- tid, rseq_cs->start_ip, rseq_cs->abort_ip, rseq_cs->post_commit_offset, rseq_cs->flags,
|
||||
- rseq_cs->version, (unsigned long)TI_IP(core));
|
||||
-
|
||||
- if (rseq_cs->version != 0) {
|
||||
- pr_err("unsupported RSEQ ABI version = %d\n", rseq_cs->version);
|
||||
- return -1;
|
||||
- }
|
||||
-
|
||||
- if (task_in_rseq(rseq_cs, TI_IP(core))) {
|
||||
- struct pid *tid = &item->threads[i];
|
||||
-
|
||||
- /*
|
||||
- * We need to fixup task instruction pointer from
|
||||
- * the original one (which lays inside rseq critical section)
|
||||
- * to rseq abort handler address. But we need to look on rseq_cs->flags
|
||||
- * (please refer to struct rseq -> flags field description).
|
||||
- * Naive idea of flags support may be like... let's change instruction pointer (IP)
|
||||
- * to rseq_cs->abort_ip if !(rseq_cs->flags & RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL).
|
||||
- * But unfortunately, it doesn't work properly, because the kernel does
|
||||
- * clean up of rseq_cs field in the struct rseq (modifies userspace memory).
|
||||
- * So, we need to preserve original value of (struct rseq)->rseq_cs field in the
|
||||
- * image and restore it's value before releasing threads (see restore_rseq_cs()).
|
||||
- *
|
||||
- * It's worth to mention that we need to fixup IP in CoreEntry
|
||||
- * (used when full dump/restore is performed) and also in
|
||||
- * the parasite regs storage (used if --leave-running option is used,
|
||||
- * or if dump error occurred and process execution is resumed).
|
||||
- */
|
||||
-
|
||||
- if (!(rseq_cs->flags & RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL)) {
|
||||
- pr_warn("The %d task is in rseq critical section. IP will be set to rseq abort handler addr\n",
|
||||
- tid->real);
|
||||
-
|
||||
- TI_IP(core) = rseq_cs->abort_ip;
|
||||
-
|
||||
- if (item->pid->real == tid->real) {
|
||||
- compel_set_leader_ip(dmpi(item)->parasite_ctl, rseq_cs->abort_ip);
|
||||
- } else {
|
||||
- compel_set_thread_ip(dmpi(item)->thread_ctls[i], rseq_cs->abort_ip);
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
static int dump_task_thread(struct parasite_ctl *parasite_ctl, const struct pstree_item *item, int id)
|
||||
{
|
||||
struct parasite_thread_ctl *tctl = dmpi(item)->thread_ctls[id];
|
||||
@@ -997,12 +932,6 @@ static int dump_task_thread(struct parasite_ctl *parasite_ctl, const struct pstr
|
||||
core->thread_core->creds->lsm_profile = dmpi(item)->thread_lsms[id]->profile;
|
||||
core->thread_core->creds->lsm_sockcreate = dmpi(item)->thread_lsms[0]->sockcreate;
|
||||
|
||||
- ret = fixup_thread_rseq(item, id);
|
||||
- if (ret) {
|
||||
- pr_err("Can't fixup rseq for pid %d\n", pid);
|
||||
- goto err;
|
||||
- }
|
||||
-
|
||||
img = open_image(CR_FD_CORE, O_DUMP, tid->ns[0].virt);
|
||||
if (!img)
|
||||
goto err;
|
||||
@@ -1148,48 +1077,6 @@ static int dump_task_signals(pid_t pid, struct pstree_item *item)
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int read_rseq_cs(pid_t tid, struct __ptrace_rseq_configuration *rseqc, struct criu_rseq_cs *rseq_cs,
|
||||
- struct criu_rseq *rseq)
|
||||
-{
|
||||
- int ret;
|
||||
-
|
||||
- /* rseq is not registered */
|
||||
- if (!rseqc->rseq_abi_pointer)
|
||||
- return 0;
|
||||
-
|
||||
- /*
|
||||
- * We need to cover the case when victim process was inside rseq critical section
|
||||
- * at the moment when CRIU comes and seized it. We need to determine the borders
|
||||
- * of rseq critical section at first. To achieve that we need to access thread
|
||||
- * memory and read pointer to struct rseq_cs.
|
||||
- *
|
||||
- * We have two ways to access thread memory: from the parasite and using ptrace().
|
||||
- * But it this case we can't use parasite, because if victim process returns to the
|
||||
- * execution, on the kernel side __rseq_handle_notify_resume hook will be called,
|
||||
- * then rseq_ip_fixup() -> clear_rseq_cs() and user space memory with struct rseq
|
||||
- * will be cleared. So, let's use ptrace(PTRACE_PEEKDATA).
|
||||
- */
|
||||
- ret = ptrace_peek_area(tid, rseq, decode_pointer(rseqc->rseq_abi_pointer), sizeof(struct criu_rseq));
|
||||
- if (ret) {
|
||||
- pr_err("ptrace_peek_area(%d, %lx, %lx, %lx): fail to read rseq struct\n", tid, (unsigned long)rseq,
|
||||
- (unsigned long)(rseqc->rseq_abi_pointer), (unsigned long)sizeof(uint64_t));
|
||||
- return -1;
|
||||
- }
|
||||
-
|
||||
- if (!rseq->rseq_cs)
|
||||
- return 0;
|
||||
-
|
||||
- ret = ptrace_peek_area(tid, rseq_cs, decode_pointer(rseq->rseq_cs), sizeof(struct criu_rseq_cs));
|
||||
- if (ret) {
|
||||
- pr_err("ptrace_peek_area(%d, %lx, %lx, %lx): fail to read rseq_cs struct\n", tid,
|
||||
- (unsigned long)rseq_cs, (unsigned long)rseq->rseq_cs,
|
||||
- (unsigned long)sizeof(struct criu_rseq_cs));
|
||||
- return -1;
|
||||
- }
|
||||
-
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
static int dump_thread_rseq(struct pstree_item *item, int i)
|
||||
{
|
||||
struct __ptrace_rseq_configuration rseqc;
|
||||
@@ -1197,8 +1084,6 @@ static int dump_thread_rseq(struct pstree_item *item, int i)
|
||||
int ret;
|
||||
CoreEntry *core = item->core[i];
|
||||
RseqEntry **rseqep = &core->thread_core->rseq_entry;
|
||||
- struct criu_rseq rseq = {};
|
||||
- struct criu_rseq_cs *rseq_cs = &dmpi(item)->thread_rseq_cs[i];
|
||||
pid_t tid = item->threads[i].real;
|
||||
|
||||
/*
|
||||
@@ -1237,56 +1122,26 @@ static int dump_thread_rseq(struct pstree_item *item, int i)
|
||||
rseqe->rseq_abi_size = rseqc.rseq_abi_size;
|
||||
rseqe->signature = rseqc.signature;
|
||||
|
||||
- if (read_rseq_cs(tid, &rseqc, rseq_cs, &rseq))
|
||||
- goto err;
|
||||
-
|
||||
- /* we won't save rseq_cs to the image (only pointer),
|
||||
- * so let's combine flags from both struct rseq and struct rseq_cs
|
||||
- * (kernel does the same when interpreting RSEQ_CS_FLAG_*)
|
||||
- */
|
||||
- rseq_cs->flags |= rseq.flags;
|
||||
-
|
||||
- if (rseq_cs->flags & RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL) {
|
||||
- rseqe->has_rseq_cs_pointer = true;
|
||||
- rseqe->rseq_cs_pointer = rseq.rseq_cs;
|
||||
- }
|
||||
-
|
||||
/* save rseq entry to the image */
|
||||
*rseqep = rseqe;
|
||||
|
||||
return 0;
|
||||
-
|
||||
-err:
|
||||
- xfree(rseqe);
|
||||
- return -1;
|
||||
}
|
||||
|
||||
static int dump_task_rseq(pid_t pid, struct pstree_item *item)
|
||||
{
|
||||
int i;
|
||||
- struct criu_rseq_cs *thread_rseq_cs;
|
||||
|
||||
/* if rseq() syscall isn't supported then nothing to dump */
|
||||
if (!kdat.has_rseq)
|
||||
return 0;
|
||||
|
||||
- thread_rseq_cs = xzalloc(sizeof(*thread_rseq_cs) * item->nr_threads);
|
||||
- if (!thread_rseq_cs)
|
||||
- return -1;
|
||||
-
|
||||
- dmpi(item)->thread_rseq_cs = thread_rseq_cs;
|
||||
-
|
||||
for (i = 0; i < item->nr_threads; i++) {
|
||||
if (dump_thread_rseq(item, i))
|
||||
- goto free_rseq;
|
||||
+ return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
-
|
||||
-free_rseq:
|
||||
- xfree(thread_rseq_cs);
|
||||
- dmpi(item)->thread_rseq_cs = NULL;
|
||||
- return -1;
|
||||
}
|
||||
|
||||
static struct proc_pid_stat pps_buf;
|
||||
@@ -1306,8 +1161,6 @@ static int dump_task_threads(struct parasite_ctl *parasite_ctl, const struct pst
|
||||
break;
|
||||
}
|
||||
|
||||
- xfree(dmpi(item)->thread_rseq_cs);
|
||||
- dmpi(item)->thread_rseq_cs = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1632,12 +1485,6 @@ static int dump_one_task(struct pstree_item *item, InventoryEntry *parent_ie)
|
||||
goto err;
|
||||
}
|
||||
|
||||
- ret = fixup_thread_rseq(item, 0);
|
||||
- if (ret) {
|
||||
- pr_err("Fixup rseq for %d failed %d\n", pid, ret);
|
||||
- goto err;
|
||||
- }
|
||||
-
|
||||
if (fault_injected(FI_DUMP_EARLY)) {
|
||||
pr_info("fault: CRIU sudden detach\n");
|
||||
kill(getpid(), SIGKILL);
|
||||
diff --git a/criu/cr-restore.c b/criu/cr-restore.c
|
||||
index 7579639a20..d8164366a0 100644
|
||||
--- a/criu/cr-restore.c
|
||||
+++ b/criu/cr-restore.c
|
||||
@@ -25,6 +25,13 @@
|
||||
|
||||
#include "linux/rseq.h"
|
||||
|
||||
+#ifdef __has_include
|
||||
+#if __has_include("sys/rseq.h")
|
||||
+#include <sys/rseq.h>
|
||||
+#include "asm/thread_pointer.h"
|
||||
+#endif
|
||||
+#endif
|
||||
+
|
||||
#include "clone-noasan.h"
|
||||
#include "cr_options.h"
|
||||
#include "servicefd.h"
|
||||
@@ -1922,7 +1929,7 @@ static void finalize_restore(void)
|
||||
continue;
|
||||
|
||||
/* Unmap the restorer blob */
|
||||
- ctl = compel_prepare_noctx(pid);
|
||||
+ ctl = compel_prepare_noctx(pid, false);
|
||||
if (ctl == NULL)
|
||||
continue;
|
||||
|
||||
diff --git a/criu/include/pstree.h b/criu/include/pstree.h
|
||||
index b750a919e6..b501ded721 100644
|
||||
--- a/criu/include/pstree.h
|
||||
+++ b/criu/include/pstree.h
|
||||
@@ -63,7 +63,6 @@ struct dmp_info {
|
||||
struct parasite_ctl *parasite_ctl;
|
||||
struct parasite_thread_ctl **thread_ctls;
|
||||
uint64_t *thread_sp;
|
||||
- struct criu_rseq_cs *thread_rseq_cs;
|
||||
|
||||
/*
|
||||
* Although we don't support dumping different struct creds in general,
|
||||
diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c
|
||||
index c2d9ad976b..1d8a388c85 100644
|
||||
--- a/criu/parasite-syscall.c
|
||||
+++ b/criu/parasite-syscall.c
|
||||
@@ -339,6 +339,7 @@ static int make_sigframe(void *arg, struct rt_sigframe *sf, struct rt_sigframe *
|
||||
|
||||
static int parasite_prepare_threads(struct parasite_ctl *ctl, struct pstree_item *item)
|
||||
{
|
||||
+ bool handle_rseq = kdat.has_ptrace_get_rseq_conf;
|
||||
struct parasite_thread_ctl **thread_ctls;
|
||||
uint64_t *thread_sp;
|
||||
int i;
|
||||
@@ -359,7 +360,7 @@ static int parasite_prepare_threads(struct parasite_ctl *ctl, struct pstree_item
|
||||
continue;
|
||||
}
|
||||
|
||||
- thread_ctls[i] = compel_prepare_thread(ctl, tid->real);
|
||||
+ thread_ctls[i] = compel_prepare_thread(ctl, tid->real, handle_rseq);
|
||||
if (!thread_ctls[i])
|
||||
goto free_sp;
|
||||
|
||||
@@ -380,6 +381,7 @@ static int parasite_prepare_threads(struct parasite_ctl *ctl, struct pstree_item
|
||||
|
||||
struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, struct vm_area_list *vma_area_list)
|
||||
{
|
||||
+ bool handle_rseq = kdat.has_ptrace_get_rseq_conf;
|
||||
struct parasite_ctl *ctl;
|
||||
struct infect_ctx *ictx;
|
||||
unsigned long p;
|
||||
@@ -393,7 +395,7 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
- ctl = compel_prepare_noctx(pid);
|
||||
+ ctl = compel_prepare_noctx(pid, handle_rseq);
|
||||
if (!ctl)
|
||||
return NULL;
|
||||
|
||||
diff --git a/criu/include/linux/rseq.h b/include/linux/rseq.h
|
||||
similarity index 98%
|
||||
rename from criu/include/linux/rseq.h
|
||||
rename to include/linux/rseq.h
|
||||
index 5ceefbf8e1..4ffc1a4f37 100644
|
||||
--- a/criu/include/linux/rseq.h
|
||||
+++ b/include/linux/rseq.h
|
||||
@@ -2,13 +2,6 @@
|
||||
#ifndef _UAPI_LINUX_RSEQ_H
|
||||
#define _UAPI_LINUX_RSEQ_H
|
||||
|
||||
-#ifdef __has_include
|
||||
-#if __has_include("sys/rseq.h")
|
||||
-#include <sys/rseq.h>
|
||||
-#include "asm/thread_pointer.h"
|
||||
-#endif
|
||||
-#endif
|
||||
-
|
||||
#include <linux/types.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
@@ -43,6 +36,8 @@ enum rseq_cs_flags {
|
||||
RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL = (1U << RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL_BIT),
|
||||
RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE = (1U << RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE_BIT),
|
||||
};
|
||||
+#else
|
||||
+#include <sys/rseq.h>
|
||||
#endif /* CONFIG_HAS_NO_LIBC_RSEQ_DEFS */
|
||||
|
||||
/*
|
||||
diff --git a/test/zdtm/transition/Makefile b/test/zdtm/transition/Makefile
|
||||
index ddf2faaad1..8ed9248c7e 100644
|
||||
--- a/test/zdtm/transition/Makefile
|
||||
+++ b/test/zdtm/transition/Makefile
|
||||
@@ -25,6 +25,7 @@ TST_NOFILE = \
|
||||
pidfd_store_sk \
|
||||
rseq01 \
|
||||
rseq02 \
|
||||
+ rseq03 \
|
||||
stack \
|
||||
|
||||
|
||||
diff --git a/test/zdtm/transition/rseq03.c b/test/zdtm/transition/rseq03.c
|
||||
new file mode 100644
|
||||
index 0000000000..5f3633b71b
|
||||
--- /dev/null
|
||||
+++ b/test/zdtm/transition/rseq03.c
|
||||
@@ -0,0 +1,287 @@
|
||||
+/*
|
||||
+ * test for rseq() syscall
|
||||
+ * See also https://www.efficios.com/blog/2019/02/08/linux-restartable-sequences/
|
||||
+ * https://github.com/torvalds/linux/commit/d7822b1e24f2df5df98c76f0e94a5416349ff759
|
||||
+ */
|
||||
+#include <stdio.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <unistd.h>
|
||||
+#include <signal.h>
|
||||
+#include <string.h>
|
||||
+
|
||||
+#include <sys/types.h>
|
||||
+#include <sys/wait.h>
|
||||
+#include <sys/stat.h>
|
||||
+#include <sys/mman.h>
|
||||
+#include <fcntl.h>
|
||||
+#include <pthread.h>
|
||||
+#include <syscall.h>
|
||||
+
|
||||
+#include "zdtmtst.h"
|
||||
+#include "lock.h"
|
||||
+
|
||||
+#ifdef __has_include
|
||||
+#if __has_include("sys/rseq.h")
|
||||
+#include <sys/rseq.h>
|
||||
+#endif
|
||||
+#endif
|
||||
+
|
||||
+#if defined(__x86_64__)
|
||||
+
|
||||
+#if defined(RSEQ_SIG)
|
||||
+static inline void *__criu_thread_pointer(void)
|
||||
+{
|
||||
+#if __GNUC_PREREQ(11, 1)
|
||||
+ return __builtin_thread_pointer();
|
||||
+#else
|
||||
+ void *__result;
|
||||
+#ifdef __x86_64__
|
||||
+ __asm__("mov %%fs:0, %0" : "=r"(__result));
|
||||
+#else
|
||||
+ __asm__("mov %%gs:0, %0" : "=r"(__result));
|
||||
+#endif /* __x86_64__ */
|
||||
+ return __result;
|
||||
+#endif /* !GCC 11 */
|
||||
+}
|
||||
+
|
||||
+static inline void unregister_glibc_rseq(void)
|
||||
+{
|
||||
+ struct rseq *rseq = (struct rseq *)((char *)__criu_thread_pointer() + __rseq_offset);
|
||||
+ unsigned int size = __rseq_size;
|
||||
+
|
||||
+ /* hack: mark glibc rseq structure as failed to register */
|
||||
+ rseq->cpu_id = RSEQ_CPU_ID_REGISTRATION_FAILED;
|
||||
+
|
||||
+ /* unregister rseq */
|
||||
+ if (__rseq_size < 32)
|
||||
+ size = 32;
|
||||
+ syscall(__NR_rseq, (void *)rseq, size, 1, RSEQ_SIG);
|
||||
+}
|
||||
+#else
|
||||
+static inline void unregister_glibc_rseq(void)
|
||||
+{
|
||||
+}
|
||||
+#endif /* defined(RSEQ_SIG) */
|
||||
+
|
||||
+const char *test_doc = "Check rseq() critical section abort during C/R";
|
||||
+const char *test_author = "Alexander Mikhalitsyn <alexander.mikhalitsyn@virtuozzo.com>";
|
||||
+
|
||||
+#ifndef RSEQ_SIG
|
||||
+
|
||||
+enum rseq_flags {
|
||||
+ RSEQ_FLAG_UNREGISTER = (1 << 0),
|
||||
+};
|
||||
+
|
||||
+struct rseq {
|
||||
+ uint32_t cpu_id_start;
|
||||
+ uint32_t cpu_id;
|
||||
+ uint64_t rseq_cs;
|
||||
+ uint32_t flags;
|
||||
+} __attribute__((aligned(4 * sizeof(uint64_t))));
|
||||
+
|
||||
+struct rseq_cs {
|
||||
+ /* Version of this structure. */
|
||||
+ uint32_t version;
|
||||
+ /* enum rseq_cs_flags */
|
||||
+ uint32_t flags;
|
||||
+ uint64_t start_ip;
|
||||
+ /* Offset from start_ip. */
|
||||
+ uint64_t post_commit_offset;
|
||||
+ uint64_t abort_ip;
|
||||
+} __attribute__((aligned(4 * sizeof(__u64))));
|
||||
+
|
||||
+#define RSEQ_SIG 0x53053053
|
||||
+
|
||||
+#endif /* RSEQ_SIG */
|
||||
+
|
||||
+#ifndef __NR_rseq
|
||||
+#define __NR_rseq 334
|
||||
+#endif
|
||||
+/* EOF */
|
||||
+
|
||||
+extern futex_t sig_received;
|
||||
+
|
||||
+static __thread volatile struct rseq __rseq_abi __attribute__((aligned(64)));
|
||||
+static __thread volatile struct rseq_cs __rseq_cs __attribute__((aligned(64)));
|
||||
+
|
||||
+static __thread volatile int rseq_state = 0;
|
||||
+
|
||||
+static int sys_rseq(volatile struct rseq *rseq_abi, uint32_t rseq_len, int flags, uint32_t sig)
|
||||
+{
|
||||
+ return syscall(__NR_rseq, rseq_abi, rseq_len, flags, sig);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Return the rseq registration size. Starting with Linux 7.0,
|
||||
+ * AT_RSEQ_ALIGN is 64 but the feature size is 33, so sizeof(struct rseq)
|
||||
+ * (padded to alignment) no longer matches the registration size the kernel
|
||||
+ * expects. Use __rseq_size when available, clamped to a minimum of 32
|
||||
+ * for older kernels.
|
||||
+ */
|
||||
+static uint32_t rseq_reg_size(void)
|
||||
+{
|
||||
+#if defined(RSEQ_SIG) && defined(__rseq_size)
|
||||
+ if (__rseq_size)
|
||||
+ return (__rseq_size < 32) ? 32 : __rseq_size;
|
||||
+#endif
|
||||
+ return sizeof(struct rseq);
|
||||
+}
|
||||
+
|
||||
+static unsigned long mmap_min_addr = 0x10000UL;
|
||||
+
|
||||
+/*
|
||||
+ * Machine code for x86_64 that emulates:
|
||||
+ * __rseq_abi.rseq_cs = &__rseq_cs;
|
||||
+ * rseq_state = 1;
|
||||
+ * while (futex_get(f) == 0) {
|
||||
+ * if (__rseq_abi.rseq_cs != &__rseq_cs)
|
||||
+ * return;
|
||||
+ * }
|
||||
+ * __rseq_abi.rseq_cs = 0;
|
||||
+ * rseq_state = 0;
|
||||
+ *
|
||||
+ * Disassembly:
|
||||
+ * 0x0: 48 89 37 mov %rsi,(%rdi) // set __rseq_abi.rseq_cs = &__rseq_cs
|
||||
+ * 0x3: c7 01 01 00 00 00 movl $1,(%rcx) // set rseq_state = 1
|
||||
+ * 0x9: 48 39 37 cmp %rsi,(%rdi) // check if __rseq_abi.rseq_cs == &__rseq_cs
|
||||
+ * 0xc: 75 13 jne 0x21 // if not equal, break out (jump to ret)
|
||||
+ * 0xe: 8b 02 mov (%rdx),%eax // load *f
|
||||
+ * 0x10: 85 c0 test %eax,%eax // check if 0
|
||||
+ * 0x12: 74 f5 je 0x9 // spin while *f == 0
|
||||
+ * 0x14: 48 c7 07 00 00 00 00 movq $0,(%rdi) // clear __rseq_abi.rseq_cs on exit
|
||||
+ * 0x1b: c7 01 00 00 00 00 movl $0,(%rcx) // set rseq_state = 0
|
||||
+ * 0x21: c3 ret // return
|
||||
+ */
|
||||
+static const uint8_t test_go_rseq_code[] = {
|
||||
+ 0x48, 0x89, 0x37,
|
||||
+ 0xc7, 0x01, 0x01, 0x00, 0x00, 0x00,
|
||||
+ 0x48, 0x39, 0x37,
|
||||
+ 0x75, 0x13,
|
||||
+ 0x8b, 0x02,
|
||||
+ 0x85, 0xc0,
|
||||
+ 0x74, 0xf5,
|
||||
+ 0x48, 0xc7, 0x07, 0x00, 0x00, 0x00, 0x00,
|
||||
+ 0xc7, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||
+ 0xc3,
|
||||
+};
|
||||
+
|
||||
+/*
|
||||
+ * Machine code for the rseq abort section:
|
||||
+ * rseq_state = 0;
|
||||
+ * return;
|
||||
+ *
|
||||
+ * Disassembly:
|
||||
+ * 0: c7 01 00 00 00 00 movl $0,(%rcx) // set rseq_state = 0
|
||||
+ * 6: c3 ret // return
|
||||
+ */
|
||||
+static const uint8_t test_go_rseq_abort_code[] = {
|
||||
+ 0xc7, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||
+ 0xc3,
|
||||
+};
|
||||
+
|
||||
+static void register_thread(void)
|
||||
+{
|
||||
+ int rc;
|
||||
+ void *addr;
|
||||
+
|
||||
+ addr = mmap((void *)mmap_min_addr, 4096, PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
+ MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
|
||||
+ if (addr == MAP_FAILED)
|
||||
+ addr = mmap(NULL, 4096, PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
+ MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
|
||||
+ if (addr == MAP_FAILED) {
|
||||
+ fail("Failed to mmap rseq critical section area");
|
||||
+ exit(1);
|
||||
+ }
|
||||
+
|
||||
+ memcpy(addr, test_go_rseq_code, sizeof(test_go_rseq_code));
|
||||
+
|
||||
+ __rseq_cs.start_ip = (uint64_t)addr;
|
||||
+ __rseq_cs.post_commit_offset = 2048;
|
||||
+ __rseq_cs.abort_ip = __rseq_cs.start_ip + 2048;
|
||||
+ *((uint32_t *)__rseq_cs.abort_ip - 1) = RSEQ_SIG;
|
||||
+ memcpy((void *)__rseq_cs.abort_ip, test_go_rseq_abort_code,
|
||||
+ sizeof(test_go_rseq_abort_code));
|
||||
+
|
||||
+ unregister_glibc_rseq();
|
||||
+ rc = sys_rseq(&__rseq_abi, rseq_reg_size(), 0, RSEQ_SIG);
|
||||
+ if (rc) {
|
||||
+ fail("Failed to register rseq");
|
||||
+ exit(1);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void check_thread(void)
|
||||
+{
|
||||
+ int rc;
|
||||
+ rc = sys_rseq(&__rseq_abi, rseq_reg_size(), 0, RSEQ_SIG);
|
||||
+ if (!(rc && errno == EBUSY)) {
|
||||
+ fail("Failed to check rseq %d", rc);
|
||||
+ exit(1);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void test_go_rseq(futex_t *f)
|
||||
+{
|
||||
+ void (*fn)(void *, volatile struct rseq_cs *, futex_t *, volatile int *) =
|
||||
+ (void (*)(void *, volatile struct rseq_cs *, futex_t *, volatile int *))__rseq_cs.start_ip;
|
||||
+
|
||||
+ while (futex_get(f) == 0) {
|
||||
+ fn((void *)&__rseq_abi.rseq_cs, &__rseq_cs, f, &rseq_state);
|
||||
+ if (rseq_state != 0) {
|
||||
+ fail("rseq_state is %d (expected 0)", rseq_state);
|
||||
+ exit(1);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void *tfunc(void *args)
|
||||
+{
|
||||
+ register_thread();
|
||||
+ test_go_rseq(&sig_received);
|
||||
+ check_thread();
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+int main(int argc, char *argv[])
|
||||
+{
|
||||
+ pthread_t th;
|
||||
+ int ret;
|
||||
+
|
||||
+ test_init(argc, argv);
|
||||
+
|
||||
+ ret = pthread_create(&th, NULL, tfunc, NULL);
|
||||
+ if (ret) {
|
||||
+ pr_err("pthread_create -> %d\n", ret);
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ register_thread();
|
||||
+
|
||||
+ test_daemon();
|
||||
+ test_go_rseq(&sig_received);
|
||||
+
|
||||
+ ret = pthread_join(th, NULL);
|
||||
+ if (ret) {
|
||||
+ pr_err("pthread_join -> %d\n", ret);
|
||||
+ return 1;
|
||||
+ }
|
||||
+ check_thread();
|
||||
+
|
||||
+ pass();
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#else /* #if defined(__x86_64__) */
|
||||
+
|
||||
+int main(int argc, char *argv[])
|
||||
+{
|
||||
+ test_init(argc, argv);
|
||||
+ skip("Unsupported arch");
|
||||
+ test_daemon();
|
||||
+ test_waitsig();
|
||||
+ pass();
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#endif /* #if defined(__x86_64__) */
|
||||
diff --git a/test/zdtm/transition/rseq03.desc b/test/zdtm/transition/rseq03.desc
|
||||
new file mode 100644
|
||||
index 0000000000..113feaee18
|
||||
--- /dev/null
|
||||
+++ b/test/zdtm/transition/rseq03.desc
|
||||
@@ -0,0 +1 @@
|
||||
+{'arch': 'x86_64', 'feature': 'get_rseq_conf'}
|
||||
11
criu.spec
11
criu.spec
@ -13,7 +13,7 @@
|
||||
|
||||
Name: criu
|
||||
Version: 4.2
|
||||
Release: 7%{?dist}.alma.1
|
||||
Release: 8%{?dist}.alma.1
|
||||
Summary: Tool for Checkpoint/Restore in User-space
|
||||
License: GPL-2.0-only AND LGPL-2.1-only AND MIT
|
||||
URL: http://criu.org/
|
||||
@ -40,6 +40,9 @@ Patch5: https://patch-diff.githubusercontent.com/raw/checkpoint-restore/criu/pul
|
||||
Patch6: https://patch-diff.githubusercontent.com/raw/checkpoint-restore/criu/pull/2881.patch
|
||||
Patch7: https://patch-diff.githubusercontent.com/raw/checkpoint-restore/criu/pull/3043.patch
|
||||
|
||||
# Based on https://github.com/checkpoint-restore/criu/pull/3097
|
||||
Patch8: compel-handle-rseq-in-generic-compel-code.patch
|
||||
|
||||
# Add protobuf-c as a dependency.
|
||||
# We use this patch because the protobuf-c package name
|
||||
# in RPM and DEB is different.
|
||||
@ -128,6 +131,7 @@ This script can help to workaround the so called "PID mismatch" problem.
|
||||
%patch -P 5 -p1
|
||||
%patch -P 6 -p1
|
||||
%patch -P 7 -p1
|
||||
%patch -P 8 -p1
|
||||
%patch -P 99 -p1
|
||||
|
||||
%build
|
||||
@ -203,9 +207,12 @@ rm -f $RPM_BUILD_ROOT%{_libdir}/libcriu.a
|
||||
%doc %{_mandir}/man1/criu-ns.1*
|
||||
|
||||
%changelog
|
||||
* Fri Jul 17 2026 Andrew Lukoshko <alukoshko@almalinux.org> - 4.2-7.alma.1
|
||||
* Thu Jul 23 2026 Andrew Lukoshko <alukoshko@almalinux.org> - 4.2-8.alma.1
|
||||
- Add riscv64 to ExclusiveArch
|
||||
|
||||
* Mon Jul 20 2026 Adrian Reber <areber@redhat.com> - 4.2-8
|
||||
- Handle rseq in generic compel code (checkpoint-restore/criu#3097)
|
||||
|
||||
* Wed Jul 08 2026 Adrian Reber <areber@redhat.com> - 4.2-7
|
||||
- Apply patch to fix RHEL-193276
|
||||
- Resolves: RHEL-193276
|
||||
|
||||
Loading…
Reference in New Issue
Block a user