1use super::LinearMemory;
17use crate::types::{CapId, SecurityLevel, Size};
18
19#[derive(Debug)]
21pub enum PluginError {
22 CapNotHeld(CapId),
24 MemoryOutOfBounds(u64, u64, u64),
26 MemoryQuotaExceeded(u64, u64, u64),
28 CapQuotaExceeded(u64, u64),
30 IpcQueueLimitExceeded(u64, u64),
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
41pub struct PluginLocal;
42
43pub const DEFAULT_QUOTA: u64 = u64::MAX / 2;
46
47#[derive(Debug, Clone, PartialEq, Eq)]
57pub struct PluginState {
58 pub(crate) level: SecurityLevel,
62
63 pub(crate) memory: LinearMemory,
67
68 pub(crate) held_caps: Vec<CapId>,
73
74 pub(crate) local_state: PluginLocal,
78
79 pub(crate) memory_quota: u64,
85
86 pub(crate) memory_used: u64,
90
91 pub(crate) cap_quota: u64,
95
96 pub(crate) ipc_queue_limit: u64,
100}
101
102impl PluginState {
103 pub fn empty(level: SecurityLevel, mem_size: Size) -> Self {
107 PluginState {
108 level,
109 memory: LinearMemory::empty(mem_size),
110 held_caps: Vec::new(),
111 local_state: PluginLocal,
112 memory_quota: DEFAULT_QUOTA,
113 memory_used: 0,
114 cap_quota: DEFAULT_QUOTA,
115 ipc_queue_limit: DEFAULT_QUOTA,
116 }
117 }
118
119 pub fn with_quotas(
123 level: SecurityLevel,
124 mem_size: Size,
125 memory_quota: u64,
126 cap_quota: u64,
127 ipc_queue_limit: u64,
128 ) -> Self {
129 PluginState {
130 level,
131 memory: LinearMemory::empty(mem_size),
132 held_caps: Vec::new(),
133 local_state: PluginLocal,
134 memory_quota,
135 memory_used: 0,
136 cap_quota,
137 ipc_queue_limit,
138 }
139 }
140
141 #[inline]
145 pub fn holds_cap(&self, cap_id: CapId) -> bool {
146 self.held_caps.binary_search(&cap_id).is_ok()
147 }
148
149 pub fn grant_cap(&self, cap_id: CapId) -> Self {
155 let mut new_caps = self.held_caps.clone();
156 Self::insert_cap_sorted(&mut new_caps, cap_id);
157 PluginState {
158 level: self.level,
159 memory: self.memory.clone(),
160 held_caps: new_caps,
161 local_state: self.local_state,
162 memory_quota: self.memory_quota,
163 memory_used: self.memory_used,
164 cap_quota: self.cap_quota,
165 ipc_queue_limit: self.ipc_queue_limit,
166 }
167 }
168
169 fn insert_cap_sorted(caps: &mut Vec<CapId>, cap_id: CapId) {
171 match caps.binary_search(&cap_id) {
172 Ok(_) => {} Err(pos) => caps.insert(pos, cap_id),
174 }
175 }
176
177 pub fn grant_cap_mut(&mut self, cap_id: CapId) {
179 Self::insert_cap_sorted(&mut self.held_caps, cap_id);
180 }
181
182 pub fn revoke_cap(&self, cap_id: CapId) -> Self {
188 let mut new_caps = self.held_caps.clone();
189 Self::remove_cap_sorted(&mut new_caps, cap_id);
190 PluginState {
191 level: self.level,
192 memory: self.memory.clone(),
193 held_caps: new_caps,
194 local_state: self.local_state,
195 memory_quota: self.memory_quota,
196 memory_used: self.memory_used,
197 cap_quota: self.cap_quota,
198 ipc_queue_limit: self.ipc_queue_limit,
199 }
200 }
201
202 fn remove_cap_sorted(caps: &mut Vec<CapId>, cap_id: CapId) {
204 if let Ok(pos) = caps.binary_search(&cap_id) {
205 caps.remove(pos);
206 }
207 }
208
209 pub fn revoke_cap_mut(&mut self, cap_id: CapId) {
211 Self::remove_cap_sorted(&mut self.held_caps, cap_id);
212 }
213
214 #[inline]
216 pub fn level(&self) -> SecurityLevel {
217 self.level
218 }
219
220 #[inline]
222 pub fn memory(&self) -> &LinearMemory {
223 &self.memory
224 }
225
226 #[inline]
228 #[allow(dead_code)] pub(crate) fn memory_mut(&mut self) -> &mut LinearMemory {
230 &mut self.memory
231 }
232
233 #[inline]
235 pub fn held_cap_count(&self) -> usize {
236 self.held_caps.len()
237 }
238
239 #[inline]
241 pub fn local_state(&self) -> PluginLocal {
242 self.local_state
243 }
244
245 pub fn held_caps(&self) -> Vec<CapId> {
250 self.held_caps.clone()
251 }
252
253 pub fn held_caps_ref(&self) -> &Vec<CapId> {
255 &self.held_caps
256 }
257
258 #[inline]
260 pub fn memory_bounds(&self) -> Size {
261 self.memory.bounds()
262 }
263
264 #[inline]
271 pub fn can_alloc_memory(&self, size: u64) -> bool {
272 match self.memory_used.checked_add(size) {
274 Some(total) => total <= self.memory_quota,
275 None => false, }
277 }
278
279 #[inline]
283 pub fn can_hold_cap(&self) -> bool {
284 (self.held_caps.len() as u64) < self.cap_quota
285 }
286
287 #[inline]
291 pub fn can_queue_ipc(&self, queue_len: u64) -> bool {
292 queue_len < self.ipc_queue_limit
293 }
294
295 pub fn alloc_memory(&mut self, size: u64) -> bool {
300 if !self.can_alloc_memory(size) {
301 return false;
302 }
303 self.memory_used = self.memory_used.saturating_add(size);
304 true
305 }
306
307 pub fn free_memory(&mut self, size: u64) {
311 self.memory_used = self.memory_used.saturating_sub(size);
312 }
313
314 #[inline]
316 pub fn memory_used(&self) -> u64 {
317 self.memory_used
318 }
319
320 #[inline]
322 pub fn memory_quota(&self) -> u64 {
323 self.memory_quota
324 }
325
326 #[inline]
328 pub fn cap_quota(&self) -> u64 {
329 self.cap_quota
330 }
331
332 #[inline]
334 pub fn ipc_queue_limit(&self) -> u64 {
335 self.ipc_queue_limit
336 }
337}
338
339impl Default for PluginState {
340 fn default() -> Self {
347 PluginState {
348 level: SecurityLevel::Public,
349 memory: LinearMemory::empty(0),
350 held_caps: Vec::new(),
351 local_state: PluginLocal,
352 memory_quota: DEFAULT_QUOTA,
353 memory_used: 0,
354 cap_quota: DEFAULT_QUOTA,
355 ipc_queue_limit: DEFAULT_QUOTA,
356 }
357 }
358}
359
360#[cfg(test)]
361mod tests {
362 use super::*;
363
364 #[test]
365 fn test_plugin_local_default() {
366 let local = PluginLocal;
367 assert_eq!(local, PluginLocal);
368 }
369
370 #[test]
371 fn test_plugin_state_empty() {
372 let ps = PluginState::empty(SecurityLevel::Confidential, 1024);
373 assert_eq!(ps.level(), SecurityLevel::Confidential);
374 assert_eq!(ps.memory_bounds(), 1024);
375 assert_eq!(ps.held_cap_count(), 0);
376 }
377
378 #[test]
379 fn test_plugin_state_default_level() {
380 let ps = PluginState::default();
382 assert_eq!(ps.level(), SecurityLevel::Public);
383 }
384
385 #[test]
386 fn test_plugin_state_grant_cap() {
387 let mut ps = PluginState::empty(SecurityLevel::Public, 0);
388
389 ps.grant_cap_mut(42);
391 assert!(ps.holds_cap(42));
392 assert_eq!(ps.held_cap_count(), 1);
393
394 ps.grant_cap_mut(42);
396 assert!(ps.holds_cap(42));
397 assert_eq!(ps.held_cap_count(), 1);
398 }
399
400 #[test]
401 fn test_plugin_state_grant_cap_mem() {
402 let ps = PluginState::empty(SecurityLevel::Public, 0);
404 let ps = ps.grant_cap(42);
405 assert!(ps.holds_cap(42));
406 }
407
408 #[test]
409 fn test_plugin_state_grant_cap_preserves() {
410 let ps = PluginState::empty(SecurityLevel::Public, 0);
412 let ps = ps.grant_cap(1);
413 let ps = ps.grant_cap(2);
414
415 assert!(ps.holds_cap(1));
417 assert!(ps.holds_cap(2));
418 }
419
420 #[test]
421 fn test_plugin_state_revoke_cap_not_mem() {
422 let ps = PluginState::empty(SecurityLevel::Public, 0);
424 let ps = ps.grant_cap(42);
425 let ps = ps.revoke_cap(42);
426
427 assert!(!ps.holds_cap(42));
428 assert_eq!(ps.held_cap_count(), 0);
429 }
430
431 #[test]
432 fn test_plugin_state_revoke_cap_preserves() {
433 let ps = PluginState::empty(SecurityLevel::Public, 0);
435 let ps = ps.grant_cap(1);
436 let ps = ps.grant_cap(2);
437 let ps = ps.revoke_cap(1);
438
439 assert!(!ps.holds_cap(1));
441 assert!(ps.holds_cap(2));
442 }
443
444 #[test]
445 fn test_plugin_state_grant_cap_memory() {
446 let ps = PluginState::empty(SecurityLevel::Public, 1024);
448 let old_memory = ps.memory().clone();
449 let ps = ps.grant_cap(42);
450
451 assert_eq!(ps.memory(), &old_memory);
453 }
454
455 #[test]
456 fn test_plugin_state_grant_cap_memory_bounds() {
457 let ps = PluginState::empty(SecurityLevel::Public, 1024);
459 let ps = ps.grant_cap(42);
460
461 assert_eq!(ps.memory_bounds(), 1024);
463 }
464
465 #[test]
466 fn test_plugin_state_grant_cap_level() {
467 let ps = PluginState::empty(SecurityLevel::Confidential, 0);
469 let ps = ps.grant_cap(42);
470
471 assert_eq!(ps.level(), SecurityLevel::Confidential);
473 }
474
475 #[test]
476 fn test_plugin_state_grant_cap_local_state() {
477 let ps = PluginState::empty(SecurityLevel::Public, 0);
479 let old_local = ps.local_state();
480 let ps = ps.grant_cap(42);
481
482 assert_eq!(ps.local_state(), old_local);
484 }
485
486 #[test]
487 fn test_plugin_state_held_caps_iterator() {
488 let mut ps = PluginState::empty(SecurityLevel::Public, 0);
489 ps.grant_cap_mut(1);
490 ps.grant_cap_mut(3);
491 ps.grant_cap_mut(2);
492
493 let caps = ps.held_caps();
495 assert_eq!(caps, vec![1, 2, 3]);
496 }
497
498 #[test]
501 fn test_default_quota() {
502 let ps = PluginState::default();
503 assert_eq!(ps.memory_quota(), DEFAULT_QUOTA);
504 assert_eq!(ps.memory_used(), 0);
505 assert_eq!(ps.cap_quota(), DEFAULT_QUOTA);
506 assert_eq!(ps.ipc_queue_limit(), DEFAULT_QUOTA);
507 }
508
509 #[test]
510 fn test_with_quotas() {
511 let ps = PluginState::with_quotas(
512 SecurityLevel::Confidential,
513 1024,
514 4096, 10, 100, );
518 assert_eq!(ps.level(), SecurityLevel::Confidential);
519 assert_eq!(ps.memory_bounds(), 1024);
520 assert_eq!(ps.memory_quota(), 4096);
521 assert_eq!(ps.cap_quota(), 10);
522 assert_eq!(ps.ipc_queue_limit(), 100);
523 }
524
525 #[test]
526 fn test_can_alloc_memory() {
527 let ps = PluginState::with_quotas(
528 SecurityLevel::Public,
529 0,
530 1000, 10,
532 100,
533 );
534
535 assert!(ps.can_alloc_memory(500));
537 assert!(ps.can_alloc_memory(1000));
538
539 assert!(!ps.can_alloc_memory(1001));
541 }
542
543 #[test]
544 fn test_alloc_memory_tracking() {
545 let mut ps = PluginState::with_quotas(SecurityLevel::Public, 0, 1000, 10, 100);
546
547 assert!(ps.alloc_memory(400));
549 assert_eq!(ps.memory_used(), 400);
550
551 assert!(ps.alloc_memory(400));
553 assert_eq!(ps.memory_used(), 800);
554
555 assert!(!ps.alloc_memory(300));
557 assert_eq!(ps.memory_used(), 800); assert!(ps.alloc_memory(200));
561 assert_eq!(ps.memory_used(), 1000);
562 }
563
564 #[test]
565 fn test_free_memory_tracking() {
566 let mut ps = PluginState::with_quotas(SecurityLevel::Public, 0, 1000, 10, 100);
567
568 ps.alloc_memory(800);
569 assert_eq!(ps.memory_used(), 800);
570
571 ps.free_memory(300);
572 assert_eq!(ps.memory_used(), 500);
573
574 assert!(ps.can_alloc_memory(500));
576 assert!(ps.alloc_memory(500));
577 assert_eq!(ps.memory_used(), 1000);
578 }
579
580 #[test]
581 fn test_can_hold_cap() {
582 let mut ps = PluginState::with_quotas(
583 SecurityLevel::Public,
584 0,
585 1000,
586 3, 100,
588 );
589
590 assert!(ps.can_hold_cap());
591 ps.grant_cap_mut(1);
592 assert!(ps.can_hold_cap());
593 ps.grant_cap_mut(2);
594 assert!(ps.can_hold_cap());
595 ps.grant_cap_mut(3);
596 assert!(!ps.can_hold_cap()); ps.revoke_cap_mut(1);
600 assert!(ps.can_hold_cap());
601 }
602
603 #[test]
604 fn test_can_queue_ipc() {
605 let ps = PluginState::with_quotas(
606 SecurityLevel::Public,
607 0,
608 1000,
609 10,
610 5, );
612
613 assert!(ps.can_queue_ipc(0));
614 assert!(ps.can_queue_ipc(4));
615 assert!(!ps.can_queue_ipc(5));
616 assert!(!ps.can_queue_ipc(100));
617 }
618
619 #[test]
620 fn test_quota_overflow_safety() {
621 let mut ps = PluginState::with_quotas(
622 SecurityLevel::Public,
623 0,
624 u64::MAX, 10,
626 100,
627 );
628
629 ps.memory_used = u64::MAX - 10;
631 assert!(!ps.can_alloc_memory(100)); assert!(ps.can_alloc_memory(5)); }
634}