Update libcontainer to 6cc5158

To pick up the fix in https://github.com/opencontainers/runc/pull/2023

Fixes https://github.com/hashicorp/nomad/issues/5836
This commit is contained in:
Mahmood Ali 2019-06-18 14:36:50 -04:00
parent 5390d71648
commit 0848f577bb
13 changed files with 316 additions and 94 deletions

View file

@ -18,6 +18,10 @@ func UseSystemd() bool {
return false return false
} }
func NewSystemdCgroupsManager() (func(config *configs.Cgroup, paths map[string]string) cgroups.Manager, error) {
return nil, fmt.Errorf("Systemd not supported")
}
func (m *Manager) Apply(pid int) error { func (m *Manager) Apply(pid int) error {
return fmt.Errorf("Systemd not supported") return fmt.Errorf("Systemd not supported")
} }

View file

@ -163,6 +163,18 @@ func UseSystemd() bool {
return hasStartTransientUnit return hasStartTransientUnit
} }
func NewSystemdCgroupsManager() (func(config *configs.Cgroup, paths map[string]string) cgroups.Manager, error) {
if !systemdUtil.IsRunningSystemd() {
return nil, fmt.Errorf("systemd not running on this host, can't use systemd as a cgroups.Manager")
}
return func(config *configs.Cgroup, paths map[string]string) cgroups.Manager {
return &Manager{
Cgroups: config,
Paths: paths,
}
}, nil
}
func (m *Manager) Apply(pid int) error { func (m *Manager) Apply(pid int) error {
var ( var (
c = m.Cgroups c = m.Cgroups

View file

@ -22,6 +22,13 @@ const (
CgroupProcesses = "cgroup.procs" CgroupProcesses = "cgroup.procs"
) )
// HugePageSizeUnitList is a list of the units used by the linux kernel when
// naming the HugePage control files.
// https://www.kernel.org/doc/Documentation/cgroup-v1/hugetlb.txt
// TODO Since the kernel only use KB, MB and GB; TB and PB should be removed,
// depends on https://github.com/docker/go-units/commit/a09cd47f892041a4fac473133d181f5aea6fa393
var HugePageSizeUnitList = []string{"B", "KB", "MB", "GB", "TB", "PB"}
// https://www.kernel.org/doc/Documentation/cgroup-v1/cgroups.txt // https://www.kernel.org/doc/Documentation/cgroup-v1/cgroups.txt
func FindCgroupMountpoint(cgroupPath, subsystem string) (string, error) { func FindCgroupMountpoint(cgroupPath, subsystem string) (string, error) {
mnt, _, err := FindCgroupMountpointAndRoot(cgroupPath, subsystem) mnt, _, err := FindCgroupMountpointAndRoot(cgroupPath, subsystem)
@ -409,19 +416,26 @@ func RemovePaths(paths map[string]string) (err error) {
} }
func GetHugePageSize() ([]string, error) { func GetHugePageSize() ([]string, error) {
var pageSizes []string
sizeList := []string{"B", "kB", "MB", "GB", "TB", "PB"}
files, err := ioutil.ReadDir("/sys/kernel/mm/hugepages") files, err := ioutil.ReadDir("/sys/kernel/mm/hugepages")
if err != nil { if err != nil {
return pageSizes, err return []string{}, err
} }
var fileNames []string
for _, st := range files { for _, st := range files {
nameArray := strings.Split(st.Name(), "-") fileNames = append(fileNames, st.Name())
}
return getHugePageSizeFromFilenames(fileNames)
}
func getHugePageSizeFromFilenames(fileNames []string) ([]string, error) {
var pageSizes []string
for _, fileName := range fileNames {
nameArray := strings.Split(fileName, "-")
pageSize, err := units.RAMInBytes(nameArray[1]) pageSize, err := units.RAMInBytes(nameArray[1])
if err != nil { if err != nil {
return []string{}, err return []string{}, err
} }
sizeString := units.CustomSize("%g%s", float64(pageSize), 1024.0, sizeList) sizeString := units.CustomSize("%g%s", float64(pageSize), 1024.0, HugePageSizeUnitList)
pageSizes = append(pageSizes, sizeString) pageSizes = append(pageSizes, sizeString)
} }

View file

@ -337,6 +337,7 @@ func (c *linuxContainer) start(process *Process) error {
if err != nil { if err != nil {
return newSystemErrorWithCause(err, "creating new parent process") return newSystemErrorWithCause(err, "creating new parent process")
} }
parent.forwardChildLogs()
if err := parent.start(); err != nil { if err := parent.start(); err != nil {
// terminate the process to ensure that it properly is reaped. // terminate the process to ensure that it properly is reaped.
if err := ignoreTerminateErrors(parent.terminate()); err != nil { if err := ignoreTerminateErrors(parent.terminate()); err != nil {
@ -438,16 +439,24 @@ func (c *linuxContainer) includeExecFifo(cmd *exec.Cmd) error {
} }
func (c *linuxContainer) newParentProcess(p *Process) (parentProcess, error) { func (c *linuxContainer) newParentProcess(p *Process) (parentProcess, error) {
parentPipe, childPipe, err := utils.NewSockPair("init") parentInitPipe, childInitPipe, err := utils.NewSockPair("init")
if err != nil { if err != nil {
return nil, newSystemErrorWithCause(err, "creating new init pipe") return nil, newSystemErrorWithCause(err, "creating new init pipe")
} }
cmd, err := c.commandTemplate(p, childPipe) messageSockPair := filePair{parentInitPipe, childInitPipe}
parentLogPipe, childLogPipe, err := os.Pipe()
if err != nil {
return nil, fmt.Errorf("Unable to create the log pipe: %s", err)
}
logFilePair := filePair{parentLogPipe, childLogPipe}
cmd, err := c.commandTemplate(p, childInitPipe, childLogPipe)
if err != nil { if err != nil {
return nil, newSystemErrorWithCause(err, "creating new command template") return nil, newSystemErrorWithCause(err, "creating new command template")
} }
if !p.Init { if !p.Init {
return c.newSetnsProcess(p, cmd, parentPipe, childPipe) return c.newSetnsProcess(p, cmd, messageSockPair, logFilePair)
} }
// We only set up fifoFd if we're not doing a `runc exec`. The historic // We only set up fifoFd if we're not doing a `runc exec`. The historic
@ -458,10 +467,10 @@ func (c *linuxContainer) newParentProcess(p *Process) (parentProcess, error) {
if err := c.includeExecFifo(cmd); err != nil { if err := c.includeExecFifo(cmd); err != nil {
return nil, newSystemErrorWithCause(err, "including execfifo in cmd.Exec setup") return nil, newSystemErrorWithCause(err, "including execfifo in cmd.Exec setup")
} }
return c.newInitProcess(p, cmd, parentPipe, childPipe) return c.newInitProcess(p, cmd, messageSockPair, logFilePair)
} }
func (c *linuxContainer) commandTemplate(p *Process, childPipe *os.File) (*exec.Cmd, error) { func (c *linuxContainer) commandTemplate(p *Process, childInitPipe *os.File, childLogPipe *os.File) (*exec.Cmd, error) {
cmd := exec.Command(c.initPath, c.initArgs[1:]...) cmd := exec.Command(c.initPath, c.initArgs[1:]...)
cmd.Args[0] = c.initArgs[0] cmd.Args[0] = c.initArgs[0]
cmd.Stdin = p.Stdin cmd.Stdin = p.Stdin
@ -479,11 +488,18 @@ func (c *linuxContainer) commandTemplate(p *Process, childPipe *os.File) (*exec.
fmt.Sprintf("_LIBCONTAINER_CONSOLE=%d", stdioFdCount+len(cmd.ExtraFiles)-1), fmt.Sprintf("_LIBCONTAINER_CONSOLE=%d", stdioFdCount+len(cmd.ExtraFiles)-1),
) )
} }
cmd.ExtraFiles = append(cmd.ExtraFiles, childPipe) cmd.ExtraFiles = append(cmd.ExtraFiles, childInitPipe)
cmd.Env = append(cmd.Env, cmd.Env = append(cmd.Env,
fmt.Sprintf("_LIBCONTAINER_INITPIPE=%d", stdioFdCount+len(cmd.ExtraFiles)-1), fmt.Sprintf("_LIBCONTAINER_INITPIPE=%d", stdioFdCount+len(cmd.ExtraFiles)-1),
fmt.Sprintf("_LIBCONTAINER_STATEDIR=%s", c.root), fmt.Sprintf("_LIBCONTAINER_STATEDIR=%s", c.root),
) )
cmd.ExtraFiles = append(cmd.ExtraFiles, childLogPipe)
cmd.Env = append(cmd.Env,
fmt.Sprintf("_LIBCONTAINER_LOGPIPE=%d", stdioFdCount+len(cmd.ExtraFiles)-1),
fmt.Sprintf("_LIBCONTAINER_LOGLEVEL=%s", p.LogLevel),
)
// NOTE: when running a container with no PID namespace and the parent process spawning the container is // NOTE: when running a container with no PID namespace and the parent process spawning the container is
// PID1 the pdeathsig is being delivered to the container's init process by the kernel for some reason // PID1 the pdeathsig is being delivered to the container's init process by the kernel for some reason
// even with the parent still running. // even with the parent still running.
@ -493,7 +509,7 @@ func (c *linuxContainer) commandTemplate(p *Process, childPipe *os.File) (*exec.
return cmd, nil return cmd, nil
} }
func (c *linuxContainer) newInitProcess(p *Process, cmd *exec.Cmd, parentPipe, childPipe *os.File) (*initProcess, error) { func (c *linuxContainer) newInitProcess(p *Process, cmd *exec.Cmd, messageSockPair, logFilePair filePair) (*initProcess, error) {
cmd.Env = append(cmd.Env, "_LIBCONTAINER_INITTYPE="+string(initStandard)) cmd.Env = append(cmd.Env, "_LIBCONTAINER_INITTYPE="+string(initStandard))
nsMaps := make(map[configs.NamespaceType]string) nsMaps := make(map[configs.NamespaceType]string)
for _, ns := range c.config.Namespaces { for _, ns := range c.config.Namespaces {
@ -508,8 +524,8 @@ func (c *linuxContainer) newInitProcess(p *Process, cmd *exec.Cmd, parentPipe, c
} }
init := &initProcess{ init := &initProcess{
cmd: cmd, cmd: cmd,
childPipe: childPipe, messageSockPair: messageSockPair,
parentPipe: parentPipe, logFilePair: logFilePair,
manager: c.cgroupManager, manager: c.cgroupManager,
intelRdtManager: c.intelRdtManager, intelRdtManager: c.intelRdtManager,
config: c.newInitConfig(p), config: c.newInitConfig(p),
@ -522,7 +538,7 @@ func (c *linuxContainer) newInitProcess(p *Process, cmd *exec.Cmd, parentPipe, c
return init, nil return init, nil
} }
func (c *linuxContainer) newSetnsProcess(p *Process, cmd *exec.Cmd, parentPipe, childPipe *os.File) (*setnsProcess, error) { func (c *linuxContainer) newSetnsProcess(p *Process, cmd *exec.Cmd, messageSockPair, logFilePair filePair) (*setnsProcess, error) {
cmd.Env = append(cmd.Env, "_LIBCONTAINER_INITTYPE="+string(initSetns)) cmd.Env = append(cmd.Env, "_LIBCONTAINER_INITTYPE="+string(initSetns))
state, err := c.currentState() state, err := c.currentState()
if err != nil { if err != nil {
@ -539,8 +555,8 @@ func (c *linuxContainer) newSetnsProcess(p *Process, cmd *exec.Cmd, parentPipe,
cgroupPaths: c.cgroupManager.GetPaths(), cgroupPaths: c.cgroupManager.GetPaths(),
rootlessCgroups: c.config.RootlessCgroups, rootlessCgroups: c.config.RootlessCgroups,
intelRdtPath: state.IntelRdtPath, intelRdtPath: state.IntelRdtPath,
childPipe: childPipe, messageSockPair: messageSockPair,
parentPipe: parentPipe, logFilePair: logFilePair,
config: c.newInitConfig(p), config: c.newInitConfig(p),
process: p, process: p,
bootstrapData: data, bootstrapData: data,

View file

@ -51,12 +51,11 @@ func InitArgs(args ...string) func(*LinuxFactory) error {
// SystemdCgroups is an options func to configure a LinuxFactory to return // SystemdCgroups is an options func to configure a LinuxFactory to return
// containers that use systemd to create and manage cgroups. // containers that use systemd to create and manage cgroups.
func SystemdCgroups(l *LinuxFactory) error { func SystemdCgroups(l *LinuxFactory) error {
l.NewCgroupsManager = func(config *configs.Cgroup, paths map[string]string) cgroups.Manager { systemdCgroupsManager, err := systemd.NewSystemdCgroupsManager()
return &systemd.Manager{ if err != nil {
Cgroups: config, return err
Paths: paths,
}
} }
l.NewCgroupsManager = systemdCgroupsManager
return nil return nil
} }

View file

@ -0,0 +1,102 @@
package logs
import (
"bufio"
"encoding/json"
"fmt"
"io"
"os"
"strconv"
"sync"
"github.com/sirupsen/logrus"
)
var (
configureMutex = sync.Mutex{}
// loggingConfigured will be set once logging has been configured via invoking `ConfigureLogging`.
// Subsequent invocations of `ConfigureLogging` would be no-op
loggingConfigured = false
)
type Config struct {
LogLevel logrus.Level
LogFormat string
LogFilePath string
LogPipeFd string
}
func ForwardLogs(logPipe io.Reader) {
lineReader := bufio.NewReader(logPipe)
for {
line, err := lineReader.ReadBytes('\n')
if len(line) > 0 {
processEntry(line)
}
if err == io.EOF {
logrus.Debugf("log pipe has been closed: %+v", err)
return
}
if err != nil {
logrus.Errorf("log pipe read error: %+v", err)
}
}
}
func processEntry(text []byte) {
type jsonLog struct {
Level string `json:"level"`
Msg string `json:"msg"`
}
var jl jsonLog
if err := json.Unmarshal(text, &jl); err != nil {
logrus.Errorf("failed to decode %q to json: %+v", text, err)
return
}
lvl, err := logrus.ParseLevel(jl.Level)
if err != nil {
logrus.Errorf("failed to parse log level %q: %v\n", jl.Level, err)
return
}
logrus.StandardLogger().Logf(lvl, jl.Msg)
}
func ConfigureLogging(config Config) error {
configureMutex.Lock()
defer configureMutex.Unlock()
if loggingConfigured {
logrus.Debug("logging has already been configured")
return nil
}
logrus.SetLevel(config.LogLevel)
if config.LogPipeFd != "" {
logPipeFdInt, err := strconv.Atoi(config.LogPipeFd)
if err != nil {
return fmt.Errorf("failed to convert _LIBCONTAINER_LOGPIPE environment variable value %q to int: %v", config.LogPipeFd, err)
}
logrus.SetOutput(os.NewFile(uintptr(logPipeFdInt), "logpipe"))
} else if config.LogFilePath != "" {
f, err := os.OpenFile(config.LogFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND|os.O_SYNC, 0644)
if err != nil {
return err
}
logrus.SetOutput(f)
}
switch config.LogFormat {
case "text":
// retain logrus's default.
case "json":
logrus.SetFormatter(new(logrus.JSONFormatter))
default:
return fmt.Errorf("unknown log-format %q", config.LogFormat)
}
loggingConfigured = true
return nil
}

View file

@ -37,9 +37,6 @@ enum sync_t {
SYNC_RECVPID_ACK = 0x43, /* PID was correctly received by parent. */ SYNC_RECVPID_ACK = 0x43, /* PID was correctly received by parent. */
SYNC_GRANDCHILD = 0x44, /* The grandchild is ready to run. */ SYNC_GRANDCHILD = 0x44, /* The grandchild is ready to run. */
SYNC_CHILD_READY = 0x45, /* The child or grandchild is ready to return. */ SYNC_CHILD_READY = 0x45, /* The child or grandchild is ready to return. */
/* XXX: This doesn't help with segfaults and other such issues. */
SYNC_ERR = 0xFF, /* Fatal error, no turning back. The error code follows. */
}; };
/* /*
@ -95,6 +92,15 @@ struct nlconfig_t {
size_t gidmappath_len; size_t gidmappath_len;
}; };
#define PANIC "panic"
#define FATAL "fatal"
#define ERROR "error"
#define WARNING "warning"
#define INFO "info"
#define DEBUG "debug"
static int logfd = -1;
/* /*
* List of netlink message types sent to us as part of bootstrapping the init. * List of netlink message types sent to us as part of bootstrapping the init.
* These constants are defined in libcontainer/message_linux.go. * These constants are defined in libcontainer/message_linux.go.
@ -131,22 +137,34 @@ int setns(int fd, int nstype)
} }
#endif #endif
static void write_log_with_info(const char *level, const char *function, int line, const char *format, ...)
{
char message[1024] = {};
va_list args;
if (logfd < 0 || level == NULL)
return;
va_start(args, format);
if (vsnprintf(message, sizeof(message), format, args) < 0)
return;
va_end(args);
if (dprintf(logfd, "{\"level\":\"%s\", \"msg\": \"%s:%d %s\"}\n", level, function, line, message) < 0)
return;
}
#define write_log(level, fmt, ...) \
write_log_with_info((level), __FUNCTION__, __LINE__, (fmt), ##__VA_ARGS__)
/* XXX: This is ugly. */ /* XXX: This is ugly. */
static int syncfd = -1; static int syncfd = -1;
/* TODO(cyphar): Fix this so it correctly deals with syncT. */
#define bail(fmt, ...) \ #define bail(fmt, ...) \
do { \ do { \
int ret = __COUNTER__ + 1; \ write_log(FATAL, "nsenter: " fmt ": %m", ##__VA_ARGS__); \
fprintf(stderr, "nsenter: " fmt ": %m\n", ##__VA_ARGS__); \ exit(1); \
if (syncfd >= 0) { \
enum sync_t s = SYNC_ERR; \
if (write(syncfd, &s, sizeof(s)) != sizeof(s)) \
fprintf(stderr, "nsenter: failed: write(s)"); \
if (write(syncfd, &ret, sizeof(ret)) != sizeof(ret)) \
fprintf(stderr, "nsenter: failed: write(ret)"); \
} \
exit(ret); \
} while(0) } while(0)
static int write_file(char *data, size_t data_len, char *pathfmt, ...) static int write_file(char *data, size_t data_len, char *pathfmt, ...)
@ -352,6 +370,23 @@ static int initpipe(void)
return pipenum; return pipenum;
} }
static void setup_logpipe(void)
{
char *logpipe, *endptr;
logpipe = getenv("_LIBCONTAINER_LOGPIPE");
if (logpipe == NULL || *logpipe == '\0') {
return;
}
logfd = strtol(logpipe, &endptr, 10);
if (logpipe == endptr || *endptr != '\0') {
fprintf(stderr, "unable to parse _LIBCONTAINER_LOGPIPE, value: %s\n", logpipe);
/* It is too early to use bail */
exit(1);
}
}
/* Returns the clone(2) flag for a namespace, given the name of a namespace. */ /* Returns the clone(2) flag for a namespace, given the name of a namespace. */
static int nsflag(char *name) static int nsflag(char *name)
{ {
@ -544,6 +579,12 @@ void nsexec(void)
int sync_child_pipe[2], sync_grandchild_pipe[2]; int sync_child_pipe[2], sync_grandchild_pipe[2];
struct nlconfig_t config = { 0 }; struct nlconfig_t config = { 0 };
/*
* Setup a pipe to send logs to the parent. This should happen
* first, because bail will use that pipe.
*/
setup_logpipe();
/* /*
* If we don't have an init pipe, just return to the go routine. * If we don't have an init pipe, just return to the go routine.
* We'll only get an init pipe for start or exec. * We'll only get an init pipe for start or exec.
@ -560,6 +601,8 @@ void nsexec(void)
if (ensure_cloned_binary() < 0) if (ensure_cloned_binary() < 0)
bail("could not ensure we are a cloned binary"); bail("could not ensure we are a cloned binary");
write_log(DEBUG, "nsexec started");
/* Parse all of the netlink configuration. */ /* Parse all of the netlink configuration. */
nl_parse(pipenum, &config); nl_parse(pipenum, &config);
@ -676,7 +719,6 @@ void nsexec(void)
*/ */
while (!ready) { while (!ready) {
enum sync_t s; enum sync_t s;
int ret;
syncfd = sync_child_pipe[1]; syncfd = sync_child_pipe[1];
close(sync_child_pipe[0]); close(sync_child_pipe[0]);
@ -685,12 +727,6 @@ void nsexec(void)
bail("failed to sync with child: next state"); bail("failed to sync with child: next state");
switch (s) { switch (s) {
case SYNC_ERR:
/* We have to mirror the error code of the child. */
if (read(syncfd, &ret, sizeof(ret)) != sizeof(ret))
bail("failed to sync with child: read(error code)");
exit(ret);
case SYNC_USERMAP_PLS: case SYNC_USERMAP_PLS:
/* /*
* Enable setgroups(2) if we've been asked to. But we also * Enable setgroups(2) if we've been asked to. But we also
@ -759,7 +795,6 @@ void nsexec(void)
ready = false; ready = false;
while (!ready) { while (!ready) {
enum sync_t s; enum sync_t s;
int ret;
syncfd = sync_grandchild_pipe[1]; syncfd = sync_grandchild_pipe[1];
close(sync_grandchild_pipe[0]); close(sync_grandchild_pipe[0]);
@ -774,12 +809,6 @@ void nsexec(void)
bail("failed to sync with child: next state"); bail("failed to sync with child: next state");
switch (s) { switch (s) {
case SYNC_ERR:
/* We have to mirror the error code of the child. */
if (read(syncfd, &ret, sizeof(ret)) != sizeof(ret))
bail("failed to sync with child: read(error code)");
exit(ret);
case SYNC_CHILD_READY: case SYNC_CHILD_READY:
ready = true; ready = true;
break; break;

View file

@ -76,6 +76,8 @@ type Process struct {
Init bool Init bool
ops processOperations ops processOperations
LogLevel string
} }
// Wait waits for the process to exit. // Wait waits for the process to exit.

View file

@ -16,6 +16,7 @@ import (
"github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/cgroups"
"github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/libcontainer/configs"
"github.com/opencontainers/runc/libcontainer/intelrdt" "github.com/opencontainers/runc/libcontainer/intelrdt"
"github.com/opencontainers/runc/libcontainer/logs"
"github.com/opencontainers/runc/libcontainer/system" "github.com/opencontainers/runc/libcontainer/system"
"github.com/opencontainers/runc/libcontainer/utils" "github.com/opencontainers/runc/libcontainer/utils"
@ -47,12 +48,19 @@ type parentProcess interface {
externalDescriptors() []string externalDescriptors() []string
setExternalDescriptors(fds []string) setExternalDescriptors(fds []string)
forwardChildLogs()
}
type filePair struct {
parent *os.File
child *os.File
} }
type setnsProcess struct { type setnsProcess struct {
cmd *exec.Cmd cmd *exec.Cmd
parentPipe *os.File messageSockPair filePair
childPipe *os.File logFilePair filePair
cgroupPaths map[string]string cgroupPaths map[string]string
rootlessCgroups bool rootlessCgroups bool
intelRdtPath string intelRdtPath string
@ -76,14 +84,16 @@ func (p *setnsProcess) signal(sig os.Signal) error {
} }
func (p *setnsProcess) start() (err error) { func (p *setnsProcess) start() (err error) {
defer p.parentPipe.Close() defer p.messageSockPair.parent.Close()
err = p.cmd.Start() err = p.cmd.Start()
p.childPipe.Close() // close the write-side of the pipes (controlled by child)
p.messageSockPair.child.Close()
p.logFilePair.child.Close()
if err != nil { if err != nil {
return newSystemErrorWithCause(err, "starting setns process") return newSystemErrorWithCause(err, "starting setns process")
} }
if p.bootstrapData != nil { if p.bootstrapData != nil {
if _, err := io.Copy(p.parentPipe, p.bootstrapData); err != nil { if _, err := io.Copy(p.messageSockPair.parent, p.bootstrapData); err != nil {
return newSystemErrorWithCause(err, "copying bootstrap data to pipe") return newSystemErrorWithCause(err, "copying bootstrap data to pipe")
} }
} }
@ -109,11 +119,11 @@ func (p *setnsProcess) start() (err error) {
if err := setupRlimits(p.config.Rlimits, p.pid()); err != nil { if err := setupRlimits(p.config.Rlimits, p.pid()); err != nil {
return newSystemErrorWithCause(err, "setting rlimits for process") return newSystemErrorWithCause(err, "setting rlimits for process")
} }
if err := utils.WriteJSON(p.parentPipe, p.config); err != nil { if err := utils.WriteJSON(p.messageSockPair.parent, p.config); err != nil {
return newSystemErrorWithCause(err, "writing config to pipe") return newSystemErrorWithCause(err, "writing config to pipe")
} }
ierr := parseSync(p.parentPipe, func(sync *syncT) error { ierr := parseSync(p.messageSockPair.parent, func(sync *syncT) error {
switch sync.Type { switch sync.Type {
case procReady: case procReady:
// This shouldn't happen. // This shouldn't happen.
@ -126,7 +136,7 @@ func (p *setnsProcess) start() (err error) {
} }
}) })
if err := unix.Shutdown(int(p.parentPipe.Fd()), unix.SHUT_WR); err != nil { if err := unix.Shutdown(int(p.messageSockPair.parent.Fd()), unix.SHUT_WR); err != nil {
return newSystemErrorWithCause(err, "calling shutdown on init pipe") return newSystemErrorWithCause(err, "calling shutdown on init pipe")
} }
// Must be done after Shutdown so the child will exit and we can wait for it. // Must be done after Shutdown so the child will exit and we can wait for it.
@ -152,16 +162,14 @@ func (p *setnsProcess) execSetns() error {
return newSystemError(&exec.ExitError{ProcessState: status}) return newSystemError(&exec.ExitError{ProcessState: status})
} }
var pid *pid var pid *pid
if err := json.NewDecoder(p.parentPipe).Decode(&pid); err != nil { if err := json.NewDecoder(p.messageSockPair.parent).Decode(&pid); err != nil {
p.cmd.Wait() p.cmd.Wait()
return newSystemErrorWithCause(err, "reading pid from init pipe") return newSystemErrorWithCause(err, "reading pid from init pipe")
} }
// Clean up the zombie parent process // Clean up the zombie parent process
firstChildProcess, err := os.FindProcess(pid.PidFirstChild) // On Unix systems FindProcess always succeeds.
if err != nil { firstChildProcess, _ := os.FindProcess(pid.PidFirstChild)
return err
}
// Ignore the error in case the child has already been reaped for any reason // Ignore the error in case the child has already been reaped for any reason
_, _ = firstChildProcess.Wait() _, _ = firstChildProcess.Wait()
@ -207,10 +215,14 @@ func (p *setnsProcess) setExternalDescriptors(newFds []string) {
p.fds = newFds p.fds = newFds
} }
func (p *setnsProcess) forwardChildLogs() {
go logs.ForwardLogs(p.logFilePair.parent)
}
type initProcess struct { type initProcess struct {
cmd *exec.Cmd cmd *exec.Cmd
parentPipe *os.File messageSockPair filePair
childPipe *os.File logFilePair filePair
config *initConfig config *initConfig
manager cgroups.Manager manager cgroups.Manager
intelRdtManager intelrdt.Manager intelRdtManager intelrdt.Manager
@ -232,10 +244,18 @@ func (p *initProcess) externalDescriptors() []string {
// getChildPid receives the final child's pid over the provided pipe. // getChildPid receives the final child's pid over the provided pipe.
func (p *initProcess) getChildPid() (int, error) { func (p *initProcess) getChildPid() (int, error) {
var pid pid var pid pid
if err := json.NewDecoder(p.parentPipe).Decode(&pid); err != nil { if err := json.NewDecoder(p.messageSockPair.parent).Decode(&pid); err != nil {
p.cmd.Wait() p.cmd.Wait()
return -1, err return -1, err
} }
// Clean up the zombie parent process
// On Unix systems FindProcess always succeeds.
firstChildProcess, _ := os.FindProcess(pid.PidFirstChild)
// Ignore the error in case the child has already been reaped for any reason
_, _ = firstChildProcess.Wait()
return pid.Pid, nil return pid.Pid, nil
} }
@ -260,10 +280,12 @@ func (p *initProcess) waitForChildExit(childPid int) error {
} }
func (p *initProcess) start() error { func (p *initProcess) start() error {
defer p.parentPipe.Close() defer p.messageSockPair.parent.Close()
err := p.cmd.Start() err := p.cmd.Start()
p.process.ops = p p.process.ops = p
p.childPipe.Close() // close the write-side of the pipes (controlled by child)
p.messageSockPair.child.Close()
p.logFilePair.child.Close()
if err != nil { if err != nil {
p.process.ops = nil p.process.ops = nil
return newSystemErrorWithCause(err, "starting init process command") return newSystemErrorWithCause(err, "starting init process command")
@ -289,7 +311,7 @@ func (p *initProcess) start() error {
} }
}() }()
if _, err := io.Copy(p.parentPipe, p.bootstrapData); err != nil { if _, err := io.Copy(p.messageSockPair.parent, p.bootstrapData); err != nil {
return newSystemErrorWithCause(err, "copying bootstrap data to pipe") return newSystemErrorWithCause(err, "copying bootstrap data to pipe")
} }
childPid, err := p.getChildPid() childPid, err := p.getChildPid()
@ -317,7 +339,7 @@ func (p *initProcess) start() error {
} }
// Now it's time to setup cgroup namesapce // Now it's time to setup cgroup namesapce
if p.config.Config.Namespaces.Contains(configs.NEWCGROUP) && p.config.Config.Namespaces.PathOf(configs.NEWCGROUP) == "" { if p.config.Config.Namespaces.Contains(configs.NEWCGROUP) && p.config.Config.Namespaces.PathOf(configs.NEWCGROUP) == "" {
if _, err := p.parentPipe.Write([]byte{createCgroupns}); err != nil { if _, err := p.messageSockPair.parent.Write([]byte{createCgroupns}); err != nil {
return newSystemErrorWithCause(err, "sending synchronization value to init process") return newSystemErrorWithCause(err, "sending synchronization value to init process")
} }
} }
@ -331,6 +353,9 @@ func (p *initProcess) start() error {
if err != nil { if err != nil {
// TODO: should not be the responsibility to call here // TODO: should not be the responsibility to call here
p.manager.Destroy() p.manager.Destroy()
if p.intelRdtManager != nil {
p.intelRdtManager.Destroy()
}
} }
}() }()
if err := p.createNetworkInterfaces(); err != nil { if err := p.createNetworkInterfaces(); err != nil {
@ -344,7 +369,7 @@ func (p *initProcess) start() error {
sentResume bool sentResume bool
) )
ierr := parseSync(p.parentPipe, func(sync *syncT) error { ierr := parseSync(p.messageSockPair.parent, func(sync *syncT) error {
switch sync.Type { switch sync.Type {
case procReady: case procReady:
// set rlimits, this has to be done here because we lose permissions // set rlimits, this has to be done here because we lose permissions
@ -380,7 +405,7 @@ func (p *initProcess) start() error {
} }
} }
// Sync with child. // Sync with child.
if err := writeSync(p.parentPipe, procRun); err != nil { if err := writeSync(p.messageSockPair.parent, procRun); err != nil {
return newSystemErrorWithCause(err, "writing syncT 'run'") return newSystemErrorWithCause(err, "writing syncT 'run'")
} }
sentRun = true sentRun = true
@ -409,7 +434,7 @@ func (p *initProcess) start() error {
} }
} }
// Sync with child. // Sync with child.
if err := writeSync(p.parentPipe, procResume); err != nil { if err := writeSync(p.messageSockPair.parent, procResume); err != nil {
return newSystemErrorWithCause(err, "writing syncT 'resume'") return newSystemErrorWithCause(err, "writing syncT 'resume'")
} }
sentResume = true sentResume = true
@ -426,7 +451,7 @@ func (p *initProcess) start() error {
if p.config.Config.Namespaces.Contains(configs.NEWNS) && !sentResume { if p.config.Config.Namespaces.Contains(configs.NEWNS) && !sentResume {
return newSystemError(fmt.Errorf("could not synchronise after executing prestart hooks with container process")) return newSystemError(fmt.Errorf("could not synchronise after executing prestart hooks with container process"))
} }
if err := unix.Shutdown(int(p.parentPipe.Fd()), unix.SHUT_WR); err != nil { if err := unix.Shutdown(int(p.messageSockPair.parent.Fd()), unix.SHUT_WR); err != nil {
return newSystemErrorWithCause(err, "shutting down init pipe") return newSystemErrorWithCause(err, "shutting down init pipe")
} }
@ -470,7 +495,7 @@ func (p *initProcess) sendConfig() error {
// send the config to the container's init process, we don't use JSON Encode // send the config to the container's init process, we don't use JSON Encode
// here because there might be a problem in JSON decoder in some cases, see: // here because there might be a problem in JSON decoder in some cases, see:
// https://github.com/docker/docker/issues/14203#issuecomment-174177790 // https://github.com/docker/docker/issues/14203#issuecomment-174177790
return utils.WriteJSON(p.parentPipe, p.config) return utils.WriteJSON(p.messageSockPair.parent, p.config)
} }
func (p *initProcess) createNetworkInterfaces() error { func (p *initProcess) createNetworkInterfaces() error {
@ -502,6 +527,10 @@ func (p *initProcess) setExternalDescriptors(newFds []string) {
p.fds = newFds p.fds = newFds
} }
func (p *initProcess) forwardChildLogs() {
go logs.ForwardLogs(p.logFilePair.parent)
}
func getPipeFds(pid int) ([]string, error) { func getPipeFds(pid int) ([]string, error) {
fds := make([]string, 3) fds := make([]string, 3)

View file

@ -76,6 +76,9 @@ func (p *restoredProcess) setExternalDescriptors(newFds []string) {
p.fds = newFds p.fds = newFds
} }
func (p *restoredProcess) forwardChildLogs() {
}
// nonChildProcess represents a process where the calling process is not // nonChildProcess represents a process where the calling process is not
// the parent process. This process is created when a factory loads a container from // the parent process. This process is created when a factory loads a container from
// a persisted state. // a persisted state.
@ -120,3 +123,6 @@ func (p *nonChildProcess) externalDescriptors() []string {
func (p *nonChildProcess) setExternalDescriptors(newFds []string) { func (p *nonChildProcess) setExternalDescriptors(newFds []string) {
p.fds = newFds p.fds = newFds
} }
func (p *nonChildProcess) forwardChildLogs() {
}

View file

@ -34,6 +34,10 @@ func (l *linuxSetnsInit) Init() error {
defer runtime.UnlockOSThread() defer runtime.UnlockOSThread()
if !l.config.Config.NoNewKeyring { if !l.config.Config.NoNewKeyring {
if err := label.SetKeyLabel(l.config.ProcessLabel); err != nil {
return err
}
defer label.SetKeyLabel("")
// Do not inherit the parent's session keyring. // Do not inherit the parent's session keyring.
if _, err := keys.JoinSessionKeyring(l.getSessionRingName()); err != nil { if _, err := keys.JoinSessionKeyring(l.getSessionRingName()); err != nil {
// Same justification as in standart_init_linux.go as to why we // Same justification as in standart_init_linux.go as to why we

View file

@ -48,6 +48,10 @@ func (l *linuxStandardInit) Init() error {
runtime.LockOSThread() runtime.LockOSThread()
defer runtime.UnlockOSThread() defer runtime.UnlockOSThread()
if !l.config.Config.NoNewKeyring { if !l.config.Config.NoNewKeyring {
if err := label.SetKeyLabel(l.config.ProcessLabel); err != nil {
return err
}
defer label.SetKeyLabel("")
ringname, keepperms, newperms := l.getSessionRingParams() ringname, keepperms, newperms := l.getSessionRingParams()
// Do not inherit the parent's session keyring. // Do not inherit the parent's session keyring.

35
vendor/vendor.json vendored
View file

@ -303,24 +303,25 @@
{"path":"github.com/opencontainers/go-digest","checksumSHA1":"NTperEHVh1uBqfTy9+oKceN4tKI=","revision":"21dfd564fd89c944783d00d069f33e3e7123c448","revisionTime":"2017-01-11T18:16:59Z"}, {"path":"github.com/opencontainers/go-digest","checksumSHA1":"NTperEHVh1uBqfTy9+oKceN4tKI=","revision":"21dfd564fd89c944783d00d069f33e3e7123c448","revisionTime":"2017-01-11T18:16:59Z"},
{"path":"github.com/opencontainers/image-spec/specs-go","checksumSHA1":"ZGlIwSRjdLYCUII7JLE++N4w7Xc=","revision":"89b51c794e9113108a2914e38e66c826a649f2b5","revisionTime":"2017-11-03T11:36:04Z"}, {"path":"github.com/opencontainers/image-spec/specs-go","checksumSHA1":"ZGlIwSRjdLYCUII7JLE++N4w7Xc=","revision":"89b51c794e9113108a2914e38e66c826a649f2b5","revisionTime":"2017-11-03T11:36:04Z"},
{"path":"github.com/opencontainers/image-spec/specs-go/v1","checksumSHA1":"jdbXRRzeu0njLE9/nCEZG+Yg/Jk=","revision":"89b51c794e9113108a2914e38e66c826a649f2b5","revisionTime":"2017-11-03T11:36:04Z"}, {"path":"github.com/opencontainers/image-spec/specs-go/v1","checksumSHA1":"jdbXRRzeu0njLE9/nCEZG+Yg/Jk=","revision":"89b51c794e9113108a2914e38e66c826a649f2b5","revisionTime":"2017-11-03T11:36:04Z"},
{"path":"github.com/opencontainers/runc/libcontainer","checksumSHA1":"tS+X1UWBpwuDSk+lC8JelSKpzpQ=","revision":"f56b4cbeadc407e715d9b2ba49e62185bd81cef4","revisionTime":"2019-03-16T06:30:56Z"}, {"path":"github.com/opencontainers/runc/libcontainer","checksumSHA1":"OJlgvnpJuV+SDPW48YVUKWDbOnU=","revision":"6cc515888830787a93d82138821f0309ad970640","revisionTime":"2019-06-11T12:12:36Z"},
{"path":"github.com/opencontainers/runc/libcontainer/apparmor","checksumSHA1":"gVVY8k2G3ws+V1czsfxfuRs8log=","revision":"f56b4cbeadc407e715d9b2ba49e62185bd81cef4","revisionTime":"2019-03-16T06:30:56Z"}, {"path":"github.com/opencontainers/runc/libcontainer/apparmor","checksumSHA1":"gVVY8k2G3ws+V1czsfxfuRs8log=","revision":"6cc515888830787a93d82138821f0309ad970640","revisionTime":"2019-06-11T12:12:36Z"},
{"path":"github.com/opencontainers/runc/libcontainer/cgroups","checksumSHA1":"Ku9h5AOZZyF7LIoruJ26Ut+1WRI=","revision":"f56b4cbeadc407e715d9b2ba49e62185bd81cef4","revisionTime":"2019-03-16T06:30:56Z"}, {"path":"github.com/opencontainers/runc/libcontainer/cgroups","checksumSHA1":"aWtm1zkVCz9l2/zQNfnc246yQew=","revision":"6cc515888830787a93d82138821f0309ad970640","revisionTime":"2019-06-11T12:12:36Z"},
{"path":"github.com/opencontainers/runc/libcontainer/cgroups/fs","checksumSHA1":"OnnBJ2WfB/Y9EQpABKetBedf6ts=","revision":"f56b4cbeadc407e715d9b2ba49e62185bd81cef4","revisionTime":"2019-03-16T06:30:56Z"}, {"path":"github.com/opencontainers/runc/libcontainer/cgroups/fs","checksumSHA1":"OnnBJ2WfB/Y9EQpABKetBedf6ts=","revision":"6cc515888830787a93d82138821f0309ad970640","revisionTime":"2019-06-11T12:12:36Z"},
{"path":"github.com/opencontainers/runc/libcontainer/cgroups/systemd","checksumSHA1":"941jSDfCIl+b1pIQwZ9r+wj8wvM=","revision":"f56b4cbeadc407e715d9b2ba49e62185bd81cef4","revisionTime":"2019-03-16T06:30:56Z"}, {"path":"github.com/opencontainers/runc/libcontainer/cgroups/systemd","checksumSHA1":"d7B9MiKb1k1Egh5qkNokIfcZ+OY=","revision":"6cc515888830787a93d82138821f0309ad970640","revisionTime":"2019-06-11T12:12:36Z"},
{"path":"github.com/opencontainers/runc/libcontainer/configs","checksumSHA1":"v9sgw4eYRNSsJUSG33OoFIwLqRI=","revision":"f56b4cbeadc407e715d9b2ba49e62185bd81cef4","revisionTime":"2019-03-16T06:30:56Z"}, {"path":"github.com/opencontainers/runc/libcontainer/configs","checksumSHA1":"v9sgw4eYRNSsJUSG33OoFIwLqRI=","revision":"6cc515888830787a93d82138821f0309ad970640","revisionTime":"2019-06-11T12:12:36Z"},
{"path":"github.com/opencontainers/runc/libcontainer/configs/validate","checksumSHA1":"hUveFGK1HhGenf0OVoYZWccoW9I=","revision":"f56b4cbeadc407e715d9b2ba49e62185bd81cef4","revisionTime":"2019-03-16T06:30:56Z"}, {"path":"github.com/opencontainers/runc/libcontainer/configs/validate","checksumSHA1":"hUveFGK1HhGenf0OVoYZWccoW9I=","revision":"6cc515888830787a93d82138821f0309ad970640","revisionTime":"2019-06-11T12:12:36Z"},
{"path":"github.com/opencontainers/runc/libcontainer/criurpc","checksumSHA1":"n7G7Egz/tOPacXuq+nkvnFai3eU=","revision":"369b920277d27630441336775cd728bc0f19e496","revisionTime":"2018-09-07T18:53:11Z"}, {"path":"github.com/opencontainers/runc/libcontainer/criurpc","checksumSHA1":"n7G7Egz/tOPacXuq+nkvnFai3eU=","revision":"369b920277d27630441336775cd728bc0f19e496","revisionTime":"2018-09-07T18:53:11Z"},
{"path":"github.com/opencontainers/runc/libcontainer/devices","checksumSHA1":"2CwtFvz9kB0RSjFlcCkmq4taJ9U=","revision":"f56b4cbeadc407e715d9b2ba49e62185bd81cef4","revisionTime":"2019-03-16T06:30:56Z"}, {"path":"github.com/opencontainers/runc/libcontainer/devices","checksumSHA1":"2CwtFvz9kB0RSjFlcCkmq4taJ9U=","revision":"6cc515888830787a93d82138821f0309ad970640","revisionTime":"2019-06-11T12:12:36Z"},
{"path":"github.com/opencontainers/runc/libcontainer/intelrdt","checksumSHA1":"sAbowQ7hjveSH5ADUD9IYXnEAJM=","revision":"f56b4cbeadc407e715d9b2ba49e62185bd81cef4","revisionTime":"2019-03-16T06:30:56Z"}, {"path":"github.com/opencontainers/runc/libcontainer/intelrdt","checksumSHA1":"sAbowQ7hjveSH5ADUD9IYXnEAJM=","revision":"6cc515888830787a93d82138821f0309ad970640","revisionTime":"2019-06-11T12:12:36Z"},
{"path":"github.com/opencontainers/runc/libcontainer/keys","checksumSHA1":"mKxBw0il2IWjWYgksX+17ufDw34=","revision":"f56b4cbeadc407e715d9b2ba49e62185bd81cef4","revisionTime":"2019-03-16T06:30:56Z"}, {"path":"github.com/opencontainers/runc/libcontainer/keys","checksumSHA1":"mKxBw0il2IWjWYgksX+17ufDw34=","revision":"6cc515888830787a93d82138821f0309ad970640","revisionTime":"2019-06-11T12:12:36Z"},
{"path":"github.com/opencontainers/runc/libcontainer/mount","checksumSHA1":"MJiogPDUU2nFr1fzQU6T+Ry1W8o=","revision":"f56b4cbeadc407e715d9b2ba49e62185bd81cef4","revisionTime":"2019-03-16T06:30:56Z"}, {"path":"github.com/opencontainers/runc/libcontainer/logs","checksumSHA1":"mBbwlspKSImoGTw4uKE40AX3PYs=","revision":"6cc515888830787a93d82138821f0309ad970640","revisionTime":"2019-06-11T12:12:36Z"},
{"path":"github.com/opencontainers/runc/libcontainer/nsenter","checksumSHA1":"VKq3tOnDPQsnwc4g3qXLlqkVt4g=","revision":"f56b4cbeadc407e715d9b2ba49e62185bd81cef4","revisionTime":"2019-03-16T06:30:56Z"}, {"path":"github.com/opencontainers/runc/libcontainer/mount","checksumSHA1":"MJiogPDUU2nFr1fzQU6T+Ry1W8o=","revision":"6cc515888830787a93d82138821f0309ad970640","revisionTime":"2019-06-11T12:12:36Z"},
{"path":"github.com/opencontainers/runc/libcontainer/seccomp","checksumSHA1":"I1Qw/btE1twMqKHpYNsC98cteak=","revision":"f56b4cbeadc407e715d9b2ba49e62185bd81cef4","revisionTime":"2019-03-16T06:30:56Z"}, {"path":"github.com/opencontainers/runc/libcontainer/nsenter","checksumSHA1":"PnGFQdbZhZ4pcxFtQep5MEQ4/8E=","revision":"6cc515888830787a93d82138821f0309ad970640","revisionTime":"2019-06-11T12:12:36Z"},
{"path":"github.com/opencontainers/runc/libcontainer/stacktrace","checksumSHA1":"yp/kYBgVqKtxlnpq4CmyxLFMAE4=","revision":"f56b4cbeadc407e715d9b2ba49e62185bd81cef4","revisionTime":"2019-03-16T06:30:56Z"}, {"path":"github.com/opencontainers/runc/libcontainer/seccomp","checksumSHA1":"I1Qw/btE1twMqKHpYNsC98cteak=","revision":"6cc515888830787a93d82138821f0309ad970640","revisionTime":"2019-06-11T12:12:36Z"},
{"path":"github.com/opencontainers/runc/libcontainer/system","checksumSHA1":"cjg/UcueM1/2/ExZ3N7010sa+hI=","revision":"f56b4cbeadc407e715d9b2ba49e62185bd81cef4","revisionTime":"2019-03-16T06:30:56Z"}, {"path":"github.com/opencontainers/runc/libcontainer/stacktrace","checksumSHA1":"yp/kYBgVqKtxlnpq4CmyxLFMAE4=","revision":"6cc515888830787a93d82138821f0309ad970640","revisionTime":"2019-06-11T12:12:36Z"},
{"path":"github.com/opencontainers/runc/libcontainer/user","checksumSHA1":"mdUukOXCVJxmT0CufSKDeMg5JFM=","revision":"f56b4cbeadc407e715d9b2ba49e62185bd81cef4","revisionTime":"2019-03-16T06:30:56Z"}, {"path":"github.com/opencontainers/runc/libcontainer/system","checksumSHA1":"cjg/UcueM1/2/ExZ3N7010sa+hI=","revision":"6cc515888830787a93d82138821f0309ad970640","revisionTime":"2019-06-11T12:12:36Z"},
{"path":"github.com/opencontainers/runc/libcontainer/utils","checksumSHA1":"PqGgeBjTHnyGrTr5ekLFEXpC3iQ=","revision":"f56b4cbeadc407e715d9b2ba49e62185bd81cef4","revisionTime":"2019-03-16T06:30:56Z"}, {"path":"github.com/opencontainers/runc/libcontainer/user","checksumSHA1":"mdUukOXCVJxmT0CufSKDeMg5JFM=","revision":"6cc515888830787a93d82138821f0309ad970640","revisionTime":"2019-06-11T12:12:36Z"},
{"path":"github.com/opencontainers/runc/libcontainer/utils","checksumSHA1":"PqGgeBjTHnyGrTr5ekLFEXpC3iQ=","revision":"6cc515888830787a93d82138821f0309ad970640","revisionTime":"2019-06-11T12:12:36Z"},
{"path":"github.com/opencontainers/runtime-spec/specs-go","checksumSHA1":"AMYc2X2O/IL6EGrq6lTl5vEhLiY=","origin":"github.com/opencontainers/runc/vendor/github.com/opencontainers/runtime-spec/specs-go","revision":"459bfaec1fc6c17d8bfb12d0a0f69e7e7271ed2a","revisionTime":"2018-08-23T14:46:37Z"}, {"path":"github.com/opencontainers/runtime-spec/specs-go","checksumSHA1":"AMYc2X2O/IL6EGrq6lTl5vEhLiY=","origin":"github.com/opencontainers/runc/vendor/github.com/opencontainers/runtime-spec/specs-go","revision":"459bfaec1fc6c17d8bfb12d0a0f69e7e7271ed2a","revisionTime":"2018-08-23T14:46:37Z"},
{"path":"github.com/opencontainers/selinux/go-selinux","checksumSHA1":"j9efF9bPmCCag+LzqwjyB8a44B8=","origin":"github.com/opencontainers/runc/vendor/github.com/opencontainers/selinux/go-selinux","revision":"459bfaec1fc6c17d8bfb12d0a0f69e7e7271ed2a","revisionTime":"2018-08-23T14:46:37Z"}, {"path":"github.com/opencontainers/selinux/go-selinux","checksumSHA1":"j9efF9bPmCCag+LzqwjyB8a44B8=","origin":"github.com/opencontainers/runc/vendor/github.com/opencontainers/selinux/go-selinux","revision":"459bfaec1fc6c17d8bfb12d0a0f69e7e7271ed2a","revisionTime":"2018-08-23T14:46:37Z"},
{"path":"github.com/opencontainers/selinux/go-selinux/label","checksumSHA1":"QbeVoKIoaJWZDH8V/588i8/Pjjs=","origin":"github.com/opencontainers/runc/vendor/github.com/opencontainers/selinux/go-selinux/label","revision":"459bfaec1fc6c17d8bfb12d0a0f69e7e7271ed2a","revisionTime":"2018-08-23T14:46:37Z"}, {"path":"github.com/opencontainers/selinux/go-selinux/label","checksumSHA1":"QbeVoKIoaJWZDH8V/588i8/Pjjs=","origin":"github.com/opencontainers/runc/vendor/github.com/opencontainers/selinux/go-selinux/label","revision":"459bfaec1fc6c17d8bfb12d0a0f69e7e7271ed2a","revisionTime":"2018-08-23T14:46:37Z"},