//go:build linux package host import ( "crypto/sha256" "encoding/hex" "fmt" "os" "path/filepath" "testing" "github.com/carlosframework/platform/internal/hostbox" "github.com/carlosframework/platform/internal/hostguard" "github.com/carlosframework/platform/internal/provision" "golang.org/x/sys/unix" ) func TestServingParkSourceUsesRootInventory(t *testing.T) { t.Parallel() for _, attack := range []string{"none", "unmaterialized", "duplicate", "owner", "revision", "enrollment", "record", "stamp", "foreign", "missing", "flat", "symlink", "replacement"} { t.Run(attack, func(t *testing.T) { f, _, _, inputs := servingRetirementFixture(t) o := servingAdmit(t, f, &inputs, "G") h := o.Claim.Holder actor := hostbox.Actor{Box: "box-1", Region: "ie", Enrollment: "enrollment", Revision: 7, Binding: "7"} root := hostguard.RootInstallation{Host: o.Host, Incarnation: h.Incarnation, Stamp: h.Stamp, Migration: 1, InventoryRevision: 3, Account: h.Account, App: h.App, Record: h.Key, Box: actor.Box, Enrollment: actor.Enrollment} d, err := os.Open(filepath.Dir(inputs.DBPath)) if err != nil { t.Fatal(err) } id, err := servingParkDirID(d) d.Close() if err != nil { t.Fatal(err) } owner := sha256.Sum256([]byte(fmt.Sprintf("%s\x00%s\x00%d\x00%s", o.Host, h.Incarnation, h.Stamp, actor.Box))) in := hostbox.StopInventory{Complete: true, Host: o.Host, Incarnation: h.Incarnation, InstallationStamp: h.Stamp, Box: actor.Box, Enrollment: actor.Enrollment, DirectoryRevision: "7", Entries: []hostbox.StopInventoryEntry{{Kind: "path", ManagedRoot: "data", RelativePath: "instances/" + provision.InstanceID(o.Host), ArtifactID: "state", Ownership: hex.EncodeToString(owner[:]), Materialization: "materialized", Device: id.Device, Inode: id.Inode, Type: unix.S_IFDIR}}} switch attack { case "unmaterialized": in.Entries[0].Materialization = "intended" case "duplicate": in.Entries = append(in.Entries, in.Entries[0]) case "owner": in.Entries[0].Ownership = "forged" case "revision": root.InventoryRevision++ case "enrollment": actor.Enrollment = "foreign" case "record": root.Record = "foreign" case "stamp": root.Stamp++ case "foreign": in.Host = "other.example" case "missing": in.Entries = nil case "flat": in.Entries[0].RelativePath = "state" case "symlink", "replacement": dir := filepath.Dir(inputs.DBPath) if err := os.Rename(dir, dir+".original"); err != nil { t.Fatal(err) } if attack == "symlink" { err = os.Symlink(dir+".original", dir) } else { err = os.Mkdir(dir, 0700) } if err != nil { t.Fatal(err) } } got, err := servingParkStateDirectory(f.guard.DataDir, o, root, in, 3, actor) if attack == "none" { if err != nil || got != id { t.Fatalf("source: %+v %v", got, err) } } else if err == nil { t.Fatal("unproved source accepted") } }) } }