mirror of
https://github.com/safedep/pmg.git
synced 2026-08-03 07:24:09 +02:00
fix: fall back to env path resolution when root has no passwd entry
Running as uid 0 without a resolvable root passwd entry (scratch containers, minimal chroots) panicked at startup on every command, because the euid-based path resolution had no fallback. Fall back to env-derived resolution there: without a passwd database there is no user switching, so the cross-user poisoning that branch prevents cannot occur. Also restore the underlying cause in the generic event-log init error (minimal output hid it after the usefulerror change), and document that root's per-user data lives under /root regardless of a preserved HOME.
This commit is contained in:
+19
-8
@@ -658,6 +658,12 @@ func rootCacheDir() (string, error) {
|
||||
return filepath.Join(home, ".cache"), nil
|
||||
}
|
||||
|
||||
// Overridable in tests to exercise the passwd-unavailable fallback.
|
||||
var (
|
||||
rootConfigDirResolver = rootConfigDir
|
||||
rootCacheDirResolver = rootCacheDir
|
||||
)
|
||||
|
||||
// realUserHomeDir returns the current user's home from the passwd database,
|
||||
// ignoring HOME and XDG_* env vars that may be leaked from another account.
|
||||
// Overridable in tests.
|
||||
@@ -707,11 +713,15 @@ func configDir() (string, error) {
|
||||
}
|
||||
|
||||
if configGeteuid() == 0 {
|
||||
base, err := rootConfigDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
if base, err := rootConfigDirResolver(); err == nil {
|
||||
return filepath.Join(base, pmgDefaultHomeRelativePath), nil
|
||||
} else {
|
||||
// No resolvable root passwd entry (e.g. scratch containers,
|
||||
// minimal chroots). Fall back to env-based resolution: without a
|
||||
// passwd database there is no user switching, so the cross-user
|
||||
// poisoning this branch prevents cannot occur.
|
||||
log.Warnf("failed to resolve root home for config dir, using environment: %v", err)
|
||||
}
|
||||
return filepath.Join(base, pmgDefaultHomeRelativePath), nil
|
||||
}
|
||||
|
||||
userConfigDir, err := os.UserConfigDir()
|
||||
@@ -835,11 +845,12 @@ func cacheDir() (string, error) {
|
||||
return filepath.Join(baseDir, pmgDefaultHomeRelativePath), nil
|
||||
case "darwin", "linux":
|
||||
if configGeteuid() == 0 {
|
||||
base, err := rootCacheDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
if base, err := rootCacheDirResolver(); err == nil {
|
||||
return filepath.Join(base, pmgDefaultHomeRelativePath), nil
|
||||
} else {
|
||||
// Same fallback rationale as configDir.
|
||||
log.Warnf("failed to resolve root home for cache dir, using environment: %v", err)
|
||||
}
|
||||
return filepath.Join(base, pmgDefaultHomeRelativePath), nil
|
||||
}
|
||||
|
||||
userCacheDir, err := os.UserCacheDir()
|
||||
|
||||
@@ -78,3 +78,23 @@ func TestCacheDirAsNonRootUsesEnvHome(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, dir, "/home/victim")
|
||||
}
|
||||
|
||||
func TestRootDirsFallBackToEnvWhenPasswdUnavailable(t *testing.T) {
|
||||
poisonUserEnv(t)
|
||||
withEuid(t, 0)
|
||||
|
||||
origConfig, origCache := rootConfigDirResolver, rootCacheDirResolver
|
||||
rootConfigDirResolver = func() (string, error) { return "", assert.AnError }
|
||||
rootCacheDirResolver = func() (string, error) { return "", assert.AnError }
|
||||
t.Cleanup(func() {
|
||||
rootConfigDirResolver, rootCacheDirResolver = origConfig, origCache
|
||||
})
|
||||
|
||||
dir, err := configDir()
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, dir, "/home/victim")
|
||||
|
||||
dir, err = cacheDir()
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, dir, "/home/victim")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user