Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package runc for openSUSE:Factory checked in at 2021-08-24 10:53:55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/runc (Old) and /work/SRC/openSUSE:Factory/.runc.new.1899 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "runc" Tue Aug 24 10:53:55 2021 rev:41 rq:913732 version:1.0.2 Changes: -------- --- /work/SRC/openSUSE:Factory/runc/runc.changes 2021-07-20 15:38:47.749400664 +0200 +++ /work/SRC/openSUSE:Factory/.runc.new.1899/runc.changes 2021-08-24 10:54:11.404375206 +0200 @@ -1,0 +2,18 @@ +Mon Aug 23 09:35:05 UTC 2021 - Aleksa Sarai <asa...@suse.com> + +- Update to runc v1.0.2. Upstream changelog is available from + https://github.com/opencontainers/runc/releases/tag/v1.0.2 + + * Fixed a failure to set CPU quota period in some cases on cgroup v1. + * Fixed the inability to start a container with the "adding seccomp filter + rule for syscall ..." error, caused by redundant seccomp rules (i.e. those + that has action equal to the default one). Such redundant rules are now + skipped. + * Made release builds reproducible from now on. + * Fixed a rare debug log race in runc init, which can result in occasional + harmful "failed to decode ..." errors from runc run or exec. + * Fixed the check in cgroup v1 systemd manager if a container needs to be + frozen before Set, and add a setting to skip such freeze unconditionally. + The previous fix for that issue, done in runc 1.0.1, was not working. + +------------------------------------------------------------------- Old: ---- runc-1.0.1.tar.xz runc-1.0.1.tar.xz.asc New: ---- runc-1.0.2.tar.xz runc-1.0.2.tar.xz.asc ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ runc.spec ++++++ --- /var/tmp/diff_new_pack.fot5kv/_old 2021-08-24 10:54:11.864374597 +0200 +++ /var/tmp/diff_new_pack.fot5kv/_new 2021-08-24 10:54:11.868374591 +0200 @@ -25,8 +25,8 @@ %define project github.com/opencontainers/runc Name: runc -Version: 1.0.1 -%define _version 1.0.1 +Version: 1.0.2 +%define _version 1.0.2 Release: 0 Summary: Tool for spawning and running OCI containers License: Apache-2.0 ++++++ runc-1.0.1.tar.xz -> runc-1.0.2.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.0.1/.cirrus.yml new/runc-1.0.2/.cirrus.yml --- old/runc-1.0.1/.cirrus.yml 1970-01-01 01:00:00.000000000 +0100 +++ new/runc-1.0.2/.cirrus.yml 2021-08-20 09:24:11.000000000 +0200 @@ -0,0 +1,157 @@ +--- +# We use Cirrus for Vagrant tests and native CentOS 7 and 8, because macOS +# instances of GHA are too slow and flaky, and Linux instances of GHA do not +# support KVM. + +# NOTE Cirrus execution environments lack a terminal, needed for +# some integration tests. So we use `ssh -tt` command to fake a terminal. + +task: + timeout_in: 30m + + env: + DEBIAN_FRONTEND: noninteractive + HOME: /root + # yamllint disable rule:key-duplicates + matrix: + DISTRO: fedora34 + + name: vagrant DISTRO:$DISTRO + + compute_engine_instance: + image_project: cirrus-images + image: family/docker-kvm + platform: linux + nested_virtualization: true + # CPU limit: `16 / NTASK`: see https://cirrus-ci.org/faq/#are-there-any-limits + cpu: 8 + # Memory limit: `4GB * NCPU` + memory: 32G + + host_info_script: | + uname -a + echo "-----" + cat /etc/os-release + echo "-----" + cat /proc/cpuinfo + echo "-----" + df -T + install_libvirt_vagrant_script: | + apt-get update + apt-get install -y libvirt-daemon libvirt-daemon-system vagrant vagrant-libvirt + systemctl enable --now libvirtd + vagrant_cache: + fingerprint_script: uname -s ; cat Vagrantfile.$DISTRO + folder: /root/.vagrant.d + vagrant_up_script: | + ln -sf Vagrantfile.$DISTRO Vagrantfile + # Retry if it fails (download.fedoraproject.org returns 404 sometimes) + vagrant up || vagrant up + mkdir -p -m 0700 /root/.ssh + vagrant ssh-config >> /root/.ssh/config + guest_info_script: | + ssh default 'sh -exc "uname -a && systemctl --version && df -T && cat /etc/os-release"' + unit_tests_script: | + ssh default 'sudo -i make -C /vagrant localunittest' + integration_systemd_script: | + ssh -tt default "sudo -i make -C /vagrant localintegration RUNC_USE_SYSTEMD=yes" + integration_fs_script: | + ssh -tt default "sudo -i make -C /vagrant localintegration" + integration_systemd_rootless_script: | + if [ $DISTRO == centos7 ]; then + echo "SKIP: integration_systemd_rootless_script requires cgroup v2" + else + ssh -tt default "sudo -i make -C /vagrant localrootlessintegration RUNC_USE_SYSTEMD=yes" + fi + integration_fs_rootless_script: | + if [ $DISTRO == centos7 ]; then + echo "SKIP: FIXME: integration_fs_rootless_script is skipped because of EPERM on writing cgroup.procs" + else + ssh -tt default "sudo -i make -C /vagrant localrootlessintegration" + fi + +task: + timeout_in: 30m + + env: + HOME: /root + CIRRUS_WORKING_DIR: /home/runc + GO_VERSION: "1.16.6" + BATS_VERSION: "v1.3.0" + # yamllint disable rule:key-duplicates + matrix: + DISTRO: centos-7 + DISTRO: centos-stream-8 + + name: ci / $DISTRO + + compute_engine_instance: + image_project: centos-cloud + image: family/$DISTRO + platform: linux + cpu: 4 + memory: 8G + + install_dependencies_script: | + yum install -y -q epel-release + 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) + # sysctl + echo "user.max_user_namespaces=15076" > /etc/sysctl.d/userns.conf + sysctl --system + ;; + centos-stream-8) + yum install -y -q dnf-plugins-core + yum config-manager --set-enabled powertools + ;; + esac + yum install -y -q gcc git iptables jq glibc-static libseccomp-devel make criu + # install Go + curl -fsSL "https://dl.google.com/go/go${GO_VERSION}.linux-amd64.tar.gz" | tar Cxz /usr/local + # install bats + cd /tmp + git clone https://github.com/bats-core/bats-core + cd bats-core + git checkout $BATS_VERSION + ./install.sh /usr/local + cd - + # Add a user for rootless tests + useradd -u2000 -m -d/home/rootless -s/bin/bash rootless + # set PATH + echo 'export PATH=/usr/local/go/bin:/usr/local/bin:$PATH' >> /root/.bashrc + # Setup ssh localhost for terminal emulation (script -e did not work) + ssh-keygen -t ed25519 -f /root/.ssh/id_ed25519 -N "" + cat /root/.ssh/id_ed25519.pub >> /root/.ssh/authorized_keys + chmod 400 /root/.ssh/authorized_keys + ssh-keyscan localhost >> /root/.ssh/known_hosts + echo -e "Host localhost\n\tStrictHostKeyChecking no\t\nIdentityFile /root/.ssh/id_ed25519\n" >> /root/.ssh/config + sed -e "s,PermitRootLogin.*,PermitRootLogin prohibit-password,g" -i /etc/ssh/sshd_config + systemctl restart sshd + host_info_script: | + uname -a + echo "-----" + cat /etc/os-release + echo "-----" + cat /proc/cpuinfo + echo "-----" + df -T + echo "-----" + systemctl --version + unit_tests_script: | + ssh -tt localhost "make -C /home/runc localunittest" + integration_systemd_script: | + ssh -tt localhost "make -C /home/runc localintegration RUNC_USE_SYSTEMD=yes" + integration_fs_script: | + ssh -tt localhost "make -C /home/runc localintegration" + integration_systemd_rootless_script: | + echo "SKIP: integration_systemd_rootless_script requires cgroup v2" + integration_fs_rootless_script: | + case $DISTRO in + centos-7) + echo "SKIP: FIXME: integration_fs_rootless_script is skipped because of EPERM on writing cgroup.procs" + ;; + centos-stream-8) + ssh -tt localhost "make -C /home/runc localrootlessintegration" + ;; + esac diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.0.1/.github/workflows/test.yml new/runc-1.0.2/.github/workflows/test.yml --- old/runc-1.0.1/.github/workflows/test.yml 2021-07-16 06:39:19.000000000 +0200 +++ new/runc-1.0.2/.github/workflows/test.yml 2021-08-20 09:24:11.000000000 +0200 @@ -1,8 +1,5 @@ # NOTE Github Actions execution environments lack a terminal, needed for -# some integration tests. Two ways to get a terminal are used below: -# -# 1. script utility -- for "local" integration tests; -# 2. ssh -tt -- for Vagrant VMs (script is buggy on CentOS 7). +# some integration tests. So we use `script` command to fake a terminal. name: ci on: @@ -73,88 +70,6 @@ if: matrix.rootless != 'rootless' run: sudo -E PATH="$PATH" script -e -c 'make RUNC_USE_SYSTEMD=yes local${{ matrix.rootless }}integration' - - # cgroup v2 unified hierarchy + very recent kernel (openat2) - fedora: - # nested virtualization is only available on macOS hosts - runs-on: macos-10.15 - timeout-minutes: 30 - # only run it if others have passed - needs: [test] - steps: - - uses: actions/checkout@v2 - - - name: "Cache ~/.vagrant.d/boxes, using hash of Vagrantfile.fedora34" - uses: actions/cache@v2 - with: - path: ~/.vagrant.d/boxes - key: vagrant-${{ hashFiles('Vagrantfile.fedora34') }} - - - name: prepare vagrant - run: | - ln -sf Vagrantfile.fedora34 Vagrantfile - # Retry if it fails (download.fedoraproject.org returns 404 sometimes) - vagrant up || vagrant up - vagrant ssh-config >> ~/.ssh/config - - - name: system info - run: ssh default 'sh -exc "uname -a && systemctl --version && df -T"' - - - name: unit tests - run: ssh default 'cd /vagrant && sudo make localunittest' - - - name: cgroupv2 with systemd - run: ssh -tt default "sudo make -C /vagrant localintegration RUNC_USE_SYSTEMD=yes" - - - name: cgroupv2 with fs2 - run: ssh -tt default "sudo make -C /vagrant localintegration" - - - name: cgroupv2 with systemd (rootless) - run: ssh -tt default "sudo make -C /vagrant localrootlessintegration RUNC_USE_SYSTEMD=yes" - - - name: cgroupv2 with fs2 (rootless) - run: ssh -tt default "sudo make -C /vagrant localrootlessintegration" - - - # kernel 3.10 (frankenized), systemd 219 - centos7: - # nested virtualization is only available on macOS hosts - runs-on: macos-10.15 - timeout-minutes: 15 - # only run it if others have passed - needs: [test] - steps: - - uses: actions/checkout@v2 - - - name: "Cache ~/.vagrant.d/boxes, using hash of Vagrantfile.centos7" - uses: actions/cache@v2 - with: - path: ~/.vagrant.d/boxes - key: vagrant-${{ hashFiles('Vagrantfile.centos7') }} - - - name: prepare vagrant - run: | - ln -sf Vagrantfile.centos7 Vagrantfile - vagrant up - vagrant ssh-config >> ~/.ssh/config - - - name: system info - run: ssh default 'rpm -q centos-release kernel systemd' - - - name: unit tests - run: ssh default 'sudo -i make -C /vagrant localunittest' - - - name: integration tests (fs cgroup driver) - run: ssh -tt default "sudo -i make -C /vagrant localintegration" - - - name: integration tests (systemd cgroup driver) - run: ssh -tt default "sudo -i make -C /vagrant localintegration RUNC_USE_SYSTEMD=1" - - - name: rootless integration - # FIXME: rootless is skipped because of EPERM on writing cgroup.procs - if: false - run: ssh default "sudo -i make -C /vagrant localrootlessintegration" - # We need to continue support for 32-bit ARM. # However, we do not have 32-bit ARM CI, so we use i386 for testing 32bit stuff. # We are not interested in providing official support for i386. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.0.1/Makefile new/runc-1.0.2/Makefile --- old/runc-1.0.1/Makefile 2021-07-16 06:39:19.000000000 +0200 +++ new/runc-1.0.2/Makefile 2021-08-20 09:24:11.000000000 +0200 @@ -27,7 +27,7 @@ GO_BUILD := $(GO) build -trimpath $(MOD_VENDOR) $(GO_BUILDMODE) $(EXTRA_FLAGS) -tags "$(BUILDTAGS)" \ -ldflags "-X main.gitCommit=$(COMMIT) -X main.version=$(VERSION) $(EXTRA_LDFLAGS)" GO_BUILD_STATIC := CGO_ENABLED=1 $(GO) build -trimpath $(MOD_VENDOR) $(EXTRA_FLAGS) -tags "$(BUILDTAGS) netgo osusergo" \ - -ldflags "-w -extldflags -static -X main.gitCommit=$(COMMIT) -X main.version=$(VERSION) $(EXTRA_LDFLAGS)" + -ldflags "-extldflags -static -X main.gitCommit=$(COMMIT) -X main.version=$(VERSION) $(EXTRA_LDFLAGS)" .DEFAULT: runc diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.0.1/VERSION new/runc-1.0.2/VERSION --- old/runc-1.0.1/VERSION 2021-07-16 06:39:19.000000000 +0200 +++ new/runc-1.0.2/VERSION 2021-08-20 09:24:11.000000000 +0200 @@ -1 +1 @@ -1.0.1 +1.0.2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.0.1/Vagrantfile.centos7 new/runc-1.0.2/Vagrantfile.centos7 --- old/runc-1.0.1/Vagrantfile.centos7 2021-07-16 06:39:19.000000000 +0200 +++ new/runc-1.0.2/Vagrantfile.centos7 1970-01-01 01:00:00.000000000 +0100 @@ -1,52 +0,0 @@ -# -*- mode: ruby -*- -# vi: set ft=ruby : - -Vagrant.configure("2") do |config| - config.vm.box = "centos/7" - config.vm.provider :virtualbox do |v| - v.memory = 2048 - v.cpus = 2 - end - config.vm.provider :libvirt do |v| - v.memory = 2048 - v.cpus = 2 - end - config.vm.provision "shell", inline: <<-SHELL - set -e -u -o pipefail - - # configuration - GO_VERSION="1.16.4" - BATS_VERSION="v1.3.0" - - # install yum packages - yum install -y -q epel-release - (cd /etc/yum.repos.d && curl -O https://copr.fedorainfracloud.org/coprs/adrian/criu-el7/repo/epel-7/adrian-criu-el7-epel-7.repo) - yum install -y -q gcc git iptables jq glibc-static libseccomp-devel make criu - yum clean all - - # install Go - curl -fsSL "https://dl.google.com/go/go${GO_VERSION}.linux-amd64.tar.gz" | tar Cxz /usr/local - - # install bats - git clone https://github.com/bats-core/bats-core - cd bats-core - git checkout $BATS_VERSION - ./install.sh /usr/local - cd .. - rm -rf bats-core - - # set PATH (NOTE: sudo without -i ignores this PATH) - cat >> /etc/profile.d/sh.local <<EOF -PATH=/usr/local/go/bin:/usr/local/bin:$PATH -export PATH -EOF - source /etc/profile.d/sh.local - - # sysctl - echo "user.max_user_namespaces=15076" > /etc/sysctl.d/userns.conf - sysctl --system - - # Add a user for rootless tests - useradd -u2000 -m -d/home/rootless -s/bin/bash rootless - SHELL -end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.0.1/libcontainer/cgroups/fs/cpu.go new/runc-1.0.2/libcontainer/cgroups/fs/cpu.go --- old/runc-1.0.1/libcontainer/cgroups/fs/cpu.go 2021-07-16 06:39:19.000000000 +0200 +++ new/runc-1.0.2/libcontainer/cgroups/fs/cpu.go 2021-08-20 09:24:11.000000000 +0200 @@ -4,6 +4,7 @@ import ( "bufio" + "errors" "fmt" "os" "strconv" @@ -11,6 +12,7 @@ "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/cgroups/fscommon" "github.com/opencontainers/runc/libcontainer/configs" + "golang.org/x/sys/unix" ) type CpuGroup struct{} @@ -71,15 +73,33 @@ return fmt.Errorf("the minimum allowed cpu-shares is %d", sharesRead) } } + + var period string if r.CpuPeriod != 0 { - if err := cgroups.WriteFile(path, "cpu.cfs_period_us", strconv.FormatUint(r.CpuPeriod, 10)); err != nil { - return err + period = strconv.FormatUint(r.CpuPeriod, 10) + if err := cgroups.WriteFile(path, "cpu.cfs_period_us", period); err != nil { + // Sometimes when the period to be set is smaller + // than the current one, it is rejected by the kernel + // (EINVAL) as old_quota/new_period exceeds the parent + // cgroup quota limit. If this happens and the quota is + // going to be set, ignore the error for now and retry + // after setting the quota. + if !errors.Is(err, unix.EINVAL) || r.CpuQuota == 0 { + return err + } + } else { + period = "" } } if r.CpuQuota != 0 { if err := cgroups.WriteFile(path, "cpu.cfs_quota_us", strconv.FormatInt(r.CpuQuota, 10)); err != nil { return err } + if period != "" { + if err := cgroups.WriteFile(path, "cpu.cfs_period_us", period); err != nil { + return err + } + } } return s.SetRtSched(path, r) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.0.1/libcontainer/cgroups/systemd/common.go new/runc-1.0.2/libcontainer/cgroups/systemd/common.go --- old/runc-1.0.1/libcontainer/cgroups/systemd/common.go 2021-07-16 06:39:19.000000000 +0200 +++ new/runc-1.0.2/libcontainer/cgroups/systemd/common.go 2021-08-20 09:24:11.000000000 +0200 @@ -310,6 +310,14 @@ return c.Name } +// This code should be in sync with getUnitName. +func getUnitType(unitName string) string { + if strings.HasSuffix(unitName, ".slice") { + return "Slice" + } + return "Scope" +} + // isDbusError returns true if the error is a specific dbus error. func isDbusError(err error, name string) bool { if err != nil { @@ -388,10 +396,10 @@ } } -func getUnitProperty(cm *dbusConnManager, unitName string, propertyName string) (*systemdDbus.Property, error) { +func getUnitTypeProperty(cm *dbusConnManager, unitName string, unitType string, propertyName string) (*systemdDbus.Property, error) { var prop *systemdDbus.Property err := cm.retryOnDisconnect(func(c *systemdDbus.Conn) (Err error) { - prop, Err = c.GetUnitPropertyContext(context.TODO(), unitName, propertyName) + prop, Err = c.GetUnitTypePropertyContext(context.TODO(), unitName, unitType, propertyName) return Err }) return prop, err diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.0.1/libcontainer/cgroups/systemd/systemd_test.go new/runc-1.0.2/libcontainer/cgroups/systemd/systemd_test.go --- old/runc-1.0.1/libcontainer/cgroups/systemd/systemd_test.go 2021-07-16 06:39:19.000000000 +0200 +++ new/runc-1.0.2/libcontainer/cgroups/systemd/systemd_test.go 2021-08-20 09:24:11.000000000 +0200 @@ -40,6 +40,23 @@ } } +func TestValidUnitTypes(t *testing.T) { + testCases := []struct { + unitName string + expectedUnitType string + }{ + {"system.slice", "Slice"}, + {"kubepods.slice", "Slice"}, + {"testing-container:ab.scope", "Scope"}, + } + for _, sdTest := range testCases { + unitType := getUnitType(sdTest.unitName) + if unitType != sdTest.expectedUnitType { + t.Errorf("getUnitType(%s); want %q; got %q", sdTest.unitName, sdTest.expectedUnitType, unitType) + } + } +} + func newManager(config *configs.Cgroup) cgroups.Manager { if cgroups.IsCgroup2UnifiedMode() { return NewUnifiedManager(config, "", false) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.0.1/libcontainer/cgroups/systemd/v1.go new/runc-1.0.2/libcontainer/cgroups/systemd/v1.go --- old/runc-1.0.1/libcontainer/cgroups/systemd/v1.go 2021-07-16 06:39:19.000000000 +0200 +++ new/runc-1.0.2/libcontainer/cgroups/systemd/v1.go 2021-08-20 09:24:11.000000000 +0200 @@ -6,6 +6,7 @@ "errors" "os" "path/filepath" + "reflect" "strings" "sync" @@ -345,6 +346,11 @@ // Special case for SkipDevices, as used by Kubernetes to create pod // cgroups with allow-all device policy). if r.SkipDevices { + if r.SkipFreezeOnSet { + // Both needsFreeze and needsThaw are false. + return + } + // No need to freeze if SkipDevices is set, and either // (1) systemd unit does not (yet) exist, or // (2) it has DevicePolicy=auto and empty DeviceAllow list. @@ -353,15 +359,20 @@ // a non-existent unit returns default properties, // and settings in (2) are the defaults. // - // Do not return errors from getUnitProperty, as they alone + // Do not return errors from getUnitTypeProperty, as they alone // should not prevent Set from working. - devPolicy, e := getUnitProperty(m.dbus, unitName, "DevicePolicy") + + unitType := getUnitType(unitName) + + devPolicy, e := getUnitTypeProperty(m.dbus, unitName, unitType, "DevicePolicy") if e == nil && devPolicy.Value == dbus.MakeVariant("auto") { - devAllow, e := getUnitProperty(m.dbus, unitName, "DeviceAllow") - if e == nil && devAllow.Value == dbus.MakeVariant([]deviceAllowEntry{}) { - needsFreeze = false - needsThaw = false - return + devAllow, e := getUnitTypeProperty(m.dbus, unitName, unitType, "DeviceAllow") + if e == nil { + if rv := reflect.ValueOf(devAllow.Value.Value()); rv.Kind() == reflect.Slice && rv.Len() == 0 { + needsFreeze = false + needsThaw = false + return + } } } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.0.1/libcontainer/cgroups/systemd/v1_test.go new/runc-1.0.2/libcontainer/cgroups/systemd/v1_test.go --- old/runc-1.0.1/libcontainer/cgroups/systemd/v1_test.go 1970-01-01 01:00:00.000000000 +0100 +++ new/runc-1.0.2/libcontainer/cgroups/systemd/v1_test.go 2021-08-20 09:24:11.000000000 +0200 @@ -0,0 +1,217 @@ +package systemd + +import ( + "os" + "os/exec" + "strings" + "testing" + + "golang.org/x/sys/unix" + + "github.com/opencontainers/runc/libcontainer/cgroups" + "github.com/opencontainers/runc/libcontainer/configs" +) + +func TestFreezeBeforeSet(t *testing.T) { + requireV1(t) + + testCases := []struct { + desc string + // Test input. + cg *configs.Cgroup + preFreeze bool + // Expected values. + // Before unit creation (Apply). + freeze0, thaw0 bool + // After unit creation. + freeze1, thaw1 bool + }{ + { + // A slice with SkipDevices. + desc: "slice,skip-devices", + cg: &configs.Cgroup{ + Name: "system-runc_test_freeze_1.slice", + Parent: "system.slice", + Resources: &configs.Resources{ + SkipDevices: true, + }, + }, + // Expected. + freeze0: false, + thaw0: false, + freeze1: false, + thaw1: false, + }, + { + // A scope with SkipDevices. Not a realistic scenario with runc + // (as container can't have SkipDevices == true), but possible + // for a standalone cgroup manager. + desc: "scope,skip-devices", + cg: &configs.Cgroup{ + ScopePrefix: "test", + Name: "testFreeze2", + Parent: "system.slice", + Resources: &configs.Resources{ + SkipDevices: true, + }, + }, + // Expected. + freeze0: false, + thaw0: false, + freeze1: false, + thaw1: false, + }, + { + // A slice that is about to be frozen in Set. + desc: "slice,will-freeze", + cg: &configs.Cgroup{ + Name: "system-runc_test_freeze_3.slice", + Parent: "system.slice", + Resources: &configs.Resources{ + Freezer: configs.Frozen, + }, + }, + // Expected. + freeze0: true, + thaw0: false, + freeze1: true, + thaw1: false, + }, + { + // A pre-frozen slice that should stay frozen. + desc: "slice,pre-frozen,will-freeze", + cg: &configs.Cgroup{ + Name: "system-runc_test_freeze_4.slice", + Parent: "system.slice", + Resources: &configs.Resources{ + Freezer: configs.Frozen, + }, + }, + preFreeze: true, + // Expected. + freeze0: true, // not actually frozen yet. + thaw0: false, + freeze1: false, + thaw1: false, + }, + { + // A pre-frozen scope with skip devices set. + desc: "scope,pre-frozen,skip-devices", + cg: &configs.Cgroup{ + ScopePrefix: "test", + Name: "testFreeze5", + Parent: "system.slice", + Resources: &configs.Resources{ + SkipDevices: true, + }, + }, + preFreeze: true, + // Expected. + freeze0: false, + thaw0: false, + freeze1: false, + thaw1: false, + }, + { + // A pre-frozen scope which will be thawed. + desc: "scope,pre-frozen", + cg: &configs.Cgroup{ + ScopePrefix: "test", + Name: "testFreeze6", + Parent: "system.slice", + Resources: &configs.Resources{}, + }, + preFreeze: true, + // Expected. + freeze0: true, // not actually frozen yet. + thaw0: true, + freeze1: false, + thaw1: false, + }, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.desc, func(t *testing.T) { + m := NewLegacyManager(tc.cg, nil) + defer m.Destroy() //nolint:errcheck + lm := m.(*legacyManager) + + // Checks for a non-existent unit. + freeze, thaw, err := lm.freezeBeforeSet(getUnitName(tc.cg), tc.cg.Resources) + if err != nil { + t.Fatal(err) + } + if freeze != tc.freeze0 || thaw != tc.thaw0 { + t.Errorf("before Apply (non-existent unit): expected freeze: %v, thaw: %v, got freeze: %v, thaw: %v", + tc.freeze0, tc.thaw0, freeze, thaw) + } + + // Create systemd unit. + pid := -1 + if strings.HasSuffix(getUnitName(tc.cg), ".scope") { + // Scopes require a process inside. + cmd := exec.Command("bash", "-c", "sleep 1m") + if err := cmd.Start(); err != nil { + t.Fatal(err) + } + pid = cmd.Process.Pid + // Make sure to not leave a zombie. + defer func() { + // These may fail, we don't care. + _ = cmd.Process.Kill() + _ = cmd.Wait() + }() + } + if err := m.Apply(pid); err != nil { + t.Fatal(err) + } + if tc.preFreeze { + if err := m.Freeze(configs.Frozen); err != nil { + t.Error(err) + return // no more checks + } + } + freeze, thaw, err = lm.freezeBeforeSet(getUnitName(tc.cg), tc.cg.Resources) + if err != nil { + t.Error(err) + return // no more checks + } + if freeze != tc.freeze1 || thaw != tc.thaw1 { + t.Errorf("expected freeze: %v, thaw: %v, got freeze: %v, thaw: %v", + tc.freeze1, tc.thaw1, freeze, thaw) + } + // Destroy() timeouts on a frozen container, so we need to thaw it. + if tc.preFreeze { + if err := m.Freeze(configs.Thawed); err != nil { + t.Error(err) + } + } + // Destroy() does not kill processes in cgroup, so we should. + if pid != -1 { + if err = unix.Kill(pid, unix.SIGKILL); err != nil { + t.Errorf("unable to kill pid %d: %s", pid, err) + } + } + // Not really needed, but may help catch some bugs. + if err := m.Destroy(); err != nil { + t.Errorf("destroy: %s", err) + } + }) + } +} + +// requireV1 skips the test unless a set of requirements (cgroup v1, +// systemd, root) is met. +func requireV1(t *testing.T) { + t.Helper() + if cgroups.IsCgroup2UnifiedMode() { + t.Skip("Test requires cgroup v1.") + } + if !IsRunningSystemd() { + t.Skip("Test requires systemd.") + } + if os.Geteuid() != 0 { + t.Skip("Test requires root.") + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.0.1/libcontainer/configs/cgroup_linux.go new/runc-1.0.2/libcontainer/configs/cgroup_linux.go --- old/runc-1.0.1/libcontainer/configs/cgroup_linux.go 2021-07-16 06:39:19.000000000 +0200 +++ new/runc-1.0.2/libcontainer/configs/cgroup_linux.go 2021-08-20 09:24:11.000000000 +0200 @@ -131,4 +131,16 @@ // // NOTE it is impossible to start a container which has this flag set. SkipDevices bool `json:"-"` + + // SkipFreezeOnSet is a flag for cgroup manager to skip the cgroup + // freeze when setting resources. Only applicable to systemd legacy + // (i.e. cgroup v1) manager (which uses freeze by default to avoid + // spurious permission errors caused by systemd inability to update + // device rules in a non-disruptive manner). + // + // If not set, a few methods (such as looking into cgroup's + // devices.list and querying the systemd unit properties) are used + // during Set() to figure out whether the freeze is required. Those + // methods may be relatively slow, thus this flag. + SkipFreezeOnSet bool `json:"-"` } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.0.1/libcontainer/nsenter/nsexec.c new/runc-1.0.2/libcontainer/nsenter/nsexec.c --- old/runc-1.0.1/libcontainer/nsenter/nsexec.c 2021-07-16 06:39:19.000000000 +0200 +++ new/runc-1.0.2/libcontainer/nsenter/nsexec.c 2021-08-20 09:24:11.000000000 +0200 @@ -142,7 +142,7 @@ static void write_log(const char *level, const char *format, ...) { - char *message = NULL, *stage = NULL; + char *message = NULL, *stage = NULL, *json = NULL; va_list args; int ret; @@ -164,11 +164,21 @@ if (ret < 0) goto out; - dprintf(logfd, "{\"level\":\"%s\", \"msg\": \"%s[%d]: %s\"}\n", level, stage, getpid(), message); + ret = asprintf(&json, "{\"level\":\"%s\", \"msg\": \"%s[%d]: %s\"}\n", level, stage, getpid(), message); + if (ret < 0) { + json = NULL; + goto out; + } + + /* This logging is on a best-effort basis. In case of a short or failed + * write there is nothing we can do, so just ignore write() errors. + */ + ssize_t __attribute__((unused)) __res = write(logfd, json, ret); out: free(message); free(stage); + free(json); } /* XXX: This is ugly. */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.0.1/libcontainer/seccomp/seccomp_linux.go new/runc-1.0.2/libcontainer/seccomp/seccomp_linux.go --- old/runc-1.0.1/libcontainer/seccomp/seccomp_linux.go 2021-07-16 06:39:19.000000000 +0200 +++ new/runc-1.0.2/libcontainer/seccomp/seccomp_linux.go 2021-08-20 09:24:11.000000000 +0200 @@ -67,7 +67,7 @@ if call == nil { return errors.New("encountered nil syscall while initializing Seccomp") } - if err := matchCall(filter, call); err != nil { + if err := matchCall(filter, call, defaultAction); err != nil { return err } } @@ -142,7 +142,7 @@ } // Add a rule to match a single syscall -func matchCall(filter *libseccomp.ScmpFilter, call *configs.Syscall) error { +func matchCall(filter *libseccomp.ScmpFilter, call *configs.Syscall, defAct libseccomp.ScmpAction) error { if call == nil || filter == nil { return errors.New("cannot use nil as syscall to block") } @@ -151,17 +151,22 @@ return errors.New("empty string is not a valid syscall") } - // If we can't resolve the syscall, assume it's not supported on this kernel - // Ignore it, don't error out - callNum, err := libseccomp.GetSyscallFromName(call.Name) + // Convert the call's action to the libseccomp equivalent + callAct, err := getAction(call.Action, call.ErrnoRet) if err != nil { + return fmt.Errorf("action in seccomp profile is invalid: %w", err) + } + if callAct == defAct { + // This rule is redundant, silently skip it + // to avoid error from AddRule. return nil } - // Convert the call's action to the libseccomp equivalent - callAct, err := getAction(call.Action, call.ErrnoRet) + // If we can't resolve the syscall, assume it's not supported on this kernel + // Ignore it, don't error out + callNum, err := libseccomp.GetSyscallFromName(call.Name) if err != nil { - return fmt.Errorf("action in seccomp profile is invalid: %s", err) + return nil } // Unconditional match - just add the rule diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.0.1/script/release.sh new/runc-1.0.2/script/release.sh --- old/runc-1.0.1/script/release.sh 2021-07-16 06:39:19.000000000 +0200 +++ new/runc-1.0.2/script/release.sh 2021-08-20 09:24:11.000000000 +0200 @@ -43,11 +43,17 @@ ) mv "$tarball"{,.asc} "$builddir" + # For reproducible builds, add these to EXTRA_LDFLAGS: + # -w to disable DWARF generation; + # -s to disable symbol table; + # -buildid= to remove variable build id. + local ldflags="-w -s -buildid=" # Add -a to go build flags to make sure it links against # the provided libseccomp, not the system one (otherwise # it can reuse cached pkg-config results). - make -C "$root" PKG_CONFIG_PATH="${prefix}/lib/pkgconfig" COMMIT_NO= EXTRA_FLAGS="-a" static + make -C "$root" PKG_CONFIG_PATH="${prefix}/lib/pkgconfig" COMMIT_NO= EXTRA_FLAGS="-a" EXTRA_LDFLAGS="${ldflags}" static rm -rf "$prefix" + strip "$root/$project" mv "$root/$project" "$1" } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.0.1/tests/integration/start_hello.bats new/runc-1.0.2/tests/integration/start_hello.bats --- old/runc-1.0.1/tests/integration/start_hello.bats 2021-07-16 06:39:19.000000000 +0200 +++ new/runc-1.0.2/tests/integration/start_hello.bats 2021-08-20 09:24:11.000000000 +0200 @@ -76,3 +76,15 @@ runc run test_hello [ "$status" -eq 0 ] } + +@test "runc run [redundant seccomp rules]" { + update_config ' .linux.seccomp = { + "defaultAction": "SCMP_ACT_ALLOW", + "syscalls": [{ + "names": ["bdflush"], + "action": "SCMP_ACT_ALLOW", + }] + }' + runc run test_hello + [ "$status" -eq 0 ] +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.0.1/tests/integration/update.bats new/runc-1.0.2/tests/integration/update.bats --- old/runc-1.0.1/tests/integration/update.bats 2021-07-16 06:39:19.000000000 +0200 +++ new/runc-1.0.2/tests/integration/update.bats 2021-08-20 09:24:11.000000000 +0200 @@ -345,6 +345,15 @@ check_cpu_quota -1 1000000 "infinity" } +@test "set cpu period with no quota (invalid period)" { + [[ "$ROOTLESS" -ne 0 ]] && requires rootless_cgroup + + update_config '.linux.resources.cpu |= { "period": 100 }' + + runc run -d --console-socket "$CONSOLE_SOCKET" test_update + [ "$status" -eq 1 ] +} + @test "set cpu quota with no period" { [[ "$ROOTLESS" -ne 0 ]] && requires rootless_cgroup @@ -537,7 +546,7 @@ root_period=$(cat "${CGROUP_CPU_BASE_PATH}/cpu.rt_period_us") root_runtime=$(cat "${CGROUP_CPU_BASE_PATH}/cpu.rt_runtime_us") # the following IFS magic sets dirs=("runc-cgroups-integration-test" "test-cgroup") - IFS='/' read -r -a dirs <<<"$REL_CGROUPS_PATH" + IFS='/' read -r -a dirs <<<"${REL_CGROUPS_PATH#/}" for ((i = 0; i < ${#dirs[@]}; i++)); do local target="$CGROUP_CPU_BASE_PATH" for ((j = 0; j <= i; j++)); do diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.0.1/tests/rootless.sh new/runc-1.0.2/tests/rootless.sh --- old/runc-1.0.1/tests/rootless.sh 2021-07-16 06:39:19.000000000 +0200 +++ new/runc-1.0.2/tests/rootless.sh 2021-08-20 09:24:11.000000000 +0200 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/bash -x # Copyright (C) 2017 SUSE LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -114,6 +114,15 @@ # necessary, and might actually be a bug in our impl of cgroup # handling. [[ "$cg" == "cpuset" ]] && chown rootless:rootless "$CGROUP_MOUNT/$cg$CGROUP_PATH/cpuset."{cpus,mems} + # The following is required by "update rt period and runtime". + if [[ "$cg" == "cpu" ]]; then + if [[ -e "$CGROUP_MOUNT/$cg$CGROUP_PATH/cpu.rt_period_us" ]]; then + chown rootless:rootless "$CGROUP_MOUNT/$cg$CGROUP_PATH/cpu.rt_period_us" + fi + if [[ -e "$CGROUP_MOUNT/$cg$CGROUP_PATH/cpu.rt_runtime_us" ]]; then + chown rootless:rootless "$CGROUP_MOUNT/$cg$CGROUP_PATH/cpu.rt_runtime_us" + fi + fi done # cgroup v2 if [[ -e "$CGROUP_MOUNT/cgroup.controllers" ]]; then