From e56366218394e1d0d30494ebf0402f63ee40d7fc Mon Sep 17 00:00:00 2001 From: Thilo Fromm Date: Fri, 6 Nov 2026 17:42:31 +0100 Subject: [PATCH] crun: remove outdated user patches Gentoo stabilised crun-1.30, upstream ingested the patches we're shipping. This change removes them to un-break the podman build. Signed-off-by: Thilo Fromm --- .../crun/0001-cve-2026-88264.patch | 132 ------------------ .../crun/0002-cve-2026-88265.patch | 106 -------------- .../app-containers/crun/README.md | 4 - 3 files changed, 242 deletions(-) delete mode 100644 sdk_container/src/third_party/coreos-overlay/coreos/user-patches/app-containers/crun/0001-cve-2026-88264.patch delete mode 100644 sdk_container/src/third_party/coreos-overlay/coreos/user-patches/app-containers/crun/0002-cve-2026-88265.patch delete mode 100644 sdk_container/src/third_party/coreos-overlay/coreos/user-patches/app-containers/crun/README.md diff --git a/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/app-containers/crun/0001-cve-2026-88264.patch b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/app-containers/crun/0001-cve-2026-88264.patch deleted file mode 100644 index 9c933c8c1e4..00000000000 --- a/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/app-containers/crun/0001-cve-2026-88264.patch +++ /dev/null @@ -1,132 +0,0 @@ -From e9e661946498b8cc7c3a68ce1ca507fc5b84aa53 Mon Sep 17 00:00:00 2001 -From: Giuseppe Scrivano -Date: Fri, 11 Sep 2026 09:01:58 +0000 -Subject: [PATCH] linux: validate /dev/null before reopening the std streams - -libcrun_reopen_dev_null() opened `/dev/null` inside the container -following symlinks and without checking that it is the null device, then -moved every std stream whose st_rdev matched to it. A rootfs providing -`/dev/null` as a symlink to a host file bind mounted into the container -made the open resolve to that file, and since regular files, pipes and -sockets all have st_rdev set to 0, the pipe- or socketpair-based std -streams were considered to be pointing to /dev/null and were replaced -with a descriptor for the host file, opened before dropping privileges. -The container payload then inherited a writable descriptor for it, and -maybe_chown_std_streams() changed its ownership to the container user. - -Open the file with O_NOFOLLOW, refuse to continue unless it is the -character device 1:3, and only consider std streams that are character -devices themselves. - -This is only reachable when nothing is mounted over /dev, so the rootfs -entry stays visible; the configurations generated by Docker, Podman, -containerd, CRI-O and `crun spec` mount a tmpfs there. - -Add a test case. - -Fixes: CVE-2026-88265 -Signed-off-by: Giuseppe Scrivano ---- - src/libcrun/linux.c | 12 ++++++++++-- - tests/test_devices.py | 41 +++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 51 insertions(+), 2 deletions(-) - -diff --git a/src/libcrun/linux.c b/src/libcrun/linux.c -index 710438b37f..11f26cc7f4 100644 ---- a/src/libcrun/linux.c -+++ b/src/libcrun/linux.c -@@ -4038,6 +4038,11 @@ libcrun_do_pivot_root (libcrun_container_t *container, bool no_pivot, char **roo - return 0; - } - -+/* Device number of the null device, as documented in -+ * Documentation/admin-guide/devices.txt. */ -+#define DEV_NULL_MAJOR 1 -+#define DEV_NULL_MINOR 3 -+ - /* If one of stdin, stdout, stderr are pointing to /dev/null on - * the outside of the container, this moves it to /dev/null inside - * of the container. This needs to run after pivot/chroot-ing. */ -@@ -4050,18 +4055,21 @@ libcrun_reopen_dev_null (libcrun_error_t *err) - int i; - - /* Open /dev/null inside of the container. */ -- fd = open ("/dev/null", O_RDWR | O_CLOEXEC); -+ fd = open ("/dev/null", O_RDWR | O_CLOEXEC | O_NOFOLLOW); - if (UNLIKELY (fd == -1)) - return crun_make_error (err, errno, "open `/dev/null`"); - - if (UNLIKELY (fstat (fd, &dev_null) == -1)) - return crun_make_error (err, errno, "stat `/dev/null`"); - -+ if (UNLIKELY (! S_ISCHR (dev_null.st_mode) || dev_null.st_rdev != makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR))) -+ return crun_make_error (err, 0, "`/dev/null` is not the null device"); -+ - for (i = 0; i <= 2; i++) - { - if (UNLIKELY (fstat (i, &statbuf) == -1)) - return crun_make_error (err, errno, "stat fd `%d`", i); -- if (statbuf.st_rdev == dev_null.st_rdev) -+ if (S_ISCHR (statbuf.st_mode) && statbuf.st_rdev == dev_null.st_rdev) - { - /* This FD is pointing to /dev/null. Point it to /dev/null inside - * of the container. */ -diff --git a/tests/test_devices.py b/tests/test_devices.py -index b6e4c5caf2..6956e2bdcf 100755 ---- a/tests/test_devices.py -+++ b/tests/test_devices.py -@@ -399,6 +399,46 @@ def test_userns_precreated_devices_flags(): - return (77, "no precreated device mounts (mknod path taken)") - return 0 - -+def test_dev_null_symlink_not_reopened(): -+ host_file = os.path.join(get_tests_root(), "host-file") -+ with open(host_file, "w") as f: -+ f.write("host content") -+ -+ fake_dev = os.path.join(get_tests_root(), "fake-dev") -+ os.makedirs(fake_dev) -+ os.symlink("/host-file", os.path.join(fake_dev, "null")) -+ -+ conf = base_config() -+ add_all_namespaces(conf) -+ conf['process']['args'] = ['/init', 'echo', 'breakout'] -+ conf['mounts'] = [i for i in conf['mounts'] if not i['destination'].startswith("/dev")] -+ conf['mounts'].append({"destination": "/host-file", "type": "bind", -+ "source": host_file, "options": ["bind", "rw"]}) -+ conf['mounts'].append({"destination": "/dev", "type": "bind", -+ "source": fake_dev, "options": ["bind", "rw"]}) -+ -+ output = None -+ try: -+ run_and_get_output(conf) -+ except Exception as e: -+ output = e.output.decode() -+ -+ with open(host_file) as f: -+ content = f.read() -+ if content != "host content": -+ logger.error("the host file was written through `/dev/null`: %s", content) -+ return -1 -+ -+ if output is None: -+ logger.error("the container was not refused") -+ return -1 -+ -+ if "open `/dev/null`" not in output: -+ logger.error("the container failed for a different reason: %s", output) -+ return -1 -+ -+ return 0 -+ - def test_dev_symlink_does_not_populate_outside_rootfs(): - if is_rootless(): - return (77, "requires root privileges") -@@ -538,6 +578,7 @@ def test_allow_device_read_only(): - all_tests = { - "mknod-fifo-device": test_mknod_fifo_device, - "mknod-char-device": test_mknod_char_device, -+ "dev-null-symlink-not-reopened": test_dev_null_symlink_not_reopened, - "dev-symlink-does-not-populate-outside-rootfs": test_dev_symlink_does_not_populate_outside_rootfs, - "userns-precreated-devices-flags": test_userns_precreated_devices_flags, - "allow-device-read-only": test_allow_device_read_only, diff --git a/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/app-containers/crun/0002-cve-2026-88265.patch b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/app-containers/crun/0002-cve-2026-88265.patch deleted file mode 100644 index 57a867f4229..00000000000 --- a/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/app-containers/crun/0002-cve-2026-88265.patch +++ /dev/null @@ -1,106 +0,0 @@ -From ef32479522af883568ce4a5482358069ff71dc8f Mon Sep 17 00:00:00 2001 -From: Giuseppe Scrivano -Date: Fri, 11 Sep 2026 09:25:48 +0000 -Subject: [PATCH] utils: do not follow symlinks when creating /dev/console - -create_file_if_missing_at() is only used to create `/dev/console` in the -container rootfs when a terminal is requested, and it opened the file -with O_CREAT but without O_NOFOLLOW. A rootfs providing `/dev/console` -as a symlink made the open follow it, and since the devices are created -before the pivot_root the target was resolved against the host file -system, so crun created a root owned file at a path chosen by the -container image. - -Open the file with O_NOFOLLOW, and check for an already existing file -without following symlinks either, so that a symlink is not mistaken for -a regular file that is already there. - -This is only reachable when nothing is mounted over /dev, so the rootfs -entry stays visible; the configurations generated by Docker, Podman, -containerd, CRI-O and `crun spec` mount a tmpfs there. - -Add a test case. - -Fixes: CVE-2026-88264 -Signed-off-by: Giuseppe Scrivano ---- - src/libcrun/utils.c | 4 ++-- - tests/test_devices.py | 36 ++++++++++++++++++++++++++++++++++++ - 2 files changed, 38 insertions(+), 2 deletions(-) - -diff --git a/src/libcrun/utils.c b/src/libcrun/utils.c -index ce44c2610a..76175411cc 100644 ---- a/src/libcrun/utils.c -+++ b/src/libcrun/utils.c -@@ -201,7 +201,7 @@ get_file_type (mode_t *mode, bool nofollow, const char *path) - int - create_file_if_missing_at (int dirfd, const char *file, mode_t mode, libcrun_error_t *err) - { -- cleanup_close int fd_write = openat (dirfd, file, O_CLOEXEC | O_CREAT | O_WRONLY, mode); -+ cleanup_close int fd_write = openat (dirfd, file, O_CLOEXEC | O_CREAT | O_WRONLY | O_NOFOLLOW, mode); - if (fd_write < 0) - { - int saved_errno = errno; -@@ -209,7 +209,7 @@ create_file_if_missing_at (int dirfd, const char *file, mode_t mode, libcrun_err - int ret; - - /* On errors, check if the file already exists. */ -- ret = get_file_type_at (dirfd, &tmp_mode, false, file); -+ ret = get_file_type_at (dirfd, &tmp_mode, true, file); - if (ret == 0 && S_ISREG (tmp_mode)) - return 0; - -diff --git a/tests/test_devices.py b/tests/test_devices.py -index 6956e2bdcf..a99753a3c4 100755 ---- a/tests/test_devices.py -+++ b/tests/test_devices.py -@@ -439,6 +439,41 @@ def test_dev_null_symlink_not_reopened(): - - return 0 - -+def test_dev_console_symlink_does_not_escape_rootfs(): -+ escaped = os.path.join(get_tests_root(), "escaped-console") -+ -+ conf = base_config() -+ add_all_namespaces(conf) -+ conf['process']['terminal'] = True -+ conf['process']['args'] = ['/init', 'true'] -+ conf['mounts'] = [i for i in conf['mounts'] if not i['destination'].startswith("/dev")] -+ # a hook forces the deferred pivot_root, so the rootfs is still reached -+ # through the host file system when the devices are created. -+ conf['hooks'] = {"createRuntime": [{"path": "/bin/true"}]} -+ -+ def prepare_rootfs(rootfs): -+ os.symlink(escaped, os.path.join(rootfs, "dev", "console")) -+ -+ output = None -+ try: -+ run_and_get_output(conf, callback_prepare_rootfs=prepare_rootfs) -+ except Exception as e: -+ output = e.output.decode() -+ -+ if os.path.lexists(escaped): -+ logger.error("`%s` was created outside the rootfs", escaped) -+ return -1 -+ -+ if output is None: -+ logger.error("the container was not refused") -+ return -1 -+ -+ if "create file `console`" not in output: -+ logger.error("the container failed for a different reason: %s", output) -+ return -1 -+ -+ return 0 -+ - def test_dev_symlink_does_not_populate_outside_rootfs(): - if is_rootless(): - return (77, "requires root privileges") -@@ -579,6 +614,7 @@ def test_allow_device_read_only(): - "mknod-fifo-device": test_mknod_fifo_device, - "mknod-char-device": test_mknod_char_device, - "dev-null-symlink-not-reopened": test_dev_null_symlink_not_reopened, -+ "dev-console-symlink-does-not-escape-rootfs": test_dev_console_symlink_does_not_escape_rootfs, - "dev-symlink-does-not-populate-outside-rootfs": test_dev_symlink_does_not_populate_outside_rootfs, - "userns-precreated-devices-flags": test_userns_precreated_devices_flags, - "allow-device-read-only": test_allow_device_read_only, diff --git a/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/app-containers/crun/README.md b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/app-containers/crun/README.md deleted file mode 100644 index 4c20010dea8..00000000000 --- a/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/app-containers/crun/README.md +++ /dev/null @@ -1,4 +0,0 @@ -Patches `0001-cve-2026-88264.patch` and `0002-cve-2026-88265.patch` -are fixing some symlink-related security issues. At the time of -writing, there is no release with these fixes. These patches could -probably be dropped when crun-1.30 or 1.29.2 is released.