Prechádzať zdrojové kódy

Merge pull request #45198 from tianon/libexec-docker-init

Prefer loading `docker-init` from an appropriate "libexec" directory
Sebastiaan van Stijn 2 rokov pred
rodič
commit
0d761d19b9
3 zmenil súbory, kde vykonal 43 pridanie a 17 odobranie
  1. 28 0
      daemon/config/config_linux.go
  2. 12 10
      daemon/info_unix.go
  3. 3 7
      daemon/oci_linux.go

+ 28 - 0
daemon/config/config_linux.go

@@ -118,6 +118,34 @@ func (conf *Config) GetInitPath() string {
 	return DefaultInitBinary
 }
 
+// LookupInitPath returns an absolute path to the "docker-init" binary by searching relevant "libexec" directories (per FHS 3.0 & 2.3) followed by PATH
+func (conf *Config) LookupInitPath() (string, error) {
+	binary := conf.GetInitPath()
+	if filepath.IsAbs(binary) {
+		return binary, nil
+	}
+
+	for _, dir := range []string{
+		// FHS 3.0: "/usr/libexec includes internal binaries that are not intended to be executed directly by users or shell scripts. Applications may use a single subdirectory under /usr/libexec."
+		// https://refspecs.linuxfoundation.org/FHS_3.0/fhs/ch04s07.html
+		"/usr/local/libexec/docker",
+		"/usr/libexec/docker",
+
+		// FHS 2.3: "/usr/lib includes object files, libraries, and internal binaries that are not intended to be executed directly by users or shell scripts."
+		// https://refspecs.linuxfoundation.org/FHS_2.3/fhs-2.3.html#USRLIBLIBRARIESFORPROGRAMMINGANDPA
+		"/usr/local/lib/docker",
+		"/usr/lib/docker",
+	} {
+		// exec.LookPath has a fast-path short-circuit for paths that contain "/" (skipping the PATH lookup) that then verifies whether the given path is likely to be an actual executable binary (so we invoke that instead of reimplementing the same checks)
+		if file, err := exec.LookPath(filepath.Join(dir, binary)); err == nil {
+			return file, nil
+		}
+	}
+
+	// if we checked all the "libexec" directories and found no matches, fall back to PATH
+	return exec.LookPath(binary)
+}
+
 // GetResolvConf returns the appropriate resolv.conf
 // Check setupResolvConf on how this is selected
 func (conf *Config) GetResolvConf() string {

+ 12 - 10
daemon/info_unix.go

@@ -40,7 +40,6 @@ func (daemon *Daemon) fillPlatformInfo(v *types.Info, sysInfo *sysinfo.SysInfo)
 	}
 	v.Runtimes = daemon.configStore.GetAllRuntimes()
 	v.DefaultRuntime = daemon.configStore.GetDefaultRuntimeName()
-	v.InitBinary = daemon.configStore.GetInitPath()
 	v.RuncCommit.ID = "N/A"
 	v.ContainerdCommit.ID = "N/A"
 	v.InitCommit.ID = "N/A"
@@ -63,15 +62,17 @@ func (daemon *Daemon) fillPlatformInfo(v *types.Info, sysInfo *sysinfo.SysInfo)
 		logrus.Warnf("failed to retrieve containerd version: %v", err)
 	}
 
-	defaultInitBinary := daemon.configStore.GetInitPath()
-	if rv, err := exec.Command(defaultInitBinary, "--version").Output(); err == nil {
+	v.InitBinary = daemon.configStore.GetInitPath()
+	if initBinary, err := daemon.configStore.LookupInitPath(); err != nil {
+		logrus.Warnf("failed to find docker-init: %s", err)
+	} else if rv, err := exec.Command(initBinary, "--version").Output(); err == nil {
 		if _, commit, err := parseInitVersion(string(rv)); err != nil {
-			logrus.Warnf("failed to parse %s version: %s", defaultInitBinary, err)
+			logrus.Warnf("failed to parse %s version: %s", initBinary, err)
 		} else {
 			v.InitCommit.ID = commit
 		}
 	} else {
-		logrus.Warnf("failed to retrieve %s version: %s", defaultInitBinary, err)
+		logrus.Warnf("failed to retrieve %s version: %s", initBinary, err)
 	}
 
 	// Set expected and actual commits to the same value to prevent the client
@@ -195,13 +196,14 @@ func (daemon *Daemon) fillPlatformVersion(v *types.Version) {
 		}
 	}
 
-	defaultInitBinary := daemon.configStore.GetInitPath()
-	if rv, err := exec.Command(defaultInitBinary, "--version").Output(); err == nil {
+	if initBinary, err := daemon.configStore.LookupInitPath(); err != nil {
+		logrus.Warnf("failed to find docker-init: %s", err)
+	} else if rv, err := exec.Command(initBinary, "--version").Output(); err == nil {
 		if ver, commit, err := parseInitVersion(string(rv)); err != nil {
-			logrus.Warnf("failed to parse %s version: %s", defaultInitBinary, err)
+			logrus.Warnf("failed to parse %s version: %s", initBinary, err)
 		} else {
 			v.Components = append(v.Components, types.ComponentVersion{
-				Name:    filepath.Base(defaultInitBinary),
+				Name:    filepath.Base(initBinary),
 				Version: ver,
 				Details: map[string]string{
 					"GitCommit": commit,
@@ -209,7 +211,7 @@ func (daemon *Daemon) fillPlatformVersion(v *types.Version) {
 			})
 		}
 	} else {
-		logrus.Warnf("failed to retrieve %s version: %s", defaultInitBinary, err)
+		logrus.Warnf("failed to retrieve %s version: %s", initBinary, err)
 	}
 
 	daemon.fillRootlessVersion(v)

+ 3 - 7
daemon/oci_linux.go

@@ -4,7 +4,6 @@ import (
 	"context"
 	"fmt"
 	"os"
-	"os/exec"
 	"path/filepath"
 	"sort"
 	"strconv"
@@ -748,12 +747,9 @@ func WithCommonOptions(daemon *Daemon, c *container.Container) coci.SpecOpts {
 			if (c.HostConfig.Init != nil && *c.HostConfig.Init) ||
 				(c.HostConfig.Init == nil && daemon.configStore.Init) {
 				s.Process.Args = append([]string{inContainerInitPath, "--", c.Path}, c.Args...)
-				path := daemon.configStore.InitPath
-				if path == "" {
-					path, err = exec.LookPath(dconfig.DefaultInitBinary)
-					if err != nil {
-						return err
-					}
+				path, err := daemon.configStore.LookupInitPath() // this will fall back to DefaultInitBinary and return an absolute path
+				if err != nil {
+					return err
 				}
 				s.Mounts = append(s.Mounts, specs.Mount{
 					Destination: inContainerInitPath,