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 "path/filepath"
6 "strings"
7
8 "github.com/carlosframework/platform/internal/cgroup"
9 "github.com/carlosframework/platform/internal/hostbox"
10 "github.com/carlosframework/platform/internal/hostguard"
11 "github.com/carlosframework/platform/internal/instancectl"
12)
13
14func claimContainmentParent(agent string, t hostguard.FenceTarget) (string, error) {
15 rel, err := filepath.Rel("/sys/fs/cgroup", agent)
16 if err != nil || !filepath.IsLocal(rel) || rel == "." || filepath.Clean(agent) != agent || !stopComponent(t.Host) || t.Incarnation == "" || t.Stamp == 0 || t.Session == 0 || t.Box == "" || t.Enrollment == "" || t.BootID == "" || t.ControllerID == "" {
17 return "", ErrClaimStopInventory
18 }
19 return filepath.Join(rel, cgroup.ExecName(claimContainmentName(t))), nil
20}
21
22func claimRoleChild(parent, p string) bool {
23 return filepath.IsLocal(p) && filepath.Clean(p) == p && filepath.Dir(p) == parent && strings.HasPrefix(filepath.Base(p), "role-") && len(filepath.Base(p)) > len("role-")
24}
25
26func validateClaimGroups(parent string, groups []hostbox.LaunchGroup) error {
27 if len(groups) == 0 {
28 return ErrClaimStopInventory
29 }
30 found := false
31 seen := map[string]bool{}
32 for _, g := range groups {
33 if g.Device == 0 || g.Inode == 0 || seen[g.RelativePath] {
34 return ErrClaimStopInventory
35 }
36 seen[g.RelativePath] = true
37 if g.RelativePath == parent {
38 if g.InvocationID != "" {
39 return ErrClaimStopInventory
40 }
41 found = true
42 } else if !claimRoleChild(parent, g.RelativePath) || g.InvocationID == "" {
43 return ErrClaimStopInventory
44 }
45 }
46 if !found {
47 return ErrClaimStopInventory
48 }
49 return nil
50}
51
52func validateClaimContainment(in hostbox.LaunchInventory, parent string) error {
53 return validateClaimContainmentUnit(in, parent, instancectl.ClaimUnitControlGroup(in.Target.Host))
54}
55
56func validateClaimContainmentUnit(in hostbox.LaunchInventory, parent, unitGroup string) error {
57 if err := validateClaimGroups(parent, in.Groups); err != nil {
58 return err
59 }
60 var parentGroup hostbox.LaunchGroup
61 groups := map[string]hostbox.LaunchGroup{}
62 for _, g := range in.Groups {
63 groups[g.RelativePath] = g
64 if g.RelativePath == parent {
65 parentGroup = g
66 }
67 }
68 claimed := map[string]bool{}
69 for _, r := range in.Reservations {
70 if !hostbox.SameLaunchOwner(in.Target, r.Target) {
71 return ErrClaimStopInventory
72 }
73 if hostbox.IsUnitReservation(r) {
74 if r.Parent != (hostbox.LaunchGroup{}) || r.Group.RelativePath != unitGroup {
75 return ErrClaimStopInventory
76 }
77 continue
78 }
79 if r.Parent != parentGroup || !claimRoleChild(parent, r.Group.RelativePath) || r.Group.InvocationID != r.InvocationID || r.InvocationID == "" || claimed[r.Group.RelativePath] {
80 return ErrClaimStopInventory
81 }
82 claimed[r.Group.RelativePath] = true
83 switch r.State {
84 case "intended":
85 if r.Group.Device != 0 || r.Group.Inode != 0 {
86 return ErrClaimStopInventory
87 }
88 case "reserved", "started", "settled":
89 // An intention settled after an absent child retains its zero identity.
90 if r.State == "settled" && r.Group.Device == 0 && r.Group.Inode == 0 {
91 continue
92 }
93 if groups[r.Group.RelativePath] != r.Group {
94 return ErrClaimStopInventory
95 }
96 default:
97 return ErrClaimStopInventory
98 }
99 }
100 for _, g := range in.Groups {
101 if g.RelativePath != parent && !claimed[g.RelativePath] {
102 return ErrClaimStopInventory
103 }
104 }
105 return nil
106}
107
108func validateClaimJournalContainment(ctx context.Context, q hostbox.JournalRequest, j *hostbox.LaunchJournal) error {
109 switch q.Op {
110 case "create", "prelaunch", "intend", "reserve":
111 default:
112 return nil
113 }
114 target := q.Launch.Target
115 if q.Op == "intend" || q.Op == "reserve" {
116 target = q.Reservation.Target
117 }
118 agent, err := claimContainmentAgentRoot(ctx)
119 if err != nil {
120 return err
121 }
122 parent, err := claimContainmentParent(agent, target)
123 if err != nil {
124 return err
125 }
126 if q.Op == "create" || q.Op == "prelaunch" {
127 if len(q.Launch.Groups) != 1 || len(q.Launch.Reservations) != 0 {
128 return ErrClaimStopInventory
129 }
130 if err := validateClaimContainment(q.Launch, parent); err != nil {
131 return err
132 }
133 captured, err := claimContainmentInspect(parent)
134 if err != nil {
135 return err
136 }
137 if captured != q.Launch.Groups[0] {
138 return ErrClaimStopIdentity
139 }
140 return nil
141 }
142 in, err := j.Read(ctx, target)
143 if err != nil {
144 return err
145 }
146 if err := validateClaimContainment(in, parent); err != nil {
147 return err
148 }
149 r := q.Reservation
150 var expected hostbox.LaunchGroup
151 for _, g := range in.Groups {
152 if g.RelativePath == parent {
153 expected = g
154 }
155 }
156 if r.Parent != expected || !claimRoleChild(parent, r.Group.RelativePath) || r.Group.InvocationID != r.InvocationID || r.InvocationID == "" {
157 return ErrClaimStopInventory
158 }
159 captured, err := claimContainmentInspect(parent)
160 if err != nil {
161 return err
162 }
163 if captured != expected {
164 return ErrClaimStopIdentity
165 }
166 if q.Op == "reserve" {
167 captured, err = claimContainmentInspect(r.Group.RelativePath)
168 if err != nil {
169 return err
170 }
171 captured.InvocationID = r.InvocationID
172 if captured != r.Group {
173 return ErrClaimStopIdentity
174 }
175 }
176 return nil
177}
178
179func validatePersistedClaimContainment(ctx context.Context, in hostbox.LaunchInventory) error {
180 agent, err := claimContainmentAgentRoot(ctx)
181 if err != nil {
182 return err
183 }
184 parent, err := claimContainmentParent(agent, in.Target)
185 if err != nil {
186 return err
187 }
188 return validateClaimContainment(in, parent)
189}
190
191func validateStopClaimGroups(t hostguard.FenceTarget, j hostbox.StopKernelJournal, agent string) error {
192 if !hostbox.SameLaunchOwner(j.Target, t) {
193 return ErrClaimStopInventory
194 }
195 parent, err := claimContainmentParent(agent, t)
196 if err != nil {
197 return err
198 }
199 groups := make([]hostbox.LaunchGroup, 0, len(j.Cgroups))
200 for _, g := range j.Cgroups {
201 groups = append(groups, hostbox.LaunchGroup{RelativePath: g.RelativePath, Device: g.Device, Inode: g.Inode, InvocationID: g.InvocationID})
202 }
203 return validateClaimGroups(parent, groups)
204}
205
206func validatePersistedUnitContainment(ctx context.Context, in hostbox.LaunchInventory, units ClaimLaunchUnits) error {
207 agent, err := claimContainmentAgentRoot(ctx)
208 if err != nil {
209 return err
210 }
211 parent, err := claimContainmentParent(agent, in.Target)
212 if err != nil {
213 return err
214 }
215 _, group, err := claimLaunchPlacement(units, in.Target.Host)
216 if err != nil {
217 return err
218 }
219 return validateClaimContainmentUnit(in, parent, group)
220}
221