Skip to content

Commit

Permalink
Add a warning if tmpdir/rundir are not on tmpfs
Browse files Browse the repository at this point in the history
Podman requires several directories to be on tmpfs so we can
properly detect (and clean up after) reboots: the tmpdir (for
Libpod files) and runroot (for c/storage files). We have not done
any validation that they are actual on tmpfs filesystems in the
past, which leads to no end of people wondering why Podman is
broken on their system (where, perhaps, /tmp is not a tmpfs,
which the FHS allows because sanity cannot exist in this world,
and there is no systemd session so /run/user/$UID does not
exist).

This adds an actual warning on launching Podman with such an
unsupported configuration. There's an environment variable if the
user is certain they want to run Podman like this (perhaps having
used systemd-tmpfiles to automatically clean the relevant dir on
reboot), but otherwise we warn every time a command is run with
runroot/tmpdir on a non-tmpfs filesystem.

Signed-off-by: Matt Heon <[email protected]>
  • Loading branch information
mheon committed Apr 1, 2024
1 parent 631cb95 commit e45a194
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 1 deletion.
2 changes: 2 additions & 0 deletions .cirrus.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ env:
# Runner statistics log file path/name
STATS_LOGFILE_SFX: 'runner_stats.log'
STATS_LOGFILE: '$GOSRC/${CIRRUS_TASK_NAME}-${STATS_LOGFILE_SFX}'
# Disable Podman warnings about /tmp not being a tmpfs
PODMAN_SUPPRESS_TMPFS_WARNING: 'true'

####
#### Cache-image names to test with (double-quotes around names are critical)
Expand Down
2 changes: 1 addition & 1 deletion contrib/cirrus/lib.sh
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ EPOCH_TEST_COMMIT="$CIRRUS_BASE_SHA"
# contexts, such as host->container or root->rootless user
#
# List of envariables which must be EXACT matches
PASSTHROUGH_ENV_EXACT='CGROUP_MANAGER|DEST_BRANCH|DISTRO_NV|GOCACHE|GOPATH|GOSRC|NETWORK_BACKEND|OCI_RUNTIME|PODMAN_IGNORE_CGROUPSV1_WARNING|ROOTLESS_USER|SCRIPT_BASE|SKIP_USERNS|EC2_INST_TYPE|PODMAN_DB|STORAGE_FS'
PASSTHROUGH_ENV_EXACT='CGROUP_MANAGER|DEST_BRANCH|DISTRO_NV|GOCACHE|GOPATH|GOSRC|NETWORK_BACKEND|OCI_RUNTIME|PODMAN_IGNORE_CGROUPSV1_WARNING|ROOTLESS_USER|SCRIPT_BASE|SKIP_USERNS|EC2_INST_TYPE|PODMAN_DB|STORAGE_FS|PODMAN_SUPPRESS_TMPFS_WARNING'

# List of envariable patterns which must match AT THE BEGINNING of the name.
PASSTHROUGH_ENV_ATSTART='CI|LANG|LC_|TEST'
Expand Down
10 changes: 10 additions & 0 deletions libpod/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,16 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (retErr error) {
// refresh runs.
runtime.valid = true

// Is the tmpdir or run root not on a tmpfs?
// If so, throw a very explicit warning that this is not a sane config.
// Allow suppression via an environment variable in case the user is
// very sure (e.g. has configured a service like systemd-tmpfiles to
// clean the dir on reboot).
// Do this very late in init so we can be sure we're not going to turn
// into the rootless userns process (if we did this earlier, we'd print
// this twice).
warnIfNotTmpfs([]string{runtime.config.Engine.TmpDir, runtime.storageConfig.RunRoot})

// If we need to refresh the state, do it now - things are guaranteed to
// be set up by now.
if doRefresh {
Expand Down
6 changes: 6 additions & 0 deletions libpod/runtime_freebsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,11 @@

package libpod


func checkCgroups2UnifiedMode(runtime *Runtime) {
return
}

func warnIfNotTmpfs(paths []string) {
return
}
34 changes: 34 additions & 0 deletions libpod/runtime_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import (
"github.com/sirupsen/logrus"
)

const TmpfsWarningEnvVar = "PODMAN_SUPPRESS_TMPFS_WARNING"

func checkCgroups2UnifiedMode(runtime *Runtime) {
unified, _ := cgroups.IsCgroup2UnifiedMode()
// DELETE ON RHEL9
Expand Down Expand Up @@ -43,3 +45,35 @@ func checkCgroups2UnifiedMode(runtime *Runtime) {
}
}
}

// Print a warning if a path is not on a tmpfs.
func warnIfNotTmpfs(paths []string) {
if os.Getenv(TmpfsWarningEnvVar) != "" {
return
}

notTmpfs := make([]string, 0, len(paths))

for _, path := range paths {
statfs := new(unix.Statfs_t)
if err := unix.Statfs(path, statfs); err != nil {
return
}

if statfs.Type != unix.TMPFS_MAGIC && uint64(statfs.Type) != unix.RAMFS_MAGIC {
notTmpfs = append(notTmpfs, path)
}
}

if len(notTmpfs) == 0 {
return
}

logrus.Warn("The following temporary files directories are not on a tmpfs filesystem:")
for _, path := range notTmpfs {
logrus.Warnf(" %q", path)
}
logrus.Warn("This may cause unpredictable behavior as Podman cannot properly detect and react to system reboots.")
logrus.Warn("It is recommended that you change the path used to one on a tmpfs or mount a tmpfs on the given path.")
logrus.Warnf("If you are certain your configuration is safe and just want to suppress this warning, set the %s environment variable to any non-empty value.", TmpfsWarningEnvVar)
}
21 changes: 21 additions & 0 deletions test/system/005-info.bats
Original file line number Diff line number Diff line change
Expand Up @@ -258,4 +258,25 @@ EOF
run_podman $safe_opts system reset --force
}

@test "podman - warning message on launching Podman with non-tmpfs tmpdir" {
skip_if_remote "Check requires a local Libpod"

# We need a directory that is not tmpfs to put Podman in
OLDTMPFS=$PODMAN_SUPPRESS_TMPFS_WARNING
unset PODMAN_SUPPRESS_TMPFS_WARNING

# Anything that creates a Libpod should trigger the warning.
nottmpfs_tmp=$(mktemp -d /var/tmp)
run_podman --tmpdir=$nottmpfs_tmp/tmp --runroot=$nottmpfs_tmp/runroot --root=$nottmpfs_tmp/root info
assert "$output" =~ "The following temporary files directories are not on a tmpfs filesystem"

# Force a run on tmpfs that should not error
tmpfs_tmp=$(mktemp -d /dev/shm)
run_podman --tmpdir=$tmpfs_tmp/tmp --runroot=$tmpfs_tmp/runroot --root=$tmpfs_tmp/root info
assert "$output" !~ "are not on a tmpfs"
rm -rf $tmpfs_tmp

export PODMAN_SUPPRESS_TMPFS_WARNING=$OLDTMPFS
}

# vim: filetype=sh

0 comments on commit e45a194

Please sign in to comment.