diff --git a/patch/0137-runc-Prohibit-proc-and-sys-to-be-symlinks.patch b/patch/0137-runc-Prohibit-proc-and-sys-to-be-symlinks.patch new file mode 100644 index 0000000..915da71 --- /dev/null +++ b/patch/0137-runc-Prohibit-proc-and-sys-to-be-symlinks.patch @@ -0,0 +1,117 @@ +From cfbeae219224f99be7c05c4a0e248a9f6931f941 Mon Sep 17 00:00:00 2001 +From: Kir Kolyshkin +Date: Thu, 16 Mar 2023 14:35:50 -0700 +Subject: [PATCH] Prohibit /proc and /sys to be symlinks + +Commit 3291d66b9844 introduced a check for /proc and /sys, making sure +the destination (dest) is a directory (and not e.g. a symlink). + +Later, a hunk from commit 0ca91f44f switched from using filepath.Join +to SecureJoin for dest. As SecureJoin follows and resolves symlinks, +the check whether dest is a symlink no longer works. + +To fix, do the check without/before using SecureJoin. + +Add integration tests to make sure we won't regress. + +Signed-off-by: Kir Kolyshkin +(cherry picked from commit 0d72adf96dda1b687815bf89bb245b937a2f603c) +Signed-off-by: Sebastiaan van Stijn +--- + libcontainer/rootfs_linux.go | 33 ++++++++++++++++++++------------- + tests/integration/mask.bats | 19 +++++++++++++++++++ + 2 files changed, 39 insertions(+), 13 deletions(-) + +diff --git a/libcontainer/rootfs_linux.go b/libcontainer/rootfs_linux.go +index dc66d8a9..855bcdb0 100644 +--- a/libcontainer/rootfs_linux.go ++++ b/libcontainer/rootfs_linux.go +@@ -160,29 +160,25 @@ func mountCmd(cmd configs.Command) error { + } + + func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error { +- var ( +- dest = m.Destination +- err error +- ) +- if !strings.HasPrefix(dest, rootfs) { +- dest, err = securejoin.SecureJoin(rootfs, m.Destination) +- if err != nil { +- return err +- } +- } ++ var err error + + switch m.Device { + case "proc", "sysfs": + // If the destination already exists and is not a directory, we bail +- // out This is to avoid mounting through a symlink or similar -- which ++ // out. This is to avoid mounting through a symlink or similar -- which + // has been a "fun" attack scenario in the past. + // TODO: This won't be necessary once we switch to libpathrs and we can + // stop all of these symlink-exchange attacks. ++ dest := filepath.Clean(m.Destination) ++ if !strings.HasPrefix(dest, rootfs) { ++ // Do not use securejoin as it resolves symlinks. ++ dest = filepath.Join(rootfs, dest) ++ } + if fi, err := os.Lstat(dest); err != nil { + if !os.IsNotExist(err) { + return err + } +- } else if fi.Mode()&os.ModeDir == 0 { ++ } else if !fi.IsDir() { + return fmt.Errorf("filesystem %q must be mounted on ordinary directory", m.Device) + } + if strings.HasPrefix(m.Destination, "/proc/sys/") { +@@ -191,8 +187,19 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error { + if err := os.MkdirAll(dest, 0755); err != nil { + return err + } +- // Selinux kernels do not support labeling of /proc or /sys ++ // Selinux kernels do not support labeling of /proc or /sys. + return mountPropagate(m, rootfs, "") ++ } ++ ++ var dest = m.Destination ++ if !strings.HasPrefix(dest, rootfs) { ++ dest, err = securejoin.SecureJoin(rootfs, m.Destination) ++ if err != nil { ++ return err ++ } ++ } ++ ++ switch m.Device { + case "mqueue": + if err := os.MkdirAll(dest, 0755); err != nil { + return err +diff --git a/tests/integration/mask.bats b/tests/integration/mask.bats +index 074b0f2e..64d53954 100644 +--- a/tests/integration/mask.bats ++++ b/tests/integration/mask.bats +@@ -61,3 +61,22 @@ function teardown() { + [ "$status" -eq 1 ] + [[ "${output}" == *"Operation not permitted"* ]] + } ++ ++@test "mask paths [prohibit symlink /proc]" { ++ ln -s /symlink rootfs/proc ++ runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox ++ [ "$status" -eq 1 ] ++ [[ "${output}" == *"must be mounted on ordinary directory"* ]] ++} ++ ++@test "mask paths [prohibit symlink /sys]" { ++ # In rootless containers, /sys is a bind mount not a real sysfs. ++ requires root ++ ++ ln -s /symlink rootfs/sys ++ runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox ++ [ "$status" -eq 1 ] ++ # On cgroup v1, this may fail before checking if /sys is a symlink, ++ # so we merely check that it fails, and do not check the exact error ++ # message like for /proc above. ++} +-- +2.33.0 + diff --git a/runc.spec b/runc.spec index 679344b..6933716 100644 --- a/runc.spec +++ b/runc.spec @@ -2,7 +2,7 @@ Name: docker-runc Version: 1.0.0.rc3 -Release: 211 +Release: 212 Summary: runc is a CLI tool for spawning and running containers according to the OCI specification. License: ASL 2.0 @@ -41,6 +41,12 @@ install -p -m 755 runc $RPM_BUILD_ROOT/%{_bindir}/runc %{_bindir}/runc %changelog +* Tue Apr 4 2023 zhongjiawei - 1.0.0.rc3-212 +- Type:bugfix +- CVE:NA +- SUG:NA +- DESC:Prohibit /proc and /sys to be symlinks + * Wed Mar 29 2023 zhongjiawei - 1.0.0.rc3-211 - Type:bugfix - CVE:NA diff --git a/series.conf b/series.conf index 862d2f5..1f7041a 100644 --- a/series.conf +++ b/series.conf @@ -128,3 +128,4 @@ 0134-runc-fix-seccomp-add-rule-failed.patch 0135-runc-libct-cg-fs-blkio-do-not-set-weight-0.patch 0136-runc-run-resolve-tmpfs-mount-dest-in-container-scope.patch +0137-runc-Prohibit-proc-and-sys-to-be-symlinks.patch