Repository: opencontainers/runc
Pull request #2883 (2021-04-01 20:11:10)

Add support for rdma cgroup introduced in Linux Kernel 4.11
RDMA controller/cgroup support is added with Linux kernel 4.11.
Similar format is used by cgroup-v2

Reference
https://www.kernel.org/doc/Documentation/cgroup-v1/rdma.txt


kolyshkin: Looks good in general, left some comments. 

We also need some integration tests for that.
flouthoc: @kolyshkin Thanks for the quick review, i have fixed almost everything. 3 comments are still unresolved but i have commented the reason on the review itself. Could you please take a look.
thaJeztah: I see there's a typo in the commit message ("kernal" instead of "kernel"); perhaps good to fix that in case we want to find it back later if someone searches for `kernel` related commits
flouthoc: @thaJeztah Thanks for pointing this out. Fixed commit message `kernal` -> `kernel` :smiley: 
AkihiroSuda: Please sign the commit with real name

flouthoc: @AkihiroSuda Done.

flouthoc: @kolyshkin Fixed requested changes. Let me know if anything else needs to be done.
flouthoc: @kolyshkin @fuweid Were you guys able to take look at reviews, are they good to be marked as resolved ? I think we have to anyways park this PR till `rc94`
fuweid: @flouthoc the cgroup v1 uses pseudo cgroup fs to test the function. I think it should be easier to add the unit test in this pr.
flouthoc: @fuweid Sure thanks a lot.
kolyshkin: I took a fresh look, at it seems that

1. If you can move common rmda code into `libcontainer/cgroups` (instead of putting it to `libcontainer/cgroups/fs` and re-using from `fs2`), it will look better. I

2. It might make more sense to use bufio's `Scan` rather than reading/returning the whole file and doing `strings.Split(contents, "\n")` on the result.
flouthoc: @kolyshkin Sure having common chunk in `libcontainer/cgroups` makes sense i'll do the required changes.
kolyshkin: Close/reopen to use latest linters in CI.
kolyshkin: @flouthoc #3024 is now merged, so you can put the common RDMA code into fscommon (or its own package if you want).
flouthoc: @kolyshkin Sure thanks for notifying. I am on it.
flouthoc: @kolyshkin @thaJeztah @fuweid Could you guys please trigger workflow on this.
flouthoc: @kolyshkin @thaJeztah  Added all the suggested changes. Just had doubt on feedback raised by @thaJeztah about naming scheme i have written reason for that.
flouthoc: @kolyshkin Could we re-trigger tests.
flouthoc: @kolyshkin Applied all the requested changes, could you please take a look again.
flouthoc: @kolyshkin Not sure why tests are failing but CI doesn't really states any error seems like they flaked but not sure.
kolyshkin: CI failures were expected (fixed in #3051).

CI restarted.
flouthoc: @kolyshkin Added fixes.
flouthoc: @fuweid @thaJeztah @kolyshkin Resolved feedback points in latest commit.
flouthoc: @fuweid @kolyshkin could you guys PTAL.
kolyshkin: Looks good except for couple of nits.

What worries me though is the absence of tests. How can we be sure this thing works (except for doing a review)?

I think there should be `fscommon/rdma_test.go` which does something similar to what fs and fs2 tests are doing. Can be added as a separate commit.
flouthoc: @kolyshkin @fuweid  Resolved all feedback points. Also added tests `fscommon/rdma_test.go` which tries writing rdma entry into a mock cgroup filesystem and verifies it. Also wrote future roadmap of tests which can be figured out later in a passive manner i.e how to verify test against an actual RdmaDevice or mimic one adding actual device to CI might be too much.
flouthoc: @kolyshkin @fuweid PTAL.
fuweid: @flouthoc would you please fix the linter issue? Thanks!
flouthoc: @fuweid Could you run checks again also would be helpful if you could make these checks trigger on every push. I think no manual intervention should be needed to run checks even for first time contributor also .
flouthoc: @fuweid @kolyshkin lint errors are fixed and resolved in latest commit. :)
flouthoc: @kolyshkin @fuweid please let me know if anything else needs to be done.
kolyshkin: @flouthoc can you please rebase? We have tweaked CI again...

Other than that I think this one is ready to go in.
flouthoc: @kolyshkin Could you please give a quick eye again. Resolved all the nits :sweat_smile:
flouthoc: @kolyshkin Resolved all of them just a small doubt in first one i have tried clarifying in review itself.
flouthoc: @kolyshkin I have made requested changes could you PTAL.
flouthoc: @kolyshkin Could you please let me know if anything is pending here from my side. 

Patch:
diff --git a/.cirrus.yml b/.cirrus.yml
index 26a579cf..74b7deae 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -58,9 +58,17 @@ task:
   integration_fs_script: |
     ssh -tt default "sudo -i make -C /vagrant localintegration"
   integration_systemd_rootless_script: |
-    ssh -tt default "sudo -i make -C /vagrant localrootlessintegration RUNC_USE_SYSTEMD=yes"
+    if [ $DISTRO == centos7 ]; then
+      echo "SKIP: integration_systemd_rootless_script requires cgroup v2"
+    else
+      ssh -tt default "sudo -i make -C /vagrant localrootlessintegration RUNC_USE_SYSTEMD=yes"
+    fi
   integration_fs_rootless_script: |
-    ssh -tt default "sudo -i make -C /vagrant localrootlessintegration"
+    if [ $DISTRO == centos7 ]; then
+      echo "SKIP: FIXME: integration_fs_rootless_script is skipped because of EPERM on writing cgroup.procs"
+    else
+      ssh -tt default "sudo -i make -C /vagrant localrootlessintegration"
+    fi
 
 task:
   timeout_in: 30m
@@ -85,6 +93,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 +102,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/exec.go b/exec.go
index f8baff3d..891fabbd 100644
--- a/exec.go
+++ b/exec.go
@@ -101,8 +101,7 @@ following will output a list of processes running in the container:
 		if err == nil {
 			os.Exit(status)
 		}
-		fatalWithCode(fmt.Errorf("exec failed: %w", err), 255)
-		return nil // to satisfy the linter
+		return fmt.Errorf("exec failed: %w", err)
 	},
 	SkipArgReorder: true,
 }
diff --git a/go.mod b/go.mod
index a45e2da8..cd512f74 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.2
 	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..fefc1fb2 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.2 h1:c4ca10UMgRcvZ6h0K4HtS15UaVSBEaE+iln2LVpAuGc=
+github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8=
+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/fs/fs.go b/libcontainer/cgroups/fs/fs.go
index 6296719b..c6d92bef 100644
--- a/libcontainer/cgroups/fs/fs.go
+++ b/libcontainer/cgroups/fs/fs.go
@@ -31,6 +31,7 @@ var (
 		&NetPrioGroup{},
 		&PerfEventGroup{},
 		&FreezerGroup{},
+		&RdmaGroup{},
 		&NameGroup{GroupName: "name=systemd", Join: true},
 	}
 	HugePageSizes, _ = cgroups.GetHugePageSize()
diff --git a/libcontainer/cgroups/fs/rdma.go b/libcontainer/cgroups/fs/rdma.go
new file mode 100644
index 00000000..5fb25abe
--- /dev/null
+++ b/libcontainer/cgroups/fs/rdma.go
@@ -0,0 +1,25 @@
+package fs
+
+import (
+	"github.com/opencontainers/runc/libcontainer/cgroups"
+	"github.com/opencontainers/runc/libcontainer/cgroups/fscommon"
+	"github.com/opencontainers/runc/libcontainer/configs"
+)
+
+type RdmaGroup struct{}
+
+func (s *RdmaGroup) Name() string {
+	return "rdma"
+}
+
+func (s *RdmaGroup) Apply(path string, d *cgroupData) error {
+	return join(path, d.pid)
+}
+
+func (s *RdmaGroup) Set(path string, r *configs.Resources) error {
+	return fscommon.RdmaSet(path, r)
+}
+
+func (s *RdmaGroup) GetStats(path string, stats *cgroups.Stats) error {
+	return fscommon.RdmaGetStats(path, stats)
+}
diff --git a/libcontainer/cgroups/fs2/fs2.go b/libcontainer/cgroups/fs2/fs2.go
index 6cd9f51f..84e4ba89 100644
--- a/libcontainer/cgroups/fs2/fs2.go
+++ b/libcontainer/cgroups/fs2/fs2.go
@@ -125,6 +125,10 @@ func (m *manager) GetStats() (*cgroups.Stats, error) {
 	if err := statHugeTlb(m.dirPath, st); err != nil && !os.IsNotExist(err) {
 		errs = append(errs, err)
 	}
+	// rdma (since kernel 4.11)
+	if err := fscommon.RdmaGetStats(m.dirPath, st); err != nil && !os.IsNotExist(err) {
+		errs = append(errs, err)
+	}
 	if len(errs) > 0 && !m.rootless {
 		return st, fmt.Errorf("error while statting cgroup v2: %+v", errs)
 	}
@@ -183,6 +187,10 @@ func (m *manager) Set(r *configs.Resources) error {
 	if err := setHugeTlb(m.dirPath, r); err != nil {
 		return err
 	}
+	// rdma (since kernel 4.11)
+	if err := fscommon.RdmaSet(m.dirPath, r); err != nil {
+		return err
+	}
 	// freezer (since kernel 5.2, pseudo-controller)
 	if err := setFreezer(m.dirPath, r.Freezer); err != nil {
 		return err
diff --git a/libcontainer/cgroups/fscommon/rdma.go b/libcontainer/cgroups/fscommon/rdma.go
new file mode 100644
index 00000000..d463d15e
--- /dev/null
+++ b/libcontainer/cgroups/fscommon/rdma.go
@@ -0,0 +1,121 @@
+package fscommon
+
+import (
+	"bufio"
+	"errors"
+	"math"
+	"os"
+	"strconv"
+	"strings"
+
+	"github.com/opencontainers/runc/libcontainer/cgroups"
+	"github.com/opencontainers/runc/libcontainer/configs"
+	"golang.org/x/sys/unix"
+)
+
+// parseRdmaKV parses raw string to RdmaEntry.
+func parseRdmaKV(raw string, entry *cgroups.RdmaEntry) error {
+	var value uint32
+
+	parts := strings.SplitN(raw, "=", 3)
+
+	if len(parts) != 2 {
+		return errors.New("Unable to parse RDMA entry")
+	}
+
+	k, v := parts[0], parts[1]
+
+	if v == "max" {
+		value = math.MaxUint32
+	} else {
+		val64, err := strconv.ParseUint(v, 10, 32)
+		if err != nil {
+			return err
+		}
+		value = uint32(val64)
+	}
+	if k == "hca_handle" {
+		entry.HcaHandles = value
+	} else if k == "hca_object" {
+		entry.HcaObjects = value
+	}
+
+	return nil
+}
+
+// readRdmaEntries reads and converts array of rawstrings to RdmaEntries from file.
+// example entry: mlx4_0 hca_handle=2 hca_object=2000
+func readRdmaEntries(dir, file string) ([]cgroups.RdmaEntry, error) {
+	rdmaEntries := make([]cgroups.RdmaEntry, 0)
+	fd, err := cgroups.OpenFile(dir, file, unix.O_RDONLY)
+	if err != nil {
+		return nil, err
+	}
+	defer fd.Close() //nolint:errorlint
+	scanner := bufio.NewScanner(fd)
+	for scanner.Scan() {
+		parts := strings.SplitN(scanner.Text(), " ", 4)
+		if len(parts) == 3 {
+			entry := new(cgroups.RdmaEntry)
+			entry.Device = parts[0]
+			err = parseRdmaKV(parts[1], entry)
+			if err != nil {
+				continue
+			}
+			err = parseRdmaKV(parts[2], entry)
+			if err != nil {
+				continue
+			}
+
+			rdmaEntries = append(rdmaEntries, *entry)
+		}
+	}
+	return rdmaEntries, scanner.Err()
+}
+
+// RdmaGetStats returns rdma stats such as totalLimit and current entries.
+func RdmaGetStats(path string, stats *cgroups.Stats) error {
+	currentEntries, err := readRdmaEntries(path, "rdma.current")
+	if err != nil {
+		if errors.Is(err, os.ErrNotExist) {
+			err = nil
+		}
+		return err
+	}
+	maxEntries, err := readRdmaEntries(path, "rdma.max")
+	if err != nil {
+		return err
+	}
+	// If device got removed between reading two files, ignore returning stats.
+	if len(currentEntries) != len(maxEntries) {
+		return nil
+	}
+
+	stats.RdmaStats = cgroups.RdmaStats{
+		RdmaLimit:   maxEntries,
+		RdmaCurrent: currentEntries,
+	}
+
+	return nil
+}
+
+func createCmdString(device string, limits configs.LinuxRdma) string {
+	cmdString := device
+	if limits.HcaHandles != nil {
+		cmdString += " hca_handle=" + strconv.FormatUint(uint64(*limits.HcaHandles), 10)
+	}
+	if limits.HcaObjects != nil {
+		cmdString += " hca_object=" + strconv.FormatUint(uint64(*limits.HcaObjects), 10)
+	}
+	return cmdString
+}
+
+// RdmaSet sets RDMA resources.
+func RdmaSet(path string, r *configs.Resources) error {
+	for device, limits := range r.Rdma {
+		if err := cgroups.WriteFile(path, "rdma.max", createCmdString(device, limits)); err != nil {
+			return err
+		}
+	}
+	return nil
+}
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..8f7301da 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"`
@@ -146,6 +146,17 @@ type HugetlbStats struct {
 	Failcnt uint64 `json:"failcnt"`
 }
 
+type RdmaEntry struct {
+	Device     string `json:"device,omitempty"`
+	HcaHandles uint32 `json:"hca_handles,omitempty"`
+	HcaObjects uint32 `json:"hca_objects,omitempty"`
+}
+
+type RdmaStats struct {
+	RdmaLimit   []RdmaEntry `json:"rdma_limit,omitempty"`
+	RdmaCurrent []RdmaEntry `json:"rdma_current,omitempty"`
+}
+
 type Stats struct {
 	CpuStats    CpuStats    `json:"cpu_stats,omitempty"`
 	CPUSetStats CPUSetStats `json:"cpuset_stats,omitempty"`
@@ -154,6 +165,7 @@ type Stats struct {
 	BlkioStats  BlkioStats  `json:"blkio_stats,omitempty"`
 	// the map is in the format "size of hugepage: stats of the hugepage"
 	HugetlbStats map[string]HugetlbStats `json:"hugetlb_stats,omitempty"`
+	RdmaStats    RdmaStats               `json:"rdma_stats,omitempty"`
 }
 
 func NewStats() *Stats {
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..a0a68c78 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"
 
@@ -59,6 +58,7 @@ var legacySubsystems = []subsystem{
 	&fs.NetPrioGroup{},
 	&fs.NetClsGroup{},
 	&fs.NameGroup{GroupName: "name=systemd"},
+	&fs.RdmaGroup{},
 }
 
 func genV1ResourcesProperties(r *configs.Resources, cm *dbusConnManager) ([]systemdDbus.Property, error) {
@@ -346,11 +346,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 +354,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..b08a3715 100644
--- a/libcontainer/configs/cgroup_linux.go
+++ b/libcontainer/configs/cgroup_linux.go
@@ -117,6 +117,9 @@ type Resources struct {
 	// Set class identifier for container's network packets
 	NetClsClassid uint32 `json:"net_cls_classid_u"`
 
+	// Rdma resource restriction configuration
+	Rdma map[string]LinuxRdma `json:"rdma"`
+
 	// Used on cgroups v2:
 
 	// CpuWeight sets a proportional bandwidth limit.
@@ -131,16 +134,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/rdma.go b/libcontainer/configs/rdma.go
new file mode 100644
index 00000000..c69f2c80
--- /dev/null
+++ b/libcontainer/configs/rdma.go
@@ -0,0 +1,9 @@
+package configs
+
+// LinuxRdma for Linux cgroup 'rdma' resource management (Linux 4.11)
+type LinuxRdma struct {
+	// Maximum number of HCA handles that can be opened. Default is "no limit".
+	HcaHandles *uint32 `json:"hca_handles,omitempty"`
+	// Maximum number of HCA objects that can be created. Default is "no limit".
+	HcaObjects *uint32 `json:"hca_objects,omitempty"`
+}
diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go
index 21e77932..19a82bbf 100644
--- a/libcontainer/container_linux.go
+++ b/libcontainer/container_linux.go
@@ -2100,7 +2100,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/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/seccomp/config.go b/libcontainer/seccomp/config.go
index 2e5adfd3..b54b7eea 100644
--- a/libcontainer/seccomp/config.go
+++ b/libcontainer/seccomp/config.go
@@ -56,7 +56,9 @@ func ConvertStringToOperator(in string) (configs.Operator, error) {
 }
 
 // ConvertStringToAction converts a string into a Seccomp rule match action.
-// Actions use the names they are assigned in Libseccomp's header.
+// Actions use the names they are assigned in Libseccomp's header, though some
+// (notable, SCMP_ACT_TRACE) are not available in this implementation and will
+// return errors.
 // Attempting to convert a string that is not a valid action results in an
 // error.
 func ConvertStringToAction(in string) (configs.Action, error) {
diff --git a/libcontainer/seccomp/seccomp_linux.go b/libcontainer/seccomp/seccomp_linux.go
index 58cad902..fbbe8219 100644
--- a/libcontainer/seccomp/seccomp_linux.go
+++ b/libcontainer/seccomp/seccomp_linux.go
@@ -6,12 +6,11 @@ import (
 	"errors"
 	"fmt"
 
-	libseccomp "github.com/seccomp/libseccomp-golang"
-	"github.com/sirupsen/logrus"
-	"golang.org/x/sys/unix"
-
 	"github.com/opencontainers/runc/libcontainer/configs"
 	"github.com/opencontainers/runc/libcontainer/seccomp/patchbpf"
+
+	libseccomp "github.com/seccomp/libseccomp-golang"
+	"golang.org/x/sys/unix"
 )
 
 var (
@@ -68,7 +67,7 @@ func InitSeccomp(config *configs.Seccomp) error {
 		if call == nil {
 			return errors.New("encountered nil syscall while initializing Seccomp")
 		}
-		if err := matchCall(filter, call, defaultAction); err != nil {
+		if err := matchCall(filter, call); err != nil {
 			return err
 		}
 	}
@@ -143,7 +142,7 @@ func getCondition(arg *configs.Arg) (libseccomp.ScmpCondition, error) {
 }
 
 // Add a rule to match a single syscall
-func matchCall(filter *libseccomp.ScmpFilter, call *configs.Syscall, defAct libseccomp.ScmpAction) error {
+func matchCall(filter *libseccomp.ScmpFilter, call *configs.Syscall) error {
 	if call == nil || filter == nil {
 		return errors.New("cannot use nil as syscall to block")
 	}
@@ -152,23 +151,17 @@ func matchCall(filter *libseccomp.ScmpFilter, call *configs.Syscall, defAct libs
 		return errors.New("empty string is not a valid syscall")
 	}
 
-	// Convert the call's action to the libseccomp equivalent
-	callAct, err := getAction(call.Action, call.ErrnoRet)
+	// If we can't resolve the syscall, assume it's not supported on this kernel
+	// Ignore it, don't error out
+	callNum, err := libseccomp.GetSyscallFromName(call.Name)
 	if err != nil {
-		return fmt.Errorf("action in seccomp profile is invalid: %w", err)
-	}
-	if callAct == defAct {
-		// This rule is redundant, silently skip it
-		// to avoid error from AddRule.
 		return nil
 	}
 
-	// If we can't resolve the syscall, assume it is not supported
-	// by this kernel. Warn about it, don't error out.
-	callNum, err := libseccomp.GetSyscallFromName(call.Name)
+	// Convert the call's action to the libseccomp equivalent
+	callAct, err := getAction(call.Action, call.ErrnoRet)
 	if err != nil {
-		logrus.Debugf("unknown seccomp syscall %q ignored", call.Name)
-		return nil
+		return fmt.Errorf("action in seccomp profile is invalid: %w", err)
 	}
 
 	// Unconditional match - just add the rule
diff --git a/libcontainer/specconv/spec_linux.go b/libcontainer/specconv/spec_linux.go
index 89172316..3831919d 100644
--- a/libcontainer/specconv/spec_linux.go
+++ b/libcontainer/specconv/spec_linux.go
@@ -607,6 +607,15 @@ func CreateCgroupConfig(opts *CreateOpts, defaultDevs []*devices.Device) (*confi
 					Limit:    l.Limit,
 				})
 			}
+			if len(r.Rdma) > 0 {
+				c.Resources.Rdma = make(map[string]configs.LinuxRdma, len(r.Rdma))
+				for k, v := range r.Rdma {
+					c.Resources.Rdma[k] = configs.LinuxRdma{
+						HcaHandles: v.HcaHandles,
+						HcaObjects: v.HcaObjects,
+					}
+				}
+			}
 			if r.Network != nil {
 				if r.Network.ClassID != nil {
 					c.Resources.NetClsClassid = *r.Network.ClassID
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/man/runc-exec.8.md b/man/runc-exec.8.md
index 49f9cab5..dafd03dc 100644
--- a/man/runc-exec.8.md
+++ b/man/runc-exec.8.md
@@ -59,11 +59,6 @@ multiple times.
 : Pass _N_ additional file descriptors to the container (**stdio** +
 **$LISTEN_FDS** + _N_ in total). Default is **0**.
 
-# EXIT STATUS
-
-Exits with a status of _command_ (unless **-d** is used), or **255** if
-an error occurred.
-
 # EXAMPLES
 If the container can run **ps**(1) command, the following
 will output a list of processes running in the container:
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/utils.go b/utils.go
index 32ab33e5..2809c3df 100644
--- a/utils.go
+++ b/utils.go
@@ -53,17 +53,13 @@ func logrusToStderr() bool {
 // fatal prints the error's details if it is a libcontainer specific error type
 // then exits the program with an exit status of 1.
 func fatal(err error) {
-	fatalWithCode(err, 1)
-}
-
-func fatalWithCode(err error, ret int) {
-	// Make sure the error is written to the logger.
+	// make sure the error is written to the logger
 	logrus.Error(err)
 	if !logrusToStderr() {
 		fmt.Fprintln(os.Stderr, err)
 	}
 
-	os.Exit(ret)
+	os.Exit(1)
 }
 
 // setupSpec performs initial setup based on the cli.Context for the container
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/label/label_linux.go b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_linux.go
index 14e1e38c..b3d142d8 100644
--- a/vendor/github.com/opencontainers/selinux/go-selinux/label/label_linux.go
+++ b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_linux.go
@@ -1,13 +1,12 @@
 package label
 
 import (
-	"errors"
-	"fmt"
 	"os"
 	"os/user"
 	"strings"
 
 	"github.com/opencontainers/selinux/go-selinux"
+	"github.com/pkg/errors"
 )
 
 // Valid Label Options
@@ -54,11 +53,11 @@ func InitLabels(options []string) (plabel string, mlabel string, retErr error) {
 				return "", selinux.PrivContainerMountLabel(), nil
 			}
 			if i := strings.Index(opt, ":"); i == -1 {
-				return "", "", fmt.Errorf("Bad label option %q, valid options 'disable' or \n'user, role, level, type, filetype' followed by ':' and a value", opt)
+				return "", "", errors.Errorf("Bad label option %q, valid options 'disable' or \n'user, role, level, type, filetype' followed by ':' and a value", opt)
 			}
 			con := strings.SplitN(opt, ":", 2)
 			if !validOptions[con[0]] {
-				return "", "", fmt.Errorf("Bad label option %q, valid options 'disable, user, role, level, type, filetype'", con[0])
+				return "", "", errors.Errorf("Bad label option %q, valid options 'disable, user, role, level, type, filetype'", con[0])
 			}
 			if con[0] == "filetype" {
 				mcon["type"] = con[1]
@@ -152,7 +151,7 @@ func Relabel(path string, fileLabel string, shared bool) error {
 		path = strings.TrimSuffix(path, "/")
 	}
 	if exclude_paths[path] {
-		return fmt.Errorf("SELinux relabeling of %s is not allowed", path)
+		return errors.Errorf("SELinux relabeling of %s is not allowed", path)
 	}
 
 	if shared {
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.go b/vendor/github.com/opencontainers/selinux/go-selinux/selinux.go
index 9ffd77af..b336ebad 100644
--- a/vendor/github.com/opencontainers/selinux/go-selinux/selinux.go
+++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux.go
@@ -1,7 +1,7 @@
 package selinux
 
 import (
-	"errors"
+	"github.com/pkg/errors"
 )
 
 const (
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..a91a116f 100644
--- a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go
+++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go
@@ -5,7 +5,6 @@ import (
 	"bytes"
 	"crypto/rand"
 	"encoding/binary"
-	"errors"
 	"fmt"
 	"io"
 	"io/ioutil"
@@ -18,6 +17,8 @@ import (
 	"sync"
 
 	"github.com/bits-and-blooms/bitset"
+	"github.com/opencontainers/selinux/pkg/pwalk"
+	"github.com/pkg/errors"
 	"golang.org/x/sys/unix"
 )
 
@@ -119,7 +120,7 @@ func verifySELinuxfsMount(mnt string) bool {
 		if err == nil {
 			break
 		}
-		if err == unix.EAGAIN || err == unix.EINTR { //nolint:errorlint // unix errors are bare
+		if err == unix.EAGAIN || err == unix.EINTR {
 			continue
 		}
 		return false
@@ -249,12 +250,12 @@ func isProcHandle(fh *os.File) error {
 		if err == nil {
 			break
 		}
-		if err != unix.EINTR { //nolint:errorlint // unix errors are bare
-			return &os.PathError{Op: "fstatfs", Path: fh.Name(), Err: err}
+		if err != unix.EINTR {
+			return errors.Wrapf(err, "statfs(%q) failed", fh.Name())
 		}
 	}
 	if buf.Type != unix.PROC_SUPER_MAGIC {
-		return fmt.Errorf("file %q is not on procfs", fh.Name())
+		return errors.Errorf("file %q is not on procfs", fh.Name())
 	}
 
 	return nil
@@ -310,8 +311,8 @@ func setFileLabel(fpath string, label string) error {
 		if err == nil {
 			break
 		}
-		if err != unix.EINTR { //nolint:errorlint // unix errors are bare
-			return &os.PathError{Op: "lsetxattr", Path: fpath, Err: err}
+		if err != unix.EINTR {
+			return errors.Wrapf(err, "failed to set file label on %s", fpath)
 		}
 	}
 
@@ -326,7 +327,7 @@ func fileLabel(fpath string) (string, error) {
 
 	label, err := lgetxattr(fpath, xattrNameSelinux)
 	if err != nil {
-		return "", &os.PathError{Op: "lgetxattr", Path: fpath, Err: err}
+		return "", err
 	}
 	// Trim the NUL byte at the end of the byte buffer, if present.
 	if len(label) > 0 && label[len(label)-1] == '\x00' {
@@ -389,7 +390,7 @@ func writeCon(fpath, val string) error {
 		_, err = out.Write(nil)
 	}
 	if err != nil {
-		return &os.PathError{Op: "write", Path: fpath, Err: err}
+		return errors.Wrapf(err, "failed to set %s on procfs", fpath)
 	}
 	return nil
 }
@@ -488,13 +489,13 @@ func (l *level) parseLevel(levelStr string) error {
 	lvl := strings.SplitN(levelStr, ":", 2)
 	sens, err := parseLevelItem(lvl[0], sensitivity)
 	if err != nil {
-		return fmt.Errorf("failed to parse sensitivity: %w", err)
+		return errors.Wrap(err, "failed to parse sensitivity")
 	}
 	l.sens = sens
 	if len(lvl) > 1 {
 		cats, err := catsToBitset(lvl[1])
 		if err != nil {
-			return fmt.Errorf("failed to parse categories: %w", err)
+			return errors.Wrap(err, "failed to parse categories")
 		}
 		l.cats = cats
 	}
@@ -512,14 +513,14 @@ func rangeStrToMLSRange(rangeStr string) (*mlsRange, error) {
 	case 2:
 		mlsRange.high = &level{}
 		if err := mlsRange.high.parseLevel(levelSlice[1]); err != nil {
-			return nil, fmt.Errorf("failed to parse high level %q: %w", levelSlice[1], err)
+			return nil, errors.Wrapf(err, "failed to parse high level %q", levelSlice[1])
 		}
 		fallthrough
 	// rangeStr that is single level, e.g. s6:c0,c3,c5,c30.c1023
 	case 1:
 		mlsRange.low = &level{}
 		if err := mlsRange.low.parseLevel(levelSlice[0]); err != nil {
-			return nil, fmt.Errorf("failed to parse low level %q: %w", levelSlice[0], err)
+			return nil, errors.Wrapf(err, "failed to parse low level %q", levelSlice[0])
 		}
 	}
 
@@ -696,21 +697,17 @@ func socketLabel() (string, error) {
 
 // peerLabel retrieves the label of the client on the other side of a socket
 func peerLabel(fd uintptr) (string, error) {
-	label, err := unix.GetsockoptString(int(fd), unix.SOL_SOCKET, unix.SO_PEERSEC)
-	if err != nil {
-		return "", &os.PathError{Op: "getsockopt", Path: "fd " + strconv.Itoa(int(fd)), Err: err}
-	}
-	return label, nil
+	return unix.GetsockoptString(int(fd), unix.SOL_SOCKET, unix.SO_PEERSEC)
 }
 
 // setKeyLabel takes a process label and tells the kernel to assign the
 // label to the next kernel keyring that gets created
 func setKeyLabel(label string) error {
 	err := writeCon("/proc/self/attr/keycreate", label)
-	if errors.Is(err, os.ErrNotExist) {
+	if os.IsNotExist(errors.Cause(err)) {
 		return nil
 	}
-	if label == "" && errors.Is(err, os.ErrPermission) {
+	if label == "" && os.IsPermission(errors.Cause(err)) {
 		return nil
 	}
 	return err
@@ -787,7 +784,7 @@ func enforceMode() int {
 // setEnforceMode sets the current SELinux mode Enforcing, Permissive.
 // Disabled is not valid, since this needs to be set at boot time.
 func setEnforceMode(mode int) error {
-	return ioutil.WriteFile(selinuxEnforcePath(), []byte(strconv.Itoa(mode)), 0o644)
+	return ioutil.WriteFile(selinuxEnforcePath(), []byte(strconv.Itoa(mode)), 0644)
 }
 
 // defaultEnforceMode returns the systems default SELinux mode Enforcing,
@@ -988,7 +985,7 @@ func addMcs(processLabel, fileLabel string) (string, string) {
 
 // securityCheckContext validates that the SELinux label is understood by the kernel
 func securityCheckContext(val string) error {
-	return ioutil.WriteFile(path.Join(getSelinuxMountPoint(), "context"), []byte(val), 0o644)
+	return ioutil.WriteFile(path.Join(getSelinuxMountPoint(), "context"), []byte(val), 0644)
 }
 
 // copyLevel returns a label with the MLS/MCS level from src label replaced on
@@ -1026,7 +1023,7 @@ func badPrefix(fpath string) error {
 	badPrefixes := []string{"/usr"}
 	for _, prefix := range badPrefixes {
 		if strings.HasPrefix(fpath, prefix) {
-			return fmt.Errorf("relabeling content in %s is not allowed", prefix)
+			return errors.Errorf("relabeling content in %s is not allowed", prefix)
 		}
 	}
 	return nil
@@ -1047,10 +1044,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 os.IsNotExist(errors.Cause(e)) {
+			return nil
+		}
+		return e
+	})
 }
 
 // dupSecOpt takes an SELinux process label and returns security options that
@@ -1068,8 +1072,7 @@ func dupSecOpt(src string) ([]string, error) {
 		con["type"] == "" {
 		return nil, nil
 	}
-	dup := []string{
-		"user:" + con["user"],
+	dup := []string{"user:" + con["user"],
 		"role:" + con["role"],
 		"type:" + con["type"],
 	}
@@ -1137,8 +1140,9 @@ func findUserInContext(context Context, r io.Reader, verifier func(string) error
 			return outConn, nil
 		}
 	}
+
 	if err := scanner.Err(); err != nil {
-		return "", fmt.Errorf("failed to scan for context: %w", err)
+		return "", errors.Wrap(err, "failed to scan for context")
 	}
 
 	return "", nil
@@ -1151,7 +1155,7 @@ func getDefaultContextFromReaders(c *defaultSECtx) (string, error) {
 
 	context, err := newContext(c.scon)
 	if err != nil {
-		return "", fmt.Errorf("failed to create label for %s: %w", c.scon, err)
+		return "", errors.Wrapf(err, "failed to create label for %s", c.scon)
 	}
 
 	// set so the verifier validates the matched context with the provided user and level.
@@ -1176,7 +1180,7 @@ func getDefaultContextFromReaders(c *defaultSECtx) (string, error) {
 		return conn, nil
 	}
 
-	return "", fmt.Errorf("context %q not found: %w", c.scon, ErrContextMissing)
+	return "", errors.Wrapf(ErrContextMissing, "context not found: %q", c.scon)
 }
 
 func getDefaultContextWithLevel(user, level, scon string) (string, error) {
diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/xattrs_linux.go b/vendor/github.com/opencontainers/selinux/go-selinux/xattrs_linux.go
index c6b0a7f2..117c255b 100644
--- a/vendor/github.com/opencontainers/selinux/go-selinux/xattrs_linux.go
+++ b/vendor/github.com/opencontainers/selinux/go-selinux/xattrs_linux.go
@@ -10,7 +10,7 @@ func lgetxattr(path, attr string) ([]byte, error) {
 	// Start with a 128 length byte array
 	dest := make([]byte, 128)
 	sz, errno := doLgetxattr(path, attr, dest)
-	for errno == unix.ERANGE { //nolint:errorlint // unix errors are bare
+	for errno == unix.ERANGE {
 		// Buffer too small, use zero-sized buffer to get the actual size
 		sz, errno = doLgetxattr(path, attr, []byte{})
 		if errno != nil {
@@ -31,7 +31,7 @@ func lgetxattr(path, attr string) ([]byte, error) {
 func doLgetxattr(path, attr string, dest []byte) (int, error) {
 	for {
 		sz, err := unix.Lgetxattr(path, attr, dest)
-		if err != unix.EINTR { //nolint:errorlint // unix errors are bare
+		if err != unix.EINTR {
 			return sz, err
 		}
 	}
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..437b12b3 100644
--- a/vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go
+++ b/vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go
@@ -1,11 +1,12 @@
 package pwalk
 
 import (
-	"fmt"
 	"os"
 	"path/filepath"
 	"runtime"
 	"sync"
+
+	"github.com/pkg/errors"
 )
 
 type WalkFunc = filepath.WalkFunc
@@ -19,7 +20,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;
@@ -41,7 +42,7 @@ func Walk(root string, walkFn WalkFunc) error {
 func WalkN(root string, walkFn WalkFunc, num int) error {
 	// make sure limit is sensible
 	if num < 1 {
-		return fmt.Errorf("walk(%q): num must be > 0", root)
+		return errors.Errorf("walk(%q): num must be > 0", root)
 	}
 
 	files := make(chan *walkArgs, 2*num)
@@ -95,7 +96,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..ffae5909 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.2
 ## 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/fscommon/rdma_test.go b/libcontainer/cgroups/fscommon/rdma_test.go
new file mode 100644
index 00000000..9bc08190
--- /dev/null
+++ b/libcontainer/cgroups/fscommon/rdma_test.go
@@ -0,0 +1,57 @@
+package fscommon
+
+import (
+	"os"
+	"path/filepath"
+	"testing"
+
+	"github.com/opencontainers/runc/libcontainer/configs"
+)
+
+/* Roadmap for future */
+// (Low-priority)  TODO: Check if it is possible to virtually mimic an actual RDMA device.
+// TODO: Think of more edge-cases to add.
+
+// TestRdmaSet performs an E2E test of RdmaSet(), parseRdmaKV() using dummy device and a dummy cgroup file-system.
+// Note: Following test does not guarantees that your host supports RDMA since this mocks underlying infrastructure.
+func TestRdmaSet(t *testing.T) {
+	testCgroupPath := filepath.Join(t.TempDir(), "rdma")
+
+	// Ensure the full mock cgroup path exists.
+	err := os.Mkdir(testCgroupPath, 0o755)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	rdmaDevice := "mlx5_1"
+	maxHandles := uint32(100)
+	maxObjects := uint32(300)
+
+	rdmaStubResource := &configs.Resources{
+		Rdma: map[string]configs.LinuxRdma{
+			rdmaDevice: {
+				HcaHandles: &maxHandles,
+				HcaObjects: &maxObjects,
+			},
+		},
+	}
+
+	if err := RdmaSet(testCgroupPath, rdmaStubResource); err != nil {
+		t.Fatal(err)
+	}
+
+	// The default rdma.max must be written.
+	rdmaEntries, err := readRdmaEntries(testCgroupPath, "rdma.max")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if len(rdmaEntries) != 1 {
+		t.Fatal("rdma_test: Got the wrong values while parsing entries from rdma.max")
+	}
+	if rdmaEntries[0].HcaHandles != maxHandles {
+		t.Fatalf("rdma_test: Got the wrong value for hca_handles")
+	}
+	if rdmaEntries[0].HcaObjects != maxObjects {
+		t.Fatalf("rdma_test: Got the wrong value for hca_Objects")
+	}
+}
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/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/exec.bats b/tests/integration/exec.bats
index a49112fa..039041cc 100644
--- a/tests/integration/exec.bats
+++ b/tests/integration/exec.bats
@@ -21,26 +21,6 @@ function teardown() {
 	[[ "${output}" == *"Hello from exec"* ]]
 }
 
-@test "runc exec [exit codes]" {
-	runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox
-	[ "$status" -eq 0 ]
-
-	runc exec test_busybox false
-	[ "$status" -eq 1 ]
-
-	runc exec test_busybox sh -c "exit 42"
-	[ "$status" -eq 42 ]
-
-	runc exec --pid-file /non-existent/directory test_busybox true
-	[ "$status" -eq 255 ]
-
-	runc exec test_busybox no-such-binary
-	[ "$status" -eq 255 ]
-
-	runc exec no_such_container true
-	[ "$status" -eq 255 ]
-}
-
 @test "runc exec --pid-file" {
 	# run busybox detached
 	runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox
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/"
diff --git a/tests/integration/start_hello.bats b/tests/integration/start_hello.bats
index 1c3c906f..85884703 100644
--- a/tests/integration/start_hello.bats
+++ b/tests/integration/start_hello.bats
@@ -76,15 +76,3 @@ function teardown() {
 	runc run test_hello
 	[ "$status" -eq 0 ]
 }
-
-@test "runc run [redundant seccomp rules]" {
-	update_config '	  .linux.seccomp = {
-				"defaultAction": "SCMP_ACT_ALLOW",
-				"syscalls": [{
-					"names": ["bdflush"],
-					"action": "SCMP_ACT_ALLOW",
-				}]
-			    }'
-	runc run test_hello
-	[ "$status" -eq 0 ]
-}