Repository: opencontainers/runc
Pull request #2920 (2021-04-26 11:30:31)

libcontainer/intelrdt: support ClosID parameter
- Handle ClosID parameter of IntelRdt. Makes it possible to use
pre-configured classes/ClosIDs and avoid running out of available IDs
which easily happens with per-container classes.

- libcontainer/intelrdt: verify ClosID existence
Check that the ClosID directory pre-exists if no L3 or MB schema has
been specified. Conform with the following line from runtime-spec
(config-linux):

  *If closID is set, and neither of l3CacheSchema and memBwSchema are
  set, runtime MUST check if corresponding pre-configured directory
  closID is present in mounted resctrl. If such pre-configured directory
  closID exists, runtime MUST assign container to this closID and
  generate an error if directory does not exist.*

- Add a TODO note for verifying existing schemata against L3/MB
parameters.

- Run unit tests irrespective of the underlying system configuration, i.e.
even if RDT has not been enabled or is not supported. The tests do not
depend on real kernel interfaces.




kolyshkin: Looks good overall, added some notes.

Also, the first commit performs a nice refactoring (which I like), but it is kind of hard to review because it also introduces ClosID support. Can you maybe split it into (1) refactoring (2) adding ClosID?
marquiz: Thanks for the review @kolyshkin!

> Also, the first commit performs a nice refactoring (which I like), but it is kind of hard to review because it also introduces ClosID support. Can you maybe split it into (1) refactoring (2) adding ClosID?

Yeah, I see 😊 I now split the first commit into two
marquiz: BTW, related, I submitted a PR against runtime-spec in an attempt to make it easier read:
https://github.com/opencontainers/runtime-spec/pull/1104
marquiz: Ping @kolyshkin. Could you enable testing?
marquiz: @kolyshkin anything I can do to advance this? The latest review comment(s) should be addressed, now
marquiz: ping @kolyshkin 
marquiz: How to re-run tests??
/retest
marquiz: ping @kolyshkin. How to get this forward?
cyphar: We need to manually retrigger them, there isn't a bot to control them unfortunately.
kolyshkin: > you can retrigger it by force pushing a new commit

One other way is to close and reopen a PR. 

marquiz: > (I've retriggered it.)

Thanks @cyphar! Everything's green now 😎
marquiz: ping @crosbymichael @mrunalp @dqminh @hqhq @cyphar @AkihiroSuda @kolyshkin

Any comments, advice?
marquiz: Rebased
kolyshkin: A linter warning that needs to be fixed; otherwise LGTM.
marquiz: > A linter warning that needs to be fixed; otherwise LGTM.

Woops, fixed

Patch:
diff --git a/.cirrus.yml b/.cirrus.yml
index 26a579cf..1d776e3c 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -85,6 +85,7 @@ task:
     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)
@@ -93,15 +94,11 @@ task:
       sysctl --system
       ;;
     centos-stream-8)
-      yum config-manager --set-enabled powertools # for glibc-static
+      yum install -y -q dnf-plugins-core
+      yum config-manager --set-enabled powertools
       ;;
     esac
-    # 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 && break
-    done
-    [ $? -eq 0 ] # fail if yum failed
+    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
diff --git a/.codespellrc b/.codespellrc
deleted file mode 100644
index c626cb1f..00000000
--- a/.codespellrc
+++ /dev/null
@@ -1,3 +0,0 @@
-[codespell]
-skip = ./vendor,./.git
-ignore-words-list = clos,creat
diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml
index 8ad6be73..fa812413 100644
--- a/.github/workflows/validate.yml
+++ b/.github/workflows/validate.yml
@@ -23,23 +23,6 @@ jobs:
           # must be specified without patch version
           version: v1.40
 
-  compile-buildtags:
-    runs-on: ubuntu-20.04
-    steps:
-      - uses: actions/checkout@v2
-      - name: compile with no build tags
-        run: make BUILDTAGS=""
-
-  codespell:
-    runs-on: ubuntu-20.04
-    steps:
-    - uses: actions/checkout@v2
-    - name: install deps
-      # Version of codespell bundled with Ubuntu is way old, so use pip.
-      run: pip install codespell
-    - name: run codespell
-      run: codespell
-
   shfmt:
     runs-on: ubuntu-20.04
     steps:
diff --git a/Dockerfile b/Dockerfile
index d98c53d5..2266903c 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,7 +1,7 @@
-ARG GO_VERSION=1.17
+ARG GO_VERSION=1.16
 ARG BATS_VERSION=v1.3.0
 
-FROM golang:${GO_VERSION}-bullseye
+FROM golang:${GO_VERSION}-buster
 ARG DEBIAN_FRONTEND=noninteractive
 
 RUN echo 'deb https://download.opensuse.org/repositories/devel:/tools:/criu/Debian_10/ /' > /etc/apt/sources.list.d/criu.list \
@@ -31,7 +31,7 @@ RUN echo 'deb https://download.opensuse.org/repositories/devel:/tools:/criu/Debi
         libseccomp-dev:ppc64el \
         libseccomp2 \
         pkg-config \
-        python3-minimal \
+        python-minimal \
         sudo \
         uidmap \
     && apt-get clean \
diff --git a/MAINTAINERS b/MAINTAINERS
index e7fa530b..17e93004 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5,4 +5,3 @@ Qiang Huang <h.huangqiang@huawei.com> (@hqhq)
 Aleksa Sarai <cyphar@cyphar.com> (@cyphar)
 Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp> (@AkihiroSuda)
 Kir Kolyshkin <kolyshkin@gmail.com> (@kolyshkin)
-Sebastiaan van Stijn <github@gone.nl> (@thaJeztah)
diff --git a/docs/systemd.md b/docs/systemd.md
index c74e2e2f..bbd7ab98 100644
--- a/docs/systemd.md
+++ b/docs/systemd.md
@@ -3,7 +3,7 @@
 By default, runc creates cgroups and sets cgroup limits on its own (this mode
 is known as fs cgroup driver). When `--systemd-cgroup` global option is given
 (as in e.g. `runc --systemd-cgroup run ...`), runc switches to systemd cgroup
-driver. This document describes its features and peculiarities.
+driver. This document describes its features and pecularities.
 
 ### systemd unit name and placement
 
diff --git a/go.mod b/go.mod
index a45e2da8..32748263 100644
--- a/go.mod
+++ b/go.mod
@@ -6,7 +6,7 @@ require (
 	github.com/bits-and-blooms/bitset v1.2.0
 	github.com/checkpoint-restore/go-criu/v5 v5.0.0
 	github.com/cilium/ebpf v0.6.2
-	github.com/containerd/console v1.0.3
+	github.com/containerd/console v1.0.2
 	github.com/coreos/go-systemd/v22 v22.3.2
 	github.com/cyphar/filepath-securejoin v0.2.3
 	github.com/docker/go-units v0.4.0
@@ -14,7 +14,7 @@ require (
 	github.com/moby/sys/mountinfo v0.4.1
 	github.com/mrunalp/fileutils v0.5.0
 	github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417
-	github.com/opencontainers/selinux v1.8.4
+	github.com/opencontainers/selinux v1.8.3
 	github.com/seccomp/libseccomp-golang v0.9.1
 	github.com/sirupsen/logrus v1.8.1
 	github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635
diff --git a/go.sum b/go.sum
index 7937c033..19078580 100644
--- a/go.sum
+++ b/go.sum
@@ -5,8 +5,8 @@ github.com/checkpoint-restore/go-criu/v5 v5.0.0 h1:TW8f/UvntYoVDMN1K2HlT82qH1rb0
 github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M=
 github.com/cilium/ebpf v0.6.2 h1:iHsfF/t4aW4heW2YKfeHrVPGdtYTL4C4KocpM8KTSnI=
 github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
-github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw=
-github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
+github.com/containerd/console v1.0.2 h1:Pi6D+aZXM+oUw1czuKgH5IJ+y0jhYcwBJfx5/Ghn9dE=
+github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ=
 github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI=
 github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
 github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
@@ -46,8 +46,10 @@ github.com/mrunalp/fileutils v0.5.0 h1:NKzVxiH7eSk+OQ4M+ZYW1K6h27RUV3MI6NUTsHhU6
 github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
 github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 h1:3snG66yBm59tKhhSPQrQ/0bCrv1LQbKt40LnUPiUxdc=
 github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
-github.com/opencontainers/selinux v1.8.4 h1:krlgQ6/j9CkCXT5oW0yVXdQFOME3NjKuuAZXuR6O7P4=
-github.com/opencontainers/selinux v1.8.4/go.mod h1:HTvjPFoGMbpQsG886e3lQwnsRWtE4TC1OF3OUvG9FAo=
+github.com/opencontainers/selinux v1.8.3 h1:tzZR7AuKB5gU1+53uBkoG4XdIFGZzvJTOVoNbRQI8/4=
+github.com/opencontainers/selinux v1.8.3/go.mod h1:HTvjPFoGMbpQsG886e3lQwnsRWtE4TC1OF3OUvG9FAo=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
diff --git a/libcontainer/cgroups/devices/devices_emulator.go b/libcontainer/cgroups/devices/devices_emulator.go
index 668dcd41..ebb8b6cd 100644
--- a/libcontainer/cgroups/devices/devices_emulator.go
+++ b/libcontainer/cgroups/devices/devices_emulator.go
@@ -305,7 +305,7 @@ func EmulatorFromList(list io.Reader) (*Emulator, error) {
 // necessary.
 //
 // This function is the sole reason for all of Emulator -- to allow us
-// to figure out how to update a containers' cgroups without causing spurious
+// to figure out how to update a containers' cgroups without causing spurrious
 // device errors (if possible).
 func (source *Emulator) Transition(target *Emulator) ([]*devices.Rule, error) {
 	var transitionRules []*devices.Rule
diff --git a/libcontainer/cgroups/ebpf/ebpf_linux.go b/libcontainer/cgroups/ebpf/ebpf_linux.go
index 104c74a8..5fc230bf 100644
--- a/libcontainer/cgroups/ebpf/ebpf_linux.go
+++ b/libcontainer/cgroups/ebpf/ebpf_linux.go
@@ -134,7 +134,7 @@ func haveBpfProgReplace() bool {
 			// not supported
 			return
 		}
-		// attach_flags test succeeded.
+		// attach_flags test succeded.
 		if !errors.Is(err, unix.EBADF) {
 			logrus.Debugf("checking for BPF_F_REPLACE: got unexpected (not EBADF or EINVAL) error: %v", err)
 		}
diff --git a/libcontainer/cgroups/fs/cpuset.go b/libcontainer/cgroups/fs/cpuset.go
index 8c49a300..c4062b7b 100644
--- a/libcontainer/cgroups/fs/cpuset.go
+++ b/libcontainer/cgroups/fs/cpuset.go
@@ -51,16 +51,16 @@ func getCpusetStat(path string, file string) ([]uint16, error) {
 	}
 
 	for _, s := range strings.Split(fileContent, ",") {
-		sp := strings.SplitN(s, "-", 3)
-		switch len(sp) {
+		splitted := strings.SplitN(s, "-", 3)
+		switch len(splitted) {
 		case 3:
 			return extracted, &parseError{Path: path, File: file, Err: errors.New("extra dash")}
 		case 2:
-			min, err := strconv.ParseUint(sp[0], 10, 16)
+			min, err := strconv.ParseUint(splitted[0], 10, 16)
 			if err != nil {
 				return extracted, &parseError{Path: path, File: file, Err: err}
 			}
-			max, err := strconv.ParseUint(sp[1], 10, 16)
+			max, err := strconv.ParseUint(splitted[1], 10, 16)
 			if err != nil {
 				return extracted, &parseError{Path: path, File: file, Err: err}
 			}
diff --git a/libcontainer/cgroups/getallpids.go b/libcontainer/cgroups/getallpids.go
deleted file mode 100644
index b218744e..00000000
--- a/libcontainer/cgroups/getallpids.go
+++ /dev/null
@@ -1,29 +0,0 @@
-// +build linux,go1.16
-
-package cgroups
-
-import (
-	"io/fs"
-	"path/filepath"
-)
-
-// GetAllPids returns all pids from the cgroup identified by path, and all its
-// sub-cgroups.
-func GetAllPids(path string) ([]int, error) {
-	var pids []int
-	err := filepath.WalkDir(path, func(p string, d fs.DirEntry, iErr error) error {
-		if iErr != nil {
-			return iErr
-		}
-		if !d.IsDir() {
-			return nil
-		}
-		cPids, err := readProcsFile(p)
-		if err != nil {
-			return err
-		}
-		pids = append(pids, cPids...)
-		return nil
-	})
-	return pids, err
-}
diff --git a/libcontainer/cgroups/getallpids_go115.go b/libcontainer/cgroups/getallpids_go115.go
deleted file mode 100644
index 5d55a685..00000000
--- a/libcontainer/cgroups/getallpids_go115.go
+++ /dev/null
@@ -1,30 +0,0 @@
-// +build linux,!go1.16
-
-package cgroups
-
-import (
-	"os"
-	"path/filepath"
-)
-
-// GetAllPids returns all pids, that were added to cgroup at path and to all its
-// subcgroups.
-func GetAllPids(path string) ([]int, error) {
-	var pids []int
-	// collect pids from all sub-cgroups
-	err := filepath.Walk(path, func(p string, info os.FileInfo, iErr error) error {
-		if iErr != nil {
-			return iErr
-		}
-		if !info.IsDir() {
-			return nil
-		}
-		cPids, err := readProcsFile(p)
-		if err != nil {
-			return err
-		}
-		pids = append(pids, cPids...)
-		return nil
-	})
-	return pids, err
-}
diff --git a/libcontainer/cgroups/stats.go b/libcontainer/cgroups/stats.go
index d2e68efe..e7f9c462 100644
--- a/libcontainer/cgroups/stats.go
+++ b/libcontainer/cgroups/stats.go
@@ -126,7 +126,7 @@ type BlkioStatEntry struct {
 }
 
 type BlkioStats struct {
-	// number of bytes transferred to and from the block device
+	// number of bytes tranferred to and from the block device
 	IoServiceBytesRecursive []BlkioStatEntry `json:"io_service_bytes_recursive,omitempty"`
 	IoServicedRecursive     []BlkioStatEntry `json:"io_serviced_recursive,omitempty"`
 	IoQueuedRecursive       []BlkioStatEntry `json:"io_queue_recursive,omitempty"`
diff --git a/libcontainer/cgroups/systemd/common.go b/libcontainer/cgroups/systemd/common.go
index 98ccc516..125f6f55 100644
--- a/libcontainer/cgroups/systemd/common.go
+++ b/libcontainer/cgroups/systemd/common.go
@@ -198,7 +198,7 @@ func generateDeviceProperties(r *configs.Resources) ([]systemdDbus.Property, err
 	}
 	// systemd doesn't support blacklists. So we log a warning, and tell
 	// systemd to act as a deny-all whitelist. This ruleset will be replaced
-	// with our normal fallback code. This may result in spurious errors, but
+	// with our normal fallback code. This may result in spurrious errors, but
 	// the only other option is to error out here.
 	if configEmu.IsBlacklist() {
 		// However, if we're dealing with an allow-all rule then we can do it.
@@ -311,14 +311,6 @@ func getUnitName(c *configs.Cgroup) string {
 	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 {
@@ -397,10 +389,10 @@ func resetFailedUnit(cm *dbusConnManager, name string) {
 	}
 }
 
-func getUnitTypeProperty(cm *dbusConnManager, unitName string, unitType string, propertyName string) (*systemdDbus.Property, error) {
+func getUnitProperty(cm *dbusConnManager, unitName string, propertyName string) (*systemdDbus.Property, error) {
 	var prop *systemdDbus.Property
 	err := cm.retryOnDisconnect(func(c *systemdDbus.Conn) (Err error) {
-		prop, Err = c.GetUnitTypePropertyContext(context.TODO(), unitName, unitType, propertyName)
+		prop, Err = c.GetUnitPropertyContext(context.TODO(), unitName, propertyName)
 		return Err
 	})
 	return prop, err
diff --git a/libcontainer/cgroups/systemd/v1.go b/libcontainer/cgroups/systemd/v1.go
index cd4720c5..1a8e1e3c 100644
--- a/libcontainer/cgroups/systemd/v1.go
+++ b/libcontainer/cgroups/systemd/v1.go
@@ -6,7 +6,6 @@ import (
 	"errors"
 	"os"
 	"path/filepath"
-	"reflect"
 	"strings"
 	"sync"
 
@@ -346,11 +345,6 @@ func (m *legacyManager) freezeBeforeSet(unitName string, r *configs.Resources) (
 	// 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.
@@ -359,20 +353,15 @@ func (m *legacyManager) freezeBeforeSet(unitName string, r *configs.Resources) (
 		// a non-existent unit returns default properties,
 		// and settings in (2) are the defaults.
 		//
-		// Do not return errors from getUnitTypeProperty, as they alone
+		// Do not return errors from getUnitProperty, as they alone
 		// should not prevent Set from working.
-
-		unitType := getUnitType(unitName)
-
-		devPolicy, e := getUnitTypeProperty(m.dbus, unitName, unitType, "DevicePolicy")
+		devPolicy, e := getUnitProperty(m.dbus, unitName, "DevicePolicy")
 		if e == nil && devPolicy.Value == dbus.MakeVariant("auto") {
-			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
-				}
+			devAllow, e := getUnitProperty(m.dbus, unitName, "DeviceAllow")
+			if e == nil && devAllow.Value == dbus.MakeVariant([]deviceAllowEntry{}) {
+				needsFreeze = false
+				needsThaw = false
+				return
 			}
 		}
 	}
diff --git a/libcontainer/cgroups/utils.go b/libcontainer/cgroups/utils.go
index b31705be..75015d66 100644
--- a/libcontainer/cgroups/utils.go
+++ b/libcontainer/cgroups/utils.go
@@ -118,8 +118,8 @@ func GetAllSubsystems() ([]string, error) {
 	return subsystems, nil
 }
 
-func readProcsFile(dir string) ([]int, error) {
-	f, err := OpenFile(dir, CgroupProcesses, os.O_RDONLY)
+func readProcsFile(file string) ([]int, error) {
+	f, err := os.Open(file)
 	if err != nil {
 		return nil, err
 	}
@@ -336,7 +336,29 @@ func getHugePageSizeFromFilenames(fileNames []string) ([]string, error) {
 
 // GetPids returns all pids, that were added to cgroup at path.
 func GetPids(dir string) ([]int, error) {
-	return readProcsFile(dir)
+	return readProcsFile(filepath.Join(dir, CgroupProcesses))
+}
+
+// GetAllPids returns all pids, that were added to cgroup at path and to all its
+// subcgroups.
+func GetAllPids(path string) ([]int, error) {
+	var pids []int
+	// collect pids from all sub-cgroups
+	err := filepath.Walk(path, func(p string, info os.FileInfo, iErr error) error {
+		if iErr != nil {
+			return iErr
+		}
+		if info.IsDir() || info.Name() != CgroupProcesses {
+			return nil
+		}
+		cPids, err := readProcsFile(p)
+		if err != nil {
+			return err
+		}
+		pids = append(pids, cPids...)
+		return nil
+	})
+	return pids, err
 }
 
 // WriteCgroupProc writes the specified pid into the cgroup's cgroup.procs file
diff --git a/libcontainer/configs/cgroup_linux.go b/libcontainer/configs/cgroup_linux.go
index 5ea9d940..a1e7f0af 100644
--- a/libcontainer/configs/cgroup_linux.go
+++ b/libcontainer/configs/cgroup_linux.go
@@ -131,16 +131,4 @@ type Resources struct {
 	//
 	// 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 --git a/libcontainer/configs/intelrdt.go b/libcontainer/configs/intelrdt.go
index 57e9f037..f8d951ab 100644
--- a/libcontainer/configs/intelrdt.go
+++ b/libcontainer/configs/intelrdt.go
@@ -1,6 +1,9 @@
 package configs
 
 type IntelRdt struct {
+	// The identity for RDT Class of Service
+	ClosID string `json:"closID,omitempty"`
+
 	// The schema for L3 cache id and capacity bitmask (CBM)
 	// Format: "L3:<cache_id0>=<cbm0>;<cache_id1>=<cbm1>;..."
 	L3CacheSchema string `json:"l3_cache_schema,omitempty"`
diff --git a/libcontainer/configs/validate/validator.go b/libcontainer/configs/validate/validator.go
index c2500a63..ab43a17f 100644
--- a/libcontainer/configs/validate/validator.go
+++ b/libcontainer/configs/validate/validator.go
@@ -205,19 +205,16 @@ func (v *ConfigValidator) intelrdt(config *configs.Config) error {
 			return errors.New("intelRdt is specified in config, but Intel RDT is not supported or enabled")
 		}
 
+		if config.IntelRdt.ClosID == "." || config.IntelRdt.ClosID == ".." || strings.Contains(config.IntelRdt.ClosID, "/") {
+			return fmt.Errorf("invalid intelRdt.ClosID %q", config.IntelRdt.ClosID)
+		}
+
 		if !intelrdt.IsCATEnabled() && config.IntelRdt.L3CacheSchema != "" {
 			return errors.New("intelRdt.l3CacheSchema is specified in config, but Intel RDT/CAT is not enabled")
 		}
 		if !intelrdt.IsMBAEnabled() && config.IntelRdt.MemBwSchema != "" {
 			return errors.New("intelRdt.memBwSchema is specified in config, but Intel RDT/MBA is not enabled")
 		}
-
-		if intelrdt.IsCATEnabled() && config.IntelRdt.L3CacheSchema == "" {
-			return errors.New("Intel RDT/CAT is enabled and intelRdt is specified in config, but intelRdt.l3CacheSchema is empty")
-		}
-		if intelrdt.IsMBAEnabled() && config.IntelRdt.MemBwSchema == "" {
-			return errors.New("Intel RDT/MBA is enabled and intelRdt is specified in config, but intelRdt.memBwSchema is empty")
-		}
 	}
 
 	return nil
diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go
index 21e77932..39932c75 100644
--- a/libcontainer/container_linux.go
+++ b/libcontainer/container_linux.go
@@ -1902,9 +1902,10 @@ func (c *linuxContainer) currentState() (*State, error) {
 		startTime, _ = c.initProcess.startTime()
 		externalDescriptors = c.initProcess.externalDescriptors()
 	}
-	intelRdtPath, err := intelrdt.GetIntelRdtPath(c.ID())
-	if err != nil {
-		intelRdtPath = ""
+
+	intelRdtPath := ""
+	if c.intelRdtManager != nil {
+		intelRdtPath = c.intelRdtManager.GetPath()
 	}
 	state := &State{
 		BaseState: BaseState{
@@ -2100,7 +2101,7 @@ func ignoreTerminateErrors(err error) error {
 	if err == nil {
 		return nil
 	}
-	// terminate() might return an error from either Kill or Wait.
+	// terminate() might return an error from ether Kill or Wait.
 	// The (*Cmd).Wait documentation says: "If the command fails to run
 	// or doesn't complete successfully, the error is of type *ExitError".
 	// Filter out such errors (like "exit status 1" or "signal: killed").
diff --git a/libcontainer/intelrdt/intelrdt.go b/libcontainer/intelrdt/intelrdt.go
index 9c32aabd..0d5628b3 100644
--- a/libcontainer/intelrdt/intelrdt.go
+++ b/libcontainer/intelrdt/intelrdt.go
@@ -72,7 +72,7 @@ import (
  * |-- ...
  * |-- schemata
  * |-- tasks
- * |-- <container_id>
+ * |-- <clos>
  *     |-- ...
  *     |-- schemata
  *     |-- tasks
@@ -155,7 +155,7 @@ type Manager interface {
 	// Returns statistics for Intel RDT
 	GetStats() (*Stats, error)
 
-	// Destroys the Intel RDT 'container_id' group
+	// 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
@@ -205,9 +205,7 @@ var (
 )
 
 type intelRdtData struct {
-	root   string
 	config *configs.Config
-	pid    int
 }
 
 // Check if Intel RDT sub-features are enabled in featuresInit()
@@ -405,18 +403,6 @@ func writeFile(dir, file, data string) error {
 	return nil
 }
 
-func getIntelRdtData(c *configs.Config, pid int) (*intelRdtData, error) {
-	rootPath, err := getIntelRdtRoot()
-	if err != nil {
-		return nil, err
-	}
-	return &intelRdtData{
-		root:   rootPath,
-		config: c,
-		pid:    pid,
-	}, nil
-}
-
 // Get the read-only L3 cache information
 func getL3CacheInfo() (*L3CacheInfo, error) {
 	l3CacheInfo := &L3CacheInfo{}
@@ -531,15 +517,19 @@ func IsMBAScEnabled() bool {
 	return mbaScEnabled
 }
 
-// Get the 'container_id' path in Intel RDT "resource control" filesystem
-func GetIntelRdtPath(id string) (string, error) {
+// Get the path of the clos group in "resource control" filesystem that the container belongs to
+func (m *intelRdtManager) getIntelRdtPath() (string, error) {
 	rootPath, err := getIntelRdtRoot()
 	if err != nil {
 		return "", err
 	}
 
-	path := filepath.Join(rootPath, id)
-	return path, nil
+	clos := m.id
+	if m.config.IntelRdt != nil && m.config.IntelRdt.ClosID != "" {
+		clos = m.config.IntelRdt.ClosID
+	}
+
+	return filepath.Join(rootPath, clos), nil
 }
 
 // Applies Intel RDT configuration to the process with the specified pid
@@ -548,30 +538,48 @@ func (m *intelRdtManager) Apply(pid int) (err error) {
 	if m.config.IntelRdt == nil {
 		return nil
 	}
-	d, err := getIntelRdtData(m.config, pid)
+
+	path, err := m.getIntelRdtPath()
 	if err != nil {
 		return err
 	}
 
 	m.mu.Lock()
 	defer m.mu.Unlock()
-	path, err := d.join(m.id)
-	if err != nil {
-		return err
+
+	if m.config.IntelRdt.ClosID != "" && m.config.IntelRdt.L3CacheSchema == "" && m.config.IntelRdt.MemBwSchema == "" {
+		// Check that the CLOS exists, i.e. it has been pre-configured to
+		// conform with the runtime spec
+		if _, err := os.Stat(path); err != nil {
+			return fmt.Errorf("clos dir not accessible (must be pre-created when l3CacheSchema and memBwSchema are empty): %w", err)
+		}
+	}
+
+	if err := os.MkdirAll(path, 0o755); err != nil {
+		return newLastCmdError(err)
+	}
+
+	if err := WriteIntelRdtTasks(path, pid); err != nil {
+		return newLastCmdError(err)
 	}
 
 	m.path = path
 	return nil
 }
 
-// Destroys the Intel RDT 'container_id' group
+// Destroys the Intel RDT container-specific 'container_id' group
 func (m *intelRdtManager) Destroy() error {
-	m.mu.Lock()
-	defer m.mu.Unlock()
-	if err := os.RemoveAll(m.GetPath()); err != nil {
-		return err
+	// 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 == "" {
+		m.mu.Lock()
+		defer m.mu.Unlock()
+		if err := os.RemoveAll(m.GetPath()); err != nil {
+			return err
+		}
+		m.path = ""
 	}
-	m.path = ""
 	return nil
 }
 
@@ -579,7 +587,7 @@ func (m *intelRdtManager) Destroy() error {
 // restore the object later
 func (m *intelRdtManager) GetPath() string {
 	if m.path == "" {
-		m.path, _ = GetIntelRdtPath(m.id)
+		m.path, _ = m.getIntelRdtPath()
 	}
 	return m.path
 }
@@ -606,7 +614,7 @@ func (m *intelRdtManager) GetStats() (*Stats, error) {
 	}
 	schemaRootStrings := strings.Split(tmpRootStrings, "\n")
 
-	// The L3 cache and memory bandwidth schemata in 'container_id' group
+	// The L3 cache and memory bandwidth schemata in container's clos group
 	containerPath := m.GetPath()
 	tmpStrings, err := getIntelRdtParamString(containerPath, "schemata")
 	if err != nil {
@@ -629,7 +637,7 @@ func (m *intelRdtManager) GetStats() (*Stats, error) {
 			}
 		}
 
-		// The L3 cache schema in 'container_id' group
+		// The L3 cache schema in container's clos group
 		for _, schema := range schemaStrings {
 			if strings.Contains(schema, "L3") {
 				stats.L3CacheSchema = strings.TrimSpace(schema)
@@ -652,7 +660,7 @@ func (m *intelRdtManager) GetStats() (*Stats, error) {
 			}
 		}
 
-		// The memory bandwidth schema in 'container_id' group
+		// The memory bandwidth schema in container's clos group
 		for _, schema := range schemaStrings {
 			if strings.Contains(schema, "MB") {
 				stats.MemBwSchema = strings.TrimSpace(schema)
@@ -722,6 +730,12 @@ func (m *intelRdtManager) Set(container *configs.Config) error {
 		l3CacheSchema := container.IntelRdt.L3CacheSchema
 		memBwSchema := container.IntelRdt.MemBwSchema
 
+		// TODO: verify that l3CacheSchema and/or memBwSchema match the
+		// existing schemata if ClosID has been specified. This is a more
+		// involved than reading the file and doing plain string comparison as
+		// the value written in does not necessarily match what gets read out
+		// (leading zeros, cache id ordering etc).
+
 		// Write a single joint schema string to schemata file
 		if l3CacheSchema != "" && memBwSchema != "" {
 			if err := writeFile(path, "schemata", l3CacheSchema+"\n"+memBwSchema); err != nil {
@@ -747,18 +761,6 @@ func (m *intelRdtManager) Set(container *configs.Config) error {
 	return nil
 }
 
-func (raw *intelRdtData) join(id string) (string, error) {
-	path := filepath.Join(raw.root, id)
-	if err := os.MkdirAll(path, 0o755); err != nil {
-		return "", newLastCmdError(err)
-	}
-
-	if err := WriteIntelRdtTasks(path, raw.pid); err != nil {
-		return "", err
-	}
-	return path, nil
-}
-
 func newLastCmdError(err error) error {
 	status, err1 := getLastCmdStatus()
 	if err1 == nil {
diff --git a/libcontainer/nsenter/nsexec.c b/libcontainer/nsenter/nsexec.c
index 23861a84..49e8f54b 100644
--- a/libcontainer/nsenter/nsexec.c
+++ b/libcontainer/nsenter/nsexec.c
@@ -136,7 +136,7 @@ int setns(int fd, int nstype)
 
 static void write_log(const char *level, const char *format, ...)
 {
-	char *message = NULL, *stage = NULL, *json = NULL;
+	char *message = NULL, *stage = NULL;
 	va_list args;
 	int ret;
 
@@ -146,10 +146,8 @@ static void write_log(const char *level, const char *format, ...)
 	va_start(args, format);
 	ret = vasprintf(&message, format, args);
 	va_end(args);
-	if (ret < 0) {
-		message = NULL;
+	if (ret < 0)
 		goto out;
-	}
 
 	message = escape_json_string(message);
 
@@ -157,26 +155,14 @@ static void write_log(const char *level, const char *format, ...)
 		stage = strdup("nsexec");
 	else
 		ret = asprintf(&stage, "nsexec-%d", current_stage);
-	if (ret < 0) {
-		stage = NULL;
-		goto out;
-	}
-
-	ret = asprintf(&json, "{\"level\":\"%s\", \"msg\": \"%s[%d]: %s\"}\n", level, stage, getpid(), message);
-	if (ret < 0) {
-		json = NULL;
+	if (ret < 0)
 		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);
+	dprintf(logfd, "{\"level\":\"%s\", \"msg\": \"%s[%d]: %s\"}\n", level, stage, getpid(), message);
 
 out:
 	free(message);
 	free(stage);
-	free(json);
 }
 
 /* XXX: This is ugly. */
@@ -318,7 +304,7 @@ static int try_mapping_tool(const char *app, int pid, char *map, size_t map_len)
 
 static void update_uidmap(const char *path, int pid, char *map, size_t map_len)
 {
-	if (map == NULL || map_len == 0)
+	if (map == NULL || map_len <= 0)
 		return;
 
 	write_log(DEBUG, "update /proc/%d/uid_map to '%s'", pid, map);
@@ -333,7 +319,7 @@ static void update_uidmap(const char *path, int pid, char *map, size_t map_len)
 
 static void update_gidmap(const char *path, int pid, char *map, size_t map_len)
 {
-	if (map == NULL || map_len == 0)
+	if (map == NULL || map_len <= 0)
 		return;
 
 	write_log(DEBUG, "update /proc/%d/gid_map to '%s'", pid, map);
@@ -348,7 +334,7 @@ static void update_gidmap(const char *path, int pid, char *map, size_t map_len)
 
 static void update_oom_score_adj(char *data, size_t len)
 {
-	if (data == NULL || len == 0)
+	if (data == NULL || len <= 0)
 		return;
 
 	write_log(DEBUG, "update /proc/self/oom_score_adj to '%s'", data);
diff --git a/libcontainer/rootfs_linux.go b/libcontainer/rootfs_linux.go
index 3c3fc0d1..361ce9d3 100644
--- a/libcontainer/rootfs_linux.go
+++ b/libcontainer/rootfs_linux.go
@@ -864,7 +864,7 @@ func pivotRoot(rootfs string) error {
 	if err := mount("", ".", "", "", unix.MS_SLAVE|unix.MS_REC, ""); err != nil {
 		return err
 	}
-	// Perform the unmount. MNT_DETACH allows us to unmount /proc/self/cwd.
+	// Preform the unmount. MNT_DETACH allows us to unmount /proc/self/cwd.
 	if err := unmount(".", unix.MNT_DETACH); err != nil {
 		return err
 	}
diff --git a/libcontainer/specconv/spec_linux.go b/libcontainer/specconv/spec_linux.go
index 89172316..bbecf2b3 100644
--- a/libcontainer/specconv/spec_linux.go
+++ b/libcontainer/specconv/spec_linux.go
@@ -301,6 +301,7 @@ func CreateLibcontainerConfig(opts *CreateOpts) (*configs.Config, error) {
 		}
 		if spec.Linux.IntelRdt != nil {
 			config.IntelRdt = &configs.IntelRdt{
+				ClosID:        spec.Linux.IntelRdt.ClosID,
 				L3CacheSchema: spec.Linux.IntelRdt.L3CacheSchema,
 				MemBwSchema:   spec.Linux.IntelRdt.MemBwSchema,
 			}
diff --git a/libcontainer/standard_init_linux.go b/libcontainer/standard_init_linux.go
index f1e20207..19892d15 100644
--- a/libcontainer/standard_init_linux.go
+++ b/libcontainer/standard_init_linux.go
@@ -71,7 +71,7 @@ func (l *linuxStandardInit) Init() error {
 				return fmt.Errorf("unable to join session keyring: %w", err)
 			}
 		} else {
-			// Make session keyring searchable. If we've gotten this far we
+			// Make session keyring searcheable. If we've gotten this far we
 			// bail on any error -- we don't want to have a keyring with bad
 			// permissions.
 			if err := keys.ModKeyringPerm(sessKeyId, keepperms, newperms); err != nil {
diff --git a/update.go b/update.go
index 7db5879d..e678e220 100644
--- a/update.go
+++ b/update.go
@@ -260,7 +260,7 @@ other options are ignored.
 		// Update the values
 		config.Cgroups.Resources.BlkioWeight = *r.BlockIO.Weight
 
-		// Setting CPU quota and period independently does not make much sense,
+		// Seting CPU quota and period independently does not make much sense,
 		// but historically runc allowed it and this needs to be supported
 		// to not break compatibility.
 		//
diff --git a/vendor/github.com/containerd/console/console_windows.go b/vendor/github.com/containerd/console/console_windows.go
index 787c11fe..129a9288 100644
--- a/vendor/github.com/containerd/console/console_windows.go
+++ b/vendor/github.com/containerd/console/console_windows.go
@@ -17,10 +17,10 @@
 package console
 
 import (
-	"errors"
 	"fmt"
 	"os"
 
+	"github.com/pkg/errors"
 	"golang.org/x/sys/windows"
 )
 
@@ -103,7 +103,7 @@ func (m *master) Reset() error {
 		{m.err, m.errMode},
 	} {
 		if err := windows.SetConsoleMode(s.fd, s.mode); err != nil {
-			return fmt.Errorf("unable to restore console mode: %w", err)
+			return errors.Wrap(err, "unable to restore console mode")
 		}
 	}
 
@@ -114,7 +114,7 @@ func (m *master) Size() (WinSize, error) {
 	var info windows.ConsoleScreenBufferInfo
 	err := windows.GetConsoleScreenBufferInfo(m.out, &info)
 	if err != nil {
-		return WinSize{}, fmt.Errorf("unable to get console info: %w", err)
+		return WinSize{}, errors.Wrap(err, "unable to get console info")
 	}
 
 	winsize := WinSize{
@@ -139,7 +139,7 @@ func (m *master) DisableEcho() error {
 	mode |= windows.ENABLE_LINE_INPUT
 
 	if err := windows.SetConsoleMode(m.in, mode); err != nil {
-		return fmt.Errorf("unable to set console to disable echo: %w", err)
+		return errors.Wrap(err, "unable to set console to disable echo")
 	}
 
 	return nil
@@ -192,7 +192,7 @@ func makeInputRaw(fd windows.Handle, mode uint32) error {
 	}
 
 	if err := windows.SetConsoleMode(fd, mode); err != nil {
-		return fmt.Errorf("unable to set console to raw mode: %w", err)
+		return errors.Wrap(err, "unable to set console to raw mode")
 	}
 
 	return nil
diff --git a/vendor/github.com/containerd/console/console_zos.go b/vendor/github.com/containerd/console/console_zos.go
deleted file mode 100644
index b348a839..00000000
--- a/vendor/github.com/containerd/console/console_zos.go
+++ /dev/null
@@ -1,163 +0,0 @@
-// +build zos
-
-/*
-   Copyright The containerd Authors.
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-*/
-
-package console
-
-import (
-	"fmt"
-	"os"
-
-	"golang.org/x/sys/unix"
-)
-
-// NewPty creates a new pty pair
-// The master is returned as the first console and a string
-// with the path to the pty slave is returned as the second
-func NewPty() (Console, string, error) {
-	var f File
-	var err error
-	var slave string
-	for i := 0;; i++ {
-		ptyp := fmt.Sprintf("/dev/ptyp%04d", i)
-		f, err = os.OpenFile(ptyp, os.O_RDWR, 0600)
-		if err == nil {
-			slave = fmt.Sprintf("/dev/ttyp%04d", i)
-			break
-		}
-		if os.IsNotExist(err) {
-			return nil, "", err
-		}
-		// else probably Resource Busy
-	}
-	m, err := newMaster(f)
-	if err != nil {
-		return nil, "", err
-	}
-	return m, slave, nil
-}
-
-type master struct {
-	f        File
-	original *unix.Termios
-}
-
-func (m *master) Read(b []byte) (int, error) {
-	return m.f.Read(b)
-}
-
-func (m *master) Write(b []byte) (int, error) {
-	return m.f.Write(b)
-}
-
-func (m *master) Close() error {
-	return m.f.Close()
-}
-
-func (m *master) Resize(ws WinSize) error {
-	return tcswinsz(m.f.Fd(), ws)
-}
-
-func (m *master) ResizeFrom(c Console) error {
-	ws, err := c.Size()
-	if err != nil {
-		return err
-	}
-	return m.Resize(ws)
-}
-
-func (m *master) Reset() error {
-	if m.original == nil {
-		return nil
-	}
-	return tcset(m.f.Fd(), m.original)
-}
-
-func (m *master) getCurrent() (unix.Termios, error) {
-	var termios unix.Termios
-	if err := tcget(m.f.Fd(), &termios); err != nil {
-		return unix.Termios{}, err
-	}
-	return termios, nil
-}
-
-func (m *master) SetRaw() error {
-	rawState, err := m.getCurrent()
-	if err != nil {
-		return err
-	}
-	rawState = cfmakeraw(rawState)
-	rawState.Oflag = rawState.Oflag | unix.OPOST
-	return tcset(m.f.Fd(), &rawState)
-}
-
-func (m *master) DisableEcho() error {
-	rawState, err := m.getCurrent()
-	if err != nil {
-		return err
-	}
-	rawState.Lflag = rawState.Lflag &^ unix.ECHO
-	return tcset(m.f.Fd(), &rawState)
-}
-
-func (m *master) Size() (WinSize, error) {
-	return tcgwinsz(m.f.Fd())
-}
-
-func (m *master) Fd() uintptr {
-	return m.f.Fd()
-}
-
-func (m *master) Name() string {
-	return m.f.Name()
-}
-
-// checkConsole checks if the provided file is a console
-func checkConsole(f File) error {
-	var termios unix.Termios
-	if tcget(f.Fd(), &termios) != nil {
-		return ErrNotAConsole
-	}
-	return nil
-}
-
-func newMaster(f File) (Console, error) {
-	m := &master{
-		f: f,
-	}
-	t, err := m.getCurrent()
-	if err != nil {
-		return nil, err
-	}
-	m.original = &t
-	return m, nil
-}
-
-// ClearONLCR sets the necessary tty_ioctl(4)s to ensure that a pty pair
-// created by us acts normally. In particular, a not-very-well-known default of
-// Linux unix98 ptys is that they have +onlcr by default. While this isn't a
-// problem for terminal emulators, because we relay data from the terminal we
-// also relay that funky line discipline.
-func ClearONLCR(fd uintptr) error {
-	return setONLCR(fd, false)
-}
-
-// SetONLCR sets the necessary tty_ioctl(4)s to ensure that a pty pair
-// created by us acts as intended for a terminal emulator.
-func SetONLCR(fd uintptr) error {
-	return setONLCR(fd, true)
-}
diff --git a/vendor/github.com/containerd/console/go.mod b/vendor/github.com/containerd/console/go.mod
index 1fe5b7fe..7fca0a9a 100644
--- a/vendor/github.com/containerd/console/go.mod
+++ b/vendor/github.com/containerd/console/go.mod
@@ -2,4 +2,7 @@ module github.com/containerd/console
 
 go 1.13
 
-require golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c
+require (
+	github.com/pkg/errors v0.9.1
+	golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c
+)
diff --git a/vendor/github.com/containerd/console/go.sum b/vendor/github.com/containerd/console/go.sum
index 1225630b..9db384d3 100644
--- a/vendor/github.com/containerd/console/go.sum
+++ b/vendor/github.com/containerd/console/go.sum
@@ -1,2 +1,4 @@
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
 golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
diff --git a/vendor/github.com/containerd/console/tc_unix.go b/vendor/github.com/containerd/console/tc_unix.go
index a6bf01e8..5cd4c550 100644
--- a/vendor/github.com/containerd/console/tc_unix.go
+++ b/vendor/github.com/containerd/console/tc_unix.go
@@ -1,4 +1,4 @@
-// +build darwin freebsd linux netbsd openbsd solaris zos
+// +build darwin freebsd linux netbsd openbsd solaris
 
 /*
    Copyright The containerd Authors.
diff --git a/vendor/github.com/containerd/console/tc_zos.go b/vendor/github.com/containerd/console/tc_zos.go
deleted file mode 100644
index 4262eaf4..00000000
--- a/vendor/github.com/containerd/console/tc_zos.go
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
-   Copyright The containerd Authors.
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-*/
-
-package console
-
-import (
-	"golang.org/x/sys/unix"
-)
-
-const (
-	cmdTcGet = unix.TCGETS
-	cmdTcSet = unix.TCSETS
-)
diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/rchcon.go b/vendor/github.com/opencontainers/selinux/go-selinux/rchcon.go
deleted file mode 100644
index 897ecbac..00000000
--- a/vendor/github.com/opencontainers/selinux/go-selinux/rchcon.go
+++ /dev/null
@@ -1,22 +0,0 @@
-// +build linux,go1.16
-
-package selinux
-
-import (
-	"errors"
-	"io/fs"
-	"os"
-
-	"github.com/opencontainers/selinux/pkg/pwalkdir"
-)
-
-func rchcon(fpath, label string) error {
-	return pwalkdir.Walk(fpath, func(p string, _ fs.DirEntry, _ error) error {
-		e := setFileLabel(p, label)
-		// Walk a file tree can race with removal, so ignore ENOENT.
-		if errors.Is(e, os.ErrNotExist) {
-			return nil
-		}
-		return e
-	})
-}
diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/rchcon_go115.go b/vendor/github.com/opencontainers/selinux/go-selinux/rchcon_go115.go
deleted file mode 100644
index 2c8b033c..00000000
--- a/vendor/github.com/opencontainers/selinux/go-selinux/rchcon_go115.go
+++ /dev/null
@@ -1,21 +0,0 @@
-// +build linux,!go1.16
-
-package selinux
-
-import (
-	"errors"
-	"os"
-
-	"github.com/opencontainers/selinux/pkg/pwalk"
-)
-
-func rchcon(fpath, label string) error {
-	return pwalk.Walk(fpath, func(p string, _ os.FileInfo, _ error) error {
-		e := setFileLabel(p, label)
-		// Walk a file tree can race with removal, so ignore ENOENT.
-		if errors.Is(e, os.ErrNotExist) {
-			return nil
-		}
-		return e
-	})
-}
diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go
index a804473e..62df82a3 100644
--- a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go
+++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go
@@ -18,6 +18,7 @@ import (
 	"sync"
 
 	"github.com/bits-and-blooms/bitset"
+	"github.com/opencontainers/selinux/pkg/pwalk"
 	"golang.org/x/sys/unix"
 )
 
@@ -1047,10 +1048,17 @@ func chcon(fpath string, label string, recurse bool) error {
 	}
 
 	if !recurse {
-		return setFileLabel(fpath, label)
+		return SetFileLabel(fpath, label)
 	}
 
-	return rchcon(fpath, label)
+	return pwalk.Walk(fpath, func(p string, info os.FileInfo, err error) error {
+		e := SetFileLabel(p, label)
+		// Walk a file tree can race with removal, so ignore ENOENT
+		if errors.Is(e, os.ErrNotExist) {
+			return nil
+		}
+		return e
+	})
 }
 
 // dupSecOpt takes an SELinux process label and returns security options that
diff --git a/vendor/github.com/opencontainers/selinux/pkg/pwalk/README.md b/vendor/github.com/opencontainers/selinux/pkg/pwalk/README.md
index 7e78dce0..16c4dfd3 100644
--- a/vendor/github.com/opencontainers/selinux/pkg/pwalk/README.md
+++ b/vendor/github.com/opencontainers/selinux/pkg/pwalk/README.md
@@ -8,12 +8,6 @@ By default, it utilizes 2\*runtime.NumCPU() goroutines for callbacks.
 This can be changed by using WalkN function which has the additional
 parameter, specifying the number of goroutines (concurrency).
 
-### pwalk vs pwalkdir
-
-This package is deprecated in favor of
-[pwalkdir](https://pkg.go.dev/github.com/opencontainers/selinux/pkg/pwalkdir),
-which is faster, but requires at least Go 1.16.
-
 ### Caveats
 
 Please note the following limitations of this code:
diff --git a/vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go b/vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go
index 011fe862..a8088a19 100644
--- a/vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go
+++ b/vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go
@@ -19,7 +19,7 @@ type WalkFunc = filepath.WalkFunc
 //
 // Note that this implementation only supports primitive error handling:
 //
-// - no errors are ever passed to walkFn;
+// - no errors are ever passed to WalkFn;
 //
 // - once a walkFn returns any error, all further processing stops
 // and the error is returned to the caller of Walk;
@@ -95,7 +95,7 @@ func WalkN(root string, walkFn WalkFunc, num int) error {
 	return err
 }
 
-// walkArgs holds the arguments that were passed to the Walk or WalkN
+// walkArgs holds the arguments that were passed to the Walk or WalkLimit
 // functions.
 type walkArgs struct {
 	path string
diff --git a/vendor/github.com/opencontainers/selinux/pkg/pwalkdir/README.md b/vendor/github.com/opencontainers/selinux/pkg/pwalkdir/README.md
deleted file mode 100644
index 068ac400..00000000
--- a/vendor/github.com/opencontainers/selinux/pkg/pwalkdir/README.md
+++ /dev/null
@@ -1,54 +0,0 @@
-## pwalkdir: parallel implementation of filepath.WalkDir
-
-This is a wrapper for [filepath.WalkDir](https://pkg.go.dev/path/filepath#WalkDir)
-which may speed it up by calling multiple callback functions (WalkDirFunc)
-in parallel, utilizing goroutines.
-
-By default, it utilizes 2\*runtime.NumCPU() goroutines for callbacks.
-This can be changed by using WalkN function which has the additional
-parameter, specifying the number of goroutines (concurrency).
-
-### pwalk vs pwalkdir
-
-This package is very similar to
-[pwalk](https://pkg.go.dev/github.com/opencontainers/selinux/pkg/pwalkdir),
-but utilizes `filepath.WalkDir` (added to Go 1.16), which does not call stat(2)
-on every entry and is therefore faster (up to 3x, depending on usage scenario).
-
-Users who are OK with requiring Go 1.16+ should switch to this
-implementation.
-
-### Caveats
-
-Please note the following limitations of this code:
-
-* Unlike filepath.WalkDir, the order of calls is non-deterministic;
-
-* Only primitive error handling is supported:
-
-  * fs.SkipDir is not supported;
-
-  * no errors are ever passed to WalkDirFunc;
-
-  * once any error is returned from any walkDirFunc instance, no more calls
-    to WalkDirFunc are made, and the error is returned to the caller of WalkDir;
-
-  * if more than one WalkDirFunc instance will return an error, only one
-    of such errors will be propagated to and returned by WalkDir, others
-    will be silently discarded.
-
-### Documentation
-
-For the official documentation, see
-https://pkg.go.dev/github.com/opencontainers/selinux/pkg/pwalkdir
-
-### Benchmarks
-
-For a WalkDirFunc that consists solely of the return statement, this
-implementation is about 15% slower than the standard library's
-filepath.WalkDir.
-
-Otherwise (if a WalkDirFunc is actually doing something) this is usually
-faster, except when the WalkDirN(..., 1) is used. Run `go test -bench .`
-to see how different operations can benefit from it, as well as how the
-level of paralellism affects the speed.
diff --git a/vendor/github.com/opencontainers/selinux/pkg/pwalkdir/pwalkdir.go b/vendor/github.com/opencontainers/selinux/pkg/pwalkdir/pwalkdir.go
deleted file mode 100644
index 22282075..00000000
--- a/vendor/github.com/opencontainers/selinux/pkg/pwalkdir/pwalkdir.go
+++ /dev/null
@@ -1,103 +0,0 @@
-// +build go1.16
-
-package pwalkdir
-
-import (
-	"fmt"
-	"io/fs"
-	"path/filepath"
-	"runtime"
-	"sync"
-)
-
-// Walk is a wrapper for filepath.WalkDir which can call multiple walkFn
-// in parallel, allowing to handle each item concurrently. A maximum of
-// twice the runtime.NumCPU() walkFn will be called at any one time.
-// If you want to change the maximum, use WalkN instead.
-//
-// The order of calls is non-deterministic.
-//
-// Note that this implementation only supports primitive error handling:
-//
-// - no errors are ever passed to walkFn;
-//
-// - once a walkFn returns any error, all further processing stops
-// and the error is returned to the caller of Walk;
-//
-// - filepath.SkipDir is not supported;
-//
-// - if more than one walkFn instance will return an error, only one
-// of such errors will be propagated and returned by Walk, others
-// will be silently discarded.
-func Walk(root string, walkFn fs.WalkDirFunc) error {
-	return WalkN(root, walkFn, runtime.NumCPU()*2)
-}
-
-// WalkN is a wrapper for filepath.WalkDir which can call multiple walkFn
-// in parallel, allowing to handle each item concurrently. A maximum of
-// num walkFn will be called at any one time.
-//
-// Please see Walk documentation for caveats of using this function.
-func WalkN(root string, walkFn fs.WalkDirFunc, num int) error {
-	// make sure limit is sensible
-	if num < 1 {
-		return fmt.Errorf("walk(%q): num must be > 0", root)
-	}
-
-	files := make(chan *walkArgs, 2*num)
-	errCh := make(chan error, 1) // Get the first error, ignore others.
-
-	// Start walking a tree asap.
-	var (
-		err error
-		wg  sync.WaitGroup
-	)
-	wg.Add(1)
-	go func() {
-		err = filepath.WalkDir(root, func(p string, entry fs.DirEntry, err error) error {
-			if err != nil {
-				close(files)
-				return err
-			}
-			// Add a file to the queue unless a callback sent an error.
-			select {
-			case e := <-errCh:
-				close(files)
-				return e
-			default:
-				files <- &walkArgs{path: p, entry: entry}
-				return nil
-			}
-		})
-		if err == nil {
-			close(files)
-		}
-		wg.Done()
-	}()
-
-	wg.Add(num)
-	for i := 0; i < num; i++ {
-		go func() {
-			for file := range files {
-				if e := walkFn(file.path, file.entry, nil); e != nil {
-					select {
-					case errCh <- e: // sent ok
-					default: // buffer full
-					}
-				}
-			}
-			wg.Done()
-		}()
-	}
-
-	wg.Wait()
-
-	return err
-}
-
-// walkArgs holds the arguments that were passed to the Walk or WalkN
-// functions.
-type walkArgs struct {
-	path  string
-	entry fs.DirEntry
-}
diff --git a/vendor/github.com/pkg/errors/.gitignore b/vendor/github.com/pkg/errors/.gitignore
new file mode 100644
index 00000000..daf913b1
--- /dev/null
+++ b/vendor/github.com/pkg/errors/.gitignore
@@ -0,0 +1,24 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+*.prof
diff --git a/vendor/github.com/pkg/errors/.travis.yml b/vendor/github.com/pkg/errors/.travis.yml
new file mode 100644
index 00000000..9159de03
--- /dev/null
+++ b/vendor/github.com/pkg/errors/.travis.yml
@@ -0,0 +1,10 @@
+language: go
+go_import_path: github.com/pkg/errors
+go:
+  - 1.11.x
+  - 1.12.x
+  - 1.13.x
+  - tip
+
+script:
+  - make check
diff --git a/vendor/github.com/pkg/errors/LICENSE b/vendor/github.com/pkg/errors/LICENSE
new file mode 100644
index 00000000..835ba3e7
--- /dev/null
+++ b/vendor/github.com/pkg/errors/LICENSE
@@ -0,0 +1,23 @@
+Copyright (c) 2015, Dave Cheney <dave@cheney.net>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/pkg/errors/Makefile b/vendor/github.com/pkg/errors/Makefile
new file mode 100644
index 00000000..ce9d7cde
--- /dev/null
+++ b/vendor/github.com/pkg/errors/Makefile
@@ -0,0 +1,44 @@
+PKGS := github.com/pkg/errors
+SRCDIRS := $(shell go list -f '{{.Dir}}' $(PKGS))
+GO := go
+
+check: test vet gofmt misspell unconvert staticcheck ineffassign unparam
+
+test: 
+	$(GO) test $(PKGS)
+
+vet: | test
+	$(GO) vet $(PKGS)
+
+staticcheck:
+	$(GO) get honnef.co/go/tools/cmd/staticcheck
+	staticcheck -checks all $(PKGS)
+
+misspell:
+	$(GO) get github.com/client9/misspell/cmd/misspell
+	misspell \
+		-locale GB \
+		-error \
+		*.md *.go
+
+unconvert:
+	$(GO) get github.com/mdempsky/unconvert
+	unconvert -v $(PKGS)
+
+ineffassign:
+	$(GO) get github.com/gordonklaus/ineffassign
+	find $(SRCDIRS) -name '*.go' | xargs ineffassign
+
+pedantic: check errcheck
+
+unparam:
+	$(GO) get mvdan.cc/unparam
+	unparam ./...
+
+errcheck:
+	$(GO) get github.com/kisielk/errcheck
+	errcheck $(PKGS)
+
+gofmt:  
+	@echo Checking code is gofmted
+	@test -z "$(shell gofmt -s -l -d -e $(SRCDIRS) | tee /dev/stderr)"
diff --git a/vendor/github.com/pkg/errors/README.md b/vendor/github.com/pkg/errors/README.md
new file mode 100644
index 00000000..54dfdcb1
--- /dev/null
+++ b/vendor/github.com/pkg/errors/README.md
@@ -0,0 +1,59 @@
+# errors [![Travis-CI](https://travis-ci.org/pkg/errors.svg)](https://travis-ci.org/pkg/errors) [![AppVeyor](https://ci.appveyor.com/api/projects/status/b98mptawhudj53ep/branch/master?svg=true)](https://ci.appveyor.com/project/davecheney/errors/branch/master) [![GoDoc](https://godoc.org/github.com/pkg/errors?status.svg)](http://godoc.org/github.com/pkg/errors) [![Report card](https://goreportcard.com/badge/github.com/pkg/errors)](https://goreportcard.com/report/github.com/pkg/errors) [![Sourcegraph](https://sourcegraph.com/github.com/pkg/errors/-/badge.svg)](https://sourcegraph.com/github.com/pkg/errors?badge)
+
+Package errors provides simple error handling primitives.
+
+`go get github.com/pkg/errors`
+
+The traditional error handling idiom in Go is roughly akin to
+```go
+if err != nil {
+        return err
+}
+```
+which applied recursively up the call stack results in error reports without context or debugging information. The errors package allows programmers to add context to the failure path in their code in a way that does not destroy the original value of the error.
+
+## Adding context to an error
+
+The errors.Wrap function returns a new error that adds context to the original error. For example
+```go
+_, err := ioutil.ReadAll(r)
+if err != nil {
+        return errors.Wrap(err, "read failed")
+}
+```
+## Retrieving the cause of an error
+
+Using `errors.Wrap` constructs a stack of errors, adding context to the preceding error. Depending on the nature of the error it may be necessary to reverse the operation of errors.Wrap to retrieve the original error for inspection. Any error value which implements this interface can be inspected by `errors.Cause`.
+```go
+type causer interface {
+        Cause() error
+}
+```
+`errors.Cause` will recursively retrieve the topmost error which does not implement `causer`, which is assumed to be the original cause. For example:
+```go
+switch err := errors.Cause(err).(type) {
+case *MyError:
+        // handle specifically
+default:
+        // unknown error
+}
+```
+
+[Read the package documentation for more information](https://godoc.org/github.com/pkg/errors).
+
+## Roadmap
+
+With the upcoming [Go2 error proposals](https://go.googlesource.com/proposal/+/master/design/go2draft.md) this package is moving into maintenance mode. The roadmap for a 1.0 release is as follows:
+
+- 0.9. Remove pre Go 1.9 and Go 1.10 support, address outstanding pull requests (if possible)
+- 1.0. Final release.
+
+## Contributing
+
+Because of the Go2 errors changes, this package is not accepting proposals for new functionality. With that said, we welcome pull requests, bug fixes and issue reports. 
+
+Before sending a PR, please discuss your change by raising an issue.
+
+## License
+
+BSD-2-Clause
diff --git a/vendor/github.com/pkg/errors/appveyor.yml b/vendor/github.com/pkg/errors/appveyor.yml
new file mode 100644
index 00000000..a932eade
--- /dev/null
+++ b/vendor/github.com/pkg/errors/appveyor.yml
@@ -0,0 +1,32 @@
+version: build-{build}.{branch}
+
+clone_folder: C:\gopath\src\github.com\pkg\errors
+shallow_clone: true # for startup speed
+
+environment:
+  GOPATH: C:\gopath
+
+platform:
+  - x64
+
+# http://www.appveyor.com/docs/installed-software
+install:
+  # some helpful output for debugging builds
+  - go version
+  - go env
+  # pre-installed MinGW at C:\MinGW is 32bit only
+  # but MSYS2 at C:\msys64 has mingw64
+  - set PATH=C:\msys64\mingw64\bin;%PATH%
+  - gcc --version
+  - g++ --version
+
+build_script:
+  - go install -v ./...
+
+test_script:
+  - set PATH=C:\gopath\bin;%PATH%
+  - go test -v ./...
+
+#artifacts:
+#  - path: '%GOPATH%\bin\*.exe'
+deploy: off
diff --git a/vendor/github.com/pkg/errors/errors.go b/vendor/github.com/pkg/errors/errors.go
new file mode 100644
index 00000000..161aea25
--- /dev/null
+++ b/vendor/github.com/pkg/errors/errors.go
@@ -0,0 +1,288 @@
+// Package errors provides simple error handling primitives.
+//
+// The traditional error handling idiom in Go is roughly akin to
+//
+//     if err != nil {
+//             return err
+//     }
+//
+// which when applied recursively up the call stack results in error reports
+// without context or debugging information. The errors package allows
+// programmers to add context to the failure path in their code in a way
+// that does not destroy the original value of the error.
+//
+// Adding context to an error
+//
+// The errors.Wrap function returns a new error that adds context to the
+// original error by recording a stack trace at the point Wrap is called,
+// together with the supplied message. For example
+//
+//     _, err := ioutil.ReadAll(r)
+//     if err != nil {
+//             return errors.Wrap(err, "read failed")
+//     }
+//
+// If additional control is required, the errors.WithStack and
+// errors.WithMessage functions destructure errors.Wrap into its component
+// operations: annotating an error with a stack trace and with a message,
+// respectively.
+//
+// Retrieving the cause of an error
+//
+// Using errors.Wrap constructs a stack of errors, adding context to the
+// preceding error. Depending on the nature of the error it may be necessary
+// to reverse the operation of errors.Wrap to retrieve the original error
+// for inspection. Any error value which implements this interface
+//
+//     type causer interface {
+//             Cause() error
+//     }
+//
+// can be inspected by errors.Cause. errors.Cause will recursively retrieve
+// the topmost error that does not implement causer, which is assumed to be
+// the original cause. For example:
+//
+//     switch err := errors.Cause(err).(type) {
+//     case *MyError:
+//             // handle specifically
+//     default:
+//             // unknown error
+//     }
+//
+// Although the causer interface is not exported by this package, it is
+// considered a part of its stable public interface.
+//
+// Formatted printing of errors
+//
+// All error values returned from this package implement fmt.Formatter and can
+// be formatted by the fmt package. The following verbs are supported:
+//
+//     %s    print the error. If the error has a Cause it will be
+//           printed recursively.
+//     %v    see %s
+//     %+v   extended format. Each Frame of the error's StackTrace will
+//           be printed in detail.
+//
+// Retrieving the stack trace of an error or wrapper
+//
+// New, Errorf, Wrap, and Wrapf record a stack trace at the point they are
+// invoked. This information can be retrieved with the following interface:
+//
+//     type stackTracer interface {
+//             StackTrace() errors.StackTrace
+//     }
+//
+// The returned errors.StackTrace type is defined as
+//
+//     type StackTrace []Frame
+//
+// The Frame type represents a call site in the stack trace. Frame supports
+// the fmt.Formatter interface that can be used for printing information about
+// the stack trace of this error. For example:
+//
+//     if err, ok := err.(stackTracer); ok {
+//             for _, f := range err.StackTrace() {
+//                     fmt.Printf("%+s:%d\n", f, f)
+//             }
+//     }
+//
+// Although the stackTracer interface is not exported by this package, it is
+// considered a part of its stable public interface.
+//
+// See the documentation for Frame.Format for more details.
+package errors
+
+import (
+	"fmt"
+	"io"
+)
+
+// New returns an error with the supplied message.
+// New also records the stack trace at the point it was called.
+func New(message string) error {
+	return &fundamental{
+		msg:   message,
+		stack: callers(),
+	}
+}
+
+// Errorf formats according to a format specifier and returns the string
+// as a value that satisfies error.
+// Errorf also records the stack trace at the point it was called.
+func Errorf(format string, args ...interface{}) error {
+	return &fundamental{
+		msg:   fmt.Sprintf(format, args...),
+		stack: callers(),
+	}
+}
+
+// fundamental is an error that has a message and a stack, but no caller.
+type fundamental struct {
+	msg string
+	*stack
+}
+
+func (f *fundamental) Error() string { return f.msg }
+
+func (f *fundamental) Format(s fmt.State, verb rune) {
+	switch verb {
+	case 'v':
+		if s.Flag('+') {
+			io.WriteString(s, f.msg)
+			f.stack.Format(s, verb)
+			return
+		}
+		fallthrough
+	case 's':
+		io.WriteString(s, f.msg)
+	case 'q':
+		fmt.Fprintf(s, "%q", f.msg)
+	}
+}
+
+// WithStack annotates err with a stack trace at the point WithStack was called.
+// If err is nil, WithStack returns nil.
+func WithStack(err error) error {
+	if err == nil {
+		return nil
+	}
+	return &withStack{
+		err,
+		callers(),
+	}
+}
+
+type withStack struct {
+	error
+	*stack
+}
+
+func (w *withStack) Cause() error { return w.error }
+
+// Unwrap provides compatibility for Go 1.13 error chains.
+func (w *withStack) Unwrap() error { return w.error }
+
+func (w *withStack) Format(s fmt.State, verb rune) {
+	switch verb {
+	case 'v':
+		if s.Flag('+') {
+			fmt.Fprintf(s, "%+v", w.Cause())
+			w.stack.Format(s, verb)
+			return
+		}
+		fallthrough
+	case 's':
+		io.WriteString(s, w.Error())
+	case 'q':
+		fmt.Fprintf(s, "%q", w.Error())
+	}
+}
+
+// Wrap returns an error annotating err with a stack trace
+// at the point Wrap is called, and the supplied message.
+// If err is nil, Wrap returns nil.
+func Wrap(err error, message string) error {
+	if err == nil {
+		return nil
+	}
+	err = &withMessage{
+		cause: err,
+		msg:   message,
+	}
+	return &withStack{
+		err,
+		callers(),
+	}
+}
+
+// Wrapf returns an error annotating err with a stack trace
+// at the point Wrapf is called, and the format specifier.
+// If err is nil, Wrapf returns nil.
+func Wrapf(err error, format string, args ...interface{}) error {
+	if err == nil {
+		return nil
+	}
+	err = &withMessage{
+		cause: err,
+		msg:   fmt.Sprintf(format, args...),
+	}
+	return &withStack{
+		err,
+		callers(),
+	}
+}
+
+// WithMessage annotates err with a new message.
+// If err is nil, WithMessage returns nil.
+func WithMessage(err error, message string) error {
+	if err == nil {
+		return nil
+	}
+	return &withMessage{
+		cause: err,
+		msg:   message,
+	}
+}
+
+// WithMessagef annotates err with the format specifier.
+// If err is nil, WithMessagef returns nil.
+func WithMessagef(err error, format string, args ...interface{}) error {
+	if err == nil {
+		return nil
+	}
+	return &withMessage{
+		cause: err,
+		msg:   fmt.Sprintf(format, args...),
+	}
+}
+
+type withMessage struct {
+	cause error
+	msg   string
+}
+
+func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() }
+func (w *withMessage) Cause() error  { return w.cause }
+
+// Unwrap provides compatibility for Go 1.13 error chains.
+func (w *withMessage) Unwrap() error { return w.cause }
+
+func (w *withMessage) Format(s fmt.State, verb rune) {
+	switch verb {
+	case 'v':
+		if s.Flag('+') {
+			fmt.Fprintf(s, "%+v\n", w.Cause())
+			io.WriteString(s, w.msg)
+			return
+		}
+		fallthrough
+	case 's', 'q':
+		io.WriteString(s, w.Error())
+	}
+}
+
+// Cause returns the underlying cause of the error, if possible.
+// An error value has a cause if it implements the following
+// interface:
+//
+//     type causer interface {
+//            Cause() error
+//     }
+//
+// If the error does not implement Cause, the original error will
+// be returned. If the error is nil, nil will be returned without further
+// investigation.
+func Cause(err error) error {
+	type causer interface {
+		Cause() error
+	}
+
+	for err != nil {
+		cause, ok := err.(causer)
+		if !ok {
+			break
+		}
+		err = cause.Cause()
+	}
+	return err
+}
diff --git a/vendor/github.com/pkg/errors/go113.go b/vendor/github.com/pkg/errors/go113.go
new file mode 100644
index 00000000..be0d10d0
--- /dev/null
+++ b/vendor/github.com/pkg/errors/go113.go
@@ -0,0 +1,38 @@
+// +build go1.13
+
+package errors
+
+import (
+	stderrors "errors"
+)
+
+// Is reports whether any error in err's chain matches target.
+//
+// The chain consists of err itself followed by the sequence of errors obtained by
+// repeatedly calling Unwrap.
+//
+// An error is considered to match a target if it is equal to that target or if
+// it implements a method Is(error) bool such that Is(target) returns true.
+func Is(err, target error) bool { return stderrors.Is(err, target) }
+
+// As finds the first error in err's chain that matches target, and if so, sets
+// target to that error value and returns true.
+//
+// The chain consists of err itself followed by the sequence of errors obtained by
+// repeatedly calling Unwrap.
+//
+// An error matches target if the error's concrete value is assignable to the value
+// pointed to by target, or if the error has a method As(interface{}) bool such that
+// As(target) returns true. In the latter case, the As method is responsible for
+// setting target.
+//
+// As will panic if target is not a non-nil pointer to either a type that implements
+// error, or to any interface type. As returns false if err is nil.
+func As(err error, target interface{}) bool { return stderrors.As(err, target) }
+
+// Unwrap returns the result of calling the Unwrap method on err, if err's
+// type contains an Unwrap method returning error.
+// Otherwise, Unwrap returns nil.
+func Unwrap(err error) error {
+	return stderrors.Unwrap(err)
+}
diff --git a/vendor/github.com/pkg/errors/stack.go b/vendor/github.com/pkg/errors/stack.go
new file mode 100644
index 00000000..779a8348
--- /dev/null
+++ b/vendor/github.com/pkg/errors/stack.go
@@ -0,0 +1,177 @@
+package errors
+
+import (
+	"fmt"
+	"io"
+	"path"
+	"runtime"
+	"strconv"
+	"strings"
+)
+
+// Frame represents a program counter inside a stack frame.
+// For historical reasons if Frame is interpreted as a uintptr
+// its value represents the program counter + 1.
+type Frame uintptr
+
+// pc returns the program counter for this frame;
+// multiple frames may have the same PC value.
+func (f Frame) pc() uintptr { return uintptr(f) - 1 }
+
+// file returns the full path to the file that contains the
+// function for this Frame's pc.
+func (f Frame) file() string {
+	fn := runtime.FuncForPC(f.pc())
+	if fn == nil {
+		return "unknown"
+	}
+	file, _ := fn.FileLine(f.pc())
+	return file
+}
+
+// line returns the line number of source code of the
+// function for this Frame's pc.
+func (f Frame) line() int {
+	fn := runtime.FuncForPC(f.pc())
+	if fn == nil {
+		return 0
+	}
+	_, line := fn.FileLine(f.pc())
+	return line
+}
+
+// name returns the name of this function, if known.
+func (f Frame) name() string {
+	fn := runtime.FuncForPC(f.pc())
+	if fn == nil {
+		return "unknown"
+	}
+	return fn.Name()
+}
+
+// Format formats the frame according to the fmt.Formatter interface.
+//
+//    %s    source file
+//    %d    source line
+//    %n    function name
+//    %v    equivalent to %s:%d
+//
+// Format accepts flags that alter the printing of some verbs, as follows:
+//
+//    %+s   function name and path of source file relative to the compile time
+//          GOPATH separated by \n\t (<funcname>\n\t<path>)
+//    %+v   equivalent to %+s:%d
+func (f Frame) Format(s fmt.State, verb rune) {
+	switch verb {
+	case 's':
+		switch {
+		case s.Flag('+'):
+			io.WriteString(s, f.name())
+			io.WriteString(s, "\n\t")
+			io.WriteString(s, f.file())
+		default:
+			io.WriteString(s, path.Base(f.file()))
+		}
+	case 'd':
+		io.WriteString(s, strconv.Itoa(f.line()))
+	case 'n':
+		io.WriteString(s, funcname(f.name()))
+	case 'v':
+		f.Format(s, 's')
+		io.WriteString(s, ":")
+		f.Format(s, 'd')
+	}
+}
+
+// MarshalText formats a stacktrace Frame as a text string. The output is the
+// same as that of fmt.Sprintf("%+v", f), but without newlines or tabs.
+func (f Frame) MarshalText() ([]byte, error) {
+	name := f.name()
+	if name == "unknown" {
+		return []byte(name), nil
+	}
+	return []byte(fmt.Sprintf("%s %s:%d", name, f.file(), f.line())), nil
+}
+
+// StackTrace is stack of Frames from innermost (newest) to outermost (oldest).
+type StackTrace []Frame
+
+// Format formats the stack of Frames according to the fmt.Formatter interface.
+//
+//    %s	lists source files for each Frame in the stack
+//    %v	lists the source file and line number for each Frame in the stack
+//
+// Format accepts flags that alter the printing of some verbs, as follows:
+//
+//    %+v   Prints filename, function, and line number for each Frame in the stack.
+func (st StackTrace) Format(s fmt.State, verb rune) {
+	switch verb {
+	case 'v':
+		switch {
+		case s.Flag('+'):
+			for _, f := range st {
+				io.WriteString(s, "\n")
+				f.Format(s, verb)
+			}
+		case s.Flag('#'):
+			fmt.Fprintf(s, "%#v", []Frame(st))
+		default:
+			st.formatSlice(s, verb)
+		}
+	case 's':
+		st.formatSlice(s, verb)
+	}
+}
+
+// formatSlice will format this StackTrace into the given buffer as a slice of
+// Frame, only valid when called with '%s' or '%v'.
+func (st StackTrace) formatSlice(s fmt.State, verb rune) {
+	io.WriteString(s, "[")
+	for i, f := range st {
+		if i > 0 {
+			io.WriteString(s, " ")
+		}
+		f.Format(s, verb)
+	}
+	io.WriteString(s, "]")
+}
+
+// stack represents a stack of program counters.
+type stack []uintptr
+
+func (s *stack) Format(st fmt.State, verb rune) {
+	switch verb {
+	case 'v':
+		switch {
+		case st.Flag('+'):
+			for _, pc := range *s {
+				f := Frame(pc)
+				fmt.Fprintf(st, "\n%+v", f)
+			}
+		}
+	}
+}
+
+func (s *stack) StackTrace() StackTrace {
+	f := make([]Frame, len(*s))
+	for i := 0; i < len(f); i++ {
+		f[i] = Frame((*s)[i])
+	}
+	return f
+}
+
+func callers() *stack {
+	const depth = 32
+	var pcs [depth]uintptr
+	n := runtime.Callers(3, pcs[:])
+	var st stack = pcs[0:n]
+	return &st
+}
+
+// funcname removes the path prefix component of a function's name reported by func.Name().
+func funcname(name string) string {
+	i := strings.LastIndex(name, "/")
+	name = name[i+1:]
+	i = strings.Index(name, ".")
+	return name[i+1:]
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 24b3c52f..5c77cf79 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -13,7 +13,7 @@ github.com/cilium/ebpf/internal
 github.com/cilium/ebpf/internal/btf
 github.com/cilium/ebpf/internal/unix
 github.com/cilium/ebpf/link
-# github.com/containerd/console v1.0.3
+# github.com/containerd/console v1.0.2
 ## explicit
 github.com/containerd/console
 # github.com/coreos/go-systemd/v22 v22.3.2
@@ -42,12 +42,13 @@ github.com/mrunalp/fileutils
 # github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417
 ## explicit
 github.com/opencontainers/runtime-spec/specs-go
-# github.com/opencontainers/selinux v1.8.4
+# github.com/opencontainers/selinux v1.8.3
 ## explicit
 github.com/opencontainers/selinux/go-selinux
 github.com/opencontainers/selinux/go-selinux/label
 github.com/opencontainers/selinux/pkg/pwalk
-github.com/opencontainers/selinux/pkg/pwalkdir
+# github.com/pkg/errors v0.9.1
+github.com/pkg/errors
 # github.com/russross/blackfriday/v2 v2.0.1
 github.com/russross/blackfriday/v2
 # github.com/seccomp/libseccomp-golang v0.9.1


Test patch:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 591a1870..2831aeb6 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -17,46 +17,22 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        go-version: [1.15.x, 1.16.x, 1.17.x]
+        go-version: [1.15.x, 1.16.x]
         rootless: ["rootless", ""]
         race: ["-race", ""]
-        criu: [""]
-        include:
-          # Also test against latest criu-dev
-          - go-version: 1.16.x
-            rootless: ""
-            race: ""
-            criu: "criu-dev"
 
     steps:
 
     - name: checkout
       uses: actions/checkout@v2
 
-    - name: Dump matrix context
-      env:
-        MATRIX_CONTEXT: ${{ toJSON(matrix) }}
-      run: echo "$MATRIX_CONTEXT"
-
     - name: install deps
-      if: matrix.criu == ''
       run: |
         # criu repo
         sudo add-apt-repository -y ppa:criu/ppa
         # apt-add-repository runs apt update so we don't have to
         sudo apt -q install libseccomp-dev criu
 
-    - name: install deps (criu ${{ matrix.criu }})
-      if: matrix.criu != ''
-      run: |
-        sudo apt -q update
-        sudo apt -q install libseccomp-dev \
-          libcap-dev libnet1-dev libnl-3-dev \
-          libprotobuf-c-dev libprotobuf-dev protobuf-c-compiler protobuf-compiler
-        git clone https://github.com/checkpoint-restore/criu.git ~/criu
-        (cd ~/criu && git checkout ${{ matrix.criu }} && sudo make install-criu)
-        rm -rf ~/criu
-
     - name: install go ${{ matrix.go-version }}
       uses: actions/setup-go@v2
       with:
diff --git a/libcontainer/cgroups/fs/stats_util_test.go b/libcontainer/cgroups/fs/stats_util_test.go
index 757e65b6..29bd01d3 100644
--- a/libcontainer/cgroups/fs/stats_util_test.go
+++ b/libcontainer/cgroups/fs/stats_util_test.go
@@ -51,7 +51,7 @@ func expectBlkioStatsEquals(t *testing.T, expected, actual cgroups.BlkioStats) {
 	}
 
 	if err := blkioStatEntryEquals(expected.IoMergedRecursive, actual.IoMergedRecursive); err != nil {
-		t.Errorf("blkio IoMergedRecursive do not match: expected: %v, actual: %v", expected.IoMergedRecursive, actual.IoMergedRecursive)
+		t.Errorf("blkio IoMergedRecursive do not match: expcted: %v, actual: %v", expected.IoMergedRecursive, actual.IoMergedRecursive)
 	}
 
 	if err := blkioStatEntryEquals(expected.IoTimeRecursive, actual.IoTimeRecursive); err != nil {
diff --git a/libcontainer/cgroups/getallpids_test.go b/libcontainer/cgroups/getallpids_test.go
deleted file mode 100644
index b6100686..00000000
--- a/libcontainer/cgroups/getallpids_test.go
+++ /dev/null
@@ -1,19 +0,0 @@
-// +build linux
-
-package cgroups
-
-import (
-	"testing"
-)
-
-func BenchmarkGetAllPids(b *testing.B) {
-	total := 0
-	for i := 0; i < b.N; i++ {
-		i, err := GetAllPids("/sys/fs/cgroup")
-		if err != nil {
-			b.Fatal(err)
-		}
-		total += len(i)
-	}
-	b.Logf("iter: %d, total: %d", b.N, total)
-}
diff --git a/libcontainer/cgroups/systemd/systemd_test.go b/libcontainer/cgroups/systemd/systemd_test.go
index 6976c4ca..55685d05 100644
--- a/libcontainer/cgroups/systemd/systemd_test.go
+++ b/libcontainer/cgroups/systemd/systemd_test.go
@@ -40,23 +40,6 @@ func TestSystemdVersion(t *testing.T) {
 	}
 }
 
-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)
@@ -358,7 +341,7 @@ func TestFreezePodCgroup(t *testing.T) {
 	containerConfig := &configs.Cgroup{
 		Parent:      "system-runc_test_pod.slice",
 		ScopePrefix: "test",
-		Name:        "inner-container",
+		Name:        "inner-contianer",
 		Resources:   &configs.Resources{},
 	}
 
diff --git a/libcontainer/cgroups/systemd/v1_test.go b/libcontainer/cgroups/systemd/v1_test.go
deleted file mode 100644
index 25ac5714..00000000
--- a/libcontainer/cgroups/systemd/v1_test.go
+++ /dev/null
@@ -1,217 +0,0 @@
-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 --git a/libcontainer/intelrdt/intelrdt_test.go b/libcontainer/intelrdt/intelrdt_test.go
index 31df5186..25257896 100644
--- a/libcontainer/intelrdt/intelrdt_test.go
+++ b/libcontainer/intelrdt/intelrdt_test.go
@@ -5,15 +5,13 @@ package intelrdt
 import (
 	"errors"
 	"io"
+	"os"
+	"path/filepath"
 	"strings"
 	"testing"
 )
 
 func TestIntelRdtSetL3CacheSchema(t *testing.T) {
-	if !IsCATEnabled() {
-		return
-	}
-
 	helper := NewIntelRdtTestUtil(t)
 
 	const (
@@ -44,10 +42,6 @@ func TestIntelRdtSetL3CacheSchema(t *testing.T) {
 }
 
 func TestIntelRdtSetMemBwSchema(t *testing.T) {
-	if !IsMBAEnabled() {
-		return
-	}
-
 	helper := NewIntelRdtTestUtil(t)
 
 	const (
@@ -78,10 +72,6 @@ func TestIntelRdtSetMemBwSchema(t *testing.T) {
 }
 
 func TestIntelRdtSetMemBwScSchema(t *testing.T) {
-	if !IsMBAScEnabled() {
-		return
-	}
-
 	helper := NewIntelRdtTestUtil(t)
 
 	const (
@@ -111,6 +101,35 @@ func TestIntelRdtSetMemBwScSchema(t *testing.T) {
 	}
 }
 
+func TestApply(t *testing.T) {
+	helper := NewIntelRdtTestUtil(t)
+
+	const closID = "test-clos"
+
+	helper.IntelRdtData.config.IntelRdt.ClosID = closID
+	intelrdt := NewManager(helper.IntelRdtData.config, "", helper.IntelRdtPath)
+	if err := intelrdt.Apply(1234); err == nil {
+		t.Fatal("unexpected success when applying pid")
+	}
+	if _, err := os.Stat(filepath.Join(helper.IntelRdtPath, closID)); err == nil {
+		t.Fatal("closid dir should not exist")
+	}
+
+	// Dir should be created if some schema has been specified
+	intelrdt.(*intelRdtManager).config.IntelRdt.L3CacheSchema = "L3:0=f"
+	if err := intelrdt.Apply(1235); err != nil {
+		t.Fatalf("Apply() failed: %v", err)
+	}
+
+	pids, err := getIntelRdtParamString(intelrdt.GetPath(), "tasks")
+	if err != nil {
+		t.Fatalf("failed to read tasks file: %v", err)
+	}
+	if pids != "1235" {
+		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
diff --git a/libcontainer/intelrdt/util_test.go b/libcontainer/intelrdt/util_test.go
index ced12779..a471c5e2 100644
--- a/libcontainer/intelrdt/util_test.go
+++ b/libcontainer/intelrdt/util_test.go
@@ -30,9 +30,9 @@ func NewIntelRdtTestUtil(t *testing.T) *intelRdtTestUtil {
 		config: &configs.Config{
 			IntelRdt: &configs.IntelRdt{},
 		},
-		root: t.TempDir(),
 	}
-	testIntelRdtPath := filepath.Join(d.root, "resctrl")
+	intelRdtRoot = t.TempDir()
+	testIntelRdtPath := filepath.Join(intelRdtRoot, "resctrl")
 
 	// Ensure the full mock Intel RDT "resource control" filesystem path exists
 	if err := os.MkdirAll(testIntelRdtPath, 0o755); err != nil {
diff --git a/libcontainer/nsenter/nsenter_test.go b/libcontainer/nsenter/nsenter_test.go
index 9201f026..9627a61f 100644
--- a/libcontainer/nsenter/nsenter_test.go
+++ b/libcontainer/nsenter/nsenter_test.go
@@ -224,7 +224,7 @@ func TestNsenterChildLogging(t *testing.T) {
 		t.Fatalf("child log: %v", err)
 	}
 	if logentry.Level == "" || logentry.Msg == "" {
-		t.Fatalf("child log: empty log fields: level=\"%s\" msg=\"%s\"", logentry.Level, logentry.Msg)
+		t.Fatalf("child log: empty log fileds: level=\"%s\" msg=\"%s\"", logentry.Level, logentry.Msg)
 	}
 
 	if err := cmd.Wait(); err != nil {
diff --git a/tests/integration/hooks.bats b/tests/integration/hooks.bats
index 01c1280e..0c57bbc7 100644
--- a/tests/integration/hooks.bats
+++ b/tests/integration/hooks.bats
@@ -6,7 +6,7 @@ function setup() {
 	requires root no_systemd
 
 	setup_debian
-	# CR = CreateRuntime, CC = CreateContainer
+	# CR = CreateRuntime, CC = CreataContainer
 	HOOKLIBCR=librunc-hooks-create-runtime.so
 	HOOKLIBCC=librunc-hooks-create-container.so
 	LIBPATH="$(pwd)/rootfs/lib/"