From 2a295a8a59fd37d35ec3576dc2a753105cb84b38 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Fri, 18 Feb 2022 16:28:54 -0800 Subject: [PATCH] libct: move StartInitialization from factory to init This is where it should belong. No code changes, just cut-n-paste. Signed-off-by: Kir Kolyshkin --- libcontainer/factory_linux.go | 105 ---------------------------------- libcontainer/init_linux.go | 105 ++++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 105 deletions(-) diff --git a/libcontainer/factory_linux.go b/libcontainer/factory_linux.go index 0469745c145..101c0fa7994 100644 --- a/libcontainer/factory_linux.go +++ b/libcontainer/factory_linux.go @@ -6,8 +6,6 @@ import ( "fmt" "os" "regexp" - "runtime/debug" - "strconv" securejoin "github.com/cyphar/filepath-securejoin" "golang.org/x/sys/unix" @@ -154,109 +152,6 @@ func Load(root, id string) (*Container, error) { return c, nil } -// StartInitialization loads a container by opening the pipe fd from the parent -// to read the configuration and state. This is a low level implementation -// detail of the reexec and should not be consumed externally. -func StartInitialization() (err error) { - // Set up logging. - level := int(logrus.DebugLevel) // default to debug - // Passing log level is optional; currently libcontainer/integration does not do it. - if levelStr := os.Getenv("_LIBCONTAINER_LOGLEVEL"); levelStr != "" { - level, err = strconv.Atoi(levelStr) - if err != nil { - panic(fmt.Errorf("unable to convert _LIBCONTAINER_LOGLEVEL: %w", err)) - } - } - - logPipeFd, err := strconv.Atoi(os.Getenv("_LIBCONTAINER_LOGPIPE")) - if err != nil { - panic(fmt.Errorf("unable to convert _LIBCONTAINER_LOGPIPE: %w", err)) - } - - logrus.SetLevel(logrus.Level(level)) - logrus.SetOutput(os.NewFile(uintptr(logPipeFd), "logpipe")) - logrus.SetFormatter(new(logrus.JSONFormatter)) - logrus.Debug("child process in init()") - - // Once logging is all set, we can use logrus to log errors. - - // Get the INITPIPE. - envInitPipe := os.Getenv("_LIBCONTAINER_INITPIPE") - pipefd, err := strconv.Atoi(envInitPipe) - if err != nil { - err = fmt.Errorf("unable to convert _LIBCONTAINER_INITPIPE: %w", err) - logrus.Error(err) - return err - } - pipe := os.NewFile(uintptr(pipefd), "pipe") - defer pipe.Close() - - // Once init pipe is set, we can send error back to parent. If this - // defer is ever called, this means initialization has failed. - defer func() { - // We have an error during the initialization of the container's init, - // send it back to the parent process in the form of an initError. - if werr := writeSync(pipe, procError); werr != nil { - fmt.Fprintln(os.Stderr, err) - return - } - if werr := utils.WriteJSON(pipe, &initError{Message: err.Error()}); werr != nil { - fmt.Fprintln(os.Stderr, err) - return - } - }() - - // Only init processes have FIFOFD. - fifofd := -1 - envInitType := os.Getenv("_LIBCONTAINER_INITTYPE") - it := initType(envInitType) - if it == initStandard { - envFifoFd := os.Getenv("_LIBCONTAINER_FIFOFD") - if fifofd, err = strconv.Atoi(envFifoFd); err != nil { - return fmt.Errorf("unable to convert _LIBCONTAINER_FIFOFD: %w", err) - } - } - - var consoleSocket *os.File - if envConsole := os.Getenv("_LIBCONTAINER_CONSOLE"); envConsole != "" { - console, err := strconv.Atoi(envConsole) - if err != nil { - return fmt.Errorf("unable to convert _LIBCONTAINER_CONSOLE: %w", err) - } - consoleSocket = os.NewFile(uintptr(console), "console-socket") - defer consoleSocket.Close() - } - - // Get mount files (O_PATH). - mountFds, err := parseMountFds() - if err != nil { - return err - } - - // clear the current process's environment to clean any libcontainer - // specific env vars. - os.Clearenv() - - defer func() { - if e := recover(); e != nil { - if e, ok := e.(error); ok { - err = fmt.Errorf("panic from initialization: %w, %s", e, debug.Stack()) - } else { - //nolint:errorlint // here e is not of error type - err = fmt.Errorf("panic from initialization: %v, %s", e, debug.Stack()) - } - } - }() - - i, err := newContainerInit(it, pipe, consoleSocket, fifofd, logPipeFd, mountFds) - if err != nil { - return err - } - - // If Init succeeds, syscall.Exec will not return, hence none of the defers will be called. - return i.Init() -} - func loadState(root string) (*State, error) { stateFilePath, err := securejoin.SecureJoin(root, stateFilename) if err != nil { diff --git a/libcontainer/init_linux.go b/libcontainer/init_linux.go index 8e8d3abd93d..dc69ecdc89b 100644 --- a/libcontainer/init_linux.go +++ b/libcontainer/init_linux.go @@ -8,6 +8,8 @@ import ( "io" "net" "os" + "runtime/debug" + "strconv" "strings" "unsafe" @@ -71,6 +73,109 @@ type initConfig struct { Cgroup2Path string `json:"cgroup2_path,omitempty"` } +// StartInitialization loads a container by opening the pipe fd from the parent +// to read the configuration and state. This is a low level implementation +// detail of the reexec and should not be consumed externally. +func StartInitialization() (err error) { + // Set up logging. + level := int(logrus.DebugLevel) // default to debug + // Passing log level is optional; currently libcontainer/integration does not do it. + if levelStr := os.Getenv("_LIBCONTAINER_LOGLEVEL"); levelStr != "" { + level, err = strconv.Atoi(levelStr) + if err != nil { + panic(fmt.Errorf("unable to convert _LIBCONTAINER_LOGLEVEL: %w", err)) + } + } + + logPipeFd, err := strconv.Atoi(os.Getenv("_LIBCONTAINER_LOGPIPE")) + if err != nil { + panic(fmt.Errorf("unable to convert _LIBCONTAINER_LOGPIPE: %w", err)) + } + + logrus.SetLevel(logrus.Level(level)) + logrus.SetOutput(os.NewFile(uintptr(logPipeFd), "logpipe")) + logrus.SetFormatter(new(logrus.JSONFormatter)) + logrus.Debug("child process in init()") + + // Once logging is all set, we can use logrus to log errors. + + // Get the INITPIPE. + envInitPipe := os.Getenv("_LIBCONTAINER_INITPIPE") + pipefd, err := strconv.Atoi(envInitPipe) + if err != nil { + err = fmt.Errorf("unable to convert _LIBCONTAINER_INITPIPE: %w", err) + logrus.Error(err) + return err + } + pipe := os.NewFile(uintptr(pipefd), "pipe") + defer pipe.Close() + + // Once init pipe is set, we can send error back to parent. If this + // defer is ever called, this means initialization has failed. + defer func() { + // We have an error during the initialization of the container's init, + // send it back to the parent process in the form of an initError. + if werr := writeSync(pipe, procError); werr != nil { + fmt.Fprintln(os.Stderr, err) + return + } + if werr := utils.WriteJSON(pipe, &initError{Message: err.Error()}); werr != nil { + fmt.Fprintln(os.Stderr, err) + return + } + }() + + // Only init processes have FIFOFD. + fifofd := -1 + envInitType := os.Getenv("_LIBCONTAINER_INITTYPE") + it := initType(envInitType) + if it == initStandard { + envFifoFd := os.Getenv("_LIBCONTAINER_FIFOFD") + if fifofd, err = strconv.Atoi(envFifoFd); err != nil { + return fmt.Errorf("unable to convert _LIBCONTAINER_FIFOFD: %w", err) + } + } + + var consoleSocket *os.File + if envConsole := os.Getenv("_LIBCONTAINER_CONSOLE"); envConsole != "" { + console, err := strconv.Atoi(envConsole) + if err != nil { + return fmt.Errorf("unable to convert _LIBCONTAINER_CONSOLE: %w", err) + } + consoleSocket = os.NewFile(uintptr(console), "console-socket") + defer consoleSocket.Close() + } + + // Get mount files (O_PATH). + mountFds, err := parseMountFds() + if err != nil { + return err + } + + // clear the current process's environment to clean any libcontainer + // specific env vars. + os.Clearenv() + + defer func() { + if e := recover(); e != nil { + if e, ok := e.(error); ok { + err = fmt.Errorf("panic from initialization: %w, %s", e, debug.Stack()) + } else { + //nolint:errorlint // here e is not of error type + err = fmt.Errorf("panic from initialization: %v, %s", e, debug.Stack()) + } + } + }() + + i, err := newContainerInit(it, pipe, consoleSocket, fifofd, logPipeFd, mountFds) + if err != nil { + return err + } + + // If Init succeeds, syscall.Exec will not return, hence none of the defers will be called. + return i.Init() +} + type initer interface { Init() error }