From patchwork Mon Sep 28 21:09:41 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Marko X-Patchwork-Id: 99528 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 26F90CA5FA1 for ; Mon, 28 Sep 2026 21:10:20 +0000 (UTC) Received: from mta-64-227.siemens.flowmailer.net (mta-64-227.siemens.flowmailer.net [185.136.64.227]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.69647.1790629814437377490 for ; Mon, 28 Sep 2026 14:10:16 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=peter.marko@siemens.com header.s=fm1 header.b=OqlY388R; spf=pass (domain: rts-flowmailer.siemens.com, ip: 185.136.64.227, mailfrom: fm-256628-20260928211011a78a3a9f76000207e0-qx1o23@rts-flowmailer.siemens.com) Received: by mta-64-227.siemens.flowmailer.net with ESMTPSA id 20260928211011a78a3a9f76000207e0 for ; Mon, 28 Sep 2026 23:10:11 +0200 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=fm1; d=siemens.com; i=peter.marko@siemens.com; h=Date:From:Subject:To:Message-ID:MIME-Version:Content-Type:Content-Transfer-Encoding:Cc; bh=UjdokxYyJT+Ta7JOz0YvVyCF+NIcAU64mVmgbR2ud7Q=; b=OqlY388ReQ/EFELrlwGWrXerh2xNCSvDaILYpSo3ewI5xrbn6SHiDmh8XR9wM+TF3JIowq kF5YebPiGH6WM5HI3ODkG9wuq6OPjeIqjkFVeSE9Iuc1et0uEzPcv7gjSdBu2BT3mQ8D3EmX nlWTwO9eyHQYhwoyuCaHnZJc/sqemak9VzgBAnXpKxX/RUA21XkGExeYGMBUYpoDPQyRa4Gk KF6W25yzFiFxZb2cVo8IjT1AK6V3ecFDZN1Mg9aQD7yEsTa1UZ+AtUhhDyQzTCqbXdKE7G+z AqXIDfBqvjwCqzyNtng/w941yCgZ91jL5Ppy9T7StrlIQOJRQCc4a3Mg==; From: Peter Marko To: yocto-patches@lists.yoctoproject.org Cc: Peter Marko Subject: [meta-virtualization][wrynose][PATCH] crun: patch CVE-2026-88264 Date: Mon, 28 Sep 2026 23:09:41 +0200 Message-ID: <20260928210941.679038-1-peter.marko@siemens.com> MIME-Version: 1.0 X-Flowmailer-Platform: Siemens Feedback-ID: 519:519-256628:519-21489:flowmailer List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Mon, 28 Sep 2026 21:10:20 -0000 X-Groupsio-URL: https://lists.yoctoproject.org/g/yocto-patches/message/4962 From: Peter Marko Pick patch referencing this CVE. Signed-off-by: Peter Marko --- .../crun/crun/CVE-2026-88264.patch | 109 ++++++++++++++++++ recipes-containers/crun/crun_git.bb | 1 + 2 files changed, 110 insertions(+) create mode 100644 recipes-containers/crun/crun/CVE-2026-88264.patch diff --git a/recipes-containers/crun/crun/CVE-2026-88264.patch b/recipes-containers/crun/crun/CVE-2026-88264.patch new file mode 100644 index 00000000..1d8eea96 --- /dev/null +++ b/recipes-containers/crun/crun/CVE-2026-88264.patch @@ -0,0 +1,109 @@ +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 + +CVE: CVE-2026-88264 +Upstream-Status: Backport [https://github.com/containers/crun/commit/ef32479522af883568ce4a5482358069ff71dc8f] +Signed-off-by: Peter Marko +--- + 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 ce44c261..76175411 100644 +--- a/src/libcrun/utils.c ++++ b/src/libcrun/utils.c +@@ -196,14 +196,14 @@ 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) + { + mode_t tmp_mode; + 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 6956e2bd..a99753a3 100755 +--- a/tests/test_devices.py ++++ b/tests/test_devices.py +@@ -369,6 +369,41 @@ def test_mknod_char_device(): + return -1 + 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") +@@ -508,6 +543,7 @@ def test_allow_device_read_only(): + all_tests = { + "mknod-fifo-device": test_mknod_fifo_device, + "mknod-char-device": test_mknod_char_device, ++ "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, + "allow-device-read-only": test_allow_device_read_only, + "owner-device" : test_owner_device, diff --git a/recipes-containers/crun/crun_git.bb b/recipes-containers/crun/crun_git.bb index 809b6c01..80468b0a 100644 --- a/recipes-containers/crun/crun_git.bb +++ b/recipes-containers/crun/crun_git.bb @@ -19,6 +19,7 @@ SRC_URI = "git://github.com/containers/crun.git;branch=main;name=crun;protocol=h file://0002-libocispec-fix-array-items-parsing.patch;patchdir=libocispec \ file://CVE-2026-30892.patch \ file://CVE-2026-47766.patch \ + file://CVE-2026-88264.patch \ " PV = "1.26.0+git"