238 Commits

Author SHA1 Message Date
sean 3805b01e8a ci(checkpoint): workaround to avoid mutate cgroupv2 mount options
add --manage-cgroups-mode ignore to avoid pollute cgroupv2 mount options
during unittest and intergration test
https://github.com/checkpoint-restore/criu/issues/3029

Signed-off-by: sean <xujihui1985@gmail.com>
2026-06-23 18:59:03 +08:00
Ricardo Branco de39d5e79b tests/int: relax testPids fork error match string
The test checked for the exact BusyBox ash diagnostic "sh: can't fork".
With BusyBox 1.38, ash reports the failure as:

  /bin/sh: line 0: can't fork: Resource temporarily unavailable

Match the stable "can't fork" part of the error message instead.

Signed-off-by: Ricardo Branco <rbranco@suse.de>
2026-05-25 21:52:19 +02:00
Ricardo Branco 3acb097f93 tests/int: build TestPids pipelines programmatically
TestPids used long hand-written /bin/true pipelines for the 4-, 32- and
64-command cases. This made the test easy to typo and hard to review, as
seen by the earlier "bin/true" entries.

Build the shell pipelines instead, preserving the existing test coverage
while making the command counts explicit.

Signed-off-by: Ricardo Branco <rbranco@suse.de>
2026-05-25 21:52:19 +02:00
Kir Kolyshkin 1d12f98f85 tests/int: fix TestHook flakiness
Since commit 3cdda46 the poststart hooks runs after the container
process start, and so they race.

Move the poststart hook check to a separate step after the container
process has exited.

Fixes 5245.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2026-04-20 16:35:49 -07:00
Kir Kolyshkin 905958ea65 tests/int: show stderr if command failed part II
This adds a few cases missed by commit bf4fcc30.

Fixes: bf4fcc30
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2026-04-18 15:43:03 -07:00
Rodrigo Campos 748af2e285 libct/test: Disable GC on test run to catch leaking fds
This test is racy for a long time now. All the logs I could find in CI
seem to be dangling symlinks, like the test shows "23 -> ". This means
the fd was closed before we did the call to readlink().

Let's try to disable the GC. This should get rid of the "fds are getting
closed before we read them" part.

Updates: #4297

Signed-off-by: Rodrigo Campos <rodrigo@amutable.com>
2026-04-15 17:08:29 -07:00
Kir Kolyshkin 9970cbfdb6 libct/int: switch from bytes.Buffer to strings.Builder
The latter is simpler and provides just enough functionality to be used
here.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2026-04-14 17:05:06 -07:00
Kir Kolyshkin 568a309225 libct/int: remove buffers.Stdin
It is never used.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2026-04-14 17:05:06 -07:00
Kir Kolyshkin 54be90bf68 libct/int: use readlink -v
By default, readlink is silent about any errors. Make it verbose so we
can better interpret any test failures.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2026-04-14 17:05:05 -07:00
Kir Kolyshkin bf4fcc3002 libct/int: show stderr if command failed
When running a process inside a container, make sure its stderr is not
nil (except for some trivial cases like cat). Modify waitProcess to show
failed command's stderr, if possible.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2026-04-14 17:04:18 -07:00
Kir Kolyshkin dd9fda7d60 libct/int: waitProcess: rm dead code
Since Wait returns an ExitError if process' exit status is not 0,
checking process status is redundant and this code is never reached.

Remove it.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2026-04-14 17:03:56 -07:00
Aleksa Sarai ca509e76ff libct: move cmsg helpers to new internal/cmsg package
These helpers all make more sense as a self-contained package and moving
them has the added benefit of removing an unneeded libpathrs dependency
(from libcontainer/utils's import of pathrs-lite) from several test
binaries.

Signed-off-by: Aleksa Sarai <aleksa@amutable.com>
2026-04-08 01:21:41 +10:00
Kir Kolyshkin 652269729d libc/int: use strings.Builder
Generated by modernize@latest (v0.21.0).

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2025-12-16 15:04:04 -08:00
Curd Becker 536e183451 Replace os.Is* error checking functions with their errors.Is counterpart
Signed-off-by: Curd Becker <me@curd-becker.de>
2025-12-11 03:16:02 +01:00
Akihiro Suda 64c3c8eea6 Merge pull request #4994 from kolyshkin/gofumpt-extra
Enable gofumpt extra rules
2025-11-28 09:30:57 +09:00
Kir Kolyshkin 5fbc3bb019 libct/int: TestFdLeaks: deflake
Since the recent CVE fixes, TestFdLeaksSystemd sometimes fails:

	=== RUN   TestFdLeaksSystemd
	    exec_test.go:1750: extra fd 9 -> /12224/task/13831/fd
	    exec_test.go:1753: found 1 extra fds after container.Run
	--- FAIL: TestFdLeaksSystemd (0.10s)

It might have been caused by the change to the test code in commit
ff6fe13 ("utils: use safe procfs for /proc/self/fd loop code") -- we are
now opening a file descriptor during the logic to get a list of file
descriptors. If the file descriptor happens to be allocated to a
different number, you'll get an error.

Let's try to filter out the fd used to read a directory.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2025-11-20 15:36:14 +08:00
Aleksa Sarai 3b75374cc7 runtime-spec: update pids.limit handling to match new guidance
The main update is actually in github.com/opencontainers/cgroups, but we
need to also update runtime-spec to a newer pre-release version to get
the updates from there as well.

In short, the behaviour change is now that "0" is treated as a valid
value to set in "pids.max", "-1" means "max" and unset/nil means "do
nothing". As described in the opencontainers/cgroups PR, this change is
actually backwards compatible because our internal state.json stores
PidsLimit, and that entry is marked as "omitempty". So, an old runc
would omit PidsLimit=0 in state.json, and this will be parsed by a new
runc as being "nil" -- and both would treat this case as "do not set
anything".

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2025-11-11 15:15:27 +11:00
Kir Kolyshkin 67840cce4b Enable gofumpt extra rules
Commit b2f8a74d "clothed" the naked return as inflicted by gofumpt
v0.9.0. Since gofumpt v0.9.2 this rule was moved to "extra" category,
not enabled by default. The only other "extra" rule is to group adjacent
parameters with the same type, which also makes sense.

Enable gofumpt "extra" rules, and reformat the code accordingly.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2025-11-10 13:18:45 -08:00
Aleksa Sarai ff6fe13246 utils: use safe procfs for /proc/self/fd loop code
From a safety perspective this might not be strictly required, but it
paves the way for us to remove utils.ProcThreadSelf.

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2025-11-01 21:24:04 +11:00
Kir Kolyshkin b2f8a74de5 all: format sources with gofumpt v0.9.1
Since gofumpt v0.9.0 there's a new formatting rule to "clothe" any naked
returns.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2025-10-07 17:08:56 -07:00
Aleksa Sarai 627054d246 lint/revive: add package doc comments
This silences all of the "should have a package comment" lint warnings
from golangci-lint.

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2025-10-03 15:17:43 +10:00
Kir Kolyshkin 89e59902c4 Modernize code for Go 1.24
Brought to you by

	modernize -fix -test ./...

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2025-08-27 19:11:02 -07:00
Kir Kolyshkin 17570625c0 Use for range over integers
This appears in Go 1.22 (see https://tip.golang.org/ref/spec#For_range).

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2025-03-31 17:15:06 -07:00
Kir Kolyshkin a638f1330b .golangci.yml: add nolintlint, fix found issues
The errrolint linter can finally ignore errors from Close,
and it also ignores direct comparisons of errors from x/sys/unix.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2025-03-24 11:59:54 -07:00
Kir Kolyshkin 65e0f2b719 libct/int: use destroyContainer
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2025-03-24 10:02:47 -07:00
Kir Kolyshkin 1aebfa3eab libct/int: don't use _ = runContainerOk
There is no need to explicitly ignore returned value.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2025-03-24 10:02:47 -07:00
Kir Kolyshkin 5ac77ed6d9 libct/int: add/use needUserNS helper
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2025-03-13 08:40:27 -07:00
Kir Kolyshkin a75076b4a4 Switch to opencontainers/cgroups
This removes libcontainer/cgroups packages and starts
using those from github.com/opencontainers/cgroups repo.

Mostly generated by:

  git rm -f libcontainer/cgroups

  find . -type f -name "*.go" -exec sed -i \
    's|github.com/opencontainers/runc/libcontainer/cgroups|github.com/opencontainers/cgroups|g' \
    {} +

  go get github.com/opencontainers/cgroups@v0.0.1
  make vendor
  gofumpt -w .

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2025-02-28 15:20:33 -08:00
Kir Kolyshkin 7dc2486889 libct: switch to numeric UID/GID/groups
This addresses the following TODO in the code (added back in 2015
by commit 845fc65e5):

> // TODO: fix libcontainer's API to better support uid/gid in a typesafe way.

Historically, libcontainer internally uses strings for user, group, and
additional (aka supplementary) groups.

Yet, runc receives those credentials as part of runtime-spec's process,
which uses integers for all of them (see [1], [2]).

What happens next is:

1. runc start/run/exec converts those credentials to strings (a User
   string containing "UID:GID", and a []string for additional GIDs) and
   passes those onto runc init.
2. runc init converts them back to int, in the most complicated way
   possible (parsing container's /etc/passwd and /etc/group).

All this conversion and, especially, parsing is totally unnecessary,
but is performed on every container exec (and start).

The only benefit of all this is, a libcontainer user could use user and
group names instead of numeric IDs (but runc itself is not using this
feature, and we don't know if there are any other users of this).

Let's remove this back and forth translation, hopefully increasing
runc exec performance.

The only remaining need to parse /etc/passwd is to set HOME environment
variable for a specified UID, in case $HOME is not explicitly set in
process.Env. This can now be done right in prepareEnv, which simplifies
the code flow a lot. Alas, we can not use standard os/user.LookupId, as
it could cache host's /etc/passwd or the current user (even with the
osusergo tag).

PS Note that the structures being changed (initConfig and Process) are
never saved to disk as JSON by runc, so there is no compatibility issue
for runc users.

Still, this is a breaking change in libcontainer, but we never promised
that libcontainer API will be stable (and there's a special package
that can handle it -- github.com/moby/sys/user). Reflect this in
CHANGELOG.

For 3998.

[1]: https://github.com/opencontainers/runtime-spec/blob/v1.0.2/config.md#posix-platform-user
[2]: https://github.com/opencontainers/runtime-spec/blob/v1.0.2/specs-go/config.go#L86

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2025-02-06 17:49:17 -08:00
Kir Kolyshkin 6c9ddcc648 libct: switch from libct/devices to libct/cgroups/devices/config
Use the old package name as an alias to minimize the patch.

No functional change; this just eliminates a bunch of deprecation
warnings.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2025-01-31 16:51:09 -08:00
Kir Kolyshkin 6171da6005 libct/configs: add HookList.SetDefaultEnv
1. Make CommandHook.Command a pointer, which reduces the amount of data
   being copied when using hooks, and allows to modify command hooks.

2. Add SetDefaultEnv, which is to be used by the next commit.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2025-01-09 18:22:53 +08:00
Kir Kolyshkin 390641d148 libct/int: improve TestExecInEnvironment
This is a slight refactor of TestExecInEnvironment, making it more
strict wrt checking the exec output.

1. Explain why DEBUG is added twice to the env.
2. Reuse the execEnv for the check.
3. Make the check more strict -- instead of looking for substrings,
   check line by line.
4. Add a check for extra environment variables.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2025-01-09 18:22:53 +08:00
Kir Kolyshkin 9a54594752 libct/int: add BenchmarkExecInBigEnv
Here's what it shows on my laptop (with -count 10 -benchtime 10s,
summarized by benchstat):

	                │   sec/op    │
	ExecTrue-20       8.477m ± 2%
	ExecInBigEnv-20   61.53m ± 1%

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2025-01-09 18:22:53 +08:00
Kir Kolyshkin a56f85f87b libct/*: switch from configs to cgroups
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2024-12-11 19:08:40 -08:00
Kir Kolyshkin 1e674098f5 libct/int: add exec benchmark
This is a benchmark which checks how fast we can execute /bin/true
inside a container.

Results from my machine are below. As you can see, in default setup
about 70% of exec time is spent for CVE-2019-5736 (copying runc binary),
and using either RUNC_DMZ=true or memfd-bind helps a lot.

This can also be used for profiling (using -test.cpuprofile option).

=== Default setup ===

[kir@kir-tp1 integration]$ sudo ./integration.test -test.run xxx -test.v -test.benchtime 5s -test.count 5 -test.bench . .
goos: linux
goarch: amd64
pkg: github.com/opencontainers/runc/libcontainer/integration
cpu: 12th Gen Intel(R) Core(TM) i7-12800H
BenchmarkExecTrue
BenchmarkExecTrue-20    	     327	  24475677 ns/op
BenchmarkExecTrue-20    	     244	  25242718 ns/op
BenchmarkExecTrue-20    	     232	  26187174 ns/op
BenchmarkExecTrue-20    	     237	  26780030 ns/op
BenchmarkExecTrue-20    	     318	  18487219 ns/op
PASS

=== With DMZ enabled ===

[kir@kir-tp1 integration]$ sudo -E RUNC_DMZ=true ./integration.test -test.run xxx -test.v -test.benchtime 5s -test.count 5 -test.bench . .
goos: linux
goarch: amd64
pkg: github.com/opencontainers/runc/libcontainer/integration
cpu: 12th Gen Intel(R) Core(TM) i7-12800H
BenchmarkExecTrue
BenchmarkExecTrue-20    	     694	   8263744 ns/op
BenchmarkExecTrue-20    	     778	   8483228 ns/op
BenchmarkExecTrue-20    	     784	   8456018 ns/op
BenchmarkExecTrue-20    	     732	   8160239 ns/op
BenchmarkExecTrue-20    	     769	   8236972 ns/op
PASS

=== With memfd-bind ===

[kir@kir-tp1 integration]$ sudo systemctl start  memfd-bind@$(systemd-escape -p $PWD/integration.test)
[kir@kir-tp1 integration]$ sudo ./integration.test -test.run xxx -test.v -test.benchtime 5s -test.count 5 -test.bench . .
goos: linux
goarch: amd64
pkg: github.com/opencontainers/runc/libcontainer/integration
cpu: 12th Gen Intel(R) Core(TM) i7-12800H
BenchmarkExecTrue
BenchmarkExecTrue-20    	     800	   7538839 ns/op
BenchmarkExecTrue-20    	     717	   7424755 ns/op
BenchmarkExecTrue-20    	     848	   7747787 ns/op
BenchmarkExecTrue-20    	     800	   7668740 ns/op
BenchmarkExecTrue-20    	     751	   7304373 ns/op
PASS

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2024-10-24 13:39:26 -07:00
Kir Kolyshkin cb20148703 libct/int: use testing.TB for utils
...so that they can be used for benchmarks, too.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2024-10-24 13:39:26 -07:00
Kir Kolyshkin 0de1953333 runc spec, libct/int: do not add ambient capabilities
Commit 98fe566c removed inheritable capabilities from the example spec
(used by runc spec) and from the libcontainer/integration test config,
but neglected to also remove ambient capabilities.

An ambient capability could only be set if the same inheritable
capability is set, so as a result of the above change ambient
capabilities were not set (but due to a bug in gocapability package,
those errors are never reported).

Once we start using a library with the fix [1], that bug will become
apparent (both bats-based and libct/int tests will fail).

[1]: https://github.com/kolyshkin/capability/pull/3

Fixes: 98fe566c ("runc: do not set inheritable capabilities")
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2024-09-25 21:48:29 -07:00
Kir Kolyshkin 2c398bb41d libct/int/seccomp_test: simplify exit code checks
In all the three cases, we check that the program returned non-zero exit
code. This can be done in a much simpler manner.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2024-08-10 14:46:43 -07:00
Aleksa Sarai 81d63f265a merge #4331 into opencontainers/runc:main
Sebastiaan van Stijn (1):
  libct/userns: split userns detection from internal userns code

LGTMs: kolyshkin cyphar
2024-07-03 14:24:05 +10:00
Sebastiaan van Stijn 30b530ca94 libct/userns: split userns detection from internal userns code
Commit 4316df8b53 isolated RunningInUserNS
to a separate package to make it easier to consume without bringing in
additional dependencies, and with the potential to move it separate in
a similar fashion as libcontainer/user was moved to a separate module
in commit ca32014adb. While RunningInUserNS
is fairly trivial to implement, it (or variants of this utility) is used
in many codebases, and moving to a separate module could consolidate
those implementations, as well as making it easier to consume without
large dependency trees (when being a package as part of a larger code
base).

Commit 1912d5988b and follow-ups introduced
cgo code into the userns package, and code introduced in those commits
are not intended for external use, therefore complicating the potential
of moving the userns package separate.

This commit moves the new code to a separate package; some of this code
was included in v1.1.11 and up, but I could not find external consumers
of `GetUserNamespaceMappings` and `IsSameMapping`. The `Mapping` and
`Handles` types (added in ba0b5e2698) only
exist in main and in non-stable releases (v1.2.0-rc.x), so don't need
an alias / deprecation.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-06-30 20:06:30 +02:00
Sebastiaan van Stijn c14213399a remove pre-go1.17 build-tags
Removed pre-go1.17 build-tags with go fix;

    go fix -mod=readonly ./...

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-06-29 15:45:25 +02:00
Kir Kolyshkin 42cea2ecb4 libct: don't allow to start second init process
By definition, every container has only 1 init (i.e. PID 1) process.

Apparently, libcontainer API supported running more than 1 init, and
at least one tests mistakenly used it.

Let's not allow that, erroring out if we already have init. Doing
otherwise _probably_ results in some confusion inside the library.

Fix two cases in libct/int which ran two inits inside a container.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2024-06-10 22:30:03 -07:00
Kir Kolyshkin 36be6d0510 libct/int: checkpoint test: skip pre-dump if not avail
Since we're now testing on ARM, the test case fails when trying to do
pre-dump since MemTrack is not available.

Skip the pre-dump part if so.

This also reverts part of commit 3f4a73d6 as it is no longer needed
(now, instead of skipping the whole test, we're just skipping the
pre-dump).

[Review with --ignore-all-space]

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2024-05-10 11:04:58 -07:00
Kir Kolyshkin e42d981d67 libct/int: rm double logging in checkpoint_test
Since commit c77aaa3f the tail of criu log is printed by runc, so
there's no need to do the same thing in tests.

This also fixes a test failure on ARM where showLog fails (because
there's no log file) and thus the conditional t.Skip is not called.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2024-05-09 15:18:29 -07:00
Kir Kolyshkin 62a314656a libct/int/cpt: simplify test pre-check
criu check --feature userns also tests for the /proc/self/ns/user
presense, so remove the redundant check, and simplify the error message.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2024-05-09 15:18:29 -07:00
lifubang 4ea0bf88fd update/add some tests for rlimit
issues:
https://github.com/opencontainers/runc/issues/4195
https://github.com/opencontainers/runc/pull/4265#discussion_r1588599809

Signed-off-by: lifubang <lifubang@acmcoder.com>
2024-05-08 10:57:10 +00:00
Aleksa Sarai 8e1cd2f56d init: verify after chdir that cwd is inside the container
If a file descriptor of a directory in the host's mount namespace is
leaked to runc init, a malicious config.json could use /proc/self/fd/...
as a working directory to allow for host filesystem access after the
container runs. This can also be exploited by a container process if it
knows that an administrator will use "runc exec --cwd" and the target
--cwd (the attacker can change that cwd to be a symlink pointing to
/proc/self/fd/... and wait for the process to exec and then snoop on
/proc/$pid/cwd to get access to the host). The former issue can lead to
a critical vulnerability in Docker and Kubernetes, while the latter is a
container breakout.

We can (ab)use the fact that getcwd(2) on Linux detects this exact case,
and getcwd(3) and Go's Getwd() return an error as a result. Thus, if we
just do os.Getwd() after chdir we can easily detect this case and error
out.

In runc 1.1, a /sys/fs/cgroup handle happens to be leaked to "runc
init", making this exploitable. On runc main it just so happens that the
leaked /sys/fs/cgroup gets clobbered and thus this is only consistently
exploitable for runc 1.1.

Fixes: GHSA-xr7r-f8xq-vfvv CVE-2024-21626
Co-developed-by: lifubang <lifubang@acmcoder.com>
Signed-off-by: lifubang <lifubang@acmcoder.com>
[refactored the implementation and added more comments]
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2024-01-24 00:20:58 +11:00
Akihiro Suda 3f4a73d632 TestCheckpoint: skip on ErrCriuMissingFeatures
Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
2023-12-19 18:47:03 +09:00
Aleksa Sarai 8e8b136c49 tree-wide: use /proc/thread-self for thread-local state
With the idmap work, we will have a tainted Go thread in our
thread-group that has a different mount namespace to the other threads.
It seems that (due to some bad luck) the Go scheduler tends to make this
thread the thread-group leader in our tests, which results in very
baffling failures where /proc/self/mountinfo produces gibberish results.

In order to avoid this, switch to using /proc/thread-self for everything
that is thread-local. This primarily includes switching all file
descriptor paths (CLONE_FS), all of the places that check the current
cgroup (technically we never will run a single runc thread in a separate
cgroup, but better to be safe than sorry), and the aforementioned
mountinfo code. We don't need to do anything for the following because
the results we need aren't thread-local:

 * Checks that certain namespaces are supported by stat(2)ing
   /proc/self/ns/...

 * /proc/self/exe and /proc/self/cmdline are not thread-local.

 * While threads can be in different cgroups, we do not do this for the
   runc binary (or libcontainer) and thus we do not need to switch to
   the thread-local version of /proc/self/cgroups.

 * All of the CLONE_NEWUSER files are not thread-local because you
   cannot set the usernamespace of a single thread (setns(CLONE_NEWUSER)
   is blocked for multi-threaded programs).

Note that we have to use runtime.LockOSThread when we have an open
handle to a tid-specific procfs file that we are operating on multiple
times. Go can reschedule us such that we are running on a different
thread and then kill the original thread (causing -ENOENT or similarly
confusing errors). This is not strictly necessary for most usages of
/proc/thread-self (such as using /proc/thread-self/fd/$n directly) since
only operating on the actual inodes associated with the tid requires
this locking, but because of the pre-3.17 fallback for CentOS, we have
to do this in most cases.

In addition, CentOS's kernel is too old for /proc/thread-self, which
requires us to emulate it -- however in rootfs_linux.go, we are in the
container pid namespace but /proc is the host's procfs. This leads to
the incredibly frustrating situation where there is no way (on pre-4.1
Linux) to figure out which /proc/self/task/... entry refers to the
current tid. We can just use /proc/self in this case.

Yes this is all pretty ugly. I also wish it wasn't necessary.

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2023-12-14 11:36:41 +11:00
Aleksa Sarai 09822c3da8 configs: disallow ambiguous userns and timens configurations
For userns and timens, the mappings (and offsets, respectively) cannot
be changed after the namespace is first configured. Thus, configuring a
container with a namespace path to join means that you cannot also
provide configuration for said namespace. Previously we would silently
ignore the configuration (and just join the provided path), but we
really should be returning an error (especially when you consider that
the configuration userns mappings are used quite a bit in runc with the
assumption that they are the correct mapping for the userns -- but in
this case they are not).

In the case of userns, the mappings are also required if you _do not_
specify a path, while in the case of the time namespace you can have a
container with a timens but no mappings specified.

It should be noted that the case checking that the user has not
specified a userns path and a userns mapping needs to be handled in
specconv (as opposed to the configuration validator) because with this
patchset we now cache the mappings of path-based userns configurations
and thus the validator can't be sure whether the mapping is a cached
mapping or a user-specified one. So we do the validation in specconv,
and thus the test for this needs to be an integration test.

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2023-12-05 17:46:09 +11:00