Browse code

homedir: remove idtools and libcontainer's user package dependencies

About github.com/opencontainers/runc/libcontainer/user:

According to https://github.com/opencontainers/runc/commit/195d8d544aca731301d8116821c75e1244dd5a0c
this package has two functions:
- Have a static implementation of user lookup, which is now supported in the
os/user stdlib package with the osusergo build tag, but wasn't at the time.
- Have extra functions that os/user doesn't have, but none of those are used
in homedir.

Since https://github.com/moby/moby/pull/11287, homedir depended directly on
libcontainer's user package for CurrentUser().
This is being replaced with os/user.Current(), because all of our static
binaries are compiled with the osusergo tag, and for dynamic libraries it
is more correct to use libc's implementation than parsing /etc/passwd.

About github.com/docker/docker/pkg/idtools:

Only dependency was from GetStatic() which uses idtools.LookupUID(uid).
The implementation of idtools.LookupUID just calls to
github.com/opencontainers/runc/libcontainer/user.LookupUid or fallbacks
to exec-ing to getent (since https://github.com/moby/moby/pull/27599).

This patch replaces calls to homedir.GetStatic by homedir.Get(), opting out
of supporting nss lookups in static binaries via exec-ing to getent for
the homedir package.

If homedir package users need to support nss lookups, they are advised
to compile dynamically instead.

Signed-off-by: Tibor Vass <tibor@docker.com>

Tibor Vass authored on 2019/09/24 07:16:38
Showing 4 changed files
... ...
@@ -11,17 +11,15 @@ import (
11 11
 // ensureHomeIfIAmStatic ensure $HOME to be set if dockerversion.IAmStatic is "true".
12 12
 // See issue #29344: gcplogs segfaults (static binary)
13 13
 // If HOME is not set, logging.NewClient() will call os/user.Current() via oauth2/google.
14
-// However, in static binary, os/user.Current() leads to segfault due to a glibc issue that won't be fixed
15
-// in a short term. (golang/go#13470, https://sourceware.org/bugzilla/show_bug.cgi?id=19341)
14
+// If compiling statically, make sure osusergo build tag is also used to prevent a segfault
15
+// due to a glibc issue that won't be fixed in a short term
16
+// (see golang/go#13470, https://sourceware.org/bugzilla/show_bug.cgi?id=19341).
16 17
 // So we forcibly set HOME so as to avoid call to os/user/Current()
17 18
 func ensureHomeIfIAmStatic() error {
18
-	// Note: dockerversion.IAmStatic and homedir.GetStatic() is only available for linux.
19
+	// Note: dockerversion.IAmStatic is only available for linux.
19 20
 	// So we need to use them in this gcplogging_linux.go rather than in gcplogging.go
20 21
 	if dockerversion.IAmStatic == "true" && os.Getenv("HOME") == "" {
21
-		home, err := homedir.GetStatic()
22
-		if err != nil {
23
-			return err
24
-		}
22
+		home := homedir.Get()
25 23
 		logrus.Warnf("gcplogs requires HOME to be set for static daemon binary. Forcibly setting HOME to %s.", home)
26 24
 		os.Setenv("HOME", home)
27 25
 	}
... ...
@@ -5,24 +5,8 @@ import (
5 5
 	"os"
6 6
 	"path/filepath"
7 7
 	"strings"
8
-
9
-	"github.com/docker/docker/pkg/idtools"
10 8
 )
11 9
 
12
-// GetStatic returns the home directory for the current user without calling
13
-// os/user.Current(). This is useful for static-linked binary on glibc-based
14
-// system, because a call to os/user.Current() in a static binary leads to
15
-// segfault due to a glibc issue that won't be fixed in a short term.
16
-// (#29344, golang/go#13470, https://sourceware.org/bugzilla/show_bug.cgi?id=19341)
17
-func GetStatic() (string, error) {
18
-	uid := os.Getuid()
19
-	usr, err := idtools.LookupUID(uid)
20
-	if err != nil {
21
-		return "", err
22
-	}
23
-	return usr.Home, nil
24
-}
25
-
26 10
 // GetRuntimeDir returns XDG_RUNTIME_DIR.
27 11
 // XDG_RUNTIME_DIR is typically configured via pam_systemd.
28 12
 // GetRuntimeDir returns non-nil error if XDG_RUNTIME_DIR is not set.
... ...
@@ -6,12 +6,6 @@ import (
6 6
 	"errors"
7 7
 )
8 8
 
9
-// GetStatic is not needed for non-linux systems.
10
-// (Precisely, it is needed only for glibc-based linux systems.)
11
-func GetStatic() (string, error) {
12
-	return "", errors.New("homedir.GetStatic() is not supported on this system")
13
-}
14
-
15 9
 // GetRuntimeDir is unsupported on non-linux system.
16 10
 func GetRuntimeDir() (string, error) {
17 11
 	return "", errors.New("homedir.GetRuntimeDir() is not supported on this system")
... ...
@@ -4,8 +4,7 @@ package homedir // import "github.com/docker/docker/pkg/homedir"
4 4
 
5 5
 import (
6 6
 	"os"
7
-
8
-	"github.com/opencontainers/runc/libcontainer/user"
7
+	"os/user"
9 8
 )
10 9
 
11 10
 // Key returns the env var name for the user's home dir based on
... ...
@@ -17,11 +16,13 @@ func Key() string {
17 17
 // Get returns the home directory of the current user with the help of
18 18
 // environment variables depending on the target operating system.
19 19
 // Returned path should be used with "path/filepath" to form new paths.
20
+// If compiling statically, ensure the osusergo build tag is used.
21
+// If needing to do nss lookups, do not compile statically.
20 22
 func Get() string {
21 23
 	home := os.Getenv(Key())
22 24
 	if home == "" {
23
-		if u, err := user.CurrentUser(); err == nil {
24
-			return u.Home
25
+		if u, err := user.Current(); err == nil {
26
+			return u.HomeDir
25 27
 		}
26 28
 	}
27 29
 	return home