Don't rely on XDG_RUNTIME_DIR when running as root

This is one more step towards enabling toolbox(1) to be run as root.
When invoked as 'sudo toolbox' there's no XDG_RUNTIME_DIR available for
the root user. Neither the environment variable nor the directory are
present.

XDG_RUNTIME_DIR is used for two reasons. First, to place the 'lock'
file to synchronize Podman migrations and the initialization stamp
file to synchronize the container's entry point with the user-facing
'enter' command running on the host. Second, it's used to propagate
things like the user D-Bus, Pipewire and Wayland sockets.

The first use-case is important for toolbox(1) itself to work. When
running as root, XDG_RUNTIME_DIR is replaced with /run/toolbox for this
purpose.

The second use-case is mostly ignored because sudo(8) doesn't create
a full-fledged user session. Graphical applications can still work by
connecting to a X11 server over the local abstract socket or the file
system socket in /tmp/.X11-unix.

https://github.com/containers/toolbox/issues/267
This commit is contained in:
Debarshi Ray 2020-10-27 18:43:13 +01:00
parent de2101464c
commit 25b647d635
5 changed files with 87 additions and 29 deletions

View File

@ -191,9 +191,23 @@ func createContainer(container, image, release string, showCommandToEnter bool)
toolboxPathEnvArg := "TOOLBOX_PATH=" + toolboxPath
toolboxPathMountArg := toolboxPath + ":/usr/bin/toolbox:ro"
xdgRuntimeDir := os.Getenv("XDG_RUNTIME_DIR")
xdgRuntimeDirEnvArg := "XDG_RUNTIME_DIR=" + xdgRuntimeDir
xdgRuntimeDirMountArg := xdgRuntimeDir + ":" + xdgRuntimeDir
var runtimeDirectory string
var xdgRuntimeDirEnv []string
if currentUser.Uid == "0" {
runtimeDirectory, err = utils.GetRuntimeDirectory(currentUser)
if err != nil {
return err
}
} else {
xdgRuntimeDir := os.Getenv("XDG_RUNTIME_DIR")
xdgRuntimeDirEnvArg := "XDG_RUNTIME_DIR=" + xdgRuntimeDir
xdgRuntimeDirEnv = []string{"--env", xdgRuntimeDirEnvArg}
runtimeDirectory = xdgRuntimeDir
}
runtimeDirectoryMountArg := runtimeDirectory + ":" + runtimeDirectory
logrus.Debug("Checking if 'podman create' supports '--mount type=devpts'")
@ -337,12 +351,16 @@ func createContainer(container, image, release string, showCommandToEnter bool)
"create",
"--dns", "none",
"--env", toolboxPathEnvArg,
"--env", xdgRuntimeDirEnvArg,
}
createArgs = append(createArgs, xdgRuntimeDirEnv...)
createArgs = append(createArgs, []string{
"--hostname", "toolbox",
"--ipc", "host",
"--label", "com.github.containers.toolbox=true",
"--label", "com.github.debarshiray.toolbox=true",
}
}...)
createArgs = append(createArgs, devPtsMount...)
@ -370,7 +388,7 @@ func createContainer(container, image, release string, showCommandToEnter bool)
"--volume", homeDirMountArg,
"--volume", toolboxPathMountArg,
"--volume", usrMountArg,
"--volume", xdgRuntimeDirMountArg,
"--volume", runtimeDirectoryMountArg,
}...)
createArgs = append(createArgs, kcmSocketMount...)

View File

@ -23,6 +23,7 @@ import (
"os"
"os/user"
"path/filepath"
"strconv"
"strings"
"time"
@ -127,15 +128,7 @@ func initContainer(cmd *cobra.Command, args []string) error {
return errors.New(errMsg)
}
runtimeDirectory := os.Getenv("XDG_RUNTIME_DIR")
if runtimeDirectory == "" {
logrus.Debug("XDG_RUNTIME_DIR is unset")
runtimeDirectory = fmt.Sprintf("/run/user/%d", initContainerFlags.uid)
os.Setenv("XDG_RUNTIME_DIR", runtimeDirectory)
logrus.Debugf("XDG_RUNTIME_DIR set to %s", runtimeDirectory)
}
utils.EnsureXdgRuntimeDirIsSet(initContainerFlags.uid)
logrus.Debug("Creating /run/.toolboxenv")
@ -285,16 +278,15 @@ func initContainer(cmd *cobra.Command, args []string) error {
logrus.Debug("Finished initializing container")
toolboxRuntimeDirectory := runtimeDirectory + "/toolbox"
logrus.Debugf("Creating runtime directory %s", toolboxRuntimeDirectory)
if err := os.MkdirAll(toolboxRuntimeDirectory, 0700); err != nil {
return fmt.Errorf("failed to create runtime directory %s", toolboxRuntimeDirectory)
uidString := strconv.Itoa(initContainerFlags.uid)
targetUser, err := user.LookupId(uidString)
if err != nil {
return fmt.Errorf("failed to lookup user ID %s: %w", uidString, err)
}
if err := os.Chown(toolboxRuntimeDirectory, initContainerFlags.uid, initContainerFlags.uid); err != nil {
return fmt.Errorf("failed to change ownership of the runtime directory %s",
toolboxRuntimeDirectory)
toolboxRuntimeDirectory, err := utils.GetRuntimeDirectory(targetUser)
if err != nil {
return err
}
pid := os.Getpid()

View File

@ -226,10 +226,9 @@ func migrate() error {
return fmt.Errorf("failed to create configuration directory")
}
runtimeDirectory := os.Getenv("XDG_RUNTIME_DIR")
toolboxRuntimeDirectory := runtimeDirectory + "/toolbox"
if err := os.MkdirAll(toolboxRuntimeDirectory, 0700); err != nil {
return fmt.Errorf("failed to create runtime directory %s", toolboxRuntimeDirectory)
toolboxRuntimeDirectory, err := utils.GetRuntimeDirectory(currentUser)
if err != nil {
return err
}
migrateLock := toolboxRuntimeDirectory + "/migrate.lock"

View File

@ -238,8 +238,11 @@ func runCommand(container string,
logrus.Debugf("Waiting for container %s to finish initializing", container)
runtimeDirectory := os.Getenv("XDG_RUNTIME_DIR")
toolboxRuntimeDirectory := runtimeDirectory + "/toolbox"
toolboxRuntimeDirectory, err := utils.GetRuntimeDirectory(currentUser)
if err != nil {
return err
}
initializedStamp := fmt.Sprintf("%s/container-initialized-%d", toolboxRuntimeDirectory, entryPointPID)
logrus.Debugf("Checking if initialization stamp %s exists", initializedStamp)

View File

@ -22,6 +22,7 @@ import (
"os"
"os/exec"
"os/user"
"path"
"path/filepath"
"regexp"
"sort"
@ -174,6 +175,17 @@ func CreateErrorInvalidRelease(executableBase string) error {
return errors.New(errMsg)
}
func EnsureXdgRuntimeDirIsSet(uid int) {
if xdgRuntimeDir, ok := os.LookupEnv("XDG_RUNTIME_DIR"); !ok {
logrus.Debug("XDG_RUNTIME_DIR is unset")
xdgRuntimeDir = fmt.Sprintf("/run/user/%d", uid)
os.Setenv("XDG_RUNTIME_DIR", xdgRuntimeDir)
logrus.Debugf("XDG_RUNTIME_DIR set to %s", xdgRuntimeDir)
}
}
func ForwardToHost() (int, error) {
envOptions := GetEnvOptionsForPreservedVariables()
toolboxPath := os.Getenv("TOOLBOX_PATH")
@ -336,6 +348,40 @@ func GetMountOptions(target string) (string, error) {
return mountOptions, nil
}
func GetRuntimeDirectory(targetUser *user.User) (string, error) {
uid, err := strconv.Atoi(targetUser.Uid)
if err != nil {
return "", fmt.Errorf("failed to convert user ID to integer: %w", err)
}
var runtimeDirectory string
if uid == 0 {
runtimeDirectory = "/run"
} else {
runtimeDirectory = os.Getenv("XDG_RUNTIME_DIR")
}
toolboxRuntimeDirectory := path.Join(runtimeDirectory, "toolbox")
logrus.Debugf("Creating runtime directory %s", toolboxRuntimeDirectory)
if err := os.MkdirAll(toolboxRuntimeDirectory, 0700); err != nil {
wrapped_err := fmt.Errorf("failed to create runtime directory %s: %w",
toolboxRuntimeDirectory,
err)
return "", wrapped_err
}
if err := os.Chown(toolboxRuntimeDirectory, uid, uid); err != nil {
wrapped_err := fmt.Errorf("failed to change ownership of the runtime directory %s: %w",
toolboxRuntimeDirectory,
err)
return "", wrapped_err
}
return toolboxRuntimeDirectory, nil
}
// HumanDuration accepts a Unix time value and converts it into a human readable
// string.
//