Pass show_test_info directly to map() instead of wrapping it
in a redundant lambda.
Assisted-by: Claude Code (claude-opus-4-6)
Signed-off-by: Adrian Reber <areber@redhat.com>
tempfile.mktemp is deprecated because it only generates a filename
without creating the file, introducing a TOCTOU race condition where
another process could create a file with the same name between the
mktemp call and the subsequent file operation.
Replace it with tempfile.mkstemp, which atomically creates the file
and returns a file descriptor, eliminating the race window.
Assisted-by: Claude Code (claude-opus-4-6)
Signed-off-by: Adrian Reber <areber@redhat.com>
Add a ZDTM test that verifies inotify watches on files inside an
overlayfs mount survive checkpoint/restore.
The test uses the external mount pattern (like mnt_ext_auto): in
the ZDTM_NEWNS=1 phase it creates an overlay mount before
unshare(CLONE_NEWNS), so CRIU treats it as an external mount and
does not attempt to reconstruct the overlay on restore. After
restore the test opens the watched file and reads back the inotify
event to confirm the watch is intact.
This is needed because the test/others/overlayfs test only checks
that the process survives C/R. This ZDTM test validates that the
inotify watch itself is properly dumped and restored by exercising
the overlay directory walk fallback added in fsnotify.c.
The test is restricted to the 'ns' flavor because the overlay
setup requires the ZDTM_NEWNS=1 lifecycle and root privileges
for mounting overlayfs.
Assisted-by: Claude Code (claude-opus-4-6):default
Signed-off-by: Adrian Reber <areber@redhat.com>
Add a test that exercises checkpoint/restore of a process with an
inotify watch on a file inside an overlayfs mount.
The test compiles inotify_test.c (a simple program that sets up an
inotify watch and blocks reading events), starts it watching a file
on an overlay mount, dumps and restores via criu, then verifies the
restored process is still alive.
Run with: make -C test/others/overlayfs run-inotify
Assisted-by: Claude Code (claude-opus-4-6):default
Signed-off-by: Adrian Reber <areber@redhat.com>
Add a test for the SIGSEGV fixed by "mem: keep COW root VMAs writable
when premapping".
The parent reserves an address range with PROT_NONE and never touches
it, so the kernel does not account it (no "ac" flag in smaps). After
fork(), the child turns the same range into a writable mapping and fills
it with data. CRIU matches COW VMAs by start/end and flags but ignores
their protection bits, so the parent's PROT_NONE, not-accountable VMA
becomes the COW root of the child's data VMA.
On restore the child inherits the root's mapping. Without the fix that
mapping is PROT_NONE, so restoring the child's pages into it faults and
the test fails at restore; with the fix it passes.
Assisted-by: Claude Code:claude-opus-4-8
Signed-off-by: Radostin Stoyanov <rstoyanov@fedoraproject.org>
Fix four "unused local/global variable" alerts reported by CodeQL:
- zdtm.py: drop unused assignment to print_next in the tail-printing
loop at the end of grep_errors(). The return value of print_error()
is not needed here since no further iterations follow.
- crit-recode.py: remove duplicate pycriu.images.dumps(pb) call
inside the except handler. The same call just raised the exception,
so re-executing it would raise again and prevent the error message
from being printed.
- exhaustive/unix.py: drop unused msg variable. The recv() call is
used for its blocking side effect to synchronize with the parent,
the received data is not needed.
- others/mounts/mounts.py: rename unused loop variable i to _ in
the range(10) iteration.
Assisted-by: Claude Code (claude-opus-4-6):claude-opus-4-6@default
Signed-off-by: Adrian Reber <areber@redhat.com>
The tst.available() and criu.available() calls were running
unconditionally for every zdtm.py subcommand (clean, list,
group, run). The zdtm_test.available() method builds umount2,
zdtm_ct, the zdtm test library, and potentially other targets.
This caused "make -C test clean" to first build all these
binaries via "./zdtm.py clean nsroot" before deleting them.
Skip the available() calls only for the clean subcommand, as
list and group still need the test binaries to be built.
Assisted-by: Claude Code (claude-opus-4-6):claude-opus-4-6@default
Signed-off-by: Adrian Reber <areber@redhat.com>
The clean target referenced libcriu, rpc, and crit directories
directly, but these are located under others/. This caused
"make -C test clean" to fail with "No such file or directory"
when reaching the sub-make calls.
Fix the paths to others/libcriu, others/rpc, and others/crit.
Assisted-by: Claude Code (claude-opus-4-6):claude-opus-4-6@default
Signed-off-by: Adrian Reber <areber@redhat.com>
test_iters.c:29:1: error: non-void function does not return a value [-Werror,-Wreturn-type]
29 | }
| ^
1 error generated.
make: *** [Makefile:48: test_iters.o] Error 1
Signed-off-by: Adrian Reber <areber@redhat.com>
The thread-bomb test frequently fails during setup with
pthread_create() returning EAGAIN (errno 11). The test creates
1024 threads in a tight loop from main(), and each of those
threads immediately spawns another thread that joins its
predecessor, resulting in a burst of ~2048 simultaneous thread
creations with 64KB stacks.
This burst causes transient EAGAIN errors from clone() due to
kernel resource pressure (VMA allocator contention, temporary
memory fragmentation, etc.). The failure is not related to hard
resource limits — ulimit, threads-max, max_map_count and cgroup
pids limits are all well above the required values. The failure
occurs both inside and outside containers and is worse on hosts
with fewer resources.
Measured failure rates on a 16GB / 9-CPU host:
Before fix: 65% failure rate (13/20 outside container)
After fix: ~2.5% failure rate (1/40), and that failure was
a C/R issue, not a pthread_create EAGAIN
Fix this by adding a pthread_create_retry() wrapper that retries
pthread_create() up to 50 times with a 10ms delay when it returns
EAGAIN. This gives the kernel time to reclaim resources between
attempts while keeping the total worst-case retry time under one
second per thread creation.
Assisted-by: Claude:claude-opus-4-6
Signed-off-by: Adrian Reber <areber@redhat.com>
CRIU dumps and restores the SO_SNDTIMEO and SO_RCVTIMEO socket
send/receive timeout options in dump_socket_opts()/restore_socket_opts()
(criu/sockets.c), but the ZDTM suite has no dedicated coverage for them:
SO_SNDTIMEO is not exercised by any test, and SO_RCVTIMEO is only used
incidentally as a receive timeout in socket_icmp, never asserted across
checkpoint/restore.
Add socket-timeo, which sets distinct send and receive timeouts on a
socket, performs checkpoint/restore, and verifies both values survive.
Whole-second timeouts are used because the kernel stores these options
with jiffy granularity: setsockopt() may round a sub-second value to the
nearest tick depending on HZ, so a literal sub-second expectation could
fail to match the stored value regardless of checkpoint/restore. The
send and receive values differ so a mix-up between the two options is
caught.
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Rocker Zhang <zhang.rocker.liyuan@gmail.com>
Starting with Linux 7.1, the kernel enforces strict read-only field
protection for the rseq V2 ABI. Userspace is no longer allowed to
modify kernel-managed fields (cpu_id_start, cpu_id, node_id, mm_cid)
while rseq is registered. Violations are detected on the next context
switch and the offending process is killed with SIGSEGV.
The rseq01 test was zeroing the entire glibc-registered rseq area
with memset() before calling test_init(), which internally calls
fork(). This corrupted the read-only fields while the glibc rseq
registration was still active, causing the kernel to send SIGSEGV
during the fork.
Fix this by calling unregister_old_rseq() before the memset in both
main() and thread_routine(), so the kernel is no longer monitoring
those fields when they are zeroed. The subsequent register_thread()
call re-registers rseq with the clean area.
Link: 7f00232152
Assisted-by: Claude Code (https://claude.ai/code):claude-opus-4-6
Signed-off-by: Adrian Reber <areber@redhat.com>
mmaps done just for reserving address space something like
void *addr = mmap(NULL, SIZE, PROT_NONE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
Ensure that these do not have ac flag set in /proc/pid/smaps.
Signed-off-by: Bhavik Sachdev <b.sachdev1904@gmail.com>
Starting with Linux 7.0, the rseq feature size has grown to 33 bytes
and AT_RSEQ_ALIGN has increased to 64. This causes sizeof(struct rseq)
from the uapi header to be 64 (33 bytes padded to aligned(32)), while
the actual registration size used by glibc (__rseq_size) is 33.
The rseq01 test was using sizeof(struct rseq) as the registration
size and a test-local __rseq_abi variable (with only 32-byte
alignment from the uapi header) as the rseq area. Both are
wrong on kernel 7.0:
- The kernel now checks alignment against __alignof__(struct rseq)
which is 64 internally; the 32-byte-aligned test variable may
not satisfy this.
- sizeof(struct rseq) = 64 does not match the feature size of 33
that glibc registered with, so re-registration with a different
size fails.
Fix by:
- Using __rseq_size (the feature size reported by glibc) as the
registration size instead of sizeof(struct rseq).
- Using the glibc-provided rseq area (at thread_pointer() +
__rseq_offset) which is allocated with proper AT_RSEQ_ALIGN
alignment, instead of a test-local variable.
Both fall back to the previous behavior when glibc rseq support
is not available.
This mirrors the glibc fix:
https://sourceware.org/cgit/glibc/commit/?id=67f303b47dc584f204e3f2441b9832082415eebc
Assisted-by: Claude Code (claude-opus-4-6):claude-opus-4-6@default
Signed-off-by: Adrian Reber <areber@redhat.com>
Kernel 7.1 removed IPPROTO_UDPLITE support. Add a checkskip
script that probes for a UDPLITE socket and skips the test
with EPROTONOSUPPORT instead of failing.
Assisted-by: Claude Code (claude-opus-4-6):claude-opus-4-6@default
Signed-off-by: Adrian Reber <areber@redhat.com>
obj->frozen is uint32_t. scanf() must use the matching SCNu32 macro for
this destination type.
Use SCNu32 in parse_bpfmap_fdinfo() for the frozen field parsing.
Signed-off-by: Farzan Aman Khan <farzanaman99@gmail.com>
Build sysctl payloads with snprintf() and check for error/truncation before writing.
Use the returned payload length for write() instead of fixed-size writes, so only formatted bytes are written.
On snprintf failure/truncation, print an explicit error message and return -1. On write/open helper failures, return -1 because callers only use success/failure and pr_perror() already logs errno.
Signed-off-by: Farzan Aman Khan <farzanaman99@gmail.com>
rand_ipc_sysctl() and rand_ipc_sem() returned on write() failure
without closing the opened sysctl fd first.
Close fd in both error paths before returning.
Also return a generic failure code (-1) in these helper paths instead of
propagating errno after close(), because close() may modify errno and
callers only use the return value as success/failure.
Signed-off-by: Farzan Aman Khan <farzanaman99@gmail.com>
check_map_is_there() parses %x:%x major/minor fields from /proc/self/maps.
Store these values in unsigned int variables to match the "%x" specifier
and keep the parser warning-free.
Keep the end-address fragment as %*x to avoid gnu_scanf
"assignment suppression + length modifier" -Werror failures.
Signed-off-by: Farzan Aman Khan <farzanaman99@gmail.com>
shared->opt_files and loop index i are size_t values. Printing them with
"%lu"/"%d" is type-mismatched and can produce incorrect output on some
platforms.
Switch these sites to "%zu" in logging and path formatting.
Signed-off-by: Farzan Aman Khan <farzanaman99@gmail.com>
Remove leftover pidfile and criu_service.socket at the start of
the run target. If these files exist from a previous interrupted
run, the service fails to start and read.py hangs forever waiting
on the status fifo.
Acked-by: Andrei Vagin <avagin@gmail.com>
Signed-off-by: Radostin Stoyanov <rstoyanov@fedoraproject.org>
Verify that the page server binds to the address given in
the RPC request when lazy_pages is enabled. Without the fix
in the previous commit, the address was silently ignored and
the page server would bind to 0.0.0.0 instead.
The test sends a PAGE_SERVER request with ps.address set to
127.0.0.1 and lazy_pages enabled, then checks /proc/net/tcp
to confirm the page server actually bound to that address.
Acked-by: Andrei Vagin <avagin@gmail.com>
Signed-off-by: Radostin Stoyanov <rstoyanov@fedoraproject.org>
Add a test that verifies pipe ownership (uid/gid) is preserved across
checkpoint/restore. This test exercises the fix for issue #2984 where
accessing pipes via /proc/self/fd/ failed after restore because the
pipe ownership was changed to root.
The test:
- Creates a pipe and optionally changes ownership (if running as root)
- Records ownership before C/R
- Verifies ownership is preserved after restore
- Tests /proc/self/fd access works after restore
Signed-off-by: Ahmed Elaidy <elaidya225@gmail.com>
Wire riscv64 CRIU core data into the Python coredump generator.
Set EM_RISCV in the ELF header, map GP registers for NT_PRSTATUS,
map FP registers for NT_FPREGSET, and enable the existing smoke test
on riscv64.
The layout follows the current CRIU riscv64 core format and the
Linux RISC-V user ABI.
Partially addresses #2433.
Signed-off-by: Shaurya Rane <ssrane_b23@ee.vjti.ac.in>
Add a ZDTM test for the timer_slack_ns checkpoint/restore feature.
The test sets a custom timer slack value (123456789 ns) before C/R
and verifies it is preserved after restore.
Signed-off-by: Ahmed Elaidy <elaidya225@gmail.com>
Add a test that exercises the broken read lease restore path. The test:
1. Opens a file O_RDONLY and takes a read lease (F_RDLCK).
2. Triggers the breaking sequence by attempting a conflicting
O_WRONLY | O_NONBLOCK open (which returns EWOULDBLOCK).
3. Forks a child to verify post-restore lease state.
4. Calls test_daemon() / test_waitsig() to go through C/R.
5. After restore, the child verifies that the lease type is F_UNLCK
(the expected target type for a broken read lease), confirming
that the breaking sequence was correctly re-established.
Without the preceding fix, restore_lease_prebreaking_state() would set a
write lease (F_WRLCK) instead of a read lease on the read-only fd,
causing either a restore failure (EACCES) or a wrong lease type
post-restore. This test fails without the fix and passes with it.
Signed-off-by: Andrei Vagin <avagin@google.com>
When running tests in parallel (-p 2) with GCOV=1, multiple
forked processes race to create ../criu.tree. The check-then-
create pattern (os.access + os.mkdir) allows two processes to
both see the directory as missing and then both attempt mkdir,
causing FileExistsError in the second process.
Replace with os.makedirs(exist_ok=True) which handles the race
atomically.
Assisted-by: Claude:claude-opus-4-6
Signed-off-by: Adrian Reber <areber@redhat.com>
With GCOV=1, zdtm.py passes the CRIU workspace parent as an
external bind-mount into the test namespace (ZDTM_CRIU). On
restore in the uns flavor CRIU calls open_tree(OPEN_TREE_CLONE)
on that path. Because the workspace is a parent of the user
namespace mount tree, its mounts are MNT_LOCKED, and open_tree
returns EINVAL.
Fix by creating a private bind-mount of the workspace parent at
'../criu.tree' before each test run, then using that path as the
source of the bind-mount inside the ZDTM namespace (ns.c). On
restore, point the external mapping at 'criu.tree' instead of
the raw workspace path.
Because criu.tree is MS_PRIVATE and is created before any CRIU
run, cgroupfs submounts that CRIU later creates inside the
workspace (cg_yard via mkdtemp) do not propagate into it.
open_tree(OPEN_TREE_CLONE, criu.tree) therefore sees no locked
submounts and succeeds.
This replaces the earlier --work-dir workaround, which was
correct in principle but broke the RPC test path where
criu_rpc.__set_opts has no handler for --work-dir.
Fixes: #2911
Signed-off-by: Ahmed Elaidy <elaidya225@gmail.com>
Hardware breakpoints were originally intended to speed up the resume process
by stopping the process at a specific point in the pie code. However, it
turned out that they don't provide a significant speedup and, in some cases,
can even slow it down. This is especially critical for hosts with a large
number of CPUs.
Hardware Breakpoint Restore Performance Benchmark
==================================================
System: Linux 6.17.0-1007-gcp x86_64
CPU: INTEL(R) XEON(R) PLATINUM 8581C CPU @ 2.10GHz
Virt: google
CRIU: Version: 4.2
Iterations per data point: 5
Threads With BP (us) Without BP (us) Diff (%)
-------- ------------ --------------- --------
>>> Benchmarking with 1 thread(s)...
1 391 326 19.9%
>>> Benchmarking with 10 thread(s)...
10 1098 695 58.0%
>>> Benchmarking with 50 thread(s)...
50 3772 2344 60.9%
>>> Benchmarking with 100 thread(s)...
100 6740 4504 49.6%
>>> Benchmarking with 500 thread(s)...
500 31382 19982 57.1%
>>> Benchmarking with 1000 thread(s)...
1000 58617 40568 44.5%
Notes:
'With BP' = hardware breakpoints enabled (current default)
'Without BP' = CRIU_FAULT=130 (FI_NO_BREAKPOINTS, uses PTRACE_SYSCALL)
Positive diff% means breakpoints are slower
Signed-off-by: Andrei Vagin <avagin@google.com>
Install libcriu into a local staging directory (.install/) using
'make install-lib' and reference only that directory during build
and test:
CFLAGS := -I$(INSTALL_DIR)/include/criu
LDFLAGS := -L$(INSTALL_DIR)/lib -lcriu
LD_LIBRARY_PATH=${MAIN_DIR}/.install/lib
Nothing from the non-test part of the repo is used at compile,
link, or run time.
The compile rule is also corrected to use $< instead of $^
for gcc -c.
Fixes: #2927
Signed-off-by: Ahmed Elaidy <elaidya225@gmail.com>
We saw compilation errors like:
error: call to ‘__open_missing_mode’ declared with attribute error:
open with O_CREAT or O_TMPFILE in second argument needs 3 arguments
Let's fix them by adding mode 0777 everywhere.
Before this change the mode was taken randomly from stack (according to
man 2 open) and that is likely not what we want.
Signed-off-by: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
Before that patch we always had exactly the same magic and extentsion
patterns generated.
While on it let's fix the data restrictions:
- The length of extension and magic should be non-zero.
- Let's explicitly wrap extension characters with 256.
Fixes: #2886
Co-developed-by: Andrei Vagin <avagin@google.com>
Signed-off-by: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
In ns flavor for instance the binfmt_misc is not c/r-ed, but without
this cleanup the test will not detect that as it would inherit correct
unchanged binfmt_misc step which was there on dump.
Signed-off-by: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
In zdtm/static/binfmt_misc we print the string which contains random
bytes, some of which may not map to utf-8. So let's ignore those bytes
we can't show in utf-8.
Else we can get:
File ".../criu/test/zdtm.py", line 660, in print_output
print(output.read())
~~~~~~~~~~~^^
File "<frozen codecs>", line 325, in decode
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe3 in position 180: invalid continuation byte
Signed-off-by: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
The Linux kernel already supports per user namespace sandboxed mounts:
21ca59b365c0 ("binfmt_misc: enable sandboxed mounts")
The overall dump/restore logic is based on the fact that a binfmt_misc
superblock is static and is allocated once per a binfmt_misc mount
within a given user namespace. So the code makes a temporary mount to
read/write the entries and then removes it. The binfmt_misc data is
stored to the USERNS image.
Signed-off-by: Dmitry Sepp <dmitry.sepp@virtuozzo.com>
Remove the OpenVZ specific code that was not used outside of the OpenVZ
infrastructure in preparation for implementing support for upstream
Linux kernel binfmt_misc sandboxing.
Signed-off-by: Dmitry Sepp <dmitry.sepp@virtuozzo.com>
Add a test that creates a SIGEV_THREAD_ID posix timer targeting the
thread leader in a multithreaded process. This exercises the code path
where encode_notify_thread_id() must look up the thread leader's vtid
in threads[0].ns[0].virt.
Without the fix in the previous commit, this test fails during dump
with:
Error (criu/timer.c:329): Unable to convert the notify thread id <pid>
The test creates a worker thread (so the process is multithreaded, which
triggers the collect_threads() path) and a SIGEV_THREAD_ID timer on the
main thread, then verifies the timer still fires after C/R.
Signed-off-by: 3idey <elaidya225@gmail.com>
Fedora rawhide ships a pre-release of GCC 16 which produces following
error:
uprobes.c:34:22: error: variable ‘dummy’ set but not used [-Werror=unused-but-set-variable=]
34 | volatile int dummy = 0;
| ^~~~~
Marking this variable as "__maybe_unused" to fix the error.
Signed-off-by: Adrian Reber <areber@redhat.com>
Introduce an opt-in mode for building and running ZDTM static tests
with Guarded Control Stack (GCS) enabled on AArch64.
Changes:
- Support `GCS_ENABLE=1` builds, adding `-mbranch-protection=standard`
and `-z experimental-gcs=check` to CFLAGS/LDFLAGS.
- Export required GLIBC_TUNABLES at runtime via `TEST_ENV`.
- %.pid rules to prefix test binaries with `$(TEST_ENV)`
so the tunables are set when running tests.
- Makefile rules for selectively enabling GCS in tests
Usage:
# Build and run with GCS enabled
make -C zdtm/static GCS_ENABLE=1 posix_timers
GCS_ENABLE=1 ./zdtm.py run --keep-img=always \
-t zdtm/static/posix_timers
By default (`GCS_ENABLE` unset or 0), test builds and runs are
unchanged.
NOTE: This assumes that the test victim was compiled also using
GCS_ENABLE=1 so that the proper GCS AArch64 ELF headers are present
Signed-off-by: Igor Svilenkov Bozic <svilenkov@gmail.com>
Reviewed-by: Alexander Mikhalitsyn aleksandr.mikhalitsyn@canonical.com
When we compare two list of vma-s, we need to take into account that
some of them could be merged.
Fixes#12286
Signed-off-by: Andrei Vagin <avagin@google.com>
The --mntns-compat-mode option is no longer parsed with CHECK.
Use --log-file instead to test the error message.
Signed-off-by: Radostin Stoyanov <rstoyanov@fedoraproject.org>