zdtm: add rseq02 transition test with NO_RESTART CS flag

Signed-off-by: Alexander Mikhalitsyn <alexander.mikhalitsyn@virtuozzo.com>
This commit is contained in:
Alexander Mikhalitsyn 2022-02-23 23:20:29 +03:00 committed by Andrei Vagin
parent 1e0bed3d69
commit db9ec13616
4 changed files with 51 additions and 0 deletions

View file

@ -24,6 +24,7 @@ TST_NOFILE = \
pid_reuse \
pidfd_store_sk \
rseq01 \
rseq02 \
TST_FILE = \
@ -82,6 +83,7 @@ ptrace: LDFLAGS += -pthread
fork2: CFLAGS += -D FORK2
thread-bomb.o: CFLAGS += -pthread
thread-bomb: LDFLAGS += -pthread
rseq02: CFLAGS += -D NORESTART
%: %.sh
cp $< $@

View file

@ -58,6 +58,18 @@ enum rseq_flags {
RSEQ_FLAG_UNREGISTER = (1 << 0),
};
enum rseq_cs_flags_bit {
RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT_BIT = 0,
RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL_BIT = 1,
RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE_BIT = 2,
};
enum rseq_cs_flags {
RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT = (1U << RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT_BIT),
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),
};
struct rseq {
uint32_t cpu_id_start;
uint32_t cpu_id;
@ -111,6 +123,7 @@ static int rseq_addv(intptr_t *v, intptr_t count, int cpu)
{
double a = 10000000000000000.0;
double b = -1;
uint64_t rseq_cs1 = 0, rseq_cs2 = 0;
/* clang-format off */
__asm__ __volatile__ goto(
@ -134,6 +147,9 @@ static int rseq_addv(intptr_t *v, intptr_t count, int cpu)
"fsqrt\n\t" /* heavy instruction */
"dec %%rcx\n\t"
"jnz 5b\n\t"
"movq %%rax, %[rseq_cs_check2]\n\t"
"movq %[rseq_cs], %%rax\n\t"
"movq %%rax, %[rseq_cs_check1]\n\t"
"fstpl %[y]\n\t"
"2:\n\t"
".pushsection __rseq_failure, \"ax\"\n\t"
@ -149,6 +165,8 @@ static int rseq_addv(intptr_t *v, intptr_t count, int cpu)
: [cpu_id] "r" (cpu),
[current_cpu_id] "m" (rseq_ptr->cpu_id),
[rseq_cs] "m" (rseq_ptr->rseq_cs),
[rseq_cs_check1] "m" (rseq_cs1),
[rseq_cs_check2] "m" (rseq_cs2),
/* final store input */
[v] "m" (*v),
[count] "er" (count),
@ -159,9 +177,22 @@ static int rseq_addv(intptr_t *v, intptr_t count, int cpu)
);
/* clang-format on */
rseq_after_asm_goto();
test_msg("exit %lx %lx %f %f\n", rseq_cs1, rseq_cs2, a, b);
if (rseq_cs1 != rseq_cs2) {
/*
* It means that we finished critical section
* *normally* (haven't jumped to abort) but the kernel had cleaned up
* rseq_ptr->rseq_cs before we left critical section
* and CRIU didn't restore it correctly.
* That's a bug picture.
*/
return -1;
}
return 0;
abort:
rseq_after_asm_goto();
test_msg("abort %lx %lx %f %f\n", rseq_cs1, rseq_cs2, a, b);
return -1;
}
@ -183,16 +214,32 @@ int main(int argc, char *argv[])
fail("calloc");
exit(EXIT_FAILURE);
}
register_thread();
/*
* We want to test that RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL
* is handled properly by CRIU, but that flag can be used
* only with all another flags set.
* Please, refer to
* https://github.com/torvalds/linux/blob/ce522ba9/kernel/rseq.c#L192
*/
#ifdef NORESTART
rseq_ptr->flags = RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT | RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL |
RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE;
#endif
test_daemon();
while (test_go()) {
cpu = RSEQ_ACCESS_ONCE(rseq_ptr->cpu_id_start);
ret = rseq_addv(&cpu_data[cpu], 2, cpu);
/* NORESTART is NOT set */
#ifndef NORESTART
/* just ignore abort */
ret = 0;
#endif
if (ret)
break;

View file

@ -0,0 +1 @@
rseq01.c

View file

@ -0,0 +1 @@
rseq01.desc