Commit Graph

7651 Commits

Author SHA1 Message Date
Aleksa Sarai 30d045fef3 utils: remove unneeded EnsureProcHandle
All of the callers of EnsureProcHandle now use filepath-securejoin's
ProcThreadSelf to get a file handle, which has much stricter
verification to avoid procfs attacks than EnsureProcHandle's very
simplistic filesystem type check.

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2025-11-05 19:12:40 +11:00
Aleksa Sarai 38c6daaeee 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-05 19:12:40 +11:00
Aleksa Sarai 43001471df apparmor: use safe procfs API for labels
EnsureProcHandle only protects us against a tmpfs mount, but the risk of
a procfs path being used (such as /proc/self/sched) has been known for a
while. Now that filepath-securejoin has a reasonably safe procfs API,
switch to it.

Fixes: GHSA-cgrx-mc8f-2prm CVE-2025-52881
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2025-11-05 19:12:40 +11:00
Aleksa Sarai 29e1e181d1 ci: add lint to forbid the usage of os.Create
os.Create is shorthand for open(O_CREAT|O_TRUNC) *without* O_EXCL, which
is incredibly unsafe for us to do when interacting with a container
rootfs (especially before pivot_root) as an attacker could swap the
target path with a symlink that points to the host filesystem, causing
us to delete the contents of or create host files.

We did have a similar bug in CVE-2024-45310, but in that case we
(luckily) didn't have O_TRUNC set which avoided the worst possible case.
However, os.Create does set O_TRUNC and we were using it in scenarios
that may have been exploitable.

Because of how easy it us for us to accidentally introduce this kind of
bug, we should simply not allow the usage of os.Create in our entire
codebase.

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2025-11-05 19:12:40 +11:00
Aleksa Sarai fb875cb9bc rootfs: avoid using os.Create for new device inodes
If an attacker were to make the target of a device inode creation be a
symlink to some host path, os.Create would happily truncate the target
which could lead to all sorts of issues. This exploit is probably not as
exploitable because device inodes are usually only bind-mounted for
rootless containers, which cannot overwrite important host files (though
user files would still be up for grabs).

The regular inode creation logic could also theoretically be tricked
into changing the access mode and ownership of host files if the
newly-created device inode was swapped with a symlink to a host path.

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2025-11-05 19:12:39 +11:00
Aleksa Sarai aa466450ae internal: add wrappers for securejoin.Proc*
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2025-11-05 19:12:39 +11:00
Aleksa Sarai 856848696e go.mod: update to github.com/cyphar/filepath-securejoin@v0.5.0
In order to avoid lint errors due to the deprecation of the top-level
securejoin methods ported from libpathrs, we need to adjust
internal/pathrs to use the new pathrs-lite subpackage instead.

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2025-11-05 19:12:39 +11:00
Aleksa Sarai 4371d08af8 console: verify /dev/pts/ptmx before use
This is primarily done out of an abudance of caution against runc exec
being attacked by a container where /dev/pts/ptmx has been replaced with
some other bad inode (a disconnected NFS handle, a symlink that goes
through a leaked runc file descriptor to reference a host ptmx, etc).

Unfortunately, we cannot trivially verify that /dev/pts/ptmx is actually
the /dev/pts from the container without storing stuff like the fsid in
the runc state.json, which is probably not worth the extra effort. This
should at least avoid the most concerning cases.

Reported-by: Aleksa Sarai <cyphar@cyphar.com>
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2025-11-05 19:12:39 +11:00
Aleksa Sarai 3b2c56b533 console: avoid trivial symlink attacks for /dev/console
An attacker could make /dev/console a symlink. This presents two
possible issues:

 1. os.Create will happily truncate targets, which could have resulted
    in a worse version of CVE-2024-4531. Luckily, this all happens after
    pivot_root(2) so the scope of that particular attack is fairly
    limited (you are unlikely to be able to easily access host rootfs
    files -- though it might be possible to take advantage of leaks such
    as in CVE-2024-21626). However, O_CREAT|O_NOFOLLOW is what we should
    be doing for all file creations.

 2. Because we passed /dev/console as the only mount path (as opposed to
    using a /proc/self/fd/$n path), an attacker could swap the symlink
    to point to any other path and thus cause us to mount over some
    other path. This is not as big of a problem because all the mounts
    are in the container namespace after pivot_root(2), and users
    usually can create arbitrary mount targets inside the container.

These issues don't seem particularly exploitable, but they deserve to be
hardened regardless.

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2025-11-05 19:12:39 +11:00
Aleksa Sarai fe3794db4a console: add fallback for pre-TIOCGPTPEER kernels
The pty driver has very consistent allocation rules for the major:minor
numbers of /dev/pts/$n inodes, so it is possible to somewhat safely open
/dev/pts/* paths if we validate that the inode is the one we expect.

It is possible for an attacker to have over-mounted a pts peer from a
different devpts instance, but to fix this would require more tracking
of devpts instances than runc currently can do.

This means runc should continue to work on very old kernels.

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2025-11-05 19:12:38 +11:00
Aleksa Sarai 967c632b37 console: use TIOCGPTPEER when allocating peer PTY
When opening the peer end of a pty, the old kernel API required us to
open /dev/pts/$num inside the container (at least since we fixed console
handling many years ago in commit 244c9fc426 ("*: console rewrite")).

The problem is that in a hostile container it is possible for
/dev/pts/$num to be an attacker-controlled symlink that runc can be
tricked into resolving when doing bind-mounts. This allows the attacker
to (among other things) persist /proc/... entries that are later masked
by runc, allowing an attacker to escape through the kernel.core_pattern
sysctl (/proc/sys/kernel/core_pattern). This is the original issue
reported by Lei Wang and Li Fu Bang in CVE-2025-52565.

However, it should be noted that this is not entirely a newly-discovered
problem. Way back in Linux 4.13 (2017), I added the TIOCGPTPEER ioctl,
which allows us to get a pty peer without touching the /dev/pts inside
the container. The original threat model was around an attacker
replacing /dev/pts/$n or /dev/pts/ptmx with some malicious inode (a DoS
inode, or possibly a PTY they wanted a confused deputy to operate on).
Unfortunately, there was no practical way for runc to cache a safe
O_PATH handle to /dev/pts/ptmx (unlike other runtimes like LXC, which
switched to TIOCGPTPEER way back in 2017). Since it wasn't clear how we
could protect against the main attack TIOCGPTPEER was meant to protect
against, we never switched to it (even though I implemented it
specifically to harden container runtimes).

Unfortunately, It turns out that mount *sources* are a threat we didn't
fully consider. Since TIOCGPTPEER already solves this problem entirely
for us in a race free way, we should just use that. In a later patch, we
will add some hardening for /dev/pts/$num opening to maintain support
for very old kernels (Linux 4.13 is very old at this point, but RHEL 7
is still kicking and is stuck on Linux 3.10).

Fixes: GHSA-qw9x-cqr3-wc7r CVE-2025-52565
Reported-by: Lei Wang <ssst0n3@gmail.com> (CVE-2025-52565)
Reported-by: lfbzhm <lifubang@acmcoder.com> (CVE-2025-52565)
Reported-by: Aleksa Sarai <cyphar@cyphar.com> (TIOCGPTPEER)
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2025-11-05 19:12:38 +11:00
Kir Kolyshkin d1affbb8d3 libct: maskPaths: don't rely on ENOTDIR for mount
Currently, we rely on mount returning ENOTDIR when the destination is a
directory (and so mount tells us that the source is not), and fall back
to read-only tmpfs bind mount for such cases.

Theoretically, ENOTDIR can also be returned in some other cases,
resulting in the wrong type of mount being used.

Let's be more straightforward here -- call fstat on destination file
descriptor, and use the proper mount depending on whether it is a
directory.

Reported-by: Rodrigo Campos <rodrigoca@microsoft.com>
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2025-11-05 19:12:38 +11:00
Kir Kolyshkin 32bce3d31a libct: maskPaths: only ignore ENOENT on mount dest
When mounting a path being masked, the /dev/null might disappear from
under us, and mount (even on an opened /dev/null file descriptor) will
return ENOENT, which we deliberately ignore, as there's no need to mask
non-existent paths.

Let's open the destination path and ignore ENOENT during open, then
mount via the destination file descriptor, not ignoring ENOENT.

Reported-by: lifubang <lifubang@acmcoder.com>
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2025-11-05 19:12:38 +11:00
Kir Kolyshkin ecf3b2d7ab libct: add/use isDevNull, verifyDevNull
The /dev/null in a container should not be trusted, because when /dev
is a bind mount, /dev/null is not created by runc itself.

1. Add isDevNull which checks the fd minor/major and device type,
   and verifyDevNull which does the stat and the check.

2. Rewrite maskPath to open and check /dev/null, and use its fd to
   perform mounts. Move the loop over the MaskPaths into the function,
   and rename it to maskPaths.

3. reOpenDevNull: use verifyDevNull and isDevNull.

4. fixStdioPermissions: use isDevNull instead of stat.

Fixes: GHSA-9493-h29p-rfm2 CVE-2025-31133
Co-authored-by: Rodrigo Campos <rodrigoca@microsoft.com>
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2025-11-05 19:12:38 +11:00
Aleksa Sarai 07fb281f0c *: switch to safer securejoin.Reopen
filepath-securejoin v0.3 gave us a much safer re-open primitive, we
should use it to avoid any theoretical attacks. Rather than using it
direcly, add a small pathrs wrapper to make libpathrs migrations in the
future easier...

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2025-11-05 19:12:37 +11:00
Aleksa Sarai adf26e11fb internal: move utils.MkdirAllInRoot to internal/pathrs
We will have more wrappers around filepath-securejoin, and so move them
to their own specific package so that we can eventually use libpathrs
fairly cleanly (by swapping out the implementation).

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2025-11-05 19:12:37 +11:00
Aleksa Sarai 67a0ae39f1 internal/sys: add VerifyInode helper
This will be used for a few security patches in later patches in this
patchset. The need to verify what kind of inode we are operating on in a
race-free way turns out to be quite a common pattern...

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2025-11-05 19:12:37 +11:00
Aleksa Sarai 1d5298a3d9 internal: linux: add package doc-comment
This is necessary for the pre-1.4 backports because internal/linux was
not present and the linters get angry when a new package without a doc
comment gets added.

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2025-11-05 19:12:37 +11:00
Aleksa Sarai 8aeb2a4bdd VERSION: release v1.4.0-rc.2
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
v1.4.0-rc.2
2025-10-09 14:35:07 +11:00
Aleksa Sarai a2f2cf31f8 CHANGELOG: add note about cpu shares changes
This was a notable change in v1.4.0-rc.1 but this was not sufficiently
well-signposted in our changelog.

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2025-10-09 14:35:06 +11:00
Aleksa Sarai b8f6fdb95a merge #4923 into opencontainers/runc:release-1.4
Joshua Rogers (1):
  fix(seccompagent): close received FDs, not loop index

LGTMs: lifubang cyphar
2025-10-09 14:29:17 +11:00
Joshua Rogers 0b8a41e38f fix(seccompagent): close received FDs, not loop index
Prevents accidentally closing 0/1/2 on error paths.

Signed-off-by: Joshua Rogers <MegaManSec@users.noreply.github.com>
(cherry picked from commit 8c1b3f9608)
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2025-10-08 16:44:42 -07:00
lfbzhm bf5aeecc03 Merge pull request #4921 from marquiz/release-1.4
[1.4] libcontainer/intelrdt: add support for EnableMonitoring field
2025-10-08 17:05:38 +08:00
lfbzhm 938693ba89 Merge pull request #4920 from cyphar/1.4-cgroup-clone-into-cgroup
[1.4] runc exec: use CLONE_INTO_CGROUP
2025-10-08 16:02:15 +08:00
Markus Lehtonen 1f9157d68d libcontainer/intelrdt: add support for EnableMonitoring field
The linux.intelRdt.enableMonitoring field enables the creation of
a per-container monitoring group. The monitoring group is removed when
the container is destroyed.

Signed-off-by: Markus Lehtonen <markus.lehtonen@intel.com>
(cherry picked from commit 7aa4e1a63d)
2025-10-08 10:46:21 +03:00
Kir Kolyshkin d792f9fdb1 [1.4] runc exec: use CLONE_INTO_CGROUP when available
It makes sense to make runc exec benefit from clone2(CLONE_INTO_CGROUP),
if it is available. Since it requires a recent kernel and might not work,
implement a fallback to older way of joining the cgroup.

Based on:
 - https://go-review.googlesource.com/c/go/+/417695
 - https://github.com/coreos/go-systemd/pull/458
 - https://github.com/opencontainers/cgroups/pull/26
 - https://github.com/opencontainers/runc/pull/4822

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
(cherry picked from commit 5af4dd4e64)
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2025-10-08 18:40:18 +11:00
Kir Kolyshkin 3338251984 [1.4] libct: use manager.AddPid to add exec to cgroup
The main benefit here is when we are using a systemd cgroup driver,
we actually ask systemd to add a PID, rather than doing it ourselves.
This way, we can add rootless exec PID to a cgroup.

This requires newer opencontainers/cgroups and coreos/go-systemd.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
(cherry picked from commit 37b5acc2d7)
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2025-10-08 18:40:17 +11:00
Kir Kolyshkin 7db9930fab [1.4] libct: move exec sub-cgroup handling down the line
Remove cgroupPaths field from struct setnsProcess, because:
 - we can get base cgroup paths from p.manager.GetPaths();
 - we can get sub-cgroup paths from p.process.SubCgroupPaths.

But mostly because we are going to need separate cgroup paths when
adopting cgroups.AddPid.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
(cherry picked from commit 5730a141f1)
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2025-10-08 18:38:56 +11:00
Kir Kolyshkin f19a4c7122 [1.4] libct: split addIntoCgroup into V1 and V2
The main idea is to maintain the code separately (and eventually kill V1
implementation).

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
(cherry picked from commit 5560020cbb)
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2025-10-08 18:38:56 +11:00
Kir Kolyshkin 207a497ce1 [1.4] libct: factor out addIntoCgroup from setnsProcess.start
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
(cherry picked from commit b39e0d6468)
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2025-10-08 18:38:56 +11:00
Kir Kolyshkin c443aee760 [1.4] script/setup_rootless.sh: chown nit
This fixes the following warning (seen on Fedora 42 and Ubuntu 24.04):

	+ sudo chown -R rootless.rootless /home/rootless
	chown: warning: '.' should be ':': ‘rootless.rootless’

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
(cherry picked from commit 7d6848f883)
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2025-10-08 18:38:55 +11:00
Kir Kolyshkin e470a84243 Merge pull request #4915 from cyphar/1.4-memory-policy
[1.4] Add memory policy and schemata support
2025-10-08 00:03:01 -07:00
Antti Kervinen 910f134598 [1.4] Add memory policy support
Implement support for Linux memory policy in OCI spec PR:
https://github.com/opencontainers/runtime-spec/pull/1282

Signed-off-by: Antti Kervinen <antti.kervinen@intel.com>
(cherry picked from commit eda7bdf80c)
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2025-10-08 13:55:50 +11:00
Markus Lehtonen 12ed7f7315 [1.4] events/intelrdt: report full schemata
Signed-off-by: Markus Lehtonen <markus.lehtonen@intel.com>
(cherry picked from commit 7be025fff3)
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2025-10-08 13:55:50 +11:00
Markus Lehtonen 517e7996d2 [1.4] libcontainer/intelrdt: add support for Schemata field
Implement support for the linux.intelRdt.schemata field of the spec.
This allows management of the "schemata" file in the resctrl group in a
generic way.

Signed-off-by: Markus Lehtonen <markus.lehtonen@intel.com>
(cherry picked from commit 41553216ee)
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2025-10-08 13:55:50 +11:00
Markus Lehtonen 3009f9d7d0 [1.4] libcontainer/intelrdt: refactor tests
Signed-off-by: Markus Lehtonen <markus.lehtonen@intel.com>
(cherry picked from commit 3867f826da)
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2025-10-08 13:55:50 +11:00
Markus Lehtonen a0858eaf3b [1.4] Update runtime-spec
Signed-off-by: Markus Lehtonen <markus.lehtonen@intel.com>
(cherry picked from commit 74c5436b7d)
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2025-10-08 05:29:27 +11:00
lfbzhm 82561ccdfc Merge pull request #4911 from cyphar/1.4-remove-libct-userns 2025-10-04 22:08:50 +08:00
Aleksa Sarai fb0268a004 libcontainer: remove deprecated package "userns"
This package was marked deprecated in commit 9b60a93cf3
("libcontainer/userns: migrate to github.com/moby/sys/userns"), which
was included in runc 1.2. Users have thus had a year to migrate to
github.com/moby/sys/userns and it's okay for us to remove this wrapper
package.

(Cherry-pick of commit e4f99b5c95b8f49434452edff82e73547c7a8252.)

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2025-10-04 14:39:19 +10:00
Aleksa Sarai f3e37f18e2 merge #4903 into opencontainers/runc:release-1.4
Li Fubang (2):
  test: runc run with personality syscall blocked by seccomp
  libct: setup personality before initializing seccomp

LGTMs: AkihiroSuda cyphar
2025-09-29 12:25:18 +10:00
lifubang edef954c3a test: runc run with personality syscall blocked by seccomp
Signed-off-by: lifubang <lifubang@acmcoder.com>
(cherry picked from commit 57f1bef422)
Signed-off-by: lifubang <lifubang@acmcoder.com>
2025-09-27 08:20:24 +00:00
lifubang a6efa62d5e libct: setup personality before initializing seccomp
Set the process personality early to ensure it takes effect before
seccomp is initialized. If seccomp filters are applied first and they
block personality-related system calls (e.g., `personality(2)`),
subsequent attempts to set the personality will fail.

Signed-off-by: lifubang <lifubang@acmcoder.com>
(cherry picked from commit f7dda6e6dc)
Signed-off-by: lifubang <lifubang@acmcoder.com>
2025-09-27 08:20:04 +00:00
Rodrigo Campos 1128fdb636 Merge pull request #4894 from rata/64k-alignment-v1.4
[1.4] tests/int/cgroups: Use 64K aligned limits for memory.max
2025-09-18 00:50:50 -03:00
donettom-1 b72f4a8d97 tests/int/cgroups: Use 64K aligned limits for memory.max
When a non–page-aligned value is written to memory.max, the kernel aligns it
down to the nearest page boundary. On systems with a page size greater
than 4K (e.g., 64K), this caused failures because the configured
memory.max value was not 64K aligned.

This patch fixes the issue by explicitly aligning the memory.max value
to 64K. Since 64K is also a multiple of 4K, the value is correctly
aligned on both 4K and 64K page size systems.

However, this approach will still fail on systems where the hardcoded
memory.max value is not aligned to the system page size.

Fixes: https://github.com/opencontainers/runc/issues/4841

Signed-off-by: Vishal Chourasia <vishalc@linux.ibm.com>
Signed-off-by: Donet Tom <donettom@linux.ibm.com>
(cherry picked from commit 830c479ae2)
Signed-off-by: Rodrigo Campos <rodrigoca@microsoft.com>
2025-09-17 09:13:39 +02:00
Rodrigo Campos 81fe240c7c Merge pull request #4892 from tych0/ucounts-1.4
[1.4] libcontainer/validator: allow setting user.* sysctls inside userns
2025-09-15 12:41:27 -03:00
Tycho Andersen bce56e0072 libcontainer/validator: allow setting user.* sysctls inside userns
These sysctls are all per-userns (termed `ucounts` in the kernel code) are
settable with CAP_SYS_RESOURCE in the user namespace.

Signed-off-by: Tycho Andersen <tycho@tycho.pizza>
(cherry picked from commit 70d88bc449)
2025-09-15 08:46:53 -06:00
Aleksa Sarai 6297cb167d [1.4] VERSION: back to development
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2025-09-05 23:51:06 +10:00
Aleksa Sarai b2ec7f9201 VERSION: release v1.4.0-rc.1
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
v1.4.0-rc.1
2025-09-05 19:03:49 +10:00
Aleksa Sarai 081b8c25b3 CHANGELOG: forward-port v1.3.1 changelog
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2025-09-05 19:03:49 +10:00
Aleksa Sarai 1931ebf739 CHANGELOG: forward-port v1.2.7 changelog
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2025-09-05 19:03:49 +10:00