We reintroduced this once already because it is quite easy to miss this
subtle aspect of proc mounting. The recent migration to
securejoin.MkdirAllInRoot could have also inadvertently reintroduced
this (though it didn't).
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
`signalAllProcesses()` depends on the cgroup and is expected to fail
when runc is running in rootless without an access to the cgroup.
When `RootlessCgroups` is set to `true`, runc just ignores the error
from `signalAllProcesses` and may leak some processes running.
(See the comments in PR 4395)
In the future, runc should walk the process tree to avoid such a leak.
Note that `RootlessCgroups` is a misnomer; it is set to `false` despite
the name when cgroup v2 delegation is configured.
This is expected to be renamed in a separate commit.
Fix issue 4394
Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
The following commands are moved from `contrib/cmd` to `tests/cmd`:
- fs-idmap
- pidfd-kill
- recvtty
- remap-rootfs
- sd-helper
- seccompagent
Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
1. Rename current -> got, expected -> want.
2. check_cgroup_value: add file name to output.
3. Improve functions description.
This is mostly to simplify debugging test failures.
Example output before:
current 500000 !? 500
After:
cpu.max.burst: got 500000, want 500
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
There's too much logic here figuring out which CPUs to use. Runc is a
low level tool and is not supposed to be that "smart". What's worse,
this logic is executed on every exec, making it slower. Some of the
logic in (*setnsProcess).start is executed even if no annotation is set,
thus making ALL execs slow.
Also, this should be a property of a process, rather than annotation.
The plan is to rework this.
This reverts commit afc23e3397.
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
It has been pointed out that some controllers can not accept multiple
lines of output at once. In particular, io.max can only set one device
at a time.
Practically, the only multi-line resource values we can get come from
unified.* -- let's write those line by line.
Add a test case.
Reported-by: Tao Shen <shentaoskyking@gmail.com>
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
There are cgroup v2 systems out there that do not have cgroup swap enabled,
and this test will probably fail in there.
Move it to a separate case, guarded with requires cgroups_swap.
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
1. Add "-maxdepth 2" to not dive too deep into cgroup hierarchy.
2. Add "-type f" to look for a regular file.
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
This test case fails when there's a single CPU. Fix this by adding
"require smp".
While at it, document the test case and add a FIXME to maybe remove
this test later.
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
The issue is the same as in commit 1b2adcf but for RT scheduler;
the fix is also the same.
Test case by ls-ggg.
Co-authored-by: ls-ggg <335814617@qq.com>
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Earlier, commit fce8dd4d already increased this timeout from 1 to 5 seconds.
Yet, I just saw this timeout being hit in actuated-arm CI.
Increase the timeout again, this time from 5 to 50 (100 * 0.5) seconds.
Also, use wait_pids_gone, and improve some comments.
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
1. A few tests use "criu check --feature" to check for a specific
feature. Let's generalize it.
2. Fix "checkpoint --pre-dump and restore" test to require memory
tracking (which is missing on ARM).
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Since commit c77aaa3f the tail of criu.log is printed by runc, so
there's no need to do the same thing in tests.
Related to 3711, 3816.
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
kcmp is often missing: https://man7.org/linux/man-pages/man2/kcmp.2.html
> Before Linux 5.12, this system call is available only if the
> kernel is configured with CONFIG_CHECKPOINT_RESTORE, since the
> original purpose of the system call was for the
> checkpoint/restore in user space (CRIU) feature. (The
> alternative to this system call would have been to expose
> suitable process information via the proc(5) filesystem; this was
> deemed to be unsuitable for security reasons.) Since Linux 5.12,
> this system call is also available if the kernel is configured
> with CONFIG_KCMP.
Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
This handles a corner case when joining a container having all
the processes running exclusively on isolated CPU cores to force
the kernel to schedule runc process on the first CPU core within the
cgroups cpuset.
The introduction of the kernel commit
46a87b3851f0d6eb05e6d83d5c5a30df0eca8f76 has affected this deterministic
scheduling behavior by distributing tasks across CPU cores within the
cgroups cpuset. Some intensive real-time application are relying on this
deterministic behavior and use the first CPU core to run a slow thread
while other CPU cores are fully used by real-time threads with SCHED_FIFO
policy. Such applications prevents runc process from joining a container
when the runc process is randomly scheduled on a CPU core owned by a
real-time thread.
Introduces isolated CPU affinity transition OCI runtime annotation
org.opencontainers.runc.exec.isolated-cpu-affinity-transition to restore
the behavior during runc exec.
Fix issue with kernel >= 6.2 not resetting CPU affinity for container processes.
Signed-off-by: Cédric Clerget <cedric.clerget@gmail.com>
When we run this:
mount --bind -o remount,diratime,strictatime "$DIR"
It fails in debian testing, when it is the second time we call this
function in the same bats test (i.e. when $DIR is defined already).
strace shows this syscall failing:
mount_setattr(3, "", AT_EMPTY_PATH, {attr_set=MOUNT_ATTR_NOSUID|MOUNT_ATTR_NODEV|MOUNT_ATTR_NOEXEC|MOUNT_ATTR_NOATIME|MOUNT_ATTR_STRICTATIME, attr_clr=MOUNT_ATTR_RDONLY|MOUNT_ATTR_NOATIME|MOUNT_ATTR_STRICTATIME|MOUNT_ATTR_NODIRATIME|0x40, propagation=0 /* MS_??? */, userns_fd=0}, 32) = -1 EINVAL (Invalid argument)
Note it has `MOUNT_ATTR_NOATIME` and `MOUNT_ATTR_STRICTATIME` which
probably causes it to return EINVAL.
This patch simply adds atime to the options, so the mount command now
works and fixes most of the tests in debian testing.
Signed-off-by: Rodrigo Campos <rodrigoca@microsoft.com>
relatime is not shown on some debian systems. Let's check that no other
setting that removes the relatime effect is set, as that should be
enough too.
For more info, see the issue linked in the comments.
Signed-off-by: Rodrigo Campos <rodrigo@sdfg.com.ar>
In issue #4210, if we don't provide `--cpu-burst` in `runc update`,
the value of cpu burst will always set to 0.
Signed-off-by: lifubang <lifubang@acmcoder.com>
Now that runc-dmz is opt-in, we no longer need to try to detect whether
SELinux would cause issues for us. We can also remove the
special-purpose build-tag we added.
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
If it is compiled, the user needs to opt-in with this env variable to
use it.
While we are there, remove the RUNC_DMZ=legacy as that is now the
default.
Signed-off-by: Rodrigo Campos <rodrigoca@microsoft.com>
It takes some time for the kernel to kill the process (and remove its
PID from cgroup.procs). To ensure we don't have flakes from reading
cgroup.procs right after the kill, check and wait for processes to
actually be gone.
Fixes: 4163
Reported-by: lifubang@acmcoder.com
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
This expression is specific to GNU awk (gawk), so if someone has other version
of awk installed, this won't work and it's not easy to see why.
Explicitly requiring gawk here is better.
Revert "tests/int/helpers: gawk -> awk"
This reverts commit 4e65118d02.
Reported-by: lifubang <lifubang@acmcoder.com>
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Our previous implementation of idmapped mounts and bind-mount sources
would open all of the source paths before we did any mounts, meaning
that mounts using sources from inside the container rootfs would not be
correct.
This has been fixed with the new on-demand system, and so add some
regression tests.
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
ridmap indicates that the id mapping should be applied recursively (only
really relevant for rbind mount entries), and idmap indicates that it
should not be applied recursively (the default). If no mappings are
specified for the mount, we use the userns configuration of the
container. This matches the behaviour in the currently-unreleased
runtime-spec.
This includes a minor change to the state.json serialisation format, but
because there has been no released version of runc with commit
fbf183c6f8 ("Add uid and gid mappings to mounts"), we can safely make
this change without affecting running containers. Doing it this way
makes it much easier to handle m.IsIDMapped() and indicating that a
mapping has been specified.
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
With the rework of nsexec.c to handle MOUNT_ATTR_IDMAP in our Go code we
can now handle arbitrary mappings without issue, so remove the primary
artificial limit of mappings (must use the same mapping as the
container's userns) and add some tests.
We still only support idmap mounts for bind-mounts because configuring
mappings for other filesystems would require switching our entire mount
machinery to the new mount API. The current design would easily allow
for this but we would need to convert new mount options entirely to the
fsopen/fsconfig/fsmount API. This can be done in the future.
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
Previously, all of our userns tests worked around the remapping issue by
creating the paths that runc would attempt to create (like /proc).
However, this isn't really accurate to how real userns containers are
created, so it's much better to actually remap the rootfs.
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
Given we've had several bugs in this behaviour that have now been fixed,
add an integration test that makes sure that you can start a container
that joins all of the namespaces of a second container.
The only namespace we do not join is the mount namespace, because
joining a namespace that has been pivot_root'd leads to a bunch of
errors. In principle, removing everything from config.json that requires
a mount _should_ work, but the root.path configuration is mandatory and
we cannot just ignore setting up the rootfs in the namespace joining
scenario (if the user has configured a different rootfs, we need to use
it or error out, and there's no reasonable way of checking if if the
rootfs paths are the same that doesn't result in spaghetti logic).
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
The owner of /proc/self/timens_offsets doesn't change after creating a
userns, meaning that we need to request stage-0 to write our timens
mappings for us. Before this patch, attempting to use timens with a
proper userns resulted in:
FATA[0000] nsexec-1[18564]: failed to update /proc/self/timens_offsets: Permission denied
FATA[0000] nsexec-0[18562]: failed to sync with stage-1: next state: Success
ERRO[0000] runc run failed: unable to start container process: can't get final child's PID from pipe: EOF
Fixes: ebc2e7c435 ("Support time namespace")
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
Our handling for name space paths with user namespaces has been broken
for a long time. In particular, the need to parse /proc/self/*id_map in
quite a few places meant that we would treat userns configurations that
had a namespace path as if they were a userns configuration without
mappings, resulting in errors.
The primary issue was down to the id translation helper functions, which
could only handle configurations that had explicit mappings. Obviously,
when joining a user namespace we need to map the ids but figuring out
the correct mapping is non-trivial in comparison.
In order to get the mapping, you need to read /proc/<pid>/*id_map of a
process inside the userns -- while most userns paths will be of the form
/proc/<pid>/ns/user (and we have a fast-path for this case), this is not
guaranteed and thus it is necessary to spawn a process inside the
container and read its /proc/<pid>/*id_map files in the general case.
As Go does not allow us spawn a subprocess into a target userns,
we have to use CGo to fork a sub-process which does the setns(2). To be
honest, this is a little dodgy in regards to POSIX signal-safety(7) but
since we do no allocations and we are executing in the forked context
from a Go program (not a C program), it should be okay. The other
alternative would be to do an expensive re-exec (a-la nsexec which would
make several other bits of runc more complicated), or to use nsenter(1)
which might not exist on the system and is less than ideal.
Because we need to logically remap users quite a few times in runc
(including in "runc init", where joining the namespace is not feasable),
we cache the mapping inside the libcontainer config struct. A future
patch will make sure that we stop allow invalid user configurations
where a mapping is specified as well as a userns path to join.
Finally, add an integration test to make sure we don't regress this again.
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
We had ignore lines for these warnings, but it turns out this is most
likely a bug in shellcheck and we can work around it by moving the
helper function definition before any of the functions that use the
helper function. Hopefully it'll be fixed soon.
Ref: https://github.com/koalaman/shellcheck/issues/2873
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
(For a container with no private PID namespace, that is).
When runc delete (or container.Destroy) is called on a stopped
container without private PID namespace and there are processes
in its cgroup, kill those.
Add a test case.
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Commit f8ad20f moved the kill logic from container destroy to container
kill (which is the right thing to do).
Alas, it broke the use case of doing "runc delete -f" for a container
which does not have its own private PID namespace, when its init process
is gone. In this case, some processes may still be running, and runc
delete -f should kill them (the same way as "runc kill" does).
It does not do that because the container status is "stopped" (as runc
considers the container with no init process as stopped), and so we only
call "destroy" (which was doing the killing before).
The fix is easy: if --force is set, call killContainer no matter what.
Add a test case, similar to the one in the previous commit.
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Commit f8ad20f made it impossible to kill leftover processes in a
stopped container that does not have its own PID namespace. In other
words, if a container init is gone, it is no longer possible to use
`runc kill` to kill the leftover processes.
Fix this by moving the check if container init exists to after the
special case of handling the container without own PID namespace.
While at it, fix the minor issue introduced by commit 9583b3d:
if signalAllProcesses is used, there is no need to thaw the
container (as freeze/thaw is either done in signalAllProcesses already,
or not needed at all).
Also, make signalAllProcesses return an error early if the container
cgroup does not exist (as it relies on it to do its job). This way, the
error message returned is more generic and easier to understand
("container not running" instead of "can't open file").
Finally, add a test case.
Fixes: f8ad20f
Fixes: 9583b3d
Co-authored-by: lifubang <lifubang@acmcoder.com>
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>