mirror of
https://github.com/containers/podman.git
synced 2025-08-06 19:44:14 +08:00
rootless: enable linger if /run/user/UID not exists
at least on Fedora 30 it creates the /run/user/UID directory for the user logged in via ssh. This needs to be done very early so that every other check when we create the default configuration file will point to the correct location. Closes: https://github.com/containers/libpod/issues/3410 Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
This commit is contained in:
@ -100,7 +100,7 @@ func initConfig() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func before(cmd *cobra.Command, args []string) error {
|
func before(cmd *cobra.Command, args []string) error {
|
||||||
if err := libpod.SetXdgRuntimeDir(""); err != nil {
|
if err := libpod.SetXdgRuntimeDir(); err != nil {
|
||||||
logrus.Errorf(err.Error())
|
logrus.Errorf(err.Error())
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/BurntSushi/toml"
|
"github.com/BurntSushi/toml"
|
||||||
is "github.com/containers/image/storage"
|
is "github.com/containers/image/storage"
|
||||||
@ -312,18 +313,39 @@ func defaultRuntimeConfig() (RuntimeConfig, error) {
|
|||||||
|
|
||||||
// SetXdgRuntimeDir ensures the XDG_RUNTIME_DIR env variable is set
|
// SetXdgRuntimeDir ensures the XDG_RUNTIME_DIR env variable is set
|
||||||
// containers/image uses XDG_RUNTIME_DIR to locate the auth file.
|
// containers/image uses XDG_RUNTIME_DIR to locate the auth file.
|
||||||
func SetXdgRuntimeDir(val string) error {
|
// It internally calls EnableLinger() so that the user's processes are not
|
||||||
|
// killed once the session is terminated. EnableLinger() also attempts to
|
||||||
|
// get the runtime directory when XDG_RUNTIME_DIR is not specified.
|
||||||
|
func SetXdgRuntimeDir() error {
|
||||||
if !rootless.IsRootless() {
|
if !rootless.IsRootless() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if val == "" {
|
|
||||||
|
runtimeDir := os.Getenv("XDG_RUNTIME_DIR")
|
||||||
|
|
||||||
|
runtimeDirLinger, err := rootless.EnableLinger()
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "error enabling user session")
|
||||||
|
}
|
||||||
|
if runtimeDir == "" && runtimeDirLinger != "" {
|
||||||
|
if _, err := os.Stat(runtimeDirLinger); err != nil && os.IsNotExist(err) {
|
||||||
|
chWait := make(chan error)
|
||||||
|
defer close(chWait)
|
||||||
|
if _, err := WaitForFile(runtimeDirLinger, chWait, time.Second*10); err != nil {
|
||||||
|
return errors.Wrapf(err, "waiting for directory '%s'", runtimeDirLinger)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
runtimeDir = runtimeDirLinger
|
||||||
|
}
|
||||||
|
|
||||||
|
if runtimeDir == "" {
|
||||||
var err error
|
var err error
|
||||||
val, err = util.GetRootlessRuntimeDir()
|
runtimeDir, err = util.GetRootlessRuntimeDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := os.Setenv("XDG_RUNTIME_DIR", val); err != nil {
|
if err := os.Setenv("XDG_RUNTIME_DIR", runtimeDir); err != nil {
|
||||||
return errors.Wrapf(err, "cannot set XDG_RUNTIME_DIR")
|
return errors.Wrapf(err, "cannot set XDG_RUNTIME_DIR")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -479,18 +501,6 @@ func newRuntimeFromConfig(ctx context.Context, userConfigPath string, options ..
|
|||||||
runtime.config.SignaturePolicyPath = newPath
|
runtime.config.SignaturePolicyPath = newPath
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
runtimeDir, err := util.GetRootlessRuntimeDir()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// containers/image uses XDG_RUNTIME_DIR to locate the auth file.
|
|
||||||
// So make sure the env variable is set.
|
|
||||||
if err := SetXdgRuntimeDir(runtimeDir); err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "cannot set XDG_RUNTIME_DIR")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if userConfigPath != "" {
|
if userConfigPath != "" {
|
||||||
|
@ -9,14 +9,17 @@ import (
|
|||||||
"os/exec"
|
"os/exec"
|
||||||
gosignal "os/signal"
|
gosignal "os/signal"
|
||||||
"os/user"
|
"os/user"
|
||||||
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/containers/storage/pkg/idtools"
|
"github.com/containers/storage/pkg/idtools"
|
||||||
"github.com/docker/docker/pkg/signal"
|
"github.com/docker/docker/pkg/signal"
|
||||||
|
"github.com/godbus/dbus"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
@ -198,24 +201,90 @@ func getUserNSFirstChild(fd uintptr) (*os.File, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func enableLinger(pausePid string) {
|
// EnableLinger configures the system to not kill the user processes once the session
|
||||||
if pausePid == "" {
|
// terminates
|
||||||
return
|
func EnableLinger() (string, error) {
|
||||||
|
uid := fmt.Sprintf("%d", GetRootlessUID())
|
||||||
|
|
||||||
|
conn, err := dbus.SystemBus()
|
||||||
|
if err == nil {
|
||||||
|
defer conn.Close()
|
||||||
}
|
}
|
||||||
// If we are trying to write a pause pid file, make sure we can leave processes
|
|
||||||
// running longer than the user session.
|
lingerEnabled := false
|
||||||
err := exec.Command("loginctl", "enable-linger", fmt.Sprintf("%d", GetRootlessUID())).Run()
|
|
||||||
|
// If we have a D-BUS connection, attempt to read the LINGER property from it.
|
||||||
|
if conn != nil {
|
||||||
|
path := dbus.ObjectPath((fmt.Sprintf("/org/freedesktop/login1/user/_%s", uid)))
|
||||||
|
ret, err := conn.Object("org.freedesktop.login1", path).GetProperty("org.freedesktop.login1.User.Linger")
|
||||||
|
if err == nil && ret.Value().(bool) {
|
||||||
|
lingerEnabled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xdgRuntimeDir := os.Getenv("XDG_RUNTIME_DIR")
|
||||||
|
lingerFile := ""
|
||||||
|
if xdgRuntimeDir != "" && !lingerEnabled {
|
||||||
|
lingerFile = filepath.Join(xdgRuntimeDir, "libpod/linger")
|
||||||
|
_, err := os.Stat(lingerFile)
|
||||||
|
if err == nil {
|
||||||
|
lingerEnabled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !lingerEnabled {
|
||||||
|
// First attempt with D-BUS, if it fails, then attempt with "loginctl enable-linger"
|
||||||
|
if conn != nil {
|
||||||
|
o := conn.Object("org.freedesktop.login1", "/org/freedesktop/login1")
|
||||||
|
ret := o.Call("org.freedesktop.login1.Manager.SetUserLinger", 0, uint32(GetRootlessUID()), true, true)
|
||||||
|
if ret.Err == nil {
|
||||||
|
lingerEnabled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !lingerEnabled {
|
||||||
|
err := exec.Command("loginctl", "enable-linger", uid).Run()
|
||||||
|
if err == nil {
|
||||||
|
lingerEnabled = true
|
||||||
|
} else {
|
||||||
|
logrus.Debugf("cannot run `loginctl enable-linger` for the current user: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if lingerEnabled && lingerFile != "" {
|
||||||
|
f, err := os.Create(lingerFile)
|
||||||
|
if err == nil {
|
||||||
|
f.Close()
|
||||||
|
} else {
|
||||||
|
logrus.Debugf("could not create linger file: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !lingerEnabled {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have a D-BUS connection, attempt to read the RUNTIME PATH from it.
|
||||||
|
if conn != nil {
|
||||||
|
path := dbus.ObjectPath((fmt.Sprintf("/org/freedesktop/login1/user/_%s", uid)))
|
||||||
|
ret, err := conn.Object("org.freedesktop.login1", path).GetProperty("org.freedesktop.login1.User.RuntimePath")
|
||||||
|
if err == nil {
|
||||||
|
return strings.Trim(ret.String(), "\"\n"), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If XDG_RUNTIME_DIR is not set and the D-BUS call didn't work, try to get the runtime path with "loginctl"
|
||||||
|
output, err := exec.Command("loginctl", "-pRuntimePath", "show-user", uid).Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Warnf("cannot run `loginctl enable-linger` for the current user: %v", err)
|
logrus.Debugf("could not get RuntimePath using loginctl: %v", err)
|
||||||
|
return "", nil
|
||||||
}
|
}
|
||||||
|
return strings.Trim(strings.Replace(string(output), "RuntimePath=", "", -1), "\"\n"), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// joinUserAndMountNS re-exec podman in a new userNS and join the user and mount
|
// joinUserAndMountNS re-exec podman in a new userNS and join the user and mount
|
||||||
// namespace of the specified PID without looking up its parent. Useful to join directly
|
// namespace of the specified PID without looking up its parent. Useful to join directly
|
||||||
// the conmon process.
|
// the conmon process.
|
||||||
func joinUserAndMountNS(pid uint, pausePid string) (bool, int, error) {
|
func joinUserAndMountNS(pid uint, pausePid string) (bool, int, error) {
|
||||||
enableLinger(pausePid)
|
|
||||||
|
|
||||||
if os.Geteuid() == 0 || os.Getenv("_CONTAINERS_USERNS_CONFIGURED") != "" {
|
if os.Geteuid() == 0 || os.Getenv("_CONTAINERS_USERNS_CONFIGURED") != "" {
|
||||||
return false, -1, nil
|
return false, -1, nil
|
||||||
}
|
}
|
||||||
@ -406,7 +475,6 @@ func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (bool,
|
|||||||
// If podman was re-executed the caller needs to propagate the error code returned by the child
|
// If podman was re-executed the caller needs to propagate the error code returned by the child
|
||||||
// process.
|
// process.
|
||||||
func BecomeRootInUserNS(pausePid string) (bool, int, error) {
|
func BecomeRootInUserNS(pausePid string) (bool, int, error) {
|
||||||
enableLinger(pausePid)
|
|
||||||
return becomeRootInUserNS(pausePid, "", nil)
|
return becomeRootInUserNS(pausePid, "", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +29,12 @@ func GetRootlessGID() int {
|
|||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EnableLinger configures the system to not kill the user processes once the session
|
||||||
|
// terminates
|
||||||
|
func EnableLinger() (string, error) {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
// TryJoinFromFilePaths attempts to join the namespaces of the pid files in paths.
|
// TryJoinFromFilePaths attempts to join the namespaces of the pid files in paths.
|
||||||
// This is useful when there are already running containers and we
|
// This is useful when there are already running containers and we
|
||||||
// don't have a pause process yet. We can use the paths to the conmon
|
// don't have a pause process yet. We can use the paths to the conmon
|
||||||
|
Reference in New Issue
Block a user