carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1//go:build linux
2
3package host
4
5import (
6 "context"
7 "os"
8 "path/filepath"
9 "testing"
10
11 "github.com/carlosframework/platform/internal/hostbox"
12 "github.com/carlosframework/platform/internal/release"
13 "github.com/carlosframework/platform/internal/rootparticipation"
14 "golang.org/x/sys/unix"
15)
16
17func TestPlan14GenerationPayloadPhysicalIdentity(t *testing.T) {
18 for _, attack := range []string{"none", "directory", "missing", "replaced", "symlink", "parent-symlink", "root-symlink", "wrong-device", "wrong-inode", "wrong-type", "intended", "intended-missing", "escape", "unknown-root", "changed-during-kernel"} {
19 t.Run(attack, func(t *testing.T) {
20 f, disk, _ := generationLaunchFixture(t)
21 if _, err := f.root.Serve(t.Context(), f.peer, f.req); err != nil {
22 t.Fatal(err)
23 }
24 r := readGenerationLaunch(t, disk)
25 views, err := f.root.Guard.Root.GenerationInstallations(t.Context())
26 if err != nil {
27 t.Fatal(err)
28 }
29 launch, err := f.journal.Read(t.Context(), f.target)
30 if err != nil {
31 t.Fatal(err)
32 }
33 dir := t.TempDir()
34 t.Setenv("CARLOS_DATA_DIR", dir)
35 parent := filepath.Join(dir, "state")
36 if err := os.Mkdir(parent, 0700); err != nil {
37 t.Fatal(err)
38 }
39 path := filepath.Join(parent, "retained")
40 if attack == "directory" {
41 err = os.Mkdir(path, 0700)
42 } else {
43 err = os.WriteFile(path, []byte("retained payload"), 0600)
44 }
45 if err != nil {
46 t.Fatal(err)
47 }
48 var st unix.Stat_t
49 if err := unix.Lstat(path, &st); err != nil {
50 t.Fatal(err)
51 }
52 entry := hostbox.StopInventoryEntry{Identity: inventoryIdentityFixture(t, dir, "state/retained"), Kind: "path", ArtifactID: "retained", ManagedRoot: "data", RelativePath: "state/retained", Ownership: "owner", Materialization: "materialized", Device: uint64(st.Dev), Inode: st.Ino, Type: st.Mode & unix.S_IFMT}
53 switch attack {
54 case "missing", "replaced", "symlink":
55 if err := os.Rename(path, path+".old"); err != nil {
56 t.Fatal(err)
57 }
58 if attack == "replaced" {
59 err = os.WriteFile(path, []byte("replacement"), 0600)
60 } else if attack == "symlink" {
61 err = os.Symlink("retained.old", path)
62 }
63 case "parent-symlink":
64 if err := os.Rename(parent, parent+".old"); err != nil {
65 t.Fatal(err)
66 }
67 err = os.Symlink("state.old", parent)
68 case "root-symlink":
69 link := dir + ".link"
70 err = os.Symlink(dir, link)
71 t.Cleanup(func() { os.Remove(link) })
72 t.Setenv("CARLOS_DATA_DIR", link)
73 case "wrong-device":
74 entry.Device++
75 case "wrong-inode":
76 entry.Inode++
77 case "wrong-type":
78 entry.Type = unix.S_IFDIR
79 case "intended", "intended-missing":
80 entry.Materialization = "intended"
81 if attack == "intended-missing" {
82 entry.Device, entry.Inode, entry.Type = 0, 0, 0
83 err = os.Remove(path)
84 }
85 case "escape":
86 entry.RelativePath = "../" + filepath.Base(dir) + "/state/retained"
87 case "unknown-root":
88 entry.ManagedRoot = "other"
89 }
90 if err != nil {
91 t.Fatal(err)
92 }
93 snapshot := generationInventory{Census: rootparticipation.Census{Schema: 1, Box: f.target.Box, Enrollment: f.target.Enrollment, Migration: 1, Revision: 1, LaunchRevision: 1, Complete: true}, Installations: views, Launches: []hostbox.LaunchInventory{launch}, Payloads: generationPayloadFixture(views)}
94 snapshot.Payloads[0].Inventory.Entries = append(snapshot.Payloads[0].Inventory.Entries, entry)
95 v := generationReconciler{read: func(context.Context) (generationInventory, error) { return snapshot, nil }, kernel: func(context.Context) (string, string, error) {
96 if attack == "changed-during-kernel" {
97 if err := os.Rename(path, path+".old"); err != nil {
98 t.Fatal(err)
99 }
100 }
101 return "boot", r.Binding.Digest, nil
102 }}
103 _, err = v.reconcile(t.Context(), []release.GenerationReservation{r})
104 if (err == nil) != (attack == "none" || attack == "directory") {
105 t.Fatalf("physical payload %s: %v", attack, err)
106 }
107 })
108 }
109}
110