carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1package host
2
3import (
4 "context"
5
6 "github.com/carlosframework/platform/internal/hostbox"
7 "github.com/carlosframework/platform/internal/hostguard"
8 "github.com/carlosframework/platform/internal/release"
9 "github.com/carlosframework/platform/internal/rootparticipation"
10 "github.com/carlosframework/platform/internal/rootstate"
11)
12
13const rootMigrationDir = "/var/lib/carlos-claims/authority/migration"
14
15var openRootMigrationParticipation = rootparticipation.OpenForUpdate
16
17// openRootMigrationState opens the root-owned migration record directory
18// read-only. A variable so tests can stand in for the root-owned directory.
19var openRootMigrationState = func() (rootstate.Store, error) {
20 return rootstate.Open(rootMigrationDir, false, false)
21}
22
23func verifyRootMigrationRetained(ctx context.Context, root *hostguard.RootAuthority, snapshot rootMigrationSnapshot) error {
24 views, err := root.MigrationInstallations(ctx)
25 if err != nil {
26 return err
27 }
28 byHost := map[string]hostguard.FenceView{}
29 for _, v := range views {
30 byHost[v.Host] = v
31 }
32 for _, item := range snapshot.Items {
33 v, ok := byHost[item.Installation.Host]
34 if !ok {
35 return errRootMigrationBusy
36 }
37 in := item.Installation
38 denied, stopped := false, false
39 for _, d := range v.MigrationDenies {
40 if d.Incarnation == in.Incarnation && d.Stamp >= in.Stamp && d.Session >= item.Session {
41 denied = true
42 }
43 }
44 for _, r := range v.Receipts {
45 if r.Target.Host == in.Host && r.Target.Incarnation == in.Incarnation && r.Target.Stamp == in.Stamp && r.Target.Session == item.Session && r.Target.Box == in.Box && r.Target.Enrollment == in.Enrollment && len(r.Bytes) > 0 && !r.EvidenceAt.IsZero() {
46 stopped = true
47 }
48 }
49 if !denied || !stopped || v.Installation.InventoryRevision == 0 || v.Installation.Artifacts.Schema != 1 {
50 return errRootMigrationBusy
51 }
52 }
53 return nil
54}
55func verifyRootMigrationState(ctx context.Context, state, execution rootstate.Store, id rootMigrationIdentity, root *hostguard.RootAuthority) error {
56 r, err := readRootMigrationState(state, execution, id)
57 if err != nil {
58 return err
59 }
60 return verifyRootMigrationRetained(ctx, root, r.Snapshot)
61}
62func readRootMigrationState(state, execution rootstate.Store, id rootMigrationIdentity) (rootMigrationRecord, error) {
63 var r rootMigrationRecord
64 c, err := (rootparticipation.Ledger{State: execution}).RecoveryCensus()
65 if err != nil {
66 return r, err
67 }
68 if c.Box != id.Box || c.Enrollment != id.Enrollment || c.Migration != id.Generation || !c.Complete || c.NeverEnrolled {
69 return r, errRootMigrationBusy
70 }
71 raw, err := state.Read("migration.json")
72 if err != nil {
73 return r, err
74 }
75 if rootparticipation.Decode(raw, &r) != nil || r.Schema != 1 || r.Identity != id || r.Phase != "complete" || r.Snapshot.preflight(id) != nil {
76 return r, errRootMigrationBusy
77 }
78 return r, nil
79}
80func verifyRootMigrationStartup(ctx context.Context, id rootFloorIdentity, inventory *hostbox.StopInventoryDB) error {
81 l, required, err := openRootMigrationParticipation()
82 if l.State != nil {
83 defer l.State.Close()
84 }
85 if err != nil || !required {
86 return err
87 }
88 c, err := l.RecoveryCensus()
89 if err != nil {
90 return err
91 }
92 state, err := openRootMigrationState()
93 if err != nil {
94 return err
95 }
96 defer state.Close()
97 fences, err := openClaimRootAuthority()
98 if err != nil {
99 return err
100 }
101 defer fences.Close()
102 root := hostguard.NewRootAuthority(fences)
103 if err := verifyRootMigrationState(ctx, state, l.State, rootMigrationIdentity{Deployment: id.Deployment, Box: id.Box, Enrollment: id.Enrollment, Generation: c.Migration}, root); err != nil {
104 return err
105 }
106 views, err := root.MigrationInstallations(ctx)
107 if err != nil {
108 return err
109 }
110 for _, v := range views {
111 if inventory == nil {
112 return errRootMigrationBusy
113 }
114 in, revision, err := inventory.Snapshot(ctx, v.Host, hostguard.Captured{Incarnation: v.Installation.Incarnation, Stamp: v.Installation.Stamp})
115 // A settled installation whose first inventory write never landed
116 // has no inventory, and root's record says so: nothing to clean.
117 if err == nil && v.Settled && revision == 0 && v.Installation.InventoryRevision == 0 && v.Installation.Box == id.Box && v.Installation.Enrollment == id.Enrollment {
118 continue
119 }
120 if err != nil || !in.Complete || revision == 0 || revision != v.Installation.InventoryRevision || v.Installation.Box != id.Box || v.Installation.Enrollment != id.Enrollment {
121 return errRootMigrationBusy
122 }
123 }
124 return rootMigrationStartupFloors(release.OptDir(), id)
125}
126
127// rootMigrationStartupFloors is the startup's installed-binary floor check.
128// A variable so tests without root-owned floor binaries can stand in for it;
129// the census before it runs unchanged.
130var rootMigrationStartupFloors = verifyRootMigrationFloors
131
132func verifyRootMigrationFloors(opt string, id rootFloorIdentity) error {
133 bound, err := readRootProtocolBound(rootFloorDir(opt), id)
134 if err != nil {
135 return err
136 }
137 for _, path := range []string{systemBinaryPath(opt), systemGuardDir(opt) + "/carlos"} {
138 b, err := readRootFloorBinary(opt, path)
139 if err != nil {
140 return err
141 }
142 if !b.supports(nil) {
143 return errRootFloorHistory
144 }
145 if !b.supports(bound) {
146 rootFloorAlert()
147 }
148 if _, err := readRootSeedsBound(opt, id); err != nil {
149 return err
150 }
151 }
152 return nil
153}
154