Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package runc for openSUSE:Factory checked in at 2023-03-30 22:50:49 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/runc (Old) and /work/SRC/openSUSE:Factory/.runc.new.31432 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "runc" Thu Mar 30 22:50:49 2023 rev:52 rq:1075228 version:1.1.5 Changes: -------- --- /work/SRC/openSUSE:Factory/runc/runc.changes 2022-09-21 14:40:04.933363880 +0200 +++ /work/SRC/openSUSE:Factory/.runc.new.31432/runc.changes 2023-03-30 22:50:52.860450845 +0200 @@ -1,0 +2,19 @@ +Wed Mar 29 07:05:52 UTC 2023 - Aleksa Sarai <asa...@suse.com> + +- Update to runc v1.1.5. Upstream changelog is available from + <https://github.com/opencontainers/runc/releases/tag/v1.1.5>. + + Includes fixes for the following CVEs: + - CVE-2023-25809 bsc#1209884 + - CVE-2023-27561 bsc#1208962 + - CVE-2023-28642 bsc#1209888 + + * Fix the inability to use `/dev/null` when inside a container. + * Fix changing the ownership of host's `/dev/null` caused by fd redirection + (a regression in 1.1.1). bsc#1168481 + * Fix rare runc exec/enter unshare error on older kernels. + * nsexec: Check for errors in `write_log()`. + +- Drop version-specific Go requirement. + +------------------------------------------------------------------- Old: ---- runc-1.1.4.tar.xz runc-1.1.4.tar.xz.asc New: ---- runc-1.1.5.tar.xz runc-1.1.5.tar.xz.asc ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ runc.spec ++++++ --- /var/tmp/diff_new_pack.T63NcY/_old 2023-03-30 22:50:53.260452986 +0200 +++ /var/tmp/diff_new_pack.T63NcY/_new 2023-03-30 22:50:53.264453007 +0200 @@ -1,7 +1,7 @@ # # spec file for package runc # -# Copyright (c) 2022 SUSE LLC +# Copyright (c) 2023 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,29 +18,24 @@ # MANUAL: Make sure you update this each time you update runc. -%define git_version a916309fff0f838eb94e928713dbc3c0d0ac7aa4 -%define git_short a916309fff0f +%define git_version f19387a6bec4944c770f7668ab51c4348d9c2f38 +%define git_short f19387a6bec4 -# Package-wide golang version -%define go_version 1.18 %define project github.com/opencontainers/runc Name: runc -Version: 1.1.4 -%define _version 1.1.4 +Version: 1.1.5 Release: 0 Summary: Tool for spawning and running OCI containers License: Apache-2.0 Group: System/Management URL: https://github.com/opencontainers/runc -Source0: https://github.com/opencontainers/runc/releases/download/v%{_version}/runc.tar.xz#/runc-%{version}.tar.xz -Source1: https://github.com/opencontainers/runc/releases/download/v%{_version}/runc.tar.xz.asc#/runc-%{version}.tar.xz.asc +Source0: https://github.com/opencontainers/runc/releases/download/v%{version}/runc.tar.xz#/runc-%{version}.tar.xz +Source1: https://github.com/opencontainers/runc/releases/download/v%{version}/runc.tar.xz.asc#/runc-%{version}.tar.xz.asc Source2: runc.keyring BuildRequires: fdupes +BuildRequires: go BuildRequires: go-go-md2man -# Due to a limitation in openSUSE's Go packaging we cannot have a BuildRequires -# for 'golang(API) >= 1.x' here, so just require 1.x exactly. bsc#1172608 -BuildRequires: go%{go_version} BuildRequires: libseccomp-devel BuildRequires: libselinux-devel Recommends: criu @@ -58,7 +53,7 @@ ExcludeArch: s390 # Construct "git describe --dirty --long --always". -%define git_describe v%{_version}-0-g%{git_short} +%define git_describe v%{version}-0-g%{git_short} %description runc is a CLI tool for spawning and running containers according to the OCI @@ -67,7 +62,7 @@ and has grown to become a separate project entirely. %prep -%setup -q -n %{name}-%{_version} +%setup -q -n %{name}-%{version} %build # build runc ++++++ runc-1.1.4.tar.xz -> runc-1.1.5.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.4/.cirrus.yml new/runc-1.1.5/.cirrus.yml --- old/runc-1.1.4/.cirrus.yml 2022-08-24 02:45:13.000000000 +0200 +++ new/runc-1.1.5/.cirrus.yml 2023-03-29 08:45:53.000000000 +0200 @@ -70,6 +70,7 @@ CIRRUS_WORKING_DIR: /home/runc GO_VERSION: "1.17.3" BATS_VERSION: "v1.3.0" + RPMS: gcc git iptables jq glibc-static libseccomp-devel make criu fuse-sshfs # yamllint disable rule:key-duplicates matrix: DISTRO: centos-7 @@ -89,6 +90,8 @@ case $DISTRO in centos-7) (cd /etc/yum.repos.d && curl -O https://copr.fedorainfracloud.org/coprs/adrian/criu-el7/repo/epel-7/adrian-criu-el7-epel-7.repo) + # EPEL is needed for jq and fuse-sshfs. + rpm -q epel-release || rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm # sysctl echo "user.max_user_namespaces=15076" > /etc/sysctl.d/userns.conf sysctl --system @@ -104,9 +107,14 @@ # Work around dnf mirror failures by retrying a few times. for i in $(seq 0 2); do sleep $i - yum install -y -q gcc git iptables jq glibc-static libseccomp-devel make criu fuse-sshfs && break + yum install -y $RPMS && break done [ $? -eq 0 ] # fail if yum failed + + # Double check that all rpms were installed (yum from CentOS 7 + # does not exit with an error if some packages were not found). + # Use --whatprovides since some packages are renamed. + rpm -q --whatprovides $RPMS # install Go curl -fsSL "https://dl.google.com/go/go${GO_VERSION}.linux-amd64.tar.gz" | tar Cxz /usr/local # install bats diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.4/.github/workflows/validate.yml new/runc-1.1.5/.github/workflows/validate.yml --- old/runc-1.1.4/.github/workflows/validate.yml 2022-08-24 02:45:13.000000000 +0200 +++ new/runc-1.1.5/.github/workflows/validate.yml 2023-03-29 08:45:53.000000000 +0200 @@ -102,9 +102,9 @@ - uses: actions/checkout@v3 - name: vars run: | - echo 'VERSION=v0.7.2' >> $GITHUB_ENV + echo 'VERSION=v0.8.0' >> $GITHUB_ENV echo 'BASEURL=https://github.com/koalaman/shellcheck/releases/download' >> $GITHUB_ENV - echo 'SHA256SUM=12ee2e0b90a3d1e9cae24ac9b2838be66b48573cb2c8e8f3c566b959df6f050c' >> $GITHUB_ENV + echo 'SHA256SUM=f4bce23c11c3919c1b20bcb0f206f6b44c44e26f2bc95f8aa708716095fa0651' >> $GITHUB_ENV echo ~/bin >> $GITHUB_PATH - name: install shellcheck run: | diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.4/CHANGELOG.md new/runc-1.1.5/CHANGELOG.md --- old/runc-1.1.4/CHANGELOG.md 2022-08-24 02:45:13.000000000 +0200 +++ new/runc-1.1.5/CHANGELOG.md 2023-03-29 08:45:53.000000000 +0200 @@ -4,7 +4,26 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [Unreleased 1.1.z] + +## [1.1.5] - 2023-03-29 + +> åãããå±è¾±ã¯ +> åæã®åç¢ã + +### Fixed + +* Prohibit container's `/proc` and `/sys` to be symlinks (CVE-2019-19921, + CVE-2023-27561, CVE-2023-28642, #3785) +* rootless: rework /sys/fs/cgroup mounts to avoid exposing the host's cgroup + hierarchy into the container. (CVE-2023-25809) +* Fix the inability to use `/dev/null` when inside a container. (#3620) +* Fix changing the ownership of host's `/dev/null` caused by fd redirection + (a regression in 1.1.1). (#3674, #3731) +* Fix rare runc exec/enter unshare error on older kernels, inlcuding + CentOS < 7.7. (#3776) +* nsexec: Check for errors in `write_log()`. (#3721) +* Various CI fixes and updates. (#3618, #3630, #3640, #3729) ## [1.1.4] - 2022-08-24 @@ -315,7 +334,7 @@ cgroups at all during `runc update`). (#2994) <!-- minor releases --> -[Unreleased]: https://github.com/opencontainers/runc/compare/v1.1.4...HEAD +[Unreleased]: https://github.com/opencontainers/runc/compare/v1.1.0...HEAD [1.1.0]: https://github.com/opencontainers/runc/compare/v1.1.0-rc.1...v1.1.0 [1.0.0]: https://github.com/opencontainers/runc/releases/tag/v1.0.0 @@ -326,7 +345,8 @@ [1.0.1]: https://github.com/opencontainers/runc/compare/v1.0.0...v1.0.1 <!-- 1.1.z patch releases --> -[Unreleased 1.1.z]: https://github.com/opencontainers/runc/compare/v1.1.4...release-1.1 +[Unreleased 1.1.z]: https://github.com/opencontainers/runc/compare/v1.1.5...release-1.1 +[1.1.5]: https://github.com/opencontainers/runc/compare/v1.1.3...v1.1.5 [1.1.4]: https://github.com/opencontainers/runc/compare/v1.1.3...v1.1.4 [1.1.3]: https://github.com/opencontainers/runc/compare/v1.1.2...v1.1.3 [1.1.2]: https://github.com/opencontainers/runc/compare/v1.1.1...v1.1.2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.4/VERSION new/runc-1.1.5/VERSION --- old/runc-1.1.4/VERSION 2022-08-24 02:45:13.000000000 +0200 +++ new/runc-1.1.5/VERSION 2023-03-29 08:45:53.000000000 +0200 @@ -1 +1 @@ -1.1.4 +1.1.5 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.4/Vagrantfile.fedora new/runc-1.1.5/Vagrantfile.fedora --- old/runc-1.1.4/Vagrantfile.fedora 2022-08-24 02:45:13.000000000 +0200 +++ new/runc-1.1.5/Vagrantfile.fedora 2023-03-29 08:45:53.000000000 +0200 @@ -3,7 +3,7 @@ Vagrant.configure("2") do |config| # Fedora box is used for testing cgroup v2 support - config.vm.box = "fedora/35-cloud-base" + config.vm.box = "fedora/37-cloud-base" config.vm.provider :virtualbox do |v| v.memory = 2048 v.cpus = 2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.4/libcontainer/cgroups/systemd/common.go new/runc-1.1.5/libcontainer/cgroups/systemd/common.go --- old/runc-1.1.4/libcontainer/cgroups/systemd/common.go 2022-08-24 02:45:13.000000000 +0200 +++ new/runc-1.1.5/libcontainer/cgroups/systemd/common.go 2023-03-29 08:45:53.000000000 +0200 @@ -293,8 +293,18 @@ // rules separately to systemd) we can safely skip entries that don't // have a corresponding path. if _, err := os.Stat(entry.Path); err != nil { - logrus.Debugf("skipping device %s for systemd: %s", entry.Path, err) - continue + // Also check /sys/dev so that we don't depend on /dev/{block,char} + // being populated. (/dev/{block,char} is populated by udev, which + // isn't strictly required for systemd). Ironically, this happens most + // easily when starting containerd within a runc created container + // itself. + + // We don't bother with securejoin here because we create entry.Path + // right above here, so we know it's safe. + if _, err := os.Stat("/sys" + entry.Path); err != nil { + logrus.Warnf("skipping device %s for systemd: %s", entry.Path, err) + continue + } } } deviceAllowList = append(deviceAllowList, entry) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.4/libcontainer/init_linux.go new/runc-1.1.5/libcontainer/init_linux.go --- old/runc-1.1.4/libcontainer/init_linux.go 2022-08-24 02:45:13.000000000 +0200 +++ new/runc-1.1.5/libcontainer/init_linux.go 2023-03-29 08:45:53.000000000 +0200 @@ -411,8 +411,9 @@ return &os.PathError{Op: "fstat", Path: file.Name(), Err: err} } - // Skip chown if uid is already the one we want. - if int(s.Uid) == u.Uid { + // Skip chown if uid is already the one we want or any of the STDIO descriptors + // were redirected to /dev/null. + if int(s.Uid) == u.Uid || s.Rdev == null.Rdev { continue } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.4/libcontainer/nsenter/nsexec.c new/runc-1.1.5/libcontainer/nsenter/nsexec.c --- old/runc-1.1.4/libcontainer/nsenter/nsexec.c 2022-08-24 02:45:13.000000000 +0200 +++ new/runc-1.1.5/libcontainer/nsenter/nsexec.c 2023-03-29 08:45:53.000000000 +0200 @@ -168,15 +168,17 @@ message = escape_json_string(message); - if (current_stage == STAGE_SETUP) + if (current_stage == STAGE_SETUP) { stage = strdup("nsexec"); - else + if (stage == NULL) + goto out; + } else { ret = asprintf(&stage, "nsexec-%d", current_stage); - if (ret < 0) { - stage = NULL; - goto out; + if (ret < 0) { + stage = NULL; + goto out; + } } - ret = asprintf(&json, "{\"level\":\"%s\", \"msg\": \"%s[%d]: %s\"}\n", level_str[level], stage, getpid(), message); if (ret < 0) { @@ -830,6 +832,25 @@ bail("failed to close container mount namespace fd %d", container_mntns_fd); } +void try_unshare(int flags, const char *msg) +{ + write_log(DEBUG, "unshare %s", msg); + /* + * Kernels prior to v4.3 may return EINVAL on unshare when another process + * reads runc's /proc/$PID/status or /proc/$PID/maps. To work around this, + * retry on EINVAL a few times. + */ + int retries = 5; + for (; retries > 0; retries--) { + if (unshare(flags) == 0) { + return; + } + if (errno != EINVAL) + break; + } + bail("failed to unshare %s", msg); +} + void nsexec(void) { int pipenum; @@ -1168,9 +1189,7 @@ * problem. */ if (config.cloneflags & CLONE_NEWUSER) { - write_log(DEBUG, "unshare user namespace"); - if (unshare(CLONE_NEWUSER) < 0) - bail("failed to unshare user namespace"); + try_unshare(CLONE_NEWUSER, "user namespace"); config.cloneflags &= ~CLONE_NEWUSER; /* @@ -1222,9 +1241,7 @@ * some old kernel versions where clone(CLONE_PARENT | CLONE_NEWPID) * was broken, so we'll just do it the long way anyway. */ - write_log(DEBUG, "unshare remaining namespace (except cgroupns)"); - if (unshare(config.cloneflags & ~CLONE_NEWCGROUP) < 0) - bail("failed to unshare remaining namespaces (except cgroupns)"); + try_unshare(config.cloneflags & ~CLONE_NEWCGROUP, "remaining namespaces (except cgroupns)"); /* Ask our parent to send the mount sources fds. */ if (config.mountsources) { @@ -1342,8 +1359,7 @@ } if (config.cloneflags & CLONE_NEWCGROUP) { - if (unshare(CLONE_NEWCGROUP) < 0) - bail("failed to unshare cgroup namespace"); + try_unshare(CLONE_NEWCGROUP, "cgroup namespace"); } write_log(DEBUG, "signal completion to stage-0"); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.4/libcontainer/rootfs_linux.go new/runc-1.1.5/libcontainer/rootfs_linux.go --- old/runc-1.1.4/libcontainer/rootfs_linux.go 2022-08-24 02:45:13.000000000 +0200 +++ new/runc-1.1.5/libcontainer/rootfs_linux.go 2023-03-29 08:45:53.000000000 +0200 @@ -329,26 +329,41 @@ if err := os.MkdirAll(dest, 0o755); err != nil { return err } - return utils.WithProcfd(c.root, m.Destination, func(procfd string) error { - if err := mount(m.Source, m.Destination, procfd, "cgroup2", uintptr(m.Flags), m.Data); err != nil { - // when we are in UserNS but CgroupNS is not unshared, we cannot mount cgroup2 (#2158) - if errors.Is(err, unix.EPERM) || errors.Is(err, unix.EBUSY) { - src := fs2.UnifiedMountpoint - if c.cgroupns && c.cgroup2Path != "" { - // Emulate cgroupns by bind-mounting - // the container cgroup path rather than - // the whole /sys/fs/cgroup. - src = c.cgroup2Path - } - err = mount(src, m.Destination, procfd, "", uintptr(m.Flags)|unix.MS_BIND, "") - if c.rootlessCgroups && errors.Is(err, unix.ENOENT) { - err = nil - } - } - return err - } - return nil + err = utils.WithProcfd(c.root, m.Destination, func(procfd string) error { + return mount(m.Source, m.Destination, procfd, "cgroup2", uintptr(m.Flags), m.Data) }) + if err == nil || !(errors.Is(err, unix.EPERM) || errors.Is(err, unix.EBUSY)) { + return err + } + + // When we are in UserNS but CgroupNS is not unshared, we cannot mount + // cgroup2 (#2158), so fall back to bind mount. + bindM := &configs.Mount{ + Device: "bind", + Source: fs2.UnifiedMountpoint, + Destination: m.Destination, + Flags: unix.MS_BIND | m.Flags, + PropagationFlags: m.PropagationFlags, + } + if c.cgroupns && c.cgroup2Path != "" { + // Emulate cgroupns by bind-mounting the container cgroup path + // rather than the whole /sys/fs/cgroup. + bindM.Source = c.cgroup2Path + } + // mountToRootfs() handles remounting for MS_RDONLY. + // No need to set c.fd here, because mountToRootfs() calls utils.WithProcfd() by itself in mountPropagate(). + err = mountToRootfs(bindM, c) + if c.rootlessCgroups && errors.Is(err, unix.ENOENT) { + // ENOENT (for `src = c.cgroup2Path`) happens when rootless runc is being executed + // outside the userns+mountns. + // + // Mask `/sys/fs/cgroup` to ensure it is read-only, even when `/sys` is mounted + // with `rbind,ro` (`runc spec --rootless` produces `rbind,ro` for `/sys`). + err = utils.WithProcfd(c.root, m.Destination, func(procfd string) error { + return maskPath(procfd, c.label) + }) + } + return err } func doTmpfsCopyUp(m *configs.Mount, rootfs, mountLabel string) (Err error) { @@ -398,32 +413,43 @@ func mountToRootfs(m *configs.Mount, c *mountConfig) error { rootfs := c.root - mountLabel := c.label - mountFd := c.fd - dest, err := securejoin.SecureJoin(rootfs, m.Destination) - if err != nil { - return err - } + // procfs and sysfs are special because we need to ensure they are actually + // mounted on a specific path in a container without any funny business. 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 err := os.MkdirAll(dest, 0o755); 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, "", nil) + } + + mountLabel := c.label + mountFd := c.fd + dest, err := securejoin.SecureJoin(rootfs, m.Destination) + if err != nil { + return err + } + + switch m.Device { case "mqueue": if err := os.MkdirAll(dest, 0o755); err != nil { return err diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.4/tests/integration/README.md new/runc-1.1.5/tests/integration/README.md --- old/runc-1.1.4/tests/integration/README.md 2022-08-24 02:45:13.000000000 +0200 +++ new/runc-1.1.5/tests/integration/README.md 2023-03-29 08:45:53.000000000 +0200 @@ -60,7 +60,7 @@ # setup is called at the beginning of every test. function setup() { - setup_hello + setup_busybox } # teardown is called at the end of every test. @@ -77,5 +77,4 @@ # check expected output [[ "${output}" == *"Hello"* ]] } - ``` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.4/tests/integration/bootstrap-get-images.sh new/runc-1.1.5/tests/integration/bootstrap-get-images.sh --- old/runc-1.1.4/tests/integration/bootstrap-get-images.sh 1970-01-01 01:00:00.000000000 +0100 +++ new/runc-1.1.5/tests/integration/bootstrap-get-images.sh 2023-03-29 08:45:53.000000000 +0200 @@ -0,0 +1,99 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +# This script generates "get-images.sh" using Official Images tooling. +# +# ./bootstrap-get-images.sh > get-images.sh +# +# This script requires "bashbrew". To get the latest version, visit +# https://github.com/docker-library/bashbrew/releases + +images=( + # pinned to an older BusyBox (prior to 1.36 becoming "latest") because 1.36.0 has some unresolved bugs, especially around sha256sum + 'https://github.com/docker-library/official-images/raw/eaed422a86b43c885a0f980d48f4bbf346086a4a/library/busybox:glibc' + + # pinned to an older Debian Buster which has more architectures than the latest does (Buster transitioned from the Debian Security Team to the LTS Team which supports a smaller set) + 'https://github.com/docker-library/official-images/raw/ce10f6b60289c0c0b5de6f785528b8725f225a58/library/debian:buster-slim' +) + +cat <<'EOH' +#!/bin/bash + +# DO NOT EDIT! Generated by "bootstrap-get-images.sh" + +# This script checks if container images needed for tests (currently +# busybox and Debian 10 "Buster") are available locally, and downloads +# them to testdata directory if not. +# +# The script is self-contained/standalone and is used from a few places +# that need to ensure the images are downloaded. Its output is suitable +# for consumption by shell via eval (see helpers.bash). + +set -e -u -o pipefail + +# Root directory of integration tests. +INTEGRATION_ROOT=$(dirname "$(readlink -f "${BASH_SOURCE[0]}")") +# Test data path. +TESTDATA="${INTEGRATION_ROOT}/testdata" +# Sanity check: $TESTDATA directory must exist. +if [ ! -d "$TESTDATA" ]; then + echo "Bad TESTDATA directory: $TESTDATA. Aborting" >&2 + exit 1 +fi + +function get() { + local dest="$1" url="$2" + + [ -e "$dest" ] && return + + # Sanity check: $TESTDATA directory must be writable. + if [ ! -w "$TESTDATA" ]; then + echo "TESTDATA directory ($TESTDATA) not writable. Aborting" >&2 + exit 1 + fi + + if ! curl -o "$dest" -fsSL --retry 5 "$url"; then + echo "Failed to get $url" 1>&2 + exit 1 + fi +} + +arch=$(go env GOARCH) +if [ "$arch" = 'arm' ]; then + arm=$(go env GOARM) + : "${arm:=7}" + arch=${arch}v$arm +fi +EOH + +# shellcheck disable=SC2016 # this generates shell code intentionally (and many of the '$' in here are intended for "text/template" not the end shell anyhow) +bashbrew cat --format ' + {{- "\n" -}} + {{- "case $arch in\n" -}} + + {{- range .TagEntry.Architectures -}} + {{- $repo := $.TagEntry.ArchGitRepo . | trimSuffixes ".git" -}} + {{- $branch := $.TagEntry.ArchGitFetch . | trimPrefixes "refs/heads/" -}} + {{- $commit := $.TagEntry.ArchGitCommit . -}} + {{- $dir := $.TagEntry.ArchDirectory . -}} + {{- $tarball := eq $.RepoName "debian" | ternary "rootfs.tar.xz" "busybox.tar.xz" -}} + + {{ . | replace "arm64v8" "arm64" "arm32" "arm" "i386" "386" }} {{- ")\n" -}} + {{- "\t" -}}# {{ $repo }}/tree/{{ $branch }}{{- "\n" -}} + {{- "\t" -}}# {{ $repo }}/tree/{{ $commit }}/{{ $dir }}{{- "\n" -}} + {{- "\t" -}} url="{{ $repo }}/raw/{{ $commit }}/{{ $dir }}/{{ $tarball }}"{{- "\n" -}} + {{- "\t" -}} ;; {{- "\n" -}} + {{- "\n" -}} + {{- end -}} + + *){{- "\n" -}} + {{- "\t" -}}echo >&2 "error: unsupported {{ $.RepoName }} architecture: $arch"{{- "\n" -}} + {{- "\t" -}}exit 1{{- "\n" -}} + {{- "\t" -}};;{{- "\n" -}} + + {{- "esac\n" -}} + {{- printf `rootfs="$TESTDATA/%s-${arch}.tar.xz"` $.RepoName -}}{{- "\n" -}} + {{- `get "$rootfs" "$url"` -}}{{- "\n" -}} + {{- printf "var=%s_image\n" $.RepoName -}} + {{- `echo "${var^^}=$rootfs"` -}} +' "${images[@]}" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.4/tests/integration/debug.bats new/runc-1.1.5/tests/integration/debug.bats --- old/runc-1.1.4/tests/integration/debug.bats 2022-08-24 02:45:13.000000000 +0200 +++ new/runc-1.1.5/tests/integration/debug.bats 2023-03-29 08:45:53.000000000 +0200 @@ -3,7 +3,8 @@ load helpers function setup() { - setup_hello + setup_busybox + update_config '.process.args = ["/bin/echo", "Hello World"]' } function teardown() { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.4/tests/integration/events.bats new/runc-1.1.5/tests/integration/events.bats --- old/runc-1.1.4/tests/integration/events.bats 2022-08-24 02:45:13.000000000 +0200 +++ new/runc-1.1.5/tests/integration/events.bats 2023-03-29 08:45:53.000000000 +0200 @@ -10,6 +10,7 @@ teardown_bundle } +# shellcheck disable=SC2030 @test "events --stats" { # XXX: currently cgroups require root containers. requires root @@ -38,6 +39,7 @@ fi runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox + # shellcheck disable=SC2031 [ "$status" -eq 0 ] # Spawn two subshels: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.4/tests/integration/exec.bats new/runc-1.1.5/tests/integration/exec.bats --- old/runc-1.1.4/tests/integration/exec.bats 2022-08-24 02:45:13.000000000 +0200 +++ new/runc-1.1.5/tests/integration/exec.bats 2023-03-29 08:45:53.000000000 +0200 @@ -125,10 +125,25 @@ runc exec --user 1000:1000 test_busybox id [ "$status" -eq 0 ] - [[ "${output}" == "uid=1000 gid=1000"* ]] } +# https://github.com/opencontainers/runc/issues/3674. +@test "runc exec --user vs /dev/null ownership" { + requires root + + runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox + [ "$status" -eq 0 ] + + ls -l /dev/null + __runc exec -d --user 1000:1000 test_busybox id </dev/null + ls -l /dev/null + UG=$(stat -c %u:%g /dev/null) + + # Host's /dev/null must be owned by root. + [ "$UG" = "0:0" ] +} + @test "runc exec --additional-gids" { requires root diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.4/tests/integration/get-images.sh new/runc-1.1.5/tests/integration/get-images.sh --- old/runc-1.1.4/tests/integration/get-images.sh 2022-08-24 02:45:13.000000000 +0200 +++ new/runc-1.1.5/tests/integration/get-images.sh 2023-03-29 08:45:53.000000000 +0200 @@ -1,5 +1,7 @@ #!/bin/bash +# DO NOT EDIT! Generated by "bootstrap-get-images.sh" + # This script checks if container images needed for tests (currently # busybox and Debian 10 "Buster") are available locally, and downloads # them to testdata directory if not. @@ -7,11 +9,6 @@ # The script is self-contained/standalone and is used from a few places # that need to ensure the images are downloaded. Its output is suitable # for consumption by shell via eval (see helpers.bash). -# -# XXX: Latest available images are fetched. Theoretically, -# this can bring some instability in case of a broken image. -# In this case, images will need to be pinned to a checksum -# on a per-image and per-architecture basis. set -e -u -o pipefail @@ -43,28 +40,126 @@ } arch=$(go env GOARCH) -# Convert from GOARCH to whatever the URLs below are using. +if [ "$arch" = 'arm' ]; then + arm=$(go env GOARM) + : "${arm:=7}" + arch=${arch}v$arm +fi + case $arch in +amd64) + # https://github.com/docker-library/busybox/tree/dist-amd64 + # https://github.com/docker-library/busybox/tree/31d342ad033e27c18723a516a2274ab39547be27/stable/glibc + url="https://github.com/docker-library/busybox/raw/31d342ad033e27c18723a516a2274ab39547be27/stable/glibc/busybox.tar.xz" + ;; + +armv5) + # https://github.com/docker-library/busybox/tree/dist-arm32v5 + # https://github.com/docker-library/busybox/tree/96ea82ea25565f78b50bd032d5768d64985d6e11/stable/glibc + url="https://github.com/docker-library/busybox/raw/96ea82ea25565f78b50bd032d5768d64985d6e11/stable/glibc/busybox.tar.xz" + ;; + +armv7) + # https://github.com/docker-library/busybox/tree/dist-arm32v7 + # https://github.com/docker-library/busybox/tree/5cb6c347469e86e4468e5e248de751b3598bb577/stable/glibc + url="https://github.com/docker-library/busybox/raw/5cb6c347469e86e4468e5e248de751b3598bb577/stable/glibc/busybox.tar.xz" + ;; + arm64) - arch=arm64v8 + # https://github.com/docker-library/busybox/tree/dist-arm64v8 + # https://github.com/docker-library/busybox/tree/94c664b5ca464546266bce54be0082874a44c7b2/stable/glibc + url="https://github.com/docker-library/busybox/raw/94c664b5ca464546266bce54be0082874a44c7b2/stable/glibc/busybox.tar.xz" ;; + 386) - arch=i386 + # https://github.com/docker-library/busybox/tree/dist-i386 + # https://github.com/docker-library/busybox/tree/461a473aef31b7726ea99909a24551bf44565c05/stable/glibc + url="https://github.com/docker-library/busybox/raw/461a473aef31b7726ea99909a24551bf44565c05/stable/glibc/busybox.tar.xz" + ;; + +mips64le) + # https://github.com/docker-library/busybox/tree/dist-mips64le + # https://github.com/docker-library/busybox/tree/47f73f7c735dcd6760a976bfe0012d251b6ef0a9/stable/glibc + url="https://github.com/docker-library/busybox/raw/47f73f7c735dcd6760a976bfe0012d251b6ef0a9/stable/glibc/busybox.tar.xz" + ;; + +ppc64le) + # https://github.com/docker-library/busybox/tree/dist-ppc64le + # https://github.com/docker-library/busybox/tree/9ca13bc214717966383cf97e08606b444b7300e4/stable/glibc + url="https://github.com/docker-library/busybox/raw/9ca13bc214717966383cf97e08606b444b7300e4/stable/glibc/busybox.tar.xz" + ;; + +s390x) + # https://github.com/docker-library/busybox/tree/dist-s390x + # https://github.com/docker-library/busybox/tree/a03814d21bcf97767121bb9422a742ec237a09e2/stable/glibc + url="https://github.com/docker-library/busybox/raw/a03814d21bcf97767121bb9422a742ec237a09e2/stable/glibc/busybox.tar.xz" + ;; + +*) + echo >&2 "error: unsupported busybox architecture: $arch" + exit 1 ;; esac +rootfs="$TESTDATA/busybox-${arch}.tar.xz" +get "$rootfs" "$url" +var=busybox_image +echo "${var^^}=$rootfs" + +case $arch in +amd64) + # https://github.com/debuerreotype/docker-debian-artifacts/tree/dist-amd64 + # https://github.com/debuerreotype/docker-debian-artifacts/tree/686d9f6eaada08a754bc7abf6f6184c65c5b378f/buster/slim + url="https://github.com/debuerreotype/docker-debian-artifacts/raw/686d9f6eaada08a754bc7abf6f6184c65c5b378f/buster/slim/rootfs.tar.xz" + ;; + +armv5) + # https://github.com/debuerreotype/docker-debian-artifacts/tree/dist-arm32v5 + # https://github.com/debuerreotype/docker-debian-artifacts/tree/155640b6e2e249dfaeee8795d5de539ef3e49417/buster/slim + url="https://github.com/debuerreotype/docker-debian-artifacts/raw/155640b6e2e249dfaeee8795d5de539ef3e49417/buster/slim/rootfs.tar.xz" + ;; + +armv7) + # https://github.com/debuerreotype/docker-debian-artifacts/tree/dist-arm32v7 + # https://github.com/debuerreotype/docker-debian-artifacts/tree/60ff0c2c6ce9556e5d8a2758dd2b3f3731716a6f/buster/slim + url="https://github.com/debuerreotype/docker-debian-artifacts/raw/60ff0c2c6ce9556e5d8a2758dd2b3f3731716a6f/buster/slim/rootfs.tar.xz" + ;; -# busybox -BUSYBOX_IMAGE="$TESTDATA/busybox-${arch}.tar.xz" -get "$BUSYBOX_IMAGE" \ - "https://github.com/docker-library/busybox/raw/dist-${arch}/stable/glibc/busybox.tar.xz" -echo "BUSYBOX_IMAGE=$BUSYBOX_IMAGE" - -# debian -DEBIAN_IMAGE="$TESTDATA/debian-${arch}.tar.xz" -get "$DEBIAN_IMAGE" \ - "https://github.com/debuerreotype/docker-debian-artifacts/raw/dist-${arch}/buster/slim/rootfs.tar.xz" -echo "DEBIAN_IMAGE=$DEBIAN_IMAGE" - -# hello-world is local, no need to download. -HELLO_IMAGE="$TESTDATA/hello-world-${arch}.tar" -echo "HELLO_IMAGE=$HELLO_IMAGE" +arm64) + # https://github.com/debuerreotype/docker-debian-artifacts/tree/dist-arm64v8 + # https://github.com/debuerreotype/docker-debian-artifacts/tree/2f108af35e22064c848b8628a7cac56192246dba/buster/slim + url="https://github.com/debuerreotype/docker-debian-artifacts/raw/2f108af35e22064c848b8628a7cac56192246dba/buster/slim/rootfs.tar.xz" + ;; + +386) + # https://github.com/debuerreotype/docker-debian-artifacts/tree/dist-i386 + # https://github.com/debuerreotype/docker-debian-artifacts/tree/e4db8aa97f4366e6f27ddbdeaed0773fe0288d47/buster/slim + url="https://github.com/debuerreotype/docker-debian-artifacts/raw/e4db8aa97f4366e6f27ddbdeaed0773fe0288d47/buster/slim/rootfs.tar.xz" + ;; + +mips64le) + # https://github.com/debuerreotype/docker-debian-artifacts/tree/dist-mips64le + # https://github.com/debuerreotype/docker-debian-artifacts/tree/e28cbd76dcfba10446b1722aebb5a996121e3d27/buster/slim + url="https://github.com/debuerreotype/docker-debian-artifacts/raw/e28cbd76dcfba10446b1722aebb5a996121e3d27/buster/slim/rootfs.tar.xz" + ;; + +ppc64le) + # https://github.com/debuerreotype/docker-debian-artifacts/tree/dist-ppc64le + # https://github.com/debuerreotype/docker-debian-artifacts/tree/3ba08903ca3fd48fe59ba92b02744a2f5d4d9d6f/buster/slim + url="https://github.com/debuerreotype/docker-debian-artifacts/raw/3ba08903ca3fd48fe59ba92b02744a2f5d4d9d6f/buster/slim/rootfs.tar.xz" + ;; + +s390x) + # https://github.com/debuerreotype/docker-debian-artifacts/tree/dist-s390x + # https://github.com/debuerreotype/docker-debian-artifacts/tree/2fddbf8fe632fc5865b140341b68a1358586fff2/buster/slim + url="https://github.com/debuerreotype/docker-debian-artifacts/raw/2fddbf8fe632fc5865b140341b68a1358586fff2/buster/slim/rootfs.tar.xz" + ;; + +*) + echo >&2 "error: unsupported debian architecture: $arch" + exit 1 + ;; +esac +rootfs="$TESTDATA/debian-${arch}.tar.xz" +get "$rootfs" "$url" +var=debian_image +echo "${var^^}=$rootfs" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.4/tests/integration/helpers.bash new/runc-1.1.5/tests/integration/helpers.bash --- old/runc-1.1.4/tests/integration/helpers.bash 2022-08-24 02:45:13.000000000 +0200 +++ new/runc-1.1.5/tests/integration/helpers.bash 2023-03-29 08:45:53.000000000 +0200 @@ -26,7 +26,7 @@ # Kernel version KERNEL_VERSION="$(uname -r)" KERNEL_MAJOR="${KERNEL_VERSION%%.*}" -KERNEL_MINOR="${KERNEL_VERSION#$KERNEL_MAJOR.}" +KERNEL_MINOR="${KERNEL_VERSION#"$KERNEL_MAJOR".}" KERNEL_MINOR="${KERNEL_MINOR%%.*}" ARCH=$(uname -m) @@ -569,11 +569,6 @@ setup_bundle "$BUSYBOX_IMAGE" } -function setup_hello() { - setup_bundle "$HELLO_IMAGE" - update_config '(.. | select(.? == "sh")) |= "/hello"' -} - function setup_debian() { setup_bundle "$DEBIAN_IMAGE" } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.4/tests/integration/mask.bats new/runc-1.1.5/tests/integration/mask.bats --- old/runc-1.1.4/tests/integration/mask.bats 2022-08-24 02:45:13.000000000 +0200 +++ new/runc-1.1.5/tests/integration/mask.bats 2023-03-29 08:45:53.000000000 +0200 @@ -56,3 +56,22 @@ [ "$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. +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.4/tests/integration/mounts.bats new/runc-1.1.5/tests/integration/mounts.bats --- old/runc-1.1.4/tests/integration/mounts.bats 2022-08-24 02:45:13.000000000 +0200 +++ new/runc-1.1.5/tests/integration/mounts.bats 2023-03-29 08:45:53.000000000 +0200 @@ -63,3 +63,20 @@ runc run test_busybox [ "$status" -eq 0 ] } + +# https://github.com/opencontainers/runc/security/advisories/GHSA-m8cg-xc2p-r3fc +@test "runc run [ro /sys/fs/cgroup mount]" { + # With cgroup namespace + update_config '.process.args |= ["sh", "-euc", "for f in `grep /sys/fs/cgroup /proc/mounts | awk \"{print \\\\$2}\"| uniq`; do grep -w $f /proc/mounts | tail -n1; done"]' + runc run test_busybox + [ "$status" -eq 0 ] + [ "${#lines[@]}" -ne 0 ] + for line in "${lines[@]}"; do [[ "${line}" == *'ro,'* ]]; done + + # Without cgroup namespace + update_config '.linux.namespaces -= [{"type": "cgroup"}]' + runc run test_busybox + [ "$status" -eq 0 ] + [ "${#lines[@]}" -ne 0 ] + for line in "${lines[@]}"; do [[ "${line}" == *'ro,'* ]]; done +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.4/tests/integration/mounts_sshfs.bats new/runc-1.1.5/tests/integration/mounts_sshfs.bats --- old/runc-1.1.4/tests/integration/mounts_sshfs.bats 2022-08-24 02:45:13.000000000 +0200 +++ new/runc-1.1.5/tests/integration/mounts_sshfs.bats 2023-03-29 08:45:53.000000000 +0200 @@ -16,7 +16,8 @@ skip "test requires working sshfs mounts" fi - setup_hello + setup_busybox + update_config '.process.args = ["/bin/echo", "Hello World"]' } function teardown() { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.4/tests/integration/run.bats new/runc-1.1.5/tests/integration/run.bats --- old/runc-1.1.4/tests/integration/run.bats 2022-08-24 02:45:13.000000000 +0200 +++ new/runc-1.1.5/tests/integration/run.bats 2023-03-29 08:45:53.000000000 +0200 @@ -3,7 +3,8 @@ load helpers function setup() { - setup_hello + setup_busybox + update_config '.process.args = ["/bin/echo", "Hello World"]' } function teardown() { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.4/tests/integration/spec.bats new/runc-1.1.5/tests/integration/spec.bats --- old/runc-1.1.4/tests/integration/spec.bats 2022-08-24 02:45:13.000000000 +0200 +++ new/runc-1.1.5/tests/integration/spec.bats 2023-03-29 08:45:53.000000000 +0200 @@ -3,7 +3,8 @@ load helpers function setup() { - setup_hello + setup_busybox + update_config '.process.args = ["/bin/echo", "Hello World"]' } function teardown() { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.4/tests/integration/start_hello.bats new/runc-1.1.5/tests/integration/start_hello.bats --- old/runc-1.1.4/tests/integration/start_hello.bats 2022-08-24 02:45:13.000000000 +0200 +++ new/runc-1.1.5/tests/integration/start_hello.bats 2023-03-29 08:45:53.000000000 +0200 @@ -3,7 +3,8 @@ load helpers function setup() { - setup_hello + setup_busybox + update_config '.process.args = ["/bin/echo", "Hello World"]' } function teardown() { Binary files old/runc-1.1.4/tests/integration/testdata/hello-world-amd64.tar and new/runc-1.1.5/tests/integration/testdata/hello-world-amd64.tar differ Binary files old/runc-1.1.4/tests/integration/testdata/hello-world-arm64v8.tar and new/runc-1.1.5/tests/integration/testdata/hello-world-arm64v8.tar differ