1use std::collections::HashMap;
22use std::sync::atomic::{AtomicBool, Ordering};
23use std::sync::{Arc, Mutex};
24
25use arc_swap::ArcSwap;
26use thiserror::Error;
27
28use crate::event::EventHub;
29
30use frame_capability::ComponentId;
31pub use frame_capability::{
32 Capability, CapabilityDenied, CapabilityKind, CapabilityRequest, CapabilityScope, CheckVerdict,
33 Grant, GrantProvenance, NetworkHost, PathRoot, ScopeValidationError,
34};
35
36pub struct CapabilityTable {
38 components: ArcSwap<HashMap<ComponentId, Arc<ComponentGrants>>>,
39 mutations: Mutex<()>,
40}
41
42impl CapabilityTable {
43 pub(crate) fn new() -> Self {
44 Self {
45 components: ArcSwap::from_pointee(HashMap::new()),
46 mutations: Mutex::new(()),
47 }
48 }
49
50 pub(crate) fn register_component(
51 &self,
52 component_id: ComponentId,
53 needs: Vec<CapabilityRequest>,
54 ) -> Result<(), CapabilityMutationError> {
55 let _mutation = self
56 .mutations
57 .lock()
58 .map_err(|_| CapabilityMutationError::SynchronizationPoisoned)?;
59 let mut components = (**self.components.load()).clone();
60 components.insert(
61 component_id,
62 Arc::new(ComponentGrants {
63 needs,
64 active: AtomicBool::new(true),
65 grants: ArcSwap::from_pointee(HashMap::new()),
66 mutations: Mutex::new(HashMap::new()),
67 }),
68 );
69 self.components.store(Arc::new(components));
70 Ok(())
71 }
72
73 pub(crate) fn remove_component(
74 &self,
75 component_id: ComponentId,
76 ) -> Result<(), CapabilityMutationError> {
77 let _table_mutation = self
78 .mutations
79 .lock()
80 .map_err(|_| CapabilityMutationError::SynchronizationPoisoned)?;
81 let component = self.component(component_id)?;
82 let mut grants = component
83 .mutations
84 .lock()
85 .map_err(|_| CapabilityMutationError::SynchronizationPoisoned)?;
86 component.active.store(false, Ordering::Release);
87 grants.clear();
88 component.grants.store(Arc::new(HashMap::new()));
89 drop(grants);
90 let mut components = (**self.components.load()).clone();
91 components.remove(&component_id);
92 self.components.store(Arc::new(components));
93 Ok(())
94 }
95
96 fn component(
97 &self,
98 component_id: ComponentId,
99 ) -> Result<Arc<ComponentGrants>, CapabilityMutationError> {
100 self.components
101 .load()
102 .get(&component_id)
103 .cloned()
104 .ok_or(CapabilityMutationError::NotRegistered { component_id })
105 }
106
107 fn grant(
108 &self,
109 component_id: ComponentId,
110 request: CapabilityRequest,
111 provenance: GrantProvenance,
112 ) -> Result<Grant, CapabilityMutationError> {
113 let component = self.component(component_id)?;
114 if !component.needs.contains(&request) {
115 return Err(CapabilityMutationError::UndeclaredNeed {
116 component_id,
117 request,
118 });
119 }
120 let mut grants = component
121 .mutations
122 .lock()
123 .map_err(|_| CapabilityMutationError::SynchronizationPoisoned)?;
124 if !component.active.load(Ordering::Acquire) {
125 return Err(CapabilityMutationError::NotRegistered { component_id });
126 }
127 if let Some(current) = grants.get(&request) {
128 return Err(CapabilityMutationError::AlreadyGranted {
129 current: current.clone(),
130 });
131 }
132 let grant = Grant {
133 component_id,
134 request: request.clone(),
135 provenance,
136 };
137 grants.insert(request, grant.clone());
138 component.grants.store(Arc::new(grants.clone()));
139 Ok(grant)
140 }
141
142 fn revoke(
143 &self,
144 component_id: ComponentId,
145 request: &CapabilityRequest,
146 ) -> Result<RevokeOutcome, CapabilityMutationError> {
147 let component = self.component(component_id)?;
148 let mut grants = component
149 .mutations
150 .lock()
151 .map_err(|_| CapabilityMutationError::SynchronizationPoisoned)?;
152 if !component.active.load(Ordering::Acquire) {
153 return Err(CapabilityMutationError::NotRegistered { component_id });
154 }
155 let removed = grants.remove(request);
156 if removed.is_some() {
157 component.grants.store(Arc::new(grants.clone()));
158 }
159 Ok(removed.map_or(RevokeOutcome::NotGranted, RevokeOutcome::Revoked))
160 }
161
162 fn grants_for(&self, component_id: ComponentId) -> Result<Vec<Grant>, CapabilityMutationError> {
163 let component = self.component(component_id)?;
164 if !component.active.load(Ordering::Acquire) {
165 return Err(CapabilityMutationError::NotRegistered { component_id });
166 }
167 let mut grants: Vec<_> = component.grants.load().values().cloned().collect();
168 sort_grants(&mut grants);
169 Ok(grants)
170 }
171
172 fn full_table(&self) -> Vec<Grant> {
173 let components = self.components.load();
174 let mut grants = Vec::new();
175 for component in components.values() {
176 if component.active.load(Ordering::Acquire) {
177 grants.extend(component.grants.load().values().cloned());
178 }
179 }
180 sort_grants(&mut grants);
181 grants
182 }
183}
184
185fn sort_grants(grants: &mut [Grant]) {
186 grants.sort_by(|left, right| {
187 left.component_id
188 .cmp(&right.component_id)
189 .then_with(|| left.request.cmp(&right.request))
190 });
191}
192
193struct ComponentGrants {
194 needs: Vec<CapabilityRequest>,
195 active: AtomicBool,
196 grants: ArcSwap<HashMap<CapabilityRequest, Grant>>,
197 mutations: Mutex<HashMap<CapabilityRequest, Grant>>,
198}
199
200#[derive(Clone)]
205pub struct CapabilityChecker {
206 component_id: ComponentId,
207 component: Arc<ComponentGrants>,
208 events: Arc<EventHub>,
209}
210
211impl CapabilityChecker {
212 #[must_use]
214 pub const fn component_id(&self) -> ComponentId {
215 self.component_id
216 }
217
218 pub fn check(&self, capability: &Capability) -> Result<CheckVerdict, CapabilityCheckError> {
225 let valid = capability.validate().is_ok();
226 let declared = valid
227 && self
228 .component
229 .needs
230 .iter()
231 .any(|need| need.capability.covers(capability));
232 let allowed = self.component.active.load(Ordering::Acquire)
233 && valid
234 && self
235 .component
236 .grants
237 .load()
238 .values()
239 .any(|grant| grant.request.capability.covers(capability));
240 if allowed {
241 return Ok(CheckVerdict::Allowed);
242 }
243 let denial = CapabilityDenied {
244 component_id: self.component_id,
245 kind: capability.kind(),
246 scope: capability.scope(),
247 declared,
248 };
249 self.events
250 .publish_denial(denial.clone())
251 .map_err(|_| CapabilityCheckError::SynchronizationPoisoned)?;
252 Ok(CheckVerdict::Denied(denial))
253 }
254}
255
256pub struct HostCapabilityFacade<'a> {
261 table: &'a CapabilityTable,
262 events: Arc<EventHub>,
263}
264
265impl<'a> HostCapabilityFacade<'a> {
266 pub(crate) fn new(table: &'a CapabilityTable, events: Arc<EventHub>) -> Self {
267 Self { table, events }
268 }
269
270 pub fn grant(
277 &self,
278 component_id: ComponentId,
279 request: CapabilityRequest,
280 provenance: GrantProvenance,
281 ) -> Result<Grant, CapabilityMutationError> {
282 self.table.grant(component_id, request, provenance)
283 }
284
285 pub fn revoke(
291 &self,
292 component_id: ComponentId,
293 request: &CapabilityRequest,
294 ) -> Result<RevokeOutcome, CapabilityMutationError> {
295 self.table.revoke(component_id, request)
296 }
297
298 pub fn grants_for(
304 &self,
305 component_id: ComponentId,
306 ) -> Result<Vec<Grant>, CapabilityMutationError> {
307 self.table.grants_for(component_id)
308 }
309
310 #[must_use]
312 pub fn full_table(&self) -> Vec<Grant> {
313 self.table.full_table()
314 }
315
316 pub fn checker(
322 &self,
323 component_id: ComponentId,
324 ) -> Result<CapabilityChecker, CapabilityMutationError> {
325 Ok(CapabilityChecker {
326 component_id,
327 component: self.table.component(component_id)?,
328 events: Arc::clone(&self.events),
329 })
330 }
331}
332
333#[derive(Clone, Debug, Eq, PartialEq)]
335pub enum RevokeOutcome {
336 Revoked(Grant),
338 NotGranted,
340}
341
342#[derive(Clone, Debug, Error, Eq, PartialEq)]
344pub enum CapabilityMutationError {
345 #[error("component {component_id} is not registered in the capability table")]
347 NotRegistered {
348 component_id: ComponentId,
350 },
351 #[error("component {component_id} did not declare capability need {request:?}")]
353 UndeclaredNeed {
354 component_id: ComponentId,
356 request: CapabilityRequest,
358 },
359 #[error("capability grant already exists: {current:?}")]
361 AlreadyGranted {
362 current: Grant,
364 },
365 #[error("capability table synchronization is poisoned")]
367 SynchronizationPoisoned,
368}
369
370#[derive(Clone, Copy, Debug, Error, Eq, PartialEq)]
372pub enum CapabilityCheckError {
373 #[error("component {component_id} is not registered for capability checks")]
375 NotRegistered {
376 component_id: ComponentId,
378 },
379 #[error("capability check synchronization is poisoned")]
381 SynchronizationPoisoned,
382}