Test uncovered launch-dir refusals #4
@@ -681,3 +681,82 @@ func TestLaunchMountsResolvedSource(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckLaunchDirDefaultRootForbidden(t *testing.T) {
|
||||
t.Setenv("HOME", "/tmp/home")
|
||||
t.Setenv("XDG_CONFIG_HOME", "/nonexistent/cfg")
|
||||
t.Setenv("XDG_DATA_HOME", "")
|
||||
t.Setenv("XDG_RUNTIME_DIR", "/nonexistent/rt")
|
||||
t.Setenv("PATH", "/usr/bin")
|
||||
_, err := checkLaunchDir("/tmp/home/proj", "/nonexistent/hosts")
|
||||
check(t, "forbidden default root", "refusing to mount /tmp/home/proj: it overlaps "+realpath("/tmp"), fmt.Sprint(err))
|
||||
}
|
||||
|
||||
// isolatedHome points every sensitive dir outside a fresh $HOME, leaving only
|
||||
// the rule under test to refuse.
|
||||
func isolatedHome(t *testing.T) (work, home string) {
|
||||
work, _ = filepath.EvalSymlinks(t.TempDir())
|
||||
elsewhere, _ := filepath.EvalSymlinks(t.TempDir())
|
||||
home = work + "/home"
|
||||
for _, d := range []string{".ssh", ".gnupg", ".config", ".local/share/containers"} {
|
||||
_ = os.MkdirAll(filepath.Join(elsewhere, d), 0o755)
|
||||
_ = os.MkdirAll(filepath.Dir(filepath.Join(home, d)), 0o755)
|
||||
_ = os.Symlink(filepath.Join(elsewhere, d), filepath.Join(home, d))
|
||||
}
|
||||
t.Setenv("HOME", home)
|
||||
t.Setenv("XDG_CONFIG_HOME", elsewhere+"/cfg")
|
||||
t.Setenv("XDG_DATA_HOME", "")
|
||||
t.Setenv("XDG_RUNTIME_DIR", elsewhere+"/rt")
|
||||
t.Setenv("PATH", "/usr/bin")
|
||||
origRoots := forbiddenRoots
|
||||
forbiddenRoots = []string{"/run"}
|
||||
t.Cleanup(func() { forbiddenRoots = origRoots })
|
||||
_ = os.MkdirAll(filepath.Dir(allowedPathsFile()), 0o755)
|
||||
return work, home
|
||||
}
|
||||
|
||||
func TestCheckLaunchDirResolvedAllowedPathsDir(t *testing.T) {
|
||||
_, home := isolatedHome(t)
|
||||
dot := home + "/src/dot"
|
||||
_ = os.MkdirAll(dot, 0o755)
|
||||
_ = os.WriteFile(dot+"/allowed-paths", []byte("~/src\n"), 0o644)
|
||||
_ = os.Symlink(dot+"/allowed-paths", allowedPathsFile())
|
||||
_ = os.MkdirAll(home+"/src/other", 0o755)
|
||||
_, err := checkLaunchDir(home+"/src/other", "/nonexistent/hosts")
|
||||
check(t, "sibling allowed", nil, err)
|
||||
_, err = checkLaunchDir(dot, "/nonexistent/hosts")
|
||||
check(t, "resolved allowed-paths dir", "refusing to mount "+dot+": it contains "+dot, fmt.Sprint(err))
|
||||
}
|
||||
|
||||
func TestAllowedRootsRejectsHomeAndDotDirs(t *testing.T) {
|
||||
work, home := isolatedHome(t)
|
||||
f := allowedPathsFile()
|
||||
for _, tc := range []struct{ root, want string }{
|
||||
{"~/.cache", `"~/.cache" is a dot-directory of $HOME`},
|
||||
{"~", `"~" is or contains $HOME`},
|
||||
{home, `"` + home + `" is or contains $HOME`},
|
||||
{work, `"` + work + `" is or contains $HOME`},
|
||||
} {
|
||||
_ = os.WriteFile(f, []byte(tc.root+"\n"), 0o644)
|
||||
_, _, err := allowedRoots(home)
|
||||
check(t, tc.root, f+": "+tc.want, fmt.Sprint(err))
|
||||
}
|
||||
_ = os.WriteFile(f, []byte("~/src\n"), 0o644)
|
||||
_, _, err := allowedRoots(home)
|
||||
check(t, "plain root", nil, err)
|
||||
}
|
||||
|
||||
func TestLaunchRefusesColonInResolvedSource(t *testing.T) {
|
||||
e := setup(t)
|
||||
_ = os.Mkdir(e.work+"/home/a:b", 0o755)
|
||||
_ = os.Symlink(e.work+"/home/a:b", e.work+"/home/link")
|
||||
stderr, _ := os.CreateTemp(t.TempDir(), "stderr")
|
||||
orig := os.Stderr
|
||||
os.Stderr = stderr
|
||||
code := e.launch(t, e.work+"/home/link", "--exec", "true")
|
||||
os.Stderr = orig
|
||||
out, _ := os.ReadFile(stderr.Name())
|
||||
check(t, "exit", 1, code)
|
||||
check(t, "stderr", "agent-sandbox: cannot mount a directory containing ':'\n", string(out))
|
||||
check(t, "podman calls", []string(nil), e.fake.calls)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user