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-09-14 16:25:05 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/runc (Old) and /work/SRC/openSUSE:Factory/.runc.new.1766 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "runc" Thu Sep 14 16:25:05 2023 rev:57 rq:1110965 version:1.1.9 Changes: -------- --- /work/SRC/openSUSE:Factory/runc/runc.changes 2023-07-25 11:25:39.740530072 +0200 +++ /work/SRC/openSUSE:Factory/.runc.new.1766/runc.changes 2023-09-14 16:27:00.861472974 +0200 @@ -1,0 +2,6 @@ +Wed Sep 6 06:42:37 UTC 2023 - Danish Prakash <danish.prak...@suse.com> + +- Update to runc v1.1.9. Upstream changelog is available from + <https://github.com/opencontainers/runc/releases/tag/v1.1.9>. + +------------------------------------------------------------------- Old: ---- runc-1.1.8.tar.xz runc-1.1.8.tar.xz.asc New: ---- runc-1.1.9.tar.xz runc-1.1.9.tar.xz.asc ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ runc.spec ++++++ --- /var/tmp/diff_new_pack.MADN97/_old 2023-09-14 16:27:02.193520560 +0200 +++ /var/tmp/diff_new_pack.MADN97/_new 2023-09-14 16:27:02.193520560 +0200 @@ -18,13 +18,13 @@ # MANUAL: Make sure you update this each time you update runc. -%define git_version 82f18fe0e44a59034f3e1f45e475fa5636e539aa -%define git_short 82f18fe0e44a +%define git_version ccaecfcbc907d70a7aa870a6650887b901b25b82 +%define git_short ccaecfcbc907 %define project github.com/opencontainers/runc Name: runc -Version: 1.1.8 +Version: 1.1.9 Release: 0 Summary: Tool for spawning and running OCI containers License: Apache-2.0 ++++++ runc-1.1.8.tar.xz -> runc-1.1.9.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.8/.cirrus.yml new/runc-1.1.9/.cirrus.yml --- old/runc-1.1.8/.cirrus.yml 2023-07-19 07:15:32.000000000 +0200 +++ new/runc-1.1.9/.cirrus.yml 2023-08-10 19:32:18.000000000 +0200 @@ -31,12 +31,12 @@ host_info_script: | uname -a - echo "-----" + # ----- cat /etc/os-release - echo "-----" - cat /proc/cpuinfo - echo "-----" + # ----- df -T + # ----- + cat /proc/cpuinfo install_libvirt_vagrant_script: | curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list @@ -77,7 +77,7 @@ env: HOME: /root CIRRUS_WORKING_DIR: /home/runc - GO_VERSION: "1.19.8" + GO_VERSION: "1.20" BATS_VERSION: "v1.9.0" RPMS: gcc git iptables jq glibc-static libseccomp-devel make criu fuse-sshfs # yamllint disable rule:key-duplicates @@ -130,7 +130,10 @@ # 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 + PREFIX="https://go.dev/dl/" + # Find out the latest minor release URL. + eval $(curl -fsSL "${PREFIX}?mode=json" | jq -r --arg Ver "$GO_VERSION" '.[] | select(.version | startswith("go\($Ver)")) | .files[] | select(.os == "linux" and .arch == "amd64" and .kind == "archive") | "filename=\"" + .filename + "\""') + curl -fsSL "$PREFIX$filename" | tar Cxz /usr/local # install bats cd /tmp git clone https://github.com/bats-core/bats-core @@ -158,14 +161,16 @@ systemctl restart sshd host_info_script: | uname -a - echo "-----" + # ----- + /usr/local/go/bin/go version + # ----- + systemctl --version + # ----- cat /etc/os-release - echo "-----" - cat /proc/cpuinfo - echo "-----" + # ----- df -T - echo "-----" - systemctl --version + # ----- + cat /proc/cpuinfo check_config_script: | /home/runc/script/check-config.sh unit_tests_script: | diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.8/.github/workflows/test.yml new/runc-1.1.9/.github/workflows/test.yml --- old/runc-1.1.8/.github/workflows/test.yml 2023-07-19 07:15:32.000000000 +0200 +++ new/runc-1.1.9/.github/workflows/test.yml 2023-08-10 19:32:18.000000000 +0200 @@ -21,7 +21,7 @@ strategy: fail-fast: false matrix: - go-version: [1.17.x, 1.19.x, 1.20.x] + go-version: [1.17.x, 1.20.x, 1.21.x] rootless: ["rootless", ""] race: ["-race", ""] criu: [""] @@ -60,7 +60,7 @@ rm -rf ~/criu - name: install go ${{ matrix.go-version }} - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: go-version: ${{ matrix.go-version }} @@ -119,7 +119,7 @@ sudo apt -q install libseccomp-dev libseccomp-dev:i386 gcc-multilib criu - name: install go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: go-version: 1.x # Latest stable diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.8/.github/workflows/validate.yml new/runc-1.1.9/.github/workflows/validate.yml --- old/runc-1.1.8/.github/workflows/validate.yml 2023-07-19 07:15:32.000000000 +0200 +++ new/runc-1.1.9/.github/workflows/validate.yml 2023-08-10 19:32:18.000000000 +0200 @@ -8,7 +8,7 @@ - release-* pull_request: env: - GO_VERSION: 1.19.x + GO_VERSION: 1.20.x jobs: keyring: @@ -24,16 +24,17 @@ - uses: actions/checkout@v3 with: fetch-depth: 2 - - uses: actions/setup-go@v3 + - uses: actions/setup-go@v4 with: go-version: "${{ env.GO_VERSION }}" + cache: false # golangci-lint-action does its own caching - name: install deps run: | sudo apt -q update sudo apt -q install libseccomp-dev - uses: golangci/golangci-lint-action@v3 with: - version: v1.48 + version: v1.53 # Extra linters, only checking new code from a pull request. - name: lint-extra if: github.event_name == 'pull_request' @@ -48,7 +49,7 @@ steps: - uses: actions/checkout@v3 - name: install go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: go-version: "${{ env.GO_VERSION }}" - name: compile with no build tags @@ -89,7 +90,7 @@ sha256sum ~/bin/shellcheck | grep -q $SHA256SUM # make sure to remove the old version sudo rm -f /usr/bin/shellcheck - - uses: lumaxis/shellcheck-problem-matchers@v1 + - uses: lumaxis/shellcheck-problem-matchers@v2 - name: shellcheck run: | make shellcheck @@ -101,17 +102,9 @@ steps: - uses: actions/checkout@v3 - name: install go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: go-version: "${{ env.GO_VERSION }}" - - name: cache go mod and $GOCACHE - uses: actions/cache@v3 - with: - path: | - ~/go/pkg/mod - ~/.cache/go-build - key: ${{ runner.os }}-go.sum-${{ hashFiles('**/go.sum') }} - restore-keys: ${{ runner.os }}-go.sum- - name: verify deps run: make verify-dependencies @@ -176,7 +169,7 @@ - name: make releaseall run: make releaseall - name: upload artifacts - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: release-${{ github.run_id }} path: release/* diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.8/CHANGELOG.md new/runc-1.1.9/CHANGELOG.md --- old/runc-1.1.8/CHANGELOG.md 2023-07-19 07:15:32.000000000 +0200 +++ new/runc-1.1.9/CHANGELOG.md 2023-08-10 19:32:18.000000000 +0200 @@ -6,6 +6,27 @@ ## [Unreleased 1.1.z] +## [1.1.9] - 2023-08-10 + +> There is a crack in everything. That's how the light gets in. + +### Added + +* Added go 1.21 to the CI matrix; other CI updates. (#3976, #3958) + +### Fixed + +* Fixed losing sticky bit on tmpfs (a regression in 1.1.8). (#3952, #3961) +* intelrdt: fixed ignoring ClosID on some systems. (#3550, #3978) + +### Changed + + * Sum `anon` and `file` from `memory.stat` for cgroupv2 root usage, + as the root does not have `memory.current` for cgroupv2. + This aligns cgroupv2 root usage more closely with cgroupv1 reporting. + Additionally, report root swap usage as sum of swap and memory usage, + aligned with v1 and existing non-root v2 reporting. (#3933) + ## [1.1.8] - 2023-07-20 > 海纳ç¾å· æå®¹ä¹å¤§ @@ -435,7 +456,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.8...release-1.1 +[Unreleased 1.1.z]: https://github.com/opencontainers/runc/compare/v1.1.9...release-1.1 +[1.1.8]: https://github.com/opencontainers/runc/compare/v1.1.8...v1.1.9 [1.1.8]: https://github.com/opencontainers/runc/compare/v1.1.7...v1.1.8 [1.1.7]: https://github.com/opencontainers/runc/compare/v1.1.6...v1.1.7 [1.1.6]: https://github.com/opencontainers/runc/compare/v1.1.5...v1.1.6 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.8/Dockerfile new/runc-1.1.9/Dockerfile --- old/runc-1.1.8/Dockerfile 2023-07-19 07:15:32.000000000 +0200 +++ new/runc-1.1.9/Dockerfile 2023-08-10 19:32:18.000000000 +0200 @@ -62,3 +62,7 @@ RUN git config --global --add safe.directory /go/src/github.com/opencontainers/runc WORKDIR /go/src/github.com/opencontainers/runc + +# Fixup for cgroup v2. +COPY script/prepare-cgroup-v2.sh / +ENTRYPOINT [ "/prepare-cgroup-v2.sh" ] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.8/VERSION new/runc-1.1.9/VERSION --- old/runc-1.1.8/VERSION 2023-07-19 07:15:32.000000000 +0200 +++ new/runc-1.1.9/VERSION 2023-08-10 19:32:18.000000000 +0200 @@ -1 +1 @@ -1.1.8 +1.1.9 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.8/libcontainer/cgroups/file_test.go new/runc-1.1.9/libcontainer/cgroups/file_test.go --- old/runc-1.1.8/libcontainer/cgroups/file_test.go 2023-07-19 07:15:32.000000000 +0200 +++ new/runc-1.1.9/libcontainer/cgroups/file_test.go 2023-08-10 19:32:18.000000000 +0200 @@ -58,8 +58,6 @@ {"/sys/fs/cgroup", "/cgroup.controllers"}, {"/sys/fs/cgroup/", "cgroup.controllers"}, {"/sys/fs/cgroup/", "/cgroup.controllers"}, - {"/sys/fs/cgroup/user.slice", "cgroup.controllers"}, - {"/sys/fs/cgroup/user.slice/", "/cgroup.controllers"}, {"/", "/sys/fs/cgroup/cgroup.controllers"}, {"/", "sys/fs/cgroup/cgroup.controllers"}, {"/sys/fs/cgroup/cgroup.controllers", ""}, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.8/libcontainer/cgroups/fs2/memory.go new/runc-1.1.9/libcontainer/cgroups/fs2/memory.go --- old/runc-1.1.8/libcontainer/cgroups/fs2/memory.go 2023-07-19 07:15:32.000000000 +0200 +++ new/runc-1.1.9/libcontainer/cgroups/fs2/memory.go 2023-08-10 19:32:18.000000000 +0200 @@ -101,8 +101,9 @@ if err != nil { if errors.Is(err, unix.ENOENT) && dirPath == UnifiedMountpoint { // The root cgroup does not have memory.{current,max} - // so emulate those using data from /proc/meminfo. - return statsFromMeminfo(stats) + // so emulate those using data from /proc/meminfo and + // /sys/fs/cgroup/memory.stat + return rootStatsFromMeminfo(stats) } return err } @@ -154,7 +155,7 @@ return memoryData, nil } -func statsFromMeminfo(stats *cgroups.Stats) error { +func rootStatsFromMeminfo(stats *cgroups.Stats) error { const file = "/proc/meminfo" f, err := os.Open(file) if err != nil { @@ -166,14 +167,10 @@ var ( swap_free uint64 swap_total uint64 - main_total uint64 - main_free uint64 ) mem := map[string]*uint64{ "SwapFree": &swap_free, "SwapTotal": &swap_total, - "MemTotal": &main_total, - "MemFree": &main_free, } found := 0 @@ -206,11 +203,18 @@ return &parseError{Path: "", File: file, Err: err} } + // cgroup v1 `usage_in_bytes` reports memory usage as the sum of + // - rss (NR_ANON_MAPPED) + // - cache (NR_FILE_PAGES) + // cgroup v1 reports SwapUsage values as mem+swap combined + // cgroup v2 reports rss and cache as anon and file. + // sum `anon` + `file` to report the same value as `usage_in_bytes` in v1. + // sum swap usage as combined mem+swap usage for consistency as well. + stats.MemoryStats.Usage.Usage = stats.MemoryStats.Stats["anon"] + stats.MemoryStats.Stats["file"] + stats.MemoryStats.Usage.Limit = math.MaxUint64 stats.MemoryStats.SwapUsage.Usage = (swap_total - swap_free) * 1024 stats.MemoryStats.SwapUsage.Limit = math.MaxUint64 - - stats.MemoryStats.Usage.Usage = (main_total - main_free) * 1024 - stats.MemoryStats.Usage.Limit = math.MaxUint64 + stats.MemoryStats.SwapUsage.Usage += stats.MemoryStats.Usage.Usage return nil } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.8/libcontainer/cgroups/fs2/memory_test.go new/runc-1.1.9/libcontainer/cgroups/fs2/memory_test.go --- old/runc-1.1.8/libcontainer/cgroups/fs2/memory_test.go 1970-01-01 01:00:00.000000000 +0100 +++ new/runc-1.1.9/libcontainer/cgroups/fs2/memory_test.go 2023-08-10 19:32:18.000000000 +0200 @@ -0,0 +1,139 @@ +package fs2 + +import ( + "os" + "path/filepath" + "strings" + "testing" + + "github.com/opencontainers/runc/libcontainer/cgroups" +) + +const exampleMemoryStatData = `anon 790425600 +file 6502666240 +kernel_stack 7012352 +pagetables 8867840 +percpu 2445520 +sock 40960 +shmem 6721536 +file_mapped 656187392 +file_dirty 1122304 +file_writeback 0 +swapcached 10 +anon_thp 438304768 +file_thp 0 +shmem_thp 0 +inactive_anon 892223488 +active_anon 2973696 +inactive_file 5307346944 +active_file 1179316224 +unevictable 31477760 +slab_reclaimable 348866240 +slab_unreclaimable 10099808 +slab 358966048 +workingset_refault_anon 0 +workingset_refault_file 0 +workingset_activate_anon 0 +workingset_activate_file 0 +workingset_restore_anon 0 +workingset_restore_file 0 +workingset_nodereclaim 0 +pgfault 103216687 +pgmajfault 6879 +pgrefill 0 +pgscan 0 +pgsteal 0 +pgactivate 1110217 +pgdeactivate 292 +pglazyfree 267 +pglazyfreed 0 +thp_fault_alloc 57411 +thp_collapse_alloc 443` + +func TestStatMemoryPodCgroupNotFound(t *testing.T) { + // We're using a fake cgroupfs. + cgroups.TestMode = true + fakeCgroupDir := t.TempDir() + + // only write memory.stat to ensure pod cgroup usage + // still reads memory.current. + statPath := filepath.Join(fakeCgroupDir, "memory.stat") + if err := os.WriteFile(statPath, []byte(exampleMemoryStatData), 0o644); err != nil { + t.Fatal(err) + } + + gotStats := cgroups.NewStats() + + // use a fake root path to mismatch the file we wrote. + // this triggers the non-root path which should fail to find memory.current. + err := statMemory(fakeCgroupDir, gotStats) + if err == nil { + t.Errorf("expected error when statting memory for cgroupv2 root, but was nil") + } + + if !strings.Contains(err.Error(), "memory.current: no such file or directory") { + t.Errorf("expected error to contain 'memory.current: no such file or directory', but was %s", err.Error()) + } +} + +func TestStatMemoryPodCgroup(t *testing.T) { + // We're using a fake cgroupfs. + cgroups.TestMode = true + fakeCgroupDir := t.TempDir() + + statPath := filepath.Join(fakeCgroupDir, "memory.stat") + if err := os.WriteFile(statPath, []byte(exampleMemoryStatData), 0o644); err != nil { + t.Fatal(err) + } + + if err := os.WriteFile(filepath.Join(fakeCgroupDir, "memory.current"), []byte("123456789"), 0o644); err != nil { + t.Fatal(err) + } + + if err := os.WriteFile(filepath.Join(fakeCgroupDir, "memory.max"), []byte("999999999"), 0o644); err != nil { + t.Fatal(err) + } + + gotStats := cgroups.NewStats() + + // use a fake root path to trigger the pod cgroup lookup. + err := statMemory(fakeCgroupDir, gotStats) + if err != nil { + t.Errorf("expected no error when statting memory for cgroupv2 root, but got %#+v", err) + } + + // result should be "memory.current" + var expectedUsageBytes uint64 = 123456789 + if gotStats.MemoryStats.Usage.Usage != expectedUsageBytes { + t.Errorf("parsed cgroupv2 memory.stat doesn't match expected result: \ngot %#v\nexpected %#v\n", gotStats.MemoryStats.Usage.Usage, expectedUsageBytes) + } +} + +func TestRootStatsFromMeminfo(t *testing.T) { + stats := &cgroups.Stats{ + MemoryStats: cgroups.MemoryStats{ + Stats: map[string]uint64{ + "anon": 790425600, + "file": 6502666240, + }, + }, + } + + if err := rootStatsFromMeminfo(stats); err != nil { + t.Fatal(err) + } + + // result is anon + file + var expectedUsageBytes uint64 = 7293091840 + if stats.MemoryStats.Usage.Usage != expectedUsageBytes { + t.Errorf("parsed cgroupv2 memory.stat doesn't match expected result: \ngot %d\nexpected %d\n", stats.MemoryStats.Usage.Usage, expectedUsageBytes) + } + + // swap is adjusted to mem+swap + if stats.MemoryStats.SwapUsage.Usage < stats.MemoryStats.Usage.Usage { + t.Errorf("swap usage %d should be at least mem usage %d", stats.MemoryStats.SwapUsage.Usage, stats.MemoryStats.Usage.Usage) + } + if stats.MemoryStats.SwapUsage.Limit < stats.MemoryStats.Usage.Limit { + t.Errorf("swap limit %d should be at least mem limit %d", stats.MemoryStats.SwapUsage.Limit, stats.MemoryStats.Usage.Limit) + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.8/libcontainer/cgroups/manager/manager_test.go new/runc-1.1.9/libcontainer/cgroups/manager/manager_test.go --- old/runc-1.1.8/libcontainer/cgroups/manager/manager_test.go 2023-07-19 07:15:32.000000000 +0200 +++ new/runc-1.1.9/libcontainer/cgroups/manager/manager_test.go 2023-08-10 19:32:18.000000000 +0200 @@ -3,6 +3,7 @@ import ( "testing" + "github.com/opencontainers/runc/libcontainer/cgroups/systemd" "github.com/opencontainers/runc/libcontainer/configs" ) @@ -10,35 +11,45 @@ // config.Resources is nil. While it does not make sense to use a // manager with no resources, it should not result in a panic. // -// This tests either v1 or v2 managers (both fs and systemd), -// depending on what cgroup version is available on the host. +// This tests either v1 or v2 fs cgroup manager, depending on which +// cgroup version is available. func TestNilResources(t *testing.T) { - for _, sd := range []bool{false, true} { - cg := &configs.Cgroup{} // .Resources is nil - cg.Systemd = sd - mgr, err := New(cg) + testNilResources(t, false) +} + +// TestNilResourcesSystemd is the same as TestNilResources, +// only checking the systemd cgroup manager. +func TestNilResourcesSystemd(t *testing.T) { + if !systemd.IsRunningSystemd() { + t.Skip("requires systemd") + } + testNilResources(t, true) +} + +func testNilResources(t *testing.T, systemd bool) { + cg := &configs.Cgroup{} // .Resources is nil + cg.Systemd = systemd + mgr, err := New(cg) + if err != nil { + // Some managers require non-nil Resources during + // instantiation -- provide and retry. In such case + // we're mostly testing Set(nil) below. + cg.Resources = &configs.Resources{} + mgr, err = New(cg) if err != nil { - // Some managers require non-nil Resources during - // instantiation -- provide and retry. In such case - // we're mostly testing Set(nil) below. - cg.Resources = &configs.Resources{} - mgr, err = New(cg) - if err != nil { - t.Error(err) - continue - } + t.Fatal(err) } - _ = mgr.Apply(-1) - _ = mgr.Set(nil) - _ = mgr.Freeze(configs.Thawed) - _ = mgr.Exists() - _, _ = mgr.GetAllPids() - _, _ = mgr.GetCgroups() - _, _ = mgr.GetFreezerState() - _ = mgr.Path("") - _ = mgr.GetPaths() - _, _ = mgr.GetStats() - _, _ = mgr.OOMKillCount() - _ = mgr.Destroy() } + _ = mgr.Apply(-1) + _ = mgr.Set(nil) + _ = mgr.Freeze(configs.Thawed) + _ = mgr.Exists() + _, _ = mgr.GetAllPids() + _, _ = mgr.GetCgroups() + _, _ = mgr.GetFreezerState() + _ = mgr.Path("") + _ = mgr.GetPaths() + _, _ = mgr.GetStats() + _, _ = mgr.OOMKillCount() + _ = mgr.Destroy() } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.8/libcontainer/container_linux.go new/runc-1.1.9/libcontainer/container_linux.go --- old/runc-1.1.8/libcontainer/container_linux.go 2023-07-19 07:15:32.000000000 +0200 +++ new/runc-1.1.9/libcontainer/container_linux.go 2023-08-10 19:32:18.000000000 +0200 @@ -40,7 +40,7 @@ root string config *configs.Config cgroupManager cgroups.Manager - intelRdtManager intelrdt.Manager + intelRdtManager *intelrdt.Manager initPath string initArgs []string initProcess parentProcess diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.8/libcontainer/container_linux_test.go new/runc-1.1.9/libcontainer/container_linux_test.go --- old/runc-1.1.8/libcontainer/container_linux_test.go 2023-07-19 07:15:32.000000000 +0200 +++ new/runc-1.1.9/libcontainer/container_linux_test.go 2023-08-10 19:32:18.000000000 +0200 @@ -7,22 +7,15 @@ "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/configs" - "github.com/opencontainers/runc/libcontainer/intelrdt" "github.com/opencontainers/runc/libcontainer/system" ) type mockCgroupManager struct { pids []int allPids []int - stats *cgroups.Stats paths map[string]string } -type mockIntelRdtManager struct { - stats *intelrdt.Stats - path string -} - func (m *mockCgroupManager) GetPids() ([]int, error) { return m.pids, nil } @@ -32,7 +25,7 @@ } func (m *mockCgroupManager) GetStats() (*cgroups.Stats, error) { - return m.stats, nil + return nil, nil } func (m *mockCgroupManager) Apply(pid int) error { @@ -76,30 +69,6 @@ return configs.Thawed, nil } -func (m *mockIntelRdtManager) Apply(pid int) error { - return nil -} - -func (m *mockIntelRdtManager) GetStats() (*intelrdt.Stats, error) { - return m.stats, nil -} - -func (m *mockIntelRdtManager) Destroy() error { - return nil -} - -func (m *mockIntelRdtManager) GetPath() string { - return m.path -} - -func (m *mockIntelRdtManager) Set(container *configs.Config) error { - return nil -} - -func (m *mockIntelRdtManager) GetCgroups() (*configs.Cgroup, error) { - return nil, nil -} - type mockProcess struct { _pid int started uint64 @@ -173,61 +142,11 @@ } } -func TestGetContainerStats(t *testing.T) { - container := &linuxContainer{ - id: "myid", - config: &configs.Config{}, - cgroupManager: &mockCgroupManager{ - pids: []int{1, 2, 3}, - stats: &cgroups.Stats{ - MemoryStats: cgroups.MemoryStats{ - Usage: cgroups.MemoryData{ - Usage: 1024, - }, - }, - }, - }, - intelRdtManager: &mockIntelRdtManager{ - stats: &intelrdt.Stats{ - L3CacheSchema: "L3:0=f;1=f0", - MemBwSchema: "MB:0=20;1=70", - }, - }, - } - stats, err := container.Stats() - if err != nil { - t.Fatal(err) - } - if stats.CgroupStats == nil { - t.Fatal("cgroup stats are nil") - } - if stats.CgroupStats.MemoryStats.Usage.Usage != 1024 { - t.Fatalf("expected memory usage 1024 but received %d", stats.CgroupStats.MemoryStats.Usage.Usage) - } - if intelrdt.IsCATEnabled() { - if stats.IntelRdtStats == nil { - t.Fatal("intel rdt stats are nil") - } - if stats.IntelRdtStats.L3CacheSchema != "L3:0=f;1=f0" { - t.Fatalf("expected L3CacheSchema L3:0=f;1=f0 but received %s", stats.IntelRdtStats.L3CacheSchema) - } - } - if intelrdt.IsMBAEnabled() { - if stats.IntelRdtStats == nil { - t.Fatal("intel rdt stats are nil") - } - if stats.IntelRdtStats.MemBwSchema != "MB:0=20;1=70" { - t.Fatalf("expected MemBwSchema MB:0=20;1=70 but received %s", stats.IntelRdtStats.MemBwSchema) - } - } -} - func TestGetContainerState(t *testing.T) { var ( - pid = os.Getpid() - expectedMemoryPath = "/sys/fs/cgroup/memory/myid" - expectedNetworkPath = fmt.Sprintf("/proc/%d/ns/net", pid) - expectedIntelRdtPath = "/sys/fs/resctrl/myid" + pid = os.Getpid() + expectedMemoryPath = "/sys/fs/cgroup/memory/myid" + expectedNetworkPath = fmt.Sprintf("/proc/%d/ns/net", pid) ) container := &linuxContainer{ id: "myid", @@ -248,24 +167,10 @@ }, cgroupManager: &mockCgroupManager{ pids: []int{1, 2, 3}, - stats: &cgroups.Stats{ - MemoryStats: cgroups.MemoryStats{ - Usage: cgroups.MemoryData{ - Usage: 1024, - }, - }, - }, paths: map[string]string{ "memory": expectedMemoryPath, }, }, - intelRdtManager: &mockIntelRdtManager{ - stats: &intelrdt.Stats{ - L3CacheSchema: "L3:0=f0;1=f", - MemBwSchema: "MB:0=70;1=20", - }, - path: expectedIntelRdtPath, - }, } container.state = &createdState{c: container} state, err := container.State() @@ -285,15 +190,6 @@ if memPath := paths["memory"]; memPath != expectedMemoryPath { t.Fatalf("expected memory path %q but received %q", expectedMemoryPath, memPath) } - if intelrdt.IsCATEnabled() || intelrdt.IsMBAEnabled() { - intelRdtPath := state.IntelRdtPath - if intelRdtPath == "" { - t.Fatal("intel rdt path should not be empty") - } - if intelRdtPath != expectedIntelRdtPath { - t.Fatalf("expected intel rdt path %q but received %q", expectedIntelRdtPath, intelRdtPath) - } - } for _, ns := range container.config.Namespaces { path := state.NamespacePaths[ns.Type] if path == "" { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.8/libcontainer/factory_linux.go new/runc-1.1.9/libcontainer/factory_linux.go --- old/runc-1.1.8/libcontainer/factory_linux.go 2023-07-19 07:15:32.000000000 +0200 +++ new/runc-1.1.9/libcontainer/factory_linux.go 2023-08-10 19:32:18.000000000 +0200 @@ -48,20 +48,6 @@ } } -// IntelRdtfs is an options func to configure a LinuxFactory to return -// containers that use the Intel RDT "resource control" filesystem to -// create and manage Intel RDT resources (e.g., L3 cache, memory bandwidth). -func IntelRdtFs(l *LinuxFactory) error { - if !intelrdt.IsCATEnabled() && !intelrdt.IsMBAEnabled() { - l.NewIntelRdtManager = nil - } else { - l.NewIntelRdtManager = func(config *configs.Config, id string, path string) intelrdt.Manager { - return intelrdt.NewManager(config, id, path) - } - } - return nil -} - // TmpfsRoot is an option func to mount LinuxFactory.Root to tmpfs. func TmpfsRoot(l *LinuxFactory) error { mounted, err := mountinfo.Mounted(l.Root) @@ -136,9 +122,6 @@ // Validator provides validation to container configurations. Validator validate.Validator - - // NewIntelRdtManager returns an initialized Intel RDT manager for a single container. - NewIntelRdtManager func(config *configs.Config, id string, path string) intelrdt.Manager } func (l *LinuxFactory) Create(id string, config *configs.Config) (Container, error) { @@ -208,18 +191,16 @@ return nil, err } c := &linuxContainer{ - id: id, - root: containerRoot, - config: config, - initPath: l.InitPath, - initArgs: l.InitArgs, - criuPath: l.CriuPath, - newuidmapPath: l.NewuidmapPath, - newgidmapPath: l.NewgidmapPath, - cgroupManager: cm, - } - if l.NewIntelRdtManager != nil { - c.intelRdtManager = l.NewIntelRdtManager(config, id, "") + id: id, + root: containerRoot, + config: config, + initPath: l.InitPath, + initArgs: l.InitArgs, + criuPath: l.CriuPath, + newuidmapPath: l.NewuidmapPath, + newgidmapPath: l.NewgidmapPath, + cgroupManager: cm, + intelRdtManager: intelrdt.NewManager(config, id, ""), } c.state = &stoppedState{c: c} return c, nil @@ -261,12 +242,10 @@ newuidmapPath: l.NewuidmapPath, newgidmapPath: l.NewgidmapPath, cgroupManager: cm, + intelRdtManager: intelrdt.NewManager(&state.Config, id, state.IntelRdtPath), root: containerRoot, created: state.Created, } - if l.NewIntelRdtManager != nil { - c.intelRdtManager = l.NewIntelRdtManager(&state.Config, id, state.IntelRdtPath) - } c.state = &loadedState{c: c} if err := c.refreshState(); err != nil { return nil, err diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.8/libcontainer/factory_linux_test.go new/runc-1.1.9/libcontainer/factory_linux_test.go --- old/runc-1.1.8/libcontainer/factory_linux_test.go 2023-07-19 07:15:32.000000000 +0200 +++ new/runc-1.1.9/libcontainer/factory_linux_test.go 2023-08-10 19:32:18.000000000 +0200 @@ -37,28 +37,6 @@ } } -func TestFactoryNewIntelRdt(t *testing.T) { - root := t.TempDir() - factory, err := New(root, IntelRdtFs) - if err != nil { - t.Fatal(err) - } - if factory == nil { - t.Fatal("factory should not be nil") - } - lfactory, ok := factory.(*LinuxFactory) - if !ok { - t.Fatal("expected linux factory returned on linux based systems") - } - if lfactory.Root != root { - t.Fatalf("expected factory root to be %q but received %q", root, lfactory.Root) - } - - if factory.Type() != "libcontainer" { - t.Fatalf("unexpected factory type: %q, expected %q", factory.Type(), "libcontainer") - } -} - func TestFactoryNewTmpfs(t *testing.T) { root := t.TempDir() factory, err := New(root, TmpfsRoot) @@ -157,7 +135,7 @@ if err := marshal(filepath.Join(root, id, stateFilename), expectedState); err != nil { t.Fatal(err) } - factory, err := New(root, IntelRdtFs) + factory, err := New(root) if err != nil { t.Fatal(err) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.8/libcontainer/intelrdt/intelrdt.go new/runc-1.1.9/libcontainer/intelrdt/intelrdt.go --- old/runc-1.1.8/libcontainer/intelrdt/intelrdt.go 2023-07-19 07:15:32.000000000 +0200 +++ new/runc-1.1.9/libcontainer/intelrdt/intelrdt.go 2023-08-10 19:32:18.000000000 +0200 @@ -1,11 +1,9 @@ package intelrdt import ( - "bufio" "bytes" "errors" "fmt" - "io" "os" "path/filepath" "strconv" @@ -13,6 +11,8 @@ "sync" "github.com/moby/sys/mountinfo" + "golang.org/x/sys/unix" + "github.com/opencontainers/runc/libcontainer/cgroups/fscommon" "github.com/opencontainers/runc/libcontainer/configs" ) @@ -145,34 +145,31 @@ * } */ -type Manager interface { - // Applies Intel RDT configuration to the process with the specified pid - Apply(pid int) error - - // Returns statistics for Intel RDT - GetStats() (*Stats, error) - - // Destroys the Intel RDT container-specific 'container_id' group - Destroy() error - - // Returns Intel RDT path to save in a state file and to be able to - // restore the object later - GetPath() string - - // Set Intel RDT "resource control" filesystem as configured. - Set(container *configs.Config) error -} - -// This implements interface Manager -type intelRdtManager struct { +type Manager struct { mu sync.Mutex config *configs.Config id string path string } -func NewManager(config *configs.Config, id string, path string) Manager { - return &intelRdtManager{ +// NewManager returns a new instance of Manager, or nil if the Intel RDT +// functionality is not specified in the config, available from hardware or +// enabled in the kernel. +func NewManager(config *configs.Config, id string, path string) *Manager { + if config.IntelRdt == nil { + return nil + } + if _, err := Root(); err != nil { + // Intel RDT is not available. + return nil + } + return newManager(config, id, path) +} + +// newManager is the same as NewManager, except it does not check if the feature +// is actually available. Used by unit tests that mock intelrdt paths. +func newManager(config *configs.Config, id string, path string) *Manager { + return &Manager{ config: config, id: id, path: path, @@ -188,71 +185,52 @@ catEnabled bool // The flag to indicate if Intel RDT/MBA is enabled mbaEnabled bool - // The flag to indicate if Intel RDT/MBA Software Controller is enabled - mbaScEnabled bool // For Intel RDT initialization initOnce sync.Once - errNotFound = errors.New("Intel RDT resctrl mount point not found") + errNotFound = errors.New("Intel RDT not available") ) // Check if Intel RDT sub-features are enabled in featuresInit() func featuresInit() { initOnce.Do(func() { - // 1. Check if hardware and kernel support Intel RDT sub-features - flagsSet, err := parseCpuInfoFile("/proc/cpuinfo") - if err != nil { - return - } - - // 2. Check if Intel RDT "resource control" filesystem is available. + // 1. Check if Intel RDT "resource control" filesystem is available. // The user guarantees to mount the filesystem. root, err := Root() if err != nil { return } - // 3. Double check if Intel RDT sub-features are available in - // "resource control" filesystem. Intel RDT sub-features can be + // 2. Check if Intel RDT sub-features are available in "resource + // control" filesystem. Intel RDT sub-features can be // selectively disabled or enabled by kernel command line // (e.g., rdt=!l3cat,mba) in 4.14 and newer kernel - if flagsSet.CAT { - if _, err := os.Stat(filepath.Join(root, "info", "L3")); err == nil { - catEnabled = true - } + if _, err := os.Stat(filepath.Join(root, "info", "L3")); err == nil { + catEnabled = true } - if mbaScEnabled { - // We confirm MBA Software Controller is enabled in step 2, - // MBA should be enabled because MBA Software Controller - // depends on MBA + if _, err := os.Stat(filepath.Join(root, "info", "MB")); err == nil { mbaEnabled = true - } else if flagsSet.MBA { - if _, err := os.Stat(filepath.Join(root, "info", "MB")); err == nil { - mbaEnabled = true - } } - if flagsSet.MBMTotal || flagsSet.MBMLocal || flagsSet.CMT { - if _, err := os.Stat(filepath.Join(root, "info", "L3_MON")); err != nil { - return - } - enabledMonFeatures, err = getMonFeatures(root) - if err != nil { - return - } - if enabledMonFeatures.mbmTotalBytes || enabledMonFeatures.mbmLocalBytes { - mbmEnabled = true - } - if enabledMonFeatures.llcOccupancy { - cmtEnabled = true - } + if _, err := os.Stat(filepath.Join(root, "info", "L3_MON")); err != nil { + return + } + enabledMonFeatures, err = getMonFeatures(root) + if err != nil { + return + } + if enabledMonFeatures.mbmTotalBytes || enabledMonFeatures.mbmLocalBytes { + mbmEnabled = true + } + if enabledMonFeatures.llcOccupancy { + cmtEnabled = true } }) } -// Return the mount point path of Intel RDT "resource control" filesysem -func findIntelRdtMountpointDir(f io.Reader) (string, error) { - mi, err := mountinfo.GetMountsFromReader(f, func(m *mountinfo.Info) (bool, bool) { +// findIntelRdtMountpointDir returns the mount point of the Intel RDT "resource control" filesystem. +func findIntelRdtMountpointDir() (string, error) { + mi, err := mountinfo.GetMounts(func(m *mountinfo.Info) (bool, bool) { // similar to mountinfo.FSTypeFilter but stops after the first match if m.FSType == "resctrl" { return false, true // don't skip, stop @@ -266,97 +244,45 @@ return "", errNotFound } - // Check if MBA Software Controller is enabled through mount option "-o mba_MBps" - if strings.Contains(","+mi[0].VFSOptions+",", ",mba_MBps,") { - mbaScEnabled = true - } - return mi[0].Mountpoint, nil } // For Root() use only. var ( - intelRdtRoot string - rootMu sync.Mutex + intelRdtRoot string + intelRdtRootErr error + rootOnce sync.Once ) +// The kernel creates this (empty) directory if resctrl is supported by the +// hardware and kernel. The user is responsible for mounting the resctrl +// filesystem, and they could mount it somewhere else if they wanted to. +const defaultResctrlMountpoint = "/sys/fs/resctrl" + // Root returns the Intel RDT "resource control" filesystem mount point. func Root() (string, error) { - rootMu.Lock() - defer rootMu.Unlock() - - if intelRdtRoot != "" { - return intelRdtRoot, nil - } - - f, err := os.Open("/proc/self/mountinfo") - if err != nil { - return "", err - } - root, err := findIntelRdtMountpointDir(f) - f.Close() - if err != nil { - return "", err - } - - if _, err := os.Stat(root); err != nil { - return "", err - } - - intelRdtRoot = root - return intelRdtRoot, nil -} - -type cpuInfoFlags struct { - CAT bool // Cache Allocation Technology - MBA bool // Memory Bandwidth Allocation - - // Memory Bandwidth Monitoring related. - MBMTotal bool - MBMLocal bool - - CMT bool // Cache Monitoring Technology -} - -func parseCpuInfoFile(path string) (cpuInfoFlags, error) { - infoFlags := cpuInfoFlags{} - - f, err := os.Open(path) - if err != nil { - return infoFlags, err - } - defer f.Close() - - s := bufio.NewScanner(f) - for s.Scan() { - line := s.Text() - - // Search "cat_l3" and "mba" flags in first "flags" line - if strings.HasPrefix(line, "flags") { - flags := strings.Split(line, " ") - // "cat_l3" flag for CAT and "mba" flag for MBA - for _, flag := range flags { - switch flag { - case "cat_l3": - infoFlags.CAT = true - case "mba": - infoFlags.MBA = true - case "cqm_mbm_total": - infoFlags.MBMTotal = true - case "cqm_mbm_local": - infoFlags.MBMLocal = true - case "cqm_occup_llc": - infoFlags.CMT = true - } + rootOnce.Do(func() { + // Does this system support resctrl? + var statfs unix.Statfs_t + if err := unix.Statfs(defaultResctrlMountpoint, &statfs); err != nil { + if errors.Is(err, unix.ENOENT) { + err = errNotFound } - return infoFlags, nil + intelRdtRootErr = err + return } - } - if err := s.Err(); err != nil { - return infoFlags, err - } - return infoFlags, nil + // Has the resctrl fs been mounted to the default mount point? + if statfs.Type == unix.RDTGROUP_SUPER_MAGIC { + intelRdtRoot = defaultResctrlMountpoint + return + } + + // The resctrl fs could have been mounted somewhere nonstandard. + intelRdtRoot, intelRdtRootErr = findIntelRdtMountpointDir() + }) + + return intelRdtRoot, intelRdtRootErr } // Gets a single uint64 value from the specified file. @@ -502,14 +428,8 @@ return mbaEnabled } -// Check if Intel RDT/MBA Software Controller is enabled -func IsMBAScEnabled() bool { - featuresInit() - return mbaScEnabled -} - // Get the path of the clos group in "resource control" filesystem that the container belongs to -func (m *intelRdtManager) getIntelRdtPath() (string, error) { +func (m *Manager) getIntelRdtPath() (string, error) { rootPath, err := Root() if err != nil { return "", err @@ -524,7 +444,7 @@ } // Applies Intel RDT configuration to the process with the specified pid -func (m *intelRdtManager) Apply(pid int) (err error) { +func (m *Manager) Apply(pid int) (err error) { // If intelRdt is not specified in config, we do nothing if m.config.IntelRdt == nil { return nil @@ -559,11 +479,11 @@ } // Destroys the Intel RDT container-specific 'container_id' group -func (m *intelRdtManager) Destroy() error { +func (m *Manager) Destroy() error { // Don't remove resctrl group if closid has been explicitly specified. The // group is likely externally managed, i.e. by some other entity than us. // There are probably other containers/tasks sharing the same group. - if m.config.IntelRdt == nil || m.config.IntelRdt.ClosID == "" { + if m.config.IntelRdt != nil && m.config.IntelRdt.ClosID == "" { m.mu.Lock() defer m.mu.Unlock() if err := os.RemoveAll(m.GetPath()); err != nil { @@ -576,7 +496,7 @@ // Returns Intel RDT path to save in a state file and to be able to // restore the object later -func (m *intelRdtManager) GetPath() string { +func (m *Manager) GetPath() string { if m.path == "" { m.path, _ = m.getIntelRdtPath() } @@ -584,7 +504,7 @@ } // Returns statistics for Intel RDT -func (m *intelRdtManager) GetStats() (*Stats, error) { +func (m *Manager) GetStats() (*Stats, error) { // If intelRdt is not specified in config if m.config.IntelRdt == nil { return nil, nil @@ -670,7 +590,7 @@ } // Set Intel RDT "resource control" filesystem as configured. -func (m *intelRdtManager) Set(container *configs.Config) error { +func (m *Manager) Set(container *configs.Config) error { // About L3 cache schema: // It has allocation bitmasks/values for L3 cache on each socket, // which contains L3 cache id and capacity bitmask (CBM). diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.8/libcontainer/intelrdt/intelrdt_test.go new/runc-1.1.9/libcontainer/intelrdt/intelrdt_test.go --- old/runc-1.1.8/libcontainer/intelrdt/intelrdt_test.go 2023-07-19 07:15:32.000000000 +0200 +++ new/runc-1.1.9/libcontainer/intelrdt/intelrdt_test.go 2023-08-10 19:32:18.000000000 +0200 @@ -1,8 +1,6 @@ package intelrdt import ( - "errors" - "io" "os" "path/filepath" "strings" @@ -22,7 +20,7 @@ }) helper.config.IntelRdt.L3CacheSchema = l3CacheSchemeAfter - intelrdt := NewManager(helper.config, "", helper.IntelRdtPath) + intelrdt := newManager(helper.config, "", helper.IntelRdtPath) if err := intelrdt.Set(helper.config); err != nil { t.Fatal(err) } @@ -52,7 +50,7 @@ }) helper.config.IntelRdt.MemBwSchema = memBwSchemeAfter - intelrdt := NewManager(helper.config, "", helper.IntelRdtPath) + intelrdt := newManager(helper.config, "", helper.IntelRdtPath) if err := intelrdt.Set(helper.config); err != nil { t.Fatal(err) } @@ -82,7 +80,7 @@ }) helper.config.IntelRdt.MemBwSchema = memBwScSchemeAfter - intelrdt := NewManager(helper.config, "", helper.IntelRdtPath) + intelrdt := newManager(helper.config, "", helper.IntelRdtPath) if err := intelrdt.Set(helper.config); err != nil { t.Fatal(err) } @@ -105,7 +103,7 @@ const closID = "test-clos" helper.config.IntelRdt.ClosID = closID - intelrdt := NewManager(helper.config, "", helper.IntelRdtPath) + intelrdt := newManager(helper.config, "", helper.IntelRdtPath) if err := intelrdt.Apply(1234); err == nil { t.Fatal("unexpected success when applying pid") } @@ -114,7 +112,7 @@ } // Dir should be created if some schema has been specified - intelrdt.(*intelRdtManager).config.IntelRdt.L3CacheSchema = "L3:0=f" + intelrdt.config.IntelRdt.L3CacheSchema = "L3:0=f" if err := intelrdt.Apply(1235); err != nil { t.Fatalf("Apply() failed: %v", err) } @@ -127,141 +125,3 @@ t.Fatalf("unexpected tasks file, expected '1235', got %q", pids) } } - -const ( - mountinfoValid = `18 40 0:18 / /sys rw,nosuid,nodev,noexec,relatime shared:6 - sysfs sysfs rw -19 40 0:3 / /proc rw,nosuid,nodev,noexec,relatime shared:5 - proc proc rw -20 40 0:5 / /dev rw,nosuid shared:2 - devtmpfs devtmpfs rw,size=131927256k,nr_inodes=32981814,mode=755 -21 18 0:17 / /sys/kernel/security rw,nosuid,nodev,noexec,relatime shared:7 - securityfs securityfs rw -22 20 0:19 / /dev/shm rw,nosuid,nodev shared:3 - tmpfs tmpfs rw -23 20 0:12 / /dev/pts rw,nosuid,noexec,relatime shared:4 - devpts devpts rw,gid=5,mode=620,ptmxmode=000 -24 40 0:20 / /run rw,nosuid,nodev shared:22 - tmpfs tmpfs rw,mode=755 -25 18 0:21 / /sys/fs/cgroup ro,nosuid,nodev,noexec shared:8 - tmpfs tmpfs ro,mode=755 -26 25 0:22 / /sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime shared:9 - cgroup cgroup rw,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd -27 18 0:23 / /sys/fs/pstore rw,nosuid,nodev,noexec,relatime shared:20 - pstore pstore rw -28 25 0:24 / /sys/fs/cgroup/perf_event rw,nosuid,nodev,noexec,relatime shared:10 - cgroup cgroup rw,perf_event -29 25 0:25 / /sys/fs/cgroup/cpu,cpuacct rw,nosuid,nodev,noexec,relatime shared:11 - cgroup cgroup rw,cpuacct,cpu -30 25 0:26 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:12 - cgroup cgroup rw,memory -31 25 0:27 / /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime shared:13 - cgroup cgroup rw,devices -32 25 0:28 / /sys/fs/cgroup/hugetlb rw,nosuid,nodev,noexec,relatime shared:14 - cgroup cgroup rw,hugetlb -33 25 0:29 / /sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime shared:15 - cgroup cgroup rw,blkio -34 25 0:30 / /sys/fs/cgroup/pids rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,pids -35 25 0:31 / /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime shared:17 - cgroup cgroup rw,cpuset -36 25 0:32 / /sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime shared:18 - cgroup cgroup rw,freezer -37 25 0:33 / /sys/fs/cgroup/net_cls,net_prio rw,nosuid,nodev,noexec,relatime shared:19 - cgroup cgroup rw,net_prio,net_cls -38 18 0:34 / /sys/kernel/config rw,relatime shared:21 - configfs configfs rw -40 0 253:0 / / rw,relatime shared:1 - ext4 /dev/mapper/vvrg-vvrg rw,data=ordered -16 18 0:6 / /sys/kernel/debug rw,relatime shared:23 - debugfs debugfs rw -41 18 0:16 / /sys/fs/resctrl rw,relatime shared:24 - resctrl resctrl rw -42 20 0:36 / /dev/hugepages rw,relatime shared:25 - hugetlbfs hugetlbfs rw -43 19 0:37 / /proc/sys/fs/binfmt_misc rw,relatime shared:26 - autofs systemd-1 rw,fd=32,pgrp=1,timeout=0,minproto=5,maxproto=5,direct,pipe_ino=35492 -44 20 0:15 / /dev/mqueue rw,relatime shared:27 - mqueue mqueue rw -45 40 8:1 / /boot rw,relatime shared:28 - ext4 /dev/sda1 rw,stripe=4,data=ordered -46 40 253:1 / /home rw,relatime shared:29 - ext4 /dev/mapper/vvhg-vvhg rw,data=ordered -47 40 0:38 / /var/lib/nfs/rpc_pipefs rw,relatime shared:30 - rpc_pipefs sunrpc rw -125 24 0:20 /mesos/containers /run/mesos/containers rw,nosuid shared:22 - tmpfs tmpfs rw,mode=755 -123 40 253:0 /var/lib/docker/containers /var/lib/docker/containers rw,relatime - ext4 /dev/mapper/vvrg-vvrg rw,data=ordered -129 40 253:0 /var/lib/docker/overlay2 /var/lib/docker/overlay2 rw,relatime - ext4 /dev/mapper/vvrg-vvrg rw,data=ordered -119 24 0:39 / /run/user/1009 rw,nosuid,nodev,relatime shared:100 - tmpfs tmpfs rw,size=26387788k,mode=700,uid=1009,gid=1009` - - mountinfoMbaSc = `18 40 0:18 / /sys rw,nosuid,nodev,noexec,relatime shared:6 - sysfs sysfs rw -19 40 0:3 / /proc rw,nosuid,nodev,noexec,relatime shared:5 - proc proc rw -20 40 0:5 / /dev rw,nosuid shared:2 - devtmpfs devtmpfs rw,size=131927256k,nr_inodes=32981814,mode=755 -21 18 0:17 / /sys/kernel/security rw,nosuid,nodev,noexec,relatime shared:7 - securityfs securityfs rw -22 20 0:19 / /dev/shm rw,nosuid,nodev shared:3 - tmpfs tmpfs rw -23 20 0:12 / /dev/pts rw,nosuid,noexec,relatime shared:4 - devpts devpts rw,gid=5,mode=620,ptmxmode=000 -24 40 0:20 / /run rw,nosuid,nodev shared:22 - tmpfs tmpfs rw,mode=755 -25 18 0:21 / /sys/fs/cgroup ro,nosuid,nodev,noexec shared:8 - tmpfs tmpfs ro,mode=755 -26 25 0:22 / /sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime shared:9 - cgroup cgroup rw,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd -27 18 0:23 / /sys/fs/pstore rw,nosuid,nodev,noexec,relatime shared:20 - pstore pstore rw -28 25 0:24 / /sys/fs/cgroup/perf_event rw,nosuid,nodev,noexec,relatime shared:10 - cgroup cgroup rw,perf_event -29 25 0:25 / /sys/fs/cgroup/cpu,cpuacct rw,nosuid,nodev,noexec,relatime shared:11 - cgroup cgroup rw,cpuacct,cpu -30 25 0:26 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:12 - cgroup cgroup rw,memory -31 25 0:27 / /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime shared:13 - cgroup cgroup rw,devices -32 25 0:28 / /sys/fs/cgroup/hugetlb rw,nosuid,nodev,noexec,relatime shared:14 - cgroup cgroup rw,hugetlb -33 25 0:29 / /sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime shared:15 - cgroup cgroup rw,blkio -34 25 0:30 / /sys/fs/cgroup/pids rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,pids -35 25 0:31 / /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime shared:17 - cgroup cgroup rw,cpuset -36 25 0:32 / /sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime shared:18 - cgroup cgroup rw,freezer -37 25 0:33 / /sys/fs/cgroup/net_cls,net_prio rw,nosuid,nodev,noexec,relatime shared:19 - cgroup cgroup rw,net_prio,net_cls -38 18 0:34 / /sys/kernel/config rw,relatime shared:21 - configfs configfs rw -40 0 253:0 / / rw,relatime shared:1 - ext4 /dev/mapper/vvrg-vvrg rw,data=ordered -16 18 0:6 / /sys/kernel/debug rw,relatime shared:23 - debugfs debugfs rw -41 18 0:16 / /sys/fs/resctrl rw,relatime shared:24 - resctrl resctrl rw,mba_MBps -42 20 0:36 / /dev/hugepages rw,relatime shared:25 - hugetlbfs hugetlbfs rw -43 19 0:37 / /proc/sys/fs/binfmt_misc rw,relatime shared:26 - autofs systemd-1 rw,fd=32,pgrp=1,timeout=0,minproto=5,maxproto=5,direct,pipe_ino=35492 -44 20 0:15 / /dev/mqueue rw,relatime shared:27 - mqueue mqueue rw -45 40 8:1 / /boot rw,relatime shared:28 - ext4 /dev/sda1 rw,stripe=4,data=ordered -46 40 253:1 / /home rw,relatime shared:29 - ext4 /dev/mapper/vvhg-vvhg rw,data=ordered -47 40 0:38 / /var/lib/nfs/rpc_pipefs rw,relatime shared:30 - rpc_pipefs sunrpc rw -125 24 0:20 /mesos/containers /run/mesos/containers rw,nosuid shared:22 - tmpfs tmpfs rw,mode=755 -123 40 253:0 /var/lib/docker/containers /var/lib/docker/containers rw,relatime - ext4 /dev/mapper/vvrg-vvrg rw,data=ordered -129 40 253:0 /var/lib/docker/overlay2 /var/lib/docker/overlay2 rw,relatime - ext4 /dev/mapper/vvrg-vvrg rw,data=ordered -119 24 0:39 / /run/user/1009 rw,nosuid,nodev,relatime shared:100 - tmpfs tmpfs rw,size=26387788k,mode=700,uid=1009,gid=1009` -) - -func TestFindIntelRdtMountpointDir(t *testing.T) { - testCases := []struct { - name string - input io.Reader - isNotFoundError bool - isError bool - mbaScEnabled bool - mountpoint string - }{ - { - name: "Valid mountinfo with MBA Software Controller disabled", - input: strings.NewReader(mountinfoValid), - mountpoint: "/sys/fs/resctrl", - }, - { - name: "Valid mountinfo with MBA Software Controller enabled", - input: strings.NewReader(mountinfoMbaSc), - mbaScEnabled: true, - mountpoint: "/sys/fs/resctrl", - }, - { - name: "Empty mountinfo", - input: strings.NewReader(""), - isNotFoundError: true, - }, - { - name: "Broken mountinfo", - input: strings.NewReader("baa"), - isError: true, - }, - } - - for _, tc := range testCases { - tc := tc - t.Run(tc.name, func(t *testing.T) { - mbaScEnabled = false - mp, err := findIntelRdtMountpointDir(tc.input) - if tc.isNotFoundError { - if !errors.Is(err, errNotFound) { - t.Errorf("expected errNotFound error, got %+v", err) - } - return - } - if tc.isError { - if err == nil { - t.Error("expected error, got nil") - } - return - } - if err != nil { - t.Errorf("expected nil, got %+v", err) - return - } - // no errors, check the results - if tc.mbaScEnabled != mbaScEnabled { - t.Errorf("expected mbaScEnabled=%v, got %v", - tc.mbaScEnabled, mbaScEnabled) - } - if tc.mountpoint != mp { - t.Errorf("expected mountpoint=%q, got %q", - tc.mountpoint, mp) - } - }) - } -} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.8/libcontainer/intelrdt/util_test.go new/runc-1.1.9/libcontainer/intelrdt/util_test.go --- old/runc-1.1.8/libcontainer/intelrdt/util_test.go 2023-07-19 07:15:32.000000000 +0200 +++ new/runc-1.1.9/libcontainer/intelrdt/util_test.go 2023-08-10 19:32:18.000000000 +0200 @@ -26,7 +26,12 @@ config := &configs.Config{ IntelRdt: &configs.IntelRdt{}, } + + // Assign fake intelRtdRoot value, returned by Root(). intelRdtRoot = t.TempDir() + // Make sure Root() won't even try to parse mountinfo. + rootOnce.Do(func() {}) + testIntelRdtPath := filepath.Join(intelRdtRoot, "resctrl") // Ensure the full mock Intel RDT "resource control" filesystem path exists diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.8/libcontainer/mount_linux.go new/runc-1.1.9/libcontainer/mount_linux.go --- old/runc-1.1.8/libcontainer/mount_linux.go 2023-07-19 07:15:32.000000000 +0200 +++ new/runc-1.1.9/libcontainer/mount_linux.go 2023-08-10 19:32:18.000000000 +0200 @@ -1,6 +1,7 @@ package libcontainer import ( + "io/fs" "strconv" "golang.org/x/sys/unix" @@ -81,3 +82,20 @@ } return nil } + +// syscallMode returns the syscall-specific mode bits from Go's portable mode bits. +// Copy from https://cs.opensource.google/go/go/+/refs/tags/go1.20.7:src/os/file_posix.go;l=61-75 +func syscallMode(i fs.FileMode) (o uint32) { + o |= uint32(i.Perm()) + if i&fs.ModeSetuid != 0 { + o |= unix.S_ISUID + } + if i&fs.ModeSetgid != 0 { + o |= unix.S_ISGID + } + if i&fs.ModeSticky != 0 { + o |= unix.S_ISVTX + } + // No mapping for Go's ModeTemporary (plan9 only). + return +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.8/libcontainer/process_linux.go new/runc-1.1.9/libcontainer/process_linux.go --- old/runc-1.1.8/libcontainer/process_linux.go 2023-07-19 07:15:32.000000000 +0200 +++ new/runc-1.1.9/libcontainer/process_linux.go 2023-08-10 19:32:18.000000000 +0200 @@ -299,7 +299,7 @@ logFilePair filePair config *initConfig manager cgroups.Manager - intelRdtManager intelrdt.Manager + intelRdtManager *intelrdt.Manager container *linuxContainer fds []string process *Process diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.8/libcontainer/rootfs_linux.go new/runc-1.1.9/libcontainer/rootfs_linux.go --- old/runc-1.1.8/libcontainer/rootfs_linux.go 2023-07-19 07:15:32.000000000 +0200 +++ new/runc-1.1.9/libcontainer/rootfs_linux.go 2023-08-10 19:32:18.000000000 +0200 @@ -464,7 +464,7 @@ return err } } else { - dt := fmt.Sprintf("mode=%04o", stat.Mode()) + dt := fmt.Sprintf("mode=%04o", syscallMode(stat.Mode())) if m.Data != "" { dt = dt + "," + m.Data } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.8/libcontainer/user/user.go new/runc-1.1.9/libcontainer/user/user.go --- old/runc-1.1.8/libcontainer/user/user.go 2023-07-19 07:15:32.000000000 +0200 +++ new/runc-1.1.9/libcontainer/user/user.go 2023-08-10 19:32:18.000000000 +0200 @@ -201,7 +201,7 @@ if err != nil { // We should return no error if EOF is reached // without a match. - if err == io.EOF { //nolint:errorlint // comparison with io.EOF is legit, https://github.com/polyfloyd/go-errorlint/pull/12 + if err == io.EOF { err = nil } return out, err diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.8/script/prepare-cgroup-v2.sh new/runc-1.1.9/script/prepare-cgroup-v2.sh --- old/runc-1.1.8/script/prepare-cgroup-v2.sh 1970-01-01 01:00:00.000000000 +0100 +++ new/runc-1.1.9/script/prepare-cgroup-v2.sh 2023-08-10 19:32:18.000000000 +0200 @@ -0,0 +1,17 @@ +#!/bin/bash +# +# This script is used from ../Dockerfile as the ENTRYPOINT. It sets up cgroup +# delegation for cgroup v2 to make sure runc tests can be properly run inside +# a container. + +# Only do this for cgroup v2. +if [ -f /sys/fs/cgroup/cgroup.controllers ]; then + set -x + # Move the current process to a sub-cgroup. + mkdir /sys/fs/cgroup/init + echo 0 >/sys/fs/cgroup/init/cgroup.procs + # Enable all controllers. + sed 's/\b\w/+\0/g' <"/sys/fs/cgroup/cgroup.controllers" >"/sys/fs/cgroup/cgroup.subtree_control" +fi + +exec "$@" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.8/tests/integration/run.bats new/runc-1.1.9/tests/integration/run.bats --- old/runc-1.1.8/tests/integration/run.bats 2023-07-19 07:15:32.000000000 +0200 +++ new/runc-1.1.9/tests/integration/run.bats 2023-08-10 19:32:18.000000000 +0200 @@ -59,6 +59,22 @@ [ "$status" -ne 0 ] } +# https://github.com/opencontainers/runc/issues/3952 +@test "runc run with tmpfs" { + requires root + + chmod 'a=rwx,ug+s,+t' rootfs/tmp # set all bits + mode=$(stat -c %A rootfs/tmp) + + # shellcheck disable=SC2016 + update_config '.process.args = ["sh", "-c", "stat -c %A /tmp"]' + update_config '.mounts += [{"destination": "/tmp", "type": "tmpfs", "source": "tmpfs", "options":["noexec","nosuid","nodev","rprivate"]}]' + + runc run test_tmpfs + [ "$status" -eq 0 ] + [ "$output" = "$mode" ] +} + @test "runc run with tmpfs perms" { # shellcheck disable=SC2016 update_config '.process.args = ["sh", "-c", "stat -c %a /tmp/test"]' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/runc-1.1.8/utils_linux.go new/runc-1.1.9/utils_linux.go --- old/runc-1.1.8/utils_linux.go 2023-07-19 07:15:32.000000000 +0200 +++ new/runc-1.1.9/utils_linux.go 2023-08-10 19:32:18.000000000 +0200 @@ -32,8 +32,6 @@ return nil, err } - intelRdtManager := libcontainer.IntelRdtFs - // We resolve the paths for {newuidmap,newgidmap} from the context of runc, // to avoid doing a path lookup in the nsexec context. TODO: The binary // names are not currently configurable. @@ -46,7 +44,7 @@ newgidmap = "" } - return libcontainer.New(abs, intelRdtManager, + return libcontainer.New(abs, libcontainer.CriuPath(context.GlobalString("criu")), libcontainer.NewuidmapPath(newuidmap), libcontainer.NewgidmapPath(newgidmap))