Merge pull request #1503 from crosbymichael/update-runc
Update runc to 593914b8bd5448a93f7c3e4902a03408b6d
This commit is contained in:
		@@ -39,7 +39,7 @@ install:
 | 
			
		||||
  - wget https://github.com/google/protobuf/releases/download/v3.3.0/protoc-3.3.0-linux-x86_64.zip -O /tmp/protoc-3.3.0-linux-x86_64.zip
 | 
			
		||||
  - sudo unzip -o -d /usr/local /tmp/protoc-3.3.0-linux-x86_64.zip
 | 
			
		||||
  - go get -u github.com/vbatts/git-validation
 | 
			
		||||
  - sudo wget https://github.com/crosbymichael/runc/releases/download/ctd-4/runc -O /bin/runc; sudo chmod +x /bin/runc
 | 
			
		||||
  - sudo wget https://github.com/crosbymichael/runc/releases/download/ctd-5/runc -O /bin/runc; sudo chmod +x /bin/runc
 | 
			
		||||
  - wget https://github.com/xemul/criu/archive/v3.0.tar.gz -O /tmp/criu.tar.gz
 | 
			
		||||
  - tar -C /tmp/ -zxf /tmp/criu.tar.gz
 | 
			
		||||
  - cd /tmp/criu-3.0 && sudo make install-criu
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								RUNC.md
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								RUNC.md
									
									
									
									
									
								
							@@ -2,7 +2,7 @@ containerd is built with OCI support and with support for advanced features prov
 | 
			
		||||
 | 
			
		||||
We depend on a specific `runc` version when dealing with advanced features.  You should have a specific runc build for development.  The current supported runc commit is:
 | 
			
		||||
 | 
			
		||||
RUNC_COMMIT = e775f0fba3ea329b8b766451c892c41a3d49594d
 | 
			
		||||
RUNC_COMMIT = 593914b8bd5448a93f7c3e4902a03408b6d5c0ce
 | 
			
		||||
 | 
			
		||||
For more information on how to clone and build runc see the runc Building [documentation](https://github.com/opencontainers/runc#building).
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,7 @@ github.com/docker/go-units v0.3.1
 | 
			
		||||
github.com/gogo/protobuf d2e1ade2d719b78fe5b061b4c18a9f7111b5bdc8
 | 
			
		||||
github.com/golang/protobuf 5a0f697c9ed9d68fef0116532c6e05cfeae00e55
 | 
			
		||||
github.com/opencontainers/runtime-spec v1.0.0
 | 
			
		||||
github.com/opencontainers/runc e775f0fba3ea329b8b766451c892c41a3d49594d
 | 
			
		||||
github.com/opencontainers/runc 593914b8bd5448a93f7c3e4902a03408b6d5c0ce
 | 
			
		||||
github.com/sirupsen/logrus v1.0.0
 | 
			
		||||
github.com/containerd/btrfs cc52c4dea2ce11a44e6639e561bb5c2af9ada9e3
 | 
			
		||||
github.com/stretchr/testify v1.1.4
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										138
									
								
								vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsexec.c
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										138
									
								
								vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsexec.c
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,3 +1,4 @@
 | 
			
		||||
 | 
			
		||||
#define _GNU_SOURCE
 | 
			
		||||
#include <endian.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
@@ -19,6 +20,8 @@
 | 
			
		||||
#include <sys/prctl.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/wait.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <linux/limits.h>
 | 
			
		||||
#include <linux/netlink.h>
 | 
			
		||||
@@ -64,7 +67,13 @@ struct clone_t {
 | 
			
		||||
 | 
			
		||||
struct nlconfig_t {
 | 
			
		||||
	char *data;
 | 
			
		||||
 | 
			
		||||
	/* Process settings. */
 | 
			
		||||
	uint32_t cloneflags;
 | 
			
		||||
	char *oom_score_adj;
 | 
			
		||||
	size_t oom_score_adj_len;
 | 
			
		||||
 | 
			
		||||
	/* User namespace settings.*/
 | 
			
		||||
	char *uidmap;
 | 
			
		||||
	size_t uidmap_len;
 | 
			
		||||
	char *gidmap;
 | 
			
		||||
@@ -72,9 +81,13 @@ struct nlconfig_t {
 | 
			
		||||
	char *namespaces;
 | 
			
		||||
	size_t namespaces_len;
 | 
			
		||||
	uint8_t is_setgroup;
 | 
			
		||||
 | 
			
		||||
	/* Rootless container settings.*/
 | 
			
		||||
	uint8_t is_rootless;
 | 
			
		||||
	char *oom_score_adj;
 | 
			
		||||
	size_t oom_score_adj_len;
 | 
			
		||||
	char *uidmappath;
 | 
			
		||||
	size_t uidmappath_len;
 | 
			
		||||
	char *gidmappath;
 | 
			
		||||
	size_t gidmappath_len;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
@@ -89,6 +102,8 @@ struct nlconfig_t {
 | 
			
		||||
#define SETGROUP_ATTR		27285
 | 
			
		||||
#define OOM_SCORE_ADJ_ATTR	27286
 | 
			
		||||
#define ROOTLESS_ATTR	    27287
 | 
			
		||||
#define UIDMAPPATH_ATTR	    27288
 | 
			
		||||
#define GIDMAPPATH_ATTR	    27289
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Use the raw syscall for versions of glibc which don't include a function for
 | 
			
		||||
@@ -191,22 +206,96 @@ static void update_setgroups(int pid, enum policy_t setgroup)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void update_uidmap(int pid, char *map, size_t map_len)
 | 
			
		||||
static int try_mapping_tool(const char *app, int pid, char *map, size_t map_len)
 | 
			
		||||
{
 | 
			
		||||
	if (map == NULL || map_len <= 0)
 | 
			
		||||
		return;
 | 
			
		||||
	int child;
 | 
			
		||||
 | 
			
		||||
	if (write_file(map, map_len, "/proc/%d/uid_map", pid) < 0)
 | 
			
		||||
		bail("failed to update /proc/%d/uid_map", pid);
 | 
			
		||||
	/*
 | 
			
		||||
	 * If @app is NULL, execve will segfault. Just check it here and bail (if
 | 
			
		||||
	 * we're in this path, the caller is already getting desparate and there
 | 
			
		||||
	 * isn't a backup to this failing). This usually would be a configuration
 | 
			
		||||
	 * or programming issue.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!app)
 | 
			
		||||
		bail("mapping tool not present");
 | 
			
		||||
 | 
			
		||||
	child = fork();
 | 
			
		||||
	if (child < 0)
 | 
			
		||||
		bail("failed to fork");
 | 
			
		||||
 | 
			
		||||
	if (!child) {
 | 
			
		||||
#define MAX_ARGV 20
 | 
			
		||||
		char *argv[MAX_ARGV];
 | 
			
		||||
		char *envp[] = {NULL};
 | 
			
		||||
		char pid_fmt[16];
 | 
			
		||||
		int argc = 0;
 | 
			
		||||
		char *next;
 | 
			
		||||
 | 
			
		||||
		snprintf(pid_fmt, 16, "%d", pid);
 | 
			
		||||
 | 
			
		||||
		argv[argc++] = (char *) app;
 | 
			
		||||
		argv[argc++] = pid_fmt;
 | 
			
		||||
		/*
 | 
			
		||||
		 * Convert the map string into a list of argument that
 | 
			
		||||
		 * newuidmap/newgidmap can understand.
 | 
			
		||||
		 */
 | 
			
		||||
 | 
			
		||||
		while (argc < MAX_ARGV) {
 | 
			
		||||
			if (*map == '\0') {
 | 
			
		||||
				argv[argc++] = NULL;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
			argv[argc++] = map;
 | 
			
		||||
			next = strpbrk(map, "\n ");
 | 
			
		||||
			if (next == NULL)
 | 
			
		||||
				break;
 | 
			
		||||
			*next++ = '\0';
 | 
			
		||||
			map = next + strspn(next, "\n ");
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		execve(app, argv, envp);
 | 
			
		||||
		bail("failed to execv");
 | 
			
		||||
	} else {
 | 
			
		||||
		int status;
 | 
			
		||||
 | 
			
		||||
		while (true) {
 | 
			
		||||
			if (waitpid(child, &status, 0) < 0) {
 | 
			
		||||
				if (errno == EINTR)
 | 
			
		||||
					continue;
 | 
			
		||||
				bail("failed to waitpid");
 | 
			
		||||
			}
 | 
			
		||||
			if (WIFEXITED(status) || WIFSIGNALED(status))
 | 
			
		||||
				return WEXITSTATUS(status);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void update_gidmap(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)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (write_file(map, map_len, "/proc/%d/gid_map", pid) < 0)
 | 
			
		||||
		bail("failed to update /proc/%d/gid_map", pid);
 | 
			
		||||
	if (write_file(map, map_len, "/proc/%d/uid_map", pid) < 0) {
 | 
			
		||||
		if (errno != EPERM)
 | 
			
		||||
			bail("failed to update /proc/%d/uid_map", pid);
 | 
			
		||||
		if (try_mapping_tool(path, pid, map, map_len))
 | 
			
		||||
			bail("failed to use newuid map on %d", pid);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void update_gidmap(const char *path, int pid, char *map, size_t map_len)
 | 
			
		||||
{
 | 
			
		||||
	if (map == NULL || map_len <= 0)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (write_file(map, map_len, "/proc/%d/gid_map", pid) < 0) {
 | 
			
		||||
		if (errno != EPERM)
 | 
			
		||||
			bail("failed to update /proc/%d/gid_map", pid);
 | 
			
		||||
		if (try_mapping_tool(path, pid, map, map_len))
 | 
			
		||||
			bail("failed to use newgid map on %d", pid);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void update_oom_score_adj(char *data, size_t len)
 | 
			
		||||
@@ -350,6 +439,14 @@ static void nl_parse(int fd, struct nlconfig_t *config)
 | 
			
		||||
			config->gidmap = current;
 | 
			
		||||
			config->gidmap_len = payload_len;
 | 
			
		||||
			break;
 | 
			
		||||
		case UIDMAPPATH_ATTR:
 | 
			
		||||
			config->uidmappath = current;
 | 
			
		||||
			config->uidmappath_len = payload_len;
 | 
			
		||||
			break;
 | 
			
		||||
		case GIDMAPPATH_ATTR:
 | 
			
		||||
			config->gidmappath = current;
 | 
			
		||||
			config->gidmappath_len = payload_len;
 | 
			
		||||
			break;
 | 
			
		||||
		case SETGROUP_ATTR:
 | 
			
		||||
			config->is_setgroup = readint8(current);
 | 
			
		||||
			break;
 | 
			
		||||
@@ -542,7 +639,7 @@ void nsexec(void)
 | 
			
		||||
	 */
 | 
			
		||||
	case JUMP_PARENT: {
 | 
			
		||||
			int len;
 | 
			
		||||
			pid_t child;
 | 
			
		||||
			pid_t child, first_child = -1;
 | 
			
		||||
			char buf[JSON_MAX];
 | 
			
		||||
			bool ready = false;
 | 
			
		||||
 | 
			
		||||
@@ -596,8 +693,8 @@ void nsexec(void)
 | 
			
		||||
						update_setgroups(child, SETGROUPS_DENY);
 | 
			
		||||
 | 
			
		||||
					/* Set up mappings. */
 | 
			
		||||
					update_uidmap(child, config.uidmap, config.uidmap_len);
 | 
			
		||||
					update_gidmap(child, config.gidmap, config.gidmap_len);
 | 
			
		||||
					update_uidmap(config.uidmappath, child, config.uidmap, config.uidmap_len);
 | 
			
		||||
					update_gidmap(config.gidmappath, child, config.gidmap, config.gidmap_len);
 | 
			
		||||
 | 
			
		||||
					s = SYNC_USERMAP_ACK;
 | 
			
		||||
					if (write(syncfd, &s, sizeof(s)) != sizeof(s)) {
 | 
			
		||||
@@ -606,18 +703,18 @@ void nsexec(void)
 | 
			
		||||
					}
 | 
			
		||||
					break;
 | 
			
		||||
				case SYNC_RECVPID_PLS: {
 | 
			
		||||
						pid_t old = child;
 | 
			
		||||
						first_child = child;
 | 
			
		||||
 | 
			
		||||
						/* Get the init_func pid. */
 | 
			
		||||
						if (read(syncfd, &child, sizeof(child)) != sizeof(child)) {
 | 
			
		||||
							kill(old, SIGKILL);
 | 
			
		||||
							kill(first_child, SIGKILL);
 | 
			
		||||
							bail("failed to sync with child: read(childpid)");
 | 
			
		||||
						}
 | 
			
		||||
 | 
			
		||||
						/* Send ACK. */
 | 
			
		||||
						s = SYNC_RECVPID_ACK;
 | 
			
		||||
						if (write(syncfd, &s, sizeof(s)) != sizeof(s)) {
 | 
			
		||||
							kill(old, SIGKILL);
 | 
			
		||||
							kill(first_child, SIGKILL);
 | 
			
		||||
							kill(child, SIGKILL);
 | 
			
		||||
							bail("failed to sync with child: write(SYNC_RECVPID_ACK)");
 | 
			
		||||
						}
 | 
			
		||||
@@ -665,8 +762,13 @@ void nsexec(void)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			/* Send the init_func pid back to our parent. */
 | 
			
		||||
			len = snprintf(buf, JSON_MAX, "{\"pid\": %d}\n", child);
 | 
			
		||||
			/*
 | 
			
		||||
			 * Send the init_func pid and the pid of the first child back to our parent.
 | 
			
		||||
			 *
 | 
			
		||||
			 * We need to send both back because we can't reap the first child we created (CLONE_PARENT).
 | 
			
		||||
			 * It becomes the responsibility of our parent to reap the first child.
 | 
			
		||||
			 */
 | 
			
		||||
			len = snprintf(buf, JSON_MAX, "{\"pid\": %d, \"pid_first\": %d}\n", child, first_child);
 | 
			
		||||
			if (len < 0) {
 | 
			
		||||
				kill(child, SIGKILL);
 | 
			
		||||
				bail("unable to generate JSON for child pid");
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										16
									
								
								vendor/github.com/opencontainers/runc/libcontainer/user/lookup.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								vendor/github.com/opencontainers/runc/libcontainer/user/lookup.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -2,8 +2,6 @@ package user
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/sys/unix"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
@@ -37,13 +35,6 @@ func lookupUser(filter func(u User) bool) (User, error) {
 | 
			
		||||
	return users[0], nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CurrentUser looks up the current user by their user id in /etc/passwd. If the
 | 
			
		||||
// user cannot be found (or there is no /etc/passwd file on the filesystem),
 | 
			
		||||
// then CurrentUser returns an error.
 | 
			
		||||
func CurrentUser() (User, error) {
 | 
			
		||||
	return LookupUid(unix.Getuid())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LookupUser looks up a user by their username in /etc/passwd. If the user
 | 
			
		||||
// cannot be found (or there is no /etc/passwd file on the filesystem), then
 | 
			
		||||
// LookupUser returns an error.
 | 
			
		||||
@@ -85,13 +76,6 @@ func lookupGroup(filter func(g Group) bool) (Group, error) {
 | 
			
		||||
	return groups[0], nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CurrentGroup looks up the current user's group by their primary group id's
 | 
			
		||||
// entry in /etc/passwd. If the group cannot be found (or there is no
 | 
			
		||||
// /etc/group file on the filesystem), then CurrentGroup returns an error.
 | 
			
		||||
func CurrentGroup() (Group, error) {
 | 
			
		||||
	return LookupGid(unix.Getgid())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LookupGroup looks up a group by its name in /etc/group. If the group cannot
 | 
			
		||||
// be found (or there is no /etc/group file on the filesystem), then LookupGroup
 | 
			
		||||
// returns an error.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										16
									
								
								vendor/github.com/opencontainers/runc/libcontainer/user/lookup_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								vendor/github.com/opencontainers/runc/libcontainer/user/lookup_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -5,6 +5,8 @@ package user
 | 
			
		||||
import (
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/sys/unix"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Unix-specific path to the passwd and group formatted files.
 | 
			
		||||
@@ -28,3 +30,17 @@ func GetGroupPath() (string, error) {
 | 
			
		||||
func GetGroup() (io.ReadCloser, error) {
 | 
			
		||||
	return os.Open(unixGroupPath)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CurrentUser looks up the current user by their user id in /etc/passwd. If the
 | 
			
		||||
// user cannot be found (or there is no /etc/passwd file on the filesystem),
 | 
			
		||||
// then CurrentUser returns an error.
 | 
			
		||||
func CurrentUser() (User, error) {
 | 
			
		||||
	return LookupUid(unix.Getuid())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CurrentGroup looks up the current user's group by their primary group id's
 | 
			
		||||
// entry in /etc/passwd. If the group cannot be found (or there is no
 | 
			
		||||
// /etc/group file on the filesystem), then CurrentGroup returns an error.
 | 
			
		||||
func CurrentGroup() (Group, error) {
 | 
			
		||||
	return LookupGid(unix.Getgid())
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										19
									
								
								vendor/github.com/opencontainers/runc/libcontainer/user/lookup_unsupported.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								vendor/github.com/opencontainers/runc/libcontainer/user/lookup_unsupported.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -2,7 +2,10 @@
 | 
			
		||||
 | 
			
		||||
package user
 | 
			
		||||
 | 
			
		||||
import "io"
 | 
			
		||||
import (
 | 
			
		||||
	"io"
 | 
			
		||||
	"syscall"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func GetPasswdPath() (string, error) {
 | 
			
		||||
	return "", ErrUnsupported
 | 
			
		||||
@@ -19,3 +22,17 @@ func GetGroupPath() (string, error) {
 | 
			
		||||
func GetGroup() (io.ReadCloser, error) {
 | 
			
		||||
	return nil, ErrUnsupported
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CurrentUser looks up the current user by their user id in /etc/passwd. If the
 | 
			
		||||
// user cannot be found (or there is no /etc/passwd file on the filesystem),
 | 
			
		||||
// then CurrentUser returns an error.
 | 
			
		||||
func CurrentUser() (User, error) {
 | 
			
		||||
	return LookupUid(syscall.Getuid())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CurrentGroup looks up the current user's group by their primary group id's
 | 
			
		||||
// entry in /etc/passwd. If the group cannot be found (or there is no
 | 
			
		||||
// /etc/group file on the filesystem), then CurrentGroup returns an error.
 | 
			
		||||
func CurrentGroup() (Group, error) {
 | 
			
		||||
	return LookupGid(syscall.Getgid())
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								vendor/github.com/opencontainers/runc/libcontainer/user/user.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/opencontainers/runc/libcontainer/user/user.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -358,8 +358,8 @@ func GetExecUser(userSpec string, defaults *ExecUser, passwd, group io.Reader) (
 | 
			
		||||
 | 
			
		||||
				// Okay, so it's numeric. We can just roll with this.
 | 
			
		||||
			}
 | 
			
		||||
		} else if len(groups) > 0 && uidErr != nil {
 | 
			
		||||
			// Supplementary group ids only make sense if in the implicit form for non-numeric users.
 | 
			
		||||
		} else if len(groups) > 0 {
 | 
			
		||||
			// Supplementary group ids only make sense if in the implicit form.
 | 
			
		||||
			user.Sgids = make([]int, len(groups))
 | 
			
		||||
			for i, group := range groups {
 | 
			
		||||
				user.Sgids[i] = group.Gid
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										5
									
								
								vendor/github.com/opencontainers/runc/vendor.conf
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								vendor/github.com/opencontainers/runc/vendor.conf
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -19,3 +19,8 @@ github.com/docker/docker 0f5c9d301b9b1cca66b3ea0f9dec3b5317d3686d
 | 
			
		||||
github.com/docker/go-units v0.2.0
 | 
			
		||||
github.com/urfave/cli d53eb991652b1d438abdd34ce4bfa3ef1539108e
 | 
			
		||||
golang.org/x/sys 0e0164865330d5cf1c00247be08330bf96e2f87c https://github.com/golang/sys
 | 
			
		||||
 | 
			
		||||
# console dependencies
 | 
			
		||||
github.com/containerd/console 2ce1c681f3c3c0dfa7d0af289428d36567c9a6bc
 | 
			
		||||
github.com/Azure/go-ansiterm fa152c58bc15761d0200cb75fe958b89a9d4888e
 | 
			
		||||
github.com/pkg/errors v0.8.0
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user