Repository: opencontainers/runc
Pull request #2898 (2021-04-08 19:17:20)

vendor: bump containerd/console to 1.0.2
This is to include https://github.com/containerd/console/pull/51

Fixes: https://github.com/opencontainers/runc/issues/2896

### Changelog entry
* fix terminal for big-endian architectures like s390 (regression in rc93)

cyphar: Do you happen to know if they'll do a new release soon?
kolyshkin: > Do you happen to know if they'll do a new release soon?

I asked for a release but I don't know if they'll make it. Maybe @crosbymichael can bake one.
AkihiroSuda: Released v1.0.2: https://github.com/containerd/console/releases/tag/v1.0.2

Patch:
diff --git a/checkpoint.go b/checkpoint.go
index 3fe4541d..e80dcc4f 100644
--- a/checkpoint.go
+++ b/checkpoint.go
@@ -11,7 +11,7 @@ import (
 
 	criu "github.com/checkpoint-restore/go-criu/v5/rpc"
 	"github.com/opencontainers/runc/libcontainer"
-	"github.com/opencontainers/runc/libcontainer/userns"
+	"github.com/opencontainers/runc/libcontainer/system"
 	"github.com/opencontainers/runtime-spec/specs-go"
 	"github.com/sirupsen/logrus"
 	"github.com/urfave/cli"
@@ -48,7 +48,7 @@ checkpointed.`,
 			return err
 		}
 		// XXX: Currently this is untested with rootless containers.
-		if os.Geteuid() != 0 || userns.RunningInUserNS() {
+		if os.Geteuid() != 0 || system.RunningInUserNS() {
 			logrus.Warn("runc checkpoint is untested with rootless containers")
 		}
 
diff --git a/go.mod b/go.mod
index 5a1cf634..2be8456a 100644
--- a/go.mod
+++ b/go.mod
@@ -5,7 +5,7 @@ go 1.14
 require (
 	github.com/checkpoint-restore/go-criu/v5 v5.0.0
 	github.com/cilium/ebpf v0.4.0
-	github.com/containerd/console v1.0.1
+	github.com/containerd/console v1.0.2
 	github.com/coreos/go-systemd/v22 v22.3.1
 	github.com/cyphar/filepath-securejoin v0.2.2
 	github.com/docker/go-units v0.4.0
diff --git a/go.sum b/go.sum
index 6045cd14..5deb0421 100644
--- a/go.sum
+++ b/go.sum
@@ -6,8 +6,8 @@ github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d8
 github.com/cilium/ebpf v0.4.0 h1:QlHdikaxALkqWasW8hAC1mfR0jdmvbfaBdBPFmRSglA=
 github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
-github.com/containerd/console v1.0.1 h1:u7SFAJyRqWcG6ogaMAx3KjSTy1e3hT9QxqX7Jco7dRc=
-github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw=
+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.1 h1:7OO2CXWMYNDdaAzP51t4lCCZWwpQHmvPbm9sxWjm3So=
 github.com/coreos/go-systemd/v22 v22.3.1/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
 github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
@@ -102,7 +102,6 @@ golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 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/libcontainer/cgroups/fs/devices.go b/libcontainer/cgroups/fs/devices.go
index a098e3b7..9a37e68e 100644
--- a/libcontainer/cgroups/fs/devices.go
+++ b/libcontainer/cgroups/fs/devices.go
@@ -12,7 +12,7 @@ import (
 	"github.com/opencontainers/runc/libcontainer/cgroups/fscommon"
 	"github.com/opencontainers/runc/libcontainer/configs"
 	"github.com/opencontainers/runc/libcontainer/devices"
-	"github.com/opencontainers/runc/libcontainer/userns"
+	"github.com/opencontainers/runc/libcontainer/system"
 )
 
 type DevicesGroup struct {
@@ -55,7 +55,7 @@ func buildEmulator(rules []*devices.Rule) (*cgroupdevices.Emulator, error) {
 }
 
 func (s *DevicesGroup) Set(path string, cgroup *configs.Cgroup) error {
-	if userns.RunningInUserNS() || cgroup.SkipDevices {
+	if system.RunningInUserNS() || cgroup.SkipDevices {
 		return nil
 	}
 
diff --git a/libcontainer/cgroups/fs2/devices.go b/libcontainer/cgroups/fs2/devices.go
index 61c00a96..99559fec 100644
--- a/libcontainer/cgroups/fs2/devices.go
+++ b/libcontainer/cgroups/fs2/devices.go
@@ -7,7 +7,7 @@ import (
 	"github.com/opencontainers/runc/libcontainer/cgroups/ebpf/devicefilter"
 	"github.com/opencontainers/runc/libcontainer/configs"
 	"github.com/opencontainers/runc/libcontainer/devices"
-	"github.com/opencontainers/runc/libcontainer/userns"
+	"github.com/opencontainers/runc/libcontainer/system"
 
 	"github.com/pkg/errors"
 	"golang.org/x/sys/unix"
@@ -36,7 +36,7 @@ func canSkipEBPFError(cgroup *configs.Cgroup) bool {
 	// have the necessary privileges to mknod(2) device inodes or access
 	// host-level instances (though ideally we would be blocking device access
 	// for rootless containers anyway).
-	if userns.RunningInUserNS() {
+	if system.RunningInUserNS() {
 		return true
 	}
 
diff --git a/libcontainer/cgroups/systemd/user.go b/libcontainer/cgroups/systemd/user.go
index 450a2469..8fe91688 100644
--- a/libcontainer/cgroups/systemd/user.go
+++ b/libcontainer/cgroups/systemd/user.go
@@ -13,7 +13,7 @@ import (
 
 	systemdDbus "github.com/coreos/go-systemd/v22/dbus"
 	dbus "github.com/godbus/dbus/v5"
-	"github.com/opencontainers/runc/libcontainer/userns"
+	"github.com/opencontainers/runc/libcontainer/system"
 	"github.com/pkg/errors"
 )
 
@@ -52,7 +52,7 @@ func NewUserSystemdDbus() (*systemdDbus.Conn, error) {
 //
 // Otherwise returns os.Getuid() .
 func DetectUID() (int, error) {
-	if !userns.RunningInUserNS() {
+	if !system.RunningInUserNS() {
 		return os.Getuid(), nil
 	}
 	b, err := exec.Command("busctl", "--user", "--no-pager", "status").CombinedOutput()
diff --git a/libcontainer/cgroups/utils.go b/libcontainer/cgroups/utils.go
index 35ce2c1c..f6d04d58 100644
--- a/libcontainer/cgroups/utils.go
+++ b/libcontainer/cgroups/utils.go
@@ -16,7 +16,7 @@ import (
 	"time"
 
 	"github.com/opencontainers/runc/libcontainer/cgroups/fscommon"
-	"github.com/opencontainers/runc/libcontainer/userns"
+	"github.com/opencontainers/runc/libcontainer/system"
 	"github.com/sirupsen/logrus"
 	"golang.org/x/sys/unix"
 )
@@ -37,7 +37,7 @@ func IsCgroup2UnifiedMode() bool {
 		var st unix.Statfs_t
 		err := unix.Statfs(unifiedMountpoint, &st)
 		if err != nil {
-			if os.IsNotExist(err) && userns.RunningInUserNS() {
+			if os.IsNotExist(err) && system.RunningInUserNS() {
 				// ignore the "not found" error if running in userns
 				logrus.WithError(err).Debugf("%s missing, assuming cgroup v1", unifiedMountpoint)
 				isUnified = false
diff --git a/libcontainer/rootfs_linux.go b/libcontainer/rootfs_linux.go
index ed38e772..411496ab 100644
--- a/libcontainer/rootfs_linux.go
+++ b/libcontainer/rootfs_linux.go
@@ -19,7 +19,7 @@ import (
 	"github.com/opencontainers/runc/libcontainer/cgroups"
 	"github.com/opencontainers/runc/libcontainer/configs"
 	"github.com/opencontainers/runc/libcontainer/devices"
-	"github.com/opencontainers/runc/libcontainer/userns"
+	"github.com/opencontainers/runc/libcontainer/system"
 	"github.com/opencontainers/runc/libcontainer/utils"
 	libcontainerUtils "github.com/opencontainers/runc/libcontainer/utils"
 	"github.com/opencontainers/runtime-spec/specs-go"
@@ -603,7 +603,7 @@ func reOpenDevNull() error {
 
 // Create the device nodes in the container.
 func createDevices(config *configs.Config) error {
-	useBindMount := userns.RunningInUserNS() || config.Namespaces.Contains(configs.NEWUSER)
+	useBindMount := system.RunningInUserNS() || config.Namespaces.Contains(configs.NEWUSER)
 	oldMask := unix.Umask(0000)
 	for _, node := range config.Devices {
 
diff --git a/libcontainer/system/linux.go b/libcontainer/system/linux.go
index 4379a207..49471960 100644
--- a/libcontainer/system/linux.go
+++ b/libcontainer/system/linux.go
@@ -3,9 +3,12 @@
 package system
 
 import (
+	"os"
 	"os/exec"
+	"sync"
 	"unsafe"
 
+	"github.com/opencontainers/runc/libcontainer/user"
 	"golang.org/x/sys/unix"
 )
 
@@ -84,6 +87,52 @@ func Setctty() error {
 	return nil
 }
 
+var (
+	inUserNS bool
+	nsOnce   sync.Once
+)
+
+// RunningInUserNS detects whether we are currently running in a user namespace.
+// Originally copied from github.com/lxc/lxd/shared/util.go
+func RunningInUserNS() bool {
+	nsOnce.Do(func() {
+		uidmap, err := user.CurrentProcessUIDMap()
+		if err != nil {
+			// This kernel-provided file only exists if user namespaces are supported
+			return
+		}
+		inUserNS = UIDMapInUserNS(uidmap)
+	})
+	return inUserNS
+}
+
+func UIDMapInUserNS(uidmap []user.IDMap) bool {
+	/*
+	 * We assume we are in the initial user namespace if we have a full
+	 * range - 4294967295 uids starting at uid 0.
+	 */
+	if len(uidmap) == 1 && uidmap[0].ID == 0 && uidmap[0].ParentID == 0 && uidmap[0].Count == 4294967295 {
+		return false
+	}
+	return true
+}
+
+// GetParentNSeuid returns the euid within the parent user namespace
+func GetParentNSeuid() int64 {
+	euid := int64(os.Geteuid())
+	uidmap, err := user.CurrentProcessUIDMap()
+	if err != nil {
+		// This kernel-provided file only exists if user namespaces are supported
+		return euid
+	}
+	for _, um := range uidmap {
+		if um.ID <= euid && euid <= um.ID+um.Count-1 {
+			return um.ParentID + euid - um.ID
+		}
+	}
+	return euid
+}
+
 // SetSubreaper sets the value i as the subreaper setting for the calling process
 func SetSubreaper(i int) error {
 	return unix.Prctl(unix.PR_SET_CHILD_SUBREAPER, uintptr(i), 0, 0, 0)
diff --git a/libcontainer/userns/userns_fuzzer.go b/libcontainer/system/system_fuzzer.go
similarity index 82%
rename from libcontainer/userns/userns_fuzzer.go
rename to libcontainer/system/system_fuzzer.go
index 529f8eae..c1d7630f 100644
--- a/libcontainer/userns/userns_fuzzer.go
+++ b/libcontainer/system/system_fuzzer.go
@@ -1,6 +1,6 @@
 // +build gofuzz
 
-package userns
+package system
 
 import (
 	"strings"
@@ -10,6 +10,6 @@ import (
 
 func FuzzUIDMap(data []byte) int {
 	uidmap, _ := user.ParseIDMap(strings.NewReader(string(data)))
-	_ = uidMapInUserNS(uidmap)
+	_ = UIDMapInUserNS(uidmap)
 	return 1
 }
diff --git a/libcontainer/system/unsupported.go b/libcontainer/system/unsupported.go
new file mode 100644
index 00000000..b94be74a
--- /dev/null
+++ b/libcontainer/system/unsupported.go
@@ -0,0 +1,27 @@
+// +build !linux
+
+package system
+
+import (
+	"os"
+
+	"github.com/opencontainers/runc/libcontainer/user"
+)
+
+// RunningInUserNS is a stub for non-Linux systems
+// Always returns false
+func RunningInUserNS() bool {
+	return false
+}
+
+// UIDMapInUserNS is a stub for non-Linux systems
+// Always returns false
+func UIDMapInUserNS(uidmap []user.IDMap) bool {
+	return false
+}
+
+// GetParentNSeuid returns the euid within the parent user namespace
+// Always returns os.Geteuid on non-linux
+func GetParentNSeuid() int {
+	return os.Geteuid()
+}
diff --git a/libcontainer/system/userns_deprecated.go b/libcontainer/system/userns_deprecated.go
deleted file mode 100644
index 2de3462a..00000000
--- a/libcontainer/system/userns_deprecated.go
+++ /dev/null
@@ -1,5 +0,0 @@
-package system
-
-import "github.com/opencontainers/runc/libcontainer/userns"
-
-var RunningInUserNS = userns.RunningInUserNS
diff --git a/libcontainer/userns/userns.go b/libcontainer/userns/userns.go
deleted file mode 100644
index f6cb98e5..00000000
--- a/libcontainer/userns/userns.go
+++ /dev/null
@@ -1,5 +0,0 @@
-package userns
-
-// RunningInUserNS detects whether we are currently running in a user namespace.
-// Originally copied from github.com/lxc/lxd/shared/util.go
-var RunningInUserNS = runningInUserNS
diff --git a/libcontainer/userns/userns_linux.go b/libcontainer/userns/userns_linux.go
deleted file mode 100644
index 724e6df0..00000000
--- a/libcontainer/userns/userns_linux.go
+++ /dev/null
@@ -1,37 +0,0 @@
-package userns
-
-import (
-	"sync"
-
-	"github.com/opencontainers/runc/libcontainer/user"
-)
-
-var (
-	inUserNS bool
-	nsOnce   sync.Once
-)
-
-// runningInUserNS detects whether we are currently running in a user namespace.
-// Originally copied from github.com/lxc/lxd/shared/util.go
-func runningInUserNS() bool {
-	nsOnce.Do(func() {
-		uidmap, err := user.CurrentProcessUIDMap()
-		if err != nil {
-			// This kernel-provided file only exists if user namespaces are supported
-			return
-		}
-		inUserNS = uidMapInUserNS(uidmap)
-	})
-	return inUserNS
-}
-
-func uidMapInUserNS(uidmap []user.IDMap) bool {
-	/*
-	 * We assume we are in the initial user namespace if we have a full
-	 * range - 4294967295 uids starting at uid 0.
-	 */
-	if len(uidmap) == 1 && uidmap[0].ID == 0 && uidmap[0].ParentID == 0 && uidmap[0].Count == 4294967295 {
-		return false
-	}
-	return true
-}
diff --git a/libcontainer/userns/userns_unsupported.go b/libcontainer/userns/userns_unsupported.go
deleted file mode 100644
index f45bb0c3..00000000
--- a/libcontainer/userns/userns_unsupported.go
+++ /dev/null
@@ -1,17 +0,0 @@
-// +build !linux
-
-package userns
-
-import "github.com/opencontainers/runc/libcontainer/user"
-
-// runningInUserNS is a stub for non-Linux systems
-// Always returns false
-func runningInUserNS() bool {
-	return false
-}
-
-// uidMapInUserNS is a stub for non-Linux systems
-// Always returns false
-func uidMapInUserNS(uidmap []user.IDMap) bool {
-	return false
-}
diff --git a/restore.go b/restore.go
index ed69d15e..ec730822 100644
--- a/restore.go
+++ b/restore.go
@@ -6,7 +6,7 @@ import (
 	"os"
 
 	"github.com/opencontainers/runc/libcontainer"
-	"github.com/opencontainers/runc/libcontainer/userns"
+	"github.com/opencontainers/runc/libcontainer/system"
 	"github.com/sirupsen/logrus"
 	"github.com/urfave/cli"
 )
@@ -97,7 +97,7 @@ using the runc checkpoint command.`,
 			return err
 		}
 		// XXX: Currently this is untested with rootless containers.
-		if os.Geteuid() != 0 || userns.RunningInUserNS() {
+		if os.Geteuid() != 0 || system.RunningInUserNS() {
 			logrus.Warn("runc checkpoint is untested with rootless containers")
 		}
 
diff --git a/rootless_linux.go b/rootless_linux.go
index 3c210538..348f7c4f 100644
--- a/rootless_linux.go
+++ b/rootless_linux.go
@@ -6,7 +6,7 @@ import (
 	"os"
 
 	"github.com/opencontainers/runc/libcontainer/cgroups/systemd"
-	"github.com/opencontainers/runc/libcontainer/userns"
+	"github.com/opencontainers/runc/libcontainer/system"
 	"github.com/sirupsen/logrus"
 	"github.com/urfave/cli"
 )
@@ -25,7 +25,7 @@ func shouldUseRootlessCgroupManager(context *cli.Context) (bool, error) {
 	if os.Geteuid() != 0 {
 		return true, nil
 	}
-	if !userns.RunningInUserNS() {
+	if !system.RunningInUserNS() {
 		// euid == 0 , in the initial ns (i.e. the real root)
 		return false, nil
 	}
@@ -60,7 +60,7 @@ func shouldHonorXDGRuntimeDir() bool {
 	if os.Geteuid() != 0 {
 		return true
 	}
-	if !userns.RunningInUserNS() {
+	if !system.RunningInUserNS() {
 		// euid == 0 , in the initial ns (i.e. the real root)
 		// in this case, we should use /run/runc and ignore
 		// $XDG_RUNTIME_DIR (e.g. /run/user/0) for backward
diff --git a/vendor/github.com/containerd/console/README.md b/vendor/github.com/containerd/console/README.md
index 5392fdaf..580b461a 100644
--- a/vendor/github.com/containerd/console/README.md
+++ b/vendor/github.com/containerd/console/README.md
@@ -1,6 +1,8 @@
 # console
 
-[![Build Status](https://travis-ci.org/containerd/console.svg?branch=master)](https://travis-ci.org/containerd/console)
+[![PkgGoDev](https://pkg.go.dev/badge/github.com/containerd/console)](https://pkg.go.dev/github.com/containerd/console)
+[![Build Status](https://github.com/containerd/console/workflows/CI/badge.svg)](https://github.com/containerd/console/actions?query=workflow%3ACI)
+[![Go Report Card](https://goreportcard.com/badge/github.com/containerd/console)](https://goreportcard.com/report/github.com/containerd/console)
 
 Golang package for dealing with consoles.  Light on deps and a simple API.
 
diff --git a/vendor/github.com/containerd/console/console_unix.go b/vendor/github.com/containerd/console/console_unix.go
index a7868752..a0811769 100644
--- a/vendor/github.com/containerd/console/console_unix.go
+++ b/vendor/github.com/containerd/console/console_unix.go
@@ -19,8 +19,6 @@
 package console
 
 import (
-	"os"
-
 	"golang.org/x/sys/unix"
 )
 
@@ -28,7 +26,7 @@ import (
 // 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) {
-	f, err := os.OpenFile("/dev/ptmx", unix.O_RDWR|unix.O_NOCTTY|unix.O_CLOEXEC, 0)
+	f, err := openpt()
 	if err != nil {
 		return nil, "", err
 	}
diff --git a/vendor/github.com/containerd/console/go.mod b/vendor/github.com/containerd/console/go.mod
index 60bf028e..7fca0a9a 100644
--- a/vendor/github.com/containerd/console/go.mod
+++ b/vendor/github.com/containerd/console/go.mod
@@ -4,5 +4,5 @@ go 1.13
 
 require (
 	github.com/pkg/errors v0.9.1
-	golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f
+	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 6b9363c4..9db384d3 100644
--- a/vendor/github.com/containerd/console/go.sum
+++ b/vendor/github.com/containerd/console/go.sum
@@ -1,4 +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-20200916030750-2334cc1a136f h1:6Sc1XOXTulBN6imkqo6XoAXDEzoQ4/ro6xy7Vn8+rOM=
-golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+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/pty_freebsd_cgo.go b/vendor/github.com/containerd/console/pty_freebsd_cgo.go
new file mode 100644
index 00000000..cbd3cd7e
--- /dev/null
+++ b/vendor/github.com/containerd/console/pty_freebsd_cgo.go
@@ -0,0 +1,45 @@
+// +build freebsd,cgo
+
+/*
+   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"
+)
+
+/*
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+*/
+import "C"
+
+// openpt allocates a new pseudo-terminal and establishes a connection with its
+// control device.
+func openpt() (*os.File, error) {
+	fd, err := C.posix_openpt(C.O_RDWR)
+	if err != nil {
+		return nil, fmt.Errorf("posix_openpt: %w", err)
+	}
+	if _, err := C.grantpt(fd); err != nil {
+		C.close(fd)
+		return nil, fmt.Errorf("grantpt: %w", err)
+	}
+	return os.NewFile(uintptr(fd), ""), nil
+}
diff --git a/vendor/github.com/containerd/console/pty_freebsd_nocgo.go b/vendor/github.com/containerd/console/pty_freebsd_nocgo.go
new file mode 100644
index 00000000..b5e43181
--- /dev/null
+++ b/vendor/github.com/containerd/console/pty_freebsd_nocgo.go
@@ -0,0 +1,36 @@
+// +build freebsd,!cgo
+
+/*
+   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 (
+	"os"
+)
+
+//
+// Implementing the functions below requires cgo support.  Non-cgo stubs
+// versions are defined below to enable cross-compilation of source code
+// that depends on these functions, but the resultant cross-compiled
+// binaries cannot actually be used.  If the stub function(s) below are
+// actually invoked they will display an error message and cause the
+// calling process to exit.
+//
+
+func openpt() (*os.File, error) {
+	panic("openpt() support requires cgo.")
+}
diff --git a/vendor/github.com/containerd/console/pty_unix.go b/vendor/github.com/containerd/console/pty_unix.go
new file mode 100644
index 00000000..d5a6bd8c
--- /dev/null
+++ b/vendor/github.com/containerd/console/pty_unix.go
@@ -0,0 +1,30 @@
+// +build darwin linux netbsd openbsd solaris
+
+/*
+   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 (
+	"os"
+
+	"golang.org/x/sys/unix"
+)
+
+// openpt allocates a new pseudo-terminal by opening the /dev/ptmx device
+func openpt() (*os.File, error) {
+	return os.OpenFile("/dev/ptmx", unix.O_RDWR|unix.O_NOCTTY|unix.O_CLOEXEC, 0)
+}
diff --git a/vendor/github.com/containerd/console/tc_freebsd.go b/vendor/github.com/containerd/console/tc_freebsd_cgo.go
similarity index 85%
rename from vendor/github.com/containerd/console/tc_freebsd.go
rename to vendor/github.com/containerd/console/tc_freebsd_cgo.go
index 04583a61..0f3d2727 100644
--- a/vendor/github.com/containerd/console/tc_freebsd.go
+++ b/vendor/github.com/containerd/console/tc_freebsd_cgo.go
@@ -1,3 +1,5 @@
+// +build freebsd,cgo
+
 /*
    Copyright The containerd Authors.
 
@@ -23,6 +25,12 @@ import (
 	"golang.org/x/sys/unix"
 )
 
+/*
+#include <stdlib.h>
+#include <unistd.h>
+*/
+import "C"
+
 const (
 	cmdTcGet = unix.TIOCGETA
 	cmdTcSet = unix.TIOCSETA
@@ -30,8 +38,12 @@ const (
 
 // unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
 // unlockpt should be called before opening the slave side of a pty.
-// This does not exist on FreeBSD, it does not allocate controlling terminals on open
 func unlockpt(f *os.File) error {
+	fd := C.int(f.Fd())
+	if _, err := C.unlockpt(fd); err != nil {
+		C.close(fd)
+		return fmt.Errorf("unlockpt: %w", err)
+	}
 	return nil
 }
 
diff --git a/vendor/github.com/containerd/console/tc_freebsd_nocgo.go b/vendor/github.com/containerd/console/tc_freebsd_nocgo.go
new file mode 100644
index 00000000..087fc158
--- /dev/null
+++ b/vendor/github.com/containerd/console/tc_freebsd_nocgo.go
@@ -0,0 +1,55 @@
+// +build freebsd,!cgo
+
+/*
+   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"
+)
+
+const (
+	cmdTcGet = unix.TIOCGETA
+	cmdTcSet = unix.TIOCSETA
+)
+
+//
+// Implementing the functions below requires cgo support.  Non-cgo stubs
+// versions are defined below to enable cross-compilation of source code
+// that depends on these functions, but the resultant cross-compiled
+// binaries cannot actually be used.  If the stub function(s) below are
+// actually invoked they will display an error message and cause the
+// calling process to exit.
+//
+
+// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
+// unlockpt should be called before opening the slave side of a pty.
+func unlockpt(f *os.File) error {
+	panic("unlockpt() support requires cgo.")
+}
+
+// ptsname retrieves the name of the first available pts for the given master.
+func ptsname(f *os.File) (string, error) {
+	n, err := unix.IoctlGetInt(int(f.Fd()), unix.TIOCGPTN)
+	if err != nil {
+		return "", err
+	}
+	return fmt.Sprintf("/dev/pts/%d", n), nil
+}
diff --git a/vendor/github.com/containerd/console/tc_linux.go b/vendor/github.com/containerd/console/tc_linux.go
index 75f8694f..7d552ea4 100644
--- a/vendor/github.com/containerd/console/tc_linux.go
+++ b/vendor/github.com/containerd/console/tc_linux.go
@@ -19,6 +19,7 @@ package console
 import (
 	"fmt"
 	"os"
+	"unsafe"
 
 	"golang.org/x/sys/unix"
 )
@@ -31,13 +32,19 @@ const (
 // unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
 // unlockpt should be called before opening the slave side of a pty.
 func unlockpt(f *os.File) error {
-	return unix.IoctlSetPointerInt(int(f.Fd()), unix.TIOCSPTLCK, 0)
+	var u int32
+	// XXX do not use unix.IoctlSetPointerInt here, see commit dbd69c59b81.
+	if _, _, err := unix.Syscall(unix.SYS_IOCTL, f.Fd(), unix.TIOCSPTLCK, uintptr(unsafe.Pointer(&u))); err != 0 {
+		return err
+	}
+	return nil
 }
 
 // ptsname retrieves the name of the first available pts for the given master.
 func ptsname(f *os.File) (string, error) {
-	u, err := unix.IoctlGetInt(int(f.Fd()), unix.TIOCGPTN)
-	if err != nil {
+	var u uint32
+	// XXX do not use unix.IoctlGetInt here, see commit dbd69c59b81.
+	if _, _, err := unix.Syscall(unix.SYS_IOCTL, f.Fd(), unix.TIOCGPTN, uintptr(unsafe.Pointer(&u))); err != 0 {
 		return "", err
 	}
 	return fmt.Sprintf("/dev/pts/%d", u), nil
diff --git a/vendor/modules.txt b/vendor/modules.txt
index a15f8673..d5fadcc6 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -9,7 +9,7 @@ github.com/cilium/ebpf/asm
 github.com/cilium/ebpf/internal
 github.com/cilium/ebpf/internal/btf
 github.com/cilium/ebpf/internal/unix
-# github.com/containerd/console v1.0.1
+# github.com/containerd/console v1.0.2
 ## explicit
 github.com/containerd/console
 # github.com/coreos/go-systemd/v22 v22.3.1


Test patch:
diff --git a/libcontainer/userns/userns_linux_test.go b/libcontainer/system/linux_test.go
similarity index 94%
rename from libcontainer/userns/userns_linux_test.go
rename to libcontainer/system/linux_test.go
index 2ddd3ff9..4d613d84 100644
--- a/libcontainer/userns/userns_linux_test.go
+++ b/libcontainer/system/linux_test.go
@@ -1,6 +1,6 @@
 // +build linux
 
-package userns
+package system
 
 import (
 	"strings"
@@ -37,7 +37,7 @@ func TestUIDMapInUserNS(t *testing.T) {
 		if err != nil {
 			t.Fatal(err)
 		}
-		actual := uidMapInUserNS(uidmap)
+		actual := UIDMapInUserNS(uidmap)
 		if c.expected != actual {
 			t.Fatalf("expected %v, got %v for %q", c.expected, actual, c.s)
 		}