92 lines
3.4 KiB
Go
92 lines
3.4 KiB
Go
//go:build linux
|
|
|
|
package apply
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/declaration"
|
|
"github.com/novox/mesh-host/internal/store"
|
|
)
|
|
|
|
// Defends novox/hq issue 358: a mesh directory outside every home is given its mode and owner only through a
|
|
// descriptor opened from /, so a parent swapped for a link between two applies cannot carry root's chmod and
|
|
// chown to the link's target — unless root alone could have made that link (/var/run is one on every node).
|
|
|
|
// A link only root could have made — itself root's, in directories no other account may write — is followed, as
|
|
// /var/run to /run is on every node; relative or absolute.
|
|
func TestALinkOnlyRootCouldMakeIsFollowed(t *testing.T) {
|
|
for name, to := range map[string]func(base string) string{
|
|
"absolute": func(base string) string { return filepath.Join(base, "elsewhere") },
|
|
"relative": func(string) string { return "elsewhere" },
|
|
} {
|
|
t.Run(name, func(t *testing.T) {
|
|
rootAlone(t, "")
|
|
base, r, previous := aMeshDirectory(t)
|
|
target := swapParentForLink(t, base, to(base))
|
|
|
|
out, err := applyDirectory(r, previous, true)
|
|
if err != nil {
|
|
t.Fatalf("a directory behind a root-only link was refused: %v", err)
|
|
}
|
|
if got := permOf(t, target); got != 0o700 {
|
|
t.Errorf("the directory behind a root-only link is mode %o, want 700", got)
|
|
}
|
|
if out.Action != "updated" {
|
|
t.Errorf("the apply said %q, want updated", out.Action)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// A link another account owns refuses the directory even in directories root alone may write, naming the account.
|
|
func TestALinkAnotherAccountOwnsIsRefused(t *testing.T) {
|
|
rootAlone(t, "the account mallory (it owns the link)")
|
|
base, r, previous := aMeshDirectory(t)
|
|
target := swapParentForLink(t, base, filepath.Join(base, "elsewhere"))
|
|
|
|
_, err := applyDirectory(r, previous, true)
|
|
if err == nil || !strings.Contains(err.Error(), "mallory") {
|
|
t.Fatalf("a link another account owns was not refused naming it: %v", err)
|
|
}
|
|
if got := permOf(t, target); got != 0o755 {
|
|
t.Errorf("the link's target was given mode %o (was 755)", got)
|
|
}
|
|
}
|
|
|
|
// A directory that is missing is made through the walk, below a link root alone could make.
|
|
func TestAMissingDirectoryIsMadeBehindARootOnlyLink(t *testing.T) {
|
|
rootAlone(t, "")
|
|
base := t.TempDir()
|
|
if err := os.Mkdir(filepath.Join(base, "real"), 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.Symlink("real", filepath.Join(base, "link")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
r := &declaration.Directory{ID: "mod.state", Path: filepath.Join(base, "link", "a", "b"), Mode: "0750"}
|
|
out, err := applyDirectory(r, store.Applied{}, false)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if out.Action != "created" {
|
|
t.Errorf("the apply said %q, want created", out.Action)
|
|
}
|
|
if got := permOf(t, filepath.Join(base, "real", "a", "b")); got != 0o750 {
|
|
t.Errorf("the made directory is mode %o, want 750", got)
|
|
}
|
|
}
|
|
|
|
// rootAlone has every directory count as writable by root alone, as /, /var and /run are on a node, and a link's
|
|
// owner be linkOwner ("" for root): a test runs below /tmp, which every account may write.
|
|
func rootAlone(t *testing.T, linkOwner string) {
|
|
t.Helper()
|
|
wasDirs, wasLinks := couldReplace, linkReplacer
|
|
couldReplace = func(string, uint32, uint32, uint32) string { return "" }
|
|
linkReplacer = func(string, uint32) string { return linkOwner }
|
|
t.Cleanup(func() { couldReplace, linkReplacer = wasDirs, wasLinks })
|
|
}
|