Skip to content

Commit

Permalink
Prefer loading docker-init from an appropriate "libexec" directory
Browse files Browse the repository at this point in the history
The `docker-init` binary is not intended to be a user-facing command, and as such it is more appropriate for it to be found in `/usr/libexec` (or similar) than in `PATH` (see the FHS, especially https://refspecs.linuxfoundation.org/FHS_3.0/fhs/ch04s07.html and https://refspecs.linuxfoundation.org/FHS_2.3/fhs-2.3.html#USRLIBLIBRARIESFORPROGRAMMINGANDPA).

This adjusts the logic for using that configuration option to take this into account and appropriately search for `docker-init` (or the user's configured alternative) in these directories before falling back to the existing `PATH` lookup behavior.

This behavior _used_ to exist for the old `dockerinit` binary (of a similar name and used in a similar way but for an alternative purpose), but that behavior was removed in 4357ed4 when that older `dockerinit` was also removed.

Most of this reasoning _also_ applies to `docker-proxy` (and various `containerd-xxx` binaries such as the shims), but this change does not affect those.  It would be relatively straightforward to adapt `LookupInitPath` to be a more generic function such as `libexecLookupPath` or similar if we wanted to explore that.

See https://github.com/docker/cli/blob/14482589df194a86b2ee07df643ba3277b40df7d/cli-plugins/manager/manager_unix.go for the related path list in the CLI which loads CLI plugins from a similar set of paths (with a similar rationale - plugin binaries are not typically intended to be run directly by users but rather invoked _via_ the CLI binary).

Signed-off-by: Tianon Gravi <admwiggin@gmail.com>
  • Loading branch information
tianon committed Mar 24, 2023
1 parent 1855a55 commit 6caaa8c
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 17 deletions.
28 changes: 28 additions & 0 deletions daemon/config/config_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
22 changes: 12 additions & 10 deletions daemon/info_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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
Expand Down Expand Up @@ -195,21 +196,22 @@ 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,
},
})
}
} else {
logrus.Warnf("failed to retrieve %s version: %s", defaultInitBinary, err)
logrus.Warnf("failed to retrieve %s version: %s", initBinary, err)
}

daemon.fillRootlessVersion(v)
Expand Down
10 changes: 3 additions & 7 deletions daemon/oci_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"fmt"
"os"
"os/exec"
"path/filepath"
"sort"
"strconv"
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit 6caaa8c

Please sign in to comment.