There is no need to use the fd libdrm duplicated from the original fd.
Just use the original one.
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
Simplify a bunch of error handling blocks by freeing the vm_info_entries
array as soon as we are done accessing it.
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
Instead of initializing and de-initializing libdrm for every buffer object
we dump (each of which consists of a few system calls), we can simply
initialize it once and by doing so simplify a bunch of the error handling
blocks.
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
When saving buffer object content the current code constantly allocates
and frees aligned memory where the GPU will copy each buffer one by one.
We can optimise this path by keeping the buffer around and only grow it if
is too small for the current object.
While doing this we also fix a theoretically incorrect freeing of memory
allocated via posix_memalign with xfree.
An alternative solution could be to probe for the maximum size before hand
by adding a pre-scan loop.
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
amdgpu_plugin_drm_dump_file() already defines a large temporary stack
buffer for the purpose of generating the file level protobuf image name.
Instead of the buffer object dumping loop defining a separate temporary
stack buffer for the buffer content protobuf images we can simply use the
top level one.
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
We can save a few lines of code and end up with a potentially more
readable function if we replace the open-coded try-retry of getting the
list of buffer objects with a loop.
While refactoring we also remove the needless copy of the entry as the
dump loop iterates the handles, and also stop returning a false success
with a made up zero buffer objects saved in cases when the kernel does not
support the DRM_IOCTL_AMDGPU_GEM_LIST_HANDLES ioctl.
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
The DRM minor local variable is shadowed between two blocks inside
amdgpu_plugin_drm_dump_file(). If at the top level we access the minor via
the copy stored in the protobuf image, we can simply drop this copy and
so avoid the buffer object dump loop shadowing it.
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
If the protobuf image allocation fails we can simply return immediately
since there aren't any other things to clean up at this point.
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
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>
When restoring inside a user namespace on a host where userfaultfd
is restricted to privileged callers, 'criu restore --lazy-pages'
fails to open a userfaultfd descriptor with EPERM. This patch improves
the error message to suggests how to fix this.
Assisted-by: Claude Code:claude-opus-4-8
Signed-off-by: Radostin Stoyanov <rstoyanov@fedoraproject.org>
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>
When a process has inotify (or fanotify) watches on files inside an
overlayfs mount, criu dump fails because open_by_handle_at() does not
work for overlay file handles (type OVL_FILEID_V1 = 0xf8). The dump
log shows:
fsnotify: wd 0x000001 s_dev 0x00002d i_ino 0x101ad2 mask 0x00033a
fsnotify: [fhandle] bytes 0x000020 type 0x0000f8 ...
fsnotify: Handle 0x2d:0x101ad2 cannot be opened
Error (criu/fsnotify.c:284): fsnotify: Can't dump that handle
To reproduce manually:
mkdir -p /tmp/{lower,upper,work,merged}
touch /tmp/lower/testfile
mount -t overlay overlay \
-o lowerdir=/tmp/lower,upperdir=/tmp/upper,workdir=/tmp/work \
/tmp/merged
inotifywait -m /tmp/merged/testfile &
PID=$!
criu dump -t $PID -D /tmp/imgs --shell-job --ext-unix-sk
alloc_openable() iterates mounts matching s_dev and tries
open_by_handle_at() for each one. Overlay file handles use the
private OVL_FILEID_V1 type which open_by_handle_at() does not
support, so the call always fails and the dump aborts.
Add a fallback for overlay mounts: when open_by_handle_at() fails
and the mount is identified as FSTYPE__OVERLAYFS, walk the overlay
mount's directory tree with opendir/readdir/fstatat to find the
file matching the (s_dev, i_ino) pair from the handle. Store the
discovered absolute path in f_handle->path so that get_mark_path()
uses the path-based openat() strategy on restore, which works on
overlay mounts.
The fallback only triggers when open_by_handle_at() fails AND the
mount type is FSTYPE__OVERLAYFS, so there is no impact on other
filesystems.
Assisted-by: Claude Code (claude-opus-4-6):default
Signed-off-by: Adrian Reber <areber@redhat.com>
Commit 2e30db5c3d added --network-lock handling and a CLI restore
warning that checks argv[optind] after option parsing.
However, CRIU can also call parse_options() from the RPC config parsing
path with argc == 0 and argv == NULL. This path was added by 99d52ec7dd
for req->config_file handling.
If an RPC configuration file contains "network-lock iptables",
has_network_lock_opt is set and the restore warning dereferences
argv[optind], crashing criu swrk.
Guard the restore warning with argv && optind < argc before accessing
argv[optind].
Fixes: 2e30db5c3d ("criu: add --network-lock option to allow nftables alternative")
Signed-off-by: Zhang Xuedong <2190206983@qq.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>
Commit 7daaa11aa ("mem: don't PROT_WRITE on reservation mmaps") started
to premap PROT_NONE and not-accountable VMAs with PROT_NONE, on the
assumption that such an area is only used to reserve address space and
will never get any data written into it.
That assumption does not hold for a COW root. check_cow_vmas() pairs two
VMAs that coincide by start/end and flags regardless of their protection
bits, so a parent's PROT_NONE, not-accountable reservation can become the
COW root of a child VMA that does have pages. premap_private_vma() maps
the root with PROT_NONE, the inherited child re-positions that mapping
with mremap(), and restore_priv_vma_content() then restores the child's
pages into it. Writing to (or memcmp()-ing against) a PROT_NONE mapping
faults, so the restored task dies:
(00.012587) 109: pr109-2 Read 409000 1 pages'
(00.012588) 109: \tpr109-2 Read page from self 409000/2000'
(00.012744) 109: pr109-2 Read 7f7bf9b2e000 1 pages'
(00.012745) 109: \tpr109-2 Read page from self 7f7bf9b2e000/3000'
(00.051495) 108: Error (criu/cr-restore.c:1268): 109 killed by signal 11: Segmentation fault'
This is easy to hit with an incremental dump of a process tree that keeps
re-mapping memory (e.g. zdtm/transition/maps007 with --pre and a forked
child), where a now-PROT_NONE region still has content in a child.
To fix this, restrict the PROT_NONE optimization to standalone VMAs
(vma->pvma == NULL). A COW root (vma->pvma == VMA_COW_ROOT) must stay
writable because its premapped area is shared via mremap() with
inherited children that may carry data.
Fixes: 7daaa11aa0 ("mem: don't PROT_WRITE on reservation mmaps")
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 custom core dump handler tries to call gdb which makes it much
easier to understand why something crashed especially in CI. For dnf
based distribution this currently does not work because gdb is missing.
This installs gdb on dnf based CI runs.
Signed-off-by: Adrian Reber <areber@redhat.com>
By default GitHub Actions cancels all in-progress and queued matrix
legs as soon as one leg fails (fail-fast: true). Re-running only the
failed job afterwards does not bring back the cancelled siblings, so
recovering from a single failure requires re-running the whole job.
Cancelling the siblings also hides information: whether the other
shards or environments would have passed or failed is exactly
what we want to know from a CI run, not something to discard
on the first failure. Set fail-fast: false on the matrix jobs
that were still inheriting the default, so every leg runs
to completion independently.
Assisted-by: Claude Code:claude-opus-4-8
Signed-off-by: Radostin Stoyanov <rstoyanov@fedoraproject.org>
Move the two remaining Cirrus CI Vagrant-based tests (no-VDSO and
non-root) into the existing vm-fedora-rawhide-test GitHub Actions
matrix job using Lima VMs.
Add fedora-no-vdso-{setup,test} and fedora-non-root-{setup,test}
functions to scripts/ci/lima.sh, expand the matrix in ci.yml with
the two new variants, make the reboot step conditional on
matrix.reboot, and remove .cirrus.yml and scripts/ci/vagrant.sh
along with their Makefile targets.
Assisted-by: Claude Code (claude-opus-4-6):claude-opus-4-6@default
Signed-off-by: Adrian Reber <areber@redhat.com>
The tests are no longer vagrant based. Remove it. Instead of naming it
lima based tests, just name it VM based tests.
Signed-off-by: Adrian Reber <areber@redhat.com>
Move the CentOS Stream 9 based test from Cirrus CI to GitHub
Actions using Lima VMs. Expand coverage to a matrix of CentOS
Stream 9 and 10 on x86_64.
Extract the common Lima VM setup steps (Lima install, image
caching, KVM enablement, VM start, source copy) into a reusable
composite action at .github/actions/lima-vm-setup.
Assisted-by: Claude:claude-opus-4-6
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>
The amdgpu plugin's local amdgpu_drm.h defines struct
drm_color_ctm_3x4 guarded by #ifndef HAVE_DRM_COLOR_CTM_3X4,
but HAVE_DRM_COLOR_CTM_3X4 was never defined by the build
system. On systems where libdrm headers already provide this
struct (e.g. Alpine with libdrm 2.4.131), clang rejects the
redefinition as a hard error, while gcc silently accepts
identical struct redefinitions as an extension.
Add a feature test that checks whether struct drm_color_ctm_3x4
is available in the system drm_mode.h and pass
-DHAVE_DRM_COLOR_CTM_3X4 when it is, so the local fallback
definition is skipped.
Assisted-by: Claude Code (claude-opus-4-6):2025-09-03
Signed-off-by: Adrian Reber <areber@redhat.com>
The CLANG=1 parameter was only used during the Docker image build
but never propagated to the container at runtime. The hardcoded
CC=gcc in docker.env always took precedence, causing the test
container to rebuild and test with gcc instead of clang.
Override CC and HOSTCC via docker run -e flags when CLANG is set.
Signed-off-by: Adrian Reber <areber@redhat.com>
Apply the same ZDTM test sharding strategy used by the Alpine CI
job to the Arch Linux CI job (GCC only). The ZDTM tests are split
across 4 shards (indices 0-3) with a 5th shard for non-shardable
tests (lazy pages, fault injection, plugins, etc.).
This reduces the Arch Linux CI time from ~30 minutes to ~10 minutes.
Assisted-by: Claude Code (https://claude.ai/code):claude-opus-4-6
Signed-off-by: Adrian Reber <areber@redhat.com>
- Explain the profile identification and namespace dumping process
- Document the use of the 'parasite profile' for non-disruptive dumping
- Detail policy loading via apparmor_parser and namespace reconstruction
- Support for modern features like Profile Stacking
- List kernel and filesystem requirements
Signed-off-by: Andrei Vagin <avagin@google.com>
- Explain the hardware-assisted shadow stack mechanism
- Document the state capture via NT_ARM_GCS ptrace regset
- Detail restoration using map_shadow_stack and sigframe integration
- List kernel requirements for AArch64 hosts
Signed-off-by: Andrei Vagin <avagin@google.com>
- Explain how zombies are identified and their exit codes captured
- Describe the 'helper technique' for restoring zombies via immediate exit
- Detail parent-child coordination to prevent premature reaping
- Add references to related technical documentation
Signed-off-by: Andrei Vagin <avagin@google.com>
- Explain the decouplling of socket paths and inodes
- Document the SIOCUNIXFILE ioctl for stable handle retrieval
- Describe the restoration workflow (tmpfs yard, peer coordination)
- Explain the capture and redelivery of in-flight file descriptors
- Clarify handling of external Unix sockets
Signed-off-by: Andrei Vagin <avagin@google.com>
- Explain the address and ABI mismatch challenges
- Detail the Proxy (Patching) method for older kernels
- Document the modern arch_prctl method for native vDSO mapping
- Explain the role and restoration of the VVAR data region
- Mention automatic feature detection via Kerndat
Signed-off-by: Andrei Vagin <avagin@google.com>
- Explain Build-ID extraction (ELF magic, 1MB mapping)
- Document 'buildid' (default) vs 'filesize' methods
- Explain the automatic fallback mechanism
- Describe the importance for security and memory pointer integrity
- Detail usage via the --file-validation flag
Signed-off-by: Andrei Vagin <avagin@google.com>
- Explain the mechanics of Lazy Migration and on-demand page loading
- Detail the Lazy Pages Daemon and the UFFD descriptor handover (SCM_RIGHTS)
- Document the use of non-cooperative UFFD features (Fork, Remap, Unmap)
- Describe the page fault handling loop and page server integration
- Clarify benefits and trade-offs of the lazy approach
Signed-off-by: Andrei Vagin <avagin@google.com>
- Detail the capture of device attributes (TUN vs TAP, Flags)
- Explain index preservation using TUNSETIFINDEX
- Document multi-queue support and re-attachment via TUNSETQUEUE
- Clarify current limitations (BPF filters, in-flight packets)
- Explain persistency management during restoration
Signed-off-by: Andrei Vagin <avagin@google.com>
- Explain the PTY index restoration 'brute-force' strategy
- Detail the capture of termios, winsize, and ownership
- Describe the restoration workflow for master and slave peers
- Clarify the status of buffered data and legacy BSD PTYs
- Document the re-binding of controlling terminals (TIOCSCTTY)
Signed-off-by: Andrei Vagin <avagin@google.com>
- Detail the mechanics of TCP Repair Mode and state manipulation
- Explain the role of libsoccr in capturing sequence numbers and options
- Document the network locking workflow using nftables/iptables
- Describe the 'Silent Close' technique to preserve peer connections
- Highlight the importance of sequence number and window restoration
Signed-off-by: Andrei Vagin <avagin@google.com>
- Formalize the CR_STATE_* state machine and synchronization mechanism
- Detail the multi-stage restoration workflow (Root Task, NS Prep, Forking, etc.)
- Explain the security rationale for Stage 6 (Credentials and Seccomp)
- Document the final transition via sigreturn and thread restoration
Signed-off-by: Andrei Vagin <avagin@google.com>
- Explain the use of sock_diag for kernel state extraction
- Describe the SCM_RIGHTS mechanism for queue inspection
- Detail TCP Repair Mode for connection restoration
- List supported families including Netlink and Packet sockets
- Improve overall structure and technical depth
Signed-off-by: Andrei Vagin <avagin@google.com>