preemptive_threads/security/
isolation.rs

1//! Thread isolation and sandboxing implementation.
2
3use crate::errors::ThreadError;
4use crate::security::{SecurityConfig, SecurityViolation, handle_security_violation};
5use crate::thread_new::ThreadId;
6use portable_atomic::{AtomicU64, AtomicUsize, Ordering};
7use alloc::{collections::BTreeMap, vec, vec::Vec};
8
9/// Thread isolation boundaries and sandboxing.
10pub struct ThreadIsolation {
11    /// Isolated thread domains
12    domains: BTreeMap<ThreadId, IsolationDomain>,
13    /// Isolation violations detected
14    violations_detected: AtomicUsize,
15    /// Domain boundary crosses
16    boundary_crosses: AtomicU64,
17}
18
19impl ThreadIsolation {
20    pub fn new() -> Self {
21        Self {
22            domains: BTreeMap::new(),
23            violations_detected: AtomicUsize::new(0),
24            boundary_crosses: AtomicU64::new(0),
25        }
26    }
27    
28    /// Create new isolation domain for thread.
29    pub fn create_domain(
30        &mut self,
31        thread_id: ThreadId,
32        config: IsolationConfig,
33    ) -> Result<(), ThreadError> {
34        let domain = IsolationDomain::new(thread_id, config)?;
35        self.domains.insert(thread_id, domain);
36        Ok(())
37    }
38    
39    /// Check if thread access is allowed.
40    pub fn check_access(
41        &self,
42        accessor_id: ThreadId,
43        target_id: ThreadId,
44        access_type: AccessType,
45    ) -> bool {
46        if accessor_id == target_id {
47            return true; // Self-access always allowed
48        }
49        
50        let accessor_domain = match self.domains.get(&accessor_id) {
51            Some(domain) => domain,
52            None => return true, // No isolation for this thread
53        };
54        
55        let allowed = accessor_domain.check_cross_domain_access(target_id, access_type);
56        
57        if !allowed {
58            self.violations_detected.fetch_add(1, Ordering::Relaxed);
59        } else {
60            self.boundary_crosses.fetch_add(1, Ordering::Relaxed);
61        }
62        
63        allowed
64    }
65    
66    /// Remove thread from isolation domain.
67    pub fn remove_domain(&mut self, thread_id: ThreadId) {
68        self.domains.remove(&thread_id);
69    }
70}
71
72/// Thread isolation domain configuration.
73#[derive(Debug, Clone)]
74pub struct IsolationConfig {
75    /// Domain security level
76    pub security_level: SecurityLevel,
77    /// Allowed cross-domain operations
78    pub allowed_operations: Vec<AccessType>,
79    /// Memory access restrictions
80    pub memory_restrictions: MemoryRestrictions,
81    /// Resource limits for this domain
82    pub resource_limits: ResourceLimits,
83    /// Inter-domain communication policy
84    pub ipc_policy: IpcPolicy,
85}
86
87impl Default for IsolationConfig {
88    fn default() -> Self {
89        Self {
90            security_level: SecurityLevel::Medium,
91            allowed_operations: vec![AccessType::Signal],
92            memory_restrictions: MemoryRestrictions::default(),
93            resource_limits: ResourceLimits::default(),
94            ipc_policy: IpcPolicy::Restricted,
95        }
96    }
97}
98
99/// Security levels for isolation domains.
100#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
101pub enum SecurityLevel {
102    /// Minimal isolation (performance-focused)
103    Low,
104    /// Standard isolation (balanced)
105    Medium,
106    /// Maximum isolation (security-focused)
107    High,
108    /// Critical isolation (for sensitive operations)
109    Critical,
110}
111
112/// Types of cross-domain access.
113#[derive(Debug, Clone, Copy, PartialEq, Eq)]
114pub enum AccessType {
115    /// Memory read access
116    MemoryRead,
117    /// Memory write access
118    MemoryWrite,
119    /// Signal delivery
120    Signal,
121    /// Resource sharing
122    ResourceShare,
123    /// IPC communication
124    Ipc,
125    /// Thread control (suspend/resume)
126    ThreadControl,
127}
128
129/// Memory access restrictions for domains.
130#[derive(Debug, Clone)]
131pub struct MemoryRestrictions {
132    /// Allowed memory regions
133    pub allowed_regions: Vec<MemoryRegion>,
134    /// Forbidden memory regions
135    pub forbidden_regions: Vec<MemoryRegion>,
136    /// Heap access policy
137    pub heap_access: HeapAccessPolicy,
138    /// Stack access policy
139    pub stack_access: StackAccessPolicy,
140}
141
142impl Default for MemoryRestrictions {
143    fn default() -> Self {
144        Self {
145            allowed_regions: Vec::new(),
146            forbidden_regions: Vec::new(),
147            heap_access: HeapAccessPolicy::Isolated,
148            stack_access: StackAccessPolicy::Private,
149        }
150    }
151}
152
153/// Memory region descriptor.
154#[derive(Debug, Clone)]
155pub struct MemoryRegion {
156    pub start: usize,
157    pub size: usize,
158    pub permissions: MemoryPermissions,
159}
160
161/// Memory permissions for regions.
162#[derive(Debug, Clone, Copy)]
163pub struct MemoryPermissions {
164    pub read: bool,
165    pub write: bool,
166    pub execute: bool,
167}
168
169/// Heap access policies.
170#[derive(Debug, Clone, Copy, PartialEq, Eq)]
171pub enum HeapAccessPolicy {
172    /// Thread has isolated heap
173    Isolated,
174    /// Thread shares global heap
175    Shared,
176    /// Thread has no heap access
177    None,
178}
179
180/// Stack access policies.
181#[derive(Debug, Clone, Copy, PartialEq, Eq)]
182pub enum StackAccessPolicy {
183    /// Private stack, no cross-access
184    Private,
185    /// Limited cross-access for debugging
186    LimitedAccess,
187    /// Full cross-access allowed
188    Shared,
189}
190
191/// Resource limits for isolation domains.
192#[derive(Debug, Clone)]
193pub struct ResourceLimits {
194    /// Maximum memory allocation
195    pub max_memory: Option<usize>,
196    /// Maximum CPU time (nanoseconds)
197    pub max_cpu_time: Option<u64>,
198    /// Maximum file handles
199    pub max_file_handles: Option<usize>,
200    /// Maximum network connections
201    pub max_network_connections: Option<usize>,
202}
203
204impl Default for ResourceLimits {
205    fn default() -> Self {
206        Self {
207            max_memory: Some(64 * 1024 * 1024), // 64MB default
208            max_cpu_time: None,
209            max_file_handles: Some(256),
210            max_network_connections: Some(16),
211        }
212    }
213}
214
215/// Inter-process communication policies.
216#[derive(Debug, Clone, Copy, PartialEq, Eq)]
217pub enum IpcPolicy {
218    /// No IPC allowed
219    Blocked,
220    /// Only with explicitly allowed domains
221    Restricted,
222    /// IPC with security checks
223    Controlled,
224    /// Full IPC access
225    Unrestricted,
226}
227
228/// Individual thread isolation domain.
229#[derive(Debug)]
230pub struct IsolationDomain {
231    /// Thread ID for this domain
232    pub thread_id: ThreadId,
233    /// Domain configuration
234    pub config: IsolationConfig,
235    /// Current resource usage
236    pub resource_usage: ResourceUsage,
237    /// Allowed domain interactions
238    pub allowed_domains: Vec<ThreadId>,
239    /// Domain creation time
240    pub created_at: u64,
241}
242
243impl IsolationDomain {
244    /// Create new isolation domain.
245    pub fn new(thread_id: ThreadId, config: IsolationConfig) -> Result<Self, ThreadError> {
246        Ok(Self {
247            thread_id,
248            config,
249            resource_usage: ResourceUsage::new(),
250            allowed_domains: Vec::new(),
251            created_at: crate::time::get_monotonic_time().as_nanos() as u64,
252        })
253    }
254    
255    /// Check if cross-domain access is allowed.
256    pub fn check_cross_domain_access(
257        &self,
258        target_domain: ThreadId,
259        access_type: AccessType,
260    ) -> bool {
261        // Always deny access to higher security levels
262        // (Would need to look up target domain's security level)
263        
264        // Check if this access type is explicitly allowed
265        if !self.config.allowed_operations.contains(&access_type) {
266            return false;
267        }
268        
269        // Check if target domain is in allowed list
270        if !self.allowed_domains.is_empty() && !self.allowed_domains.contains(&target_domain) {
271            return false;
272        }
273        
274        // Apply security level-specific checks
275        match self.config.security_level {
276            SecurityLevel::Low => true,
277            SecurityLevel::Medium => match access_type {
278                AccessType::MemoryWrite | AccessType::ThreadControl => false,
279                _ => true,
280            },
281            SecurityLevel::High => match access_type {
282                AccessType::Signal => true,
283                _ => false,
284            },
285            SecurityLevel::Critical => false, // Deny all cross-domain access
286        }
287    }
288    
289    /// Add allowed domain for interaction.
290    pub fn allow_domain_interaction(&mut self, domain_id: ThreadId) {
291        if !self.allowed_domains.contains(&domain_id) {
292            self.allowed_domains.push(domain_id);
293        }
294    }
295    
296    /// Remove allowed domain.
297    pub fn disallow_domain_interaction(&mut self, domain_id: ThreadId) {
298        self.allowed_domains.retain(|&id| id != domain_id);
299    }
300    
301    /// Check if memory access is allowed.
302    pub fn check_memory_access(&self, address: usize, size: usize, write: bool) -> bool {
303        // Check against forbidden regions first
304        for region in &self.config.memory_restrictions.forbidden_regions {
305            if address >= region.start && address < region.start + region.size {
306                return false;
307            }
308        }
309        
310        // If allowed regions specified, must be in one of them
311        if !self.config.memory_restrictions.allowed_regions.is_empty() {
312            let mut found = false;
313            for region in &self.config.memory_restrictions.allowed_regions {
314                if address >= region.start 
315                   && address + size <= region.start + region.size 
316                   && (!write || region.permissions.write) {
317                    found = true;
318                    break;
319                }
320            }
321            if !found {
322                return false;
323            }
324        }
325        
326        true
327    }
328    
329    /// Update resource usage and check limits.
330    pub fn update_resource_usage(&mut self, usage: ResourceUsage) -> Result<(), ThreadError> {
331        // Check memory limit
332        if let Some(max_memory) = self.config.resource_limits.max_memory {
333            if usage.memory_used > max_memory {
334                return Err(ThreadError::ResourceExhaustion());
335            }
336        }
337        
338        // Check CPU time limit
339        if let Some(max_cpu) = self.config.resource_limits.max_cpu_time {
340            if usage.cpu_time_used > max_cpu {
341                return Err(ThreadError::ResourceExhaustion());
342            }
343        }
344        
345        self.resource_usage = usage;
346        Ok(())
347    }
348}
349
350/// Current resource usage for a domain.
351#[derive(Debug, Clone)]
352pub struct ResourceUsage {
353    pub memory_used: usize,
354    pub cpu_time_used: u64,
355    pub file_handles_used: usize,
356    pub network_connections_used: usize,
357}
358
359impl ResourceUsage {
360    pub fn new() -> Self {
361        Self {
362            memory_used: 0,
363            cpu_time_used: 0,
364            file_handles_used: 0,
365            network_connections_used: 0,
366        }
367    }
368}
369
370/// Global thread isolation manager.
371static mut THREAD_ISOLATION: Option<ThreadIsolation> = None;
372
373/// Memory access guard for isolated domains.
374pub struct MemoryAccessGuard {
375    domain_id: ThreadId,
376    address: usize,
377    size: usize,
378}
379
380impl MemoryAccessGuard {
381    /// Create new memory access guard.
382    pub fn new(domain_id: ThreadId, address: usize, size: usize) -> Result<Self, ThreadError> {
383        // Verify access is allowed
384        if !check_memory_access(domain_id, address, size, false) {
385            handle_security_violation(SecurityViolation::IsolationViolation);
386        }
387        
388        Ok(Self {
389            domain_id,
390            address,
391            size,
392        })
393    }
394    
395    /// Get safe pointer for reading.
396    pub unsafe fn read_ptr<T>(&self) -> *const T {
397        self.address as *const T
398    }
399    
400    /// Get safe pointer for writing (requires write access check).
401    pub unsafe fn write_ptr<T>(&self) -> Result<*mut T, ThreadError> {
402        if !check_memory_access(self.domain_id, self.address, self.size, true) {
403            handle_security_violation(SecurityViolation::IsolationViolation);
404        }
405        Ok(self.address as *mut T)
406    }
407}
408
409/// Cross-domain communication channel.
410pub struct CrossDomainChannel {
411    sender_domain: ThreadId,
412    receiver_domain: ThreadId,
413    allowed: bool,
414}
415
416impl CrossDomainChannel {
417    /// Create new cross-domain communication channel.
418    pub fn new(sender: ThreadId, receiver: ThreadId) -> Result<Self, ThreadError> {
419        let allowed = check_cross_domain_access(sender, receiver, AccessType::Ipc);
420        
421        if !allowed {
422            return Err(ThreadError::PermissionDenied());
423        }
424        
425        Ok(Self {
426            sender_domain: sender,
427            receiver_domain: receiver,
428            allowed,
429        })
430    }
431    
432    /// Send message through channel.
433    pub fn send<T>(&self, message: T) -> Result<(), ThreadError> {
434        if !self.allowed {
435            return Err(ThreadError::PermissionDenied());
436        }
437        
438        // In real implementation, this would use secure IPC mechanism
439        // For now, just validate the operation is allowed
440        Ok(())
441    }
442}
443
444/// Helper functions for isolation management.
445
446/// Initialize thread isolation subsystem.
447pub fn init_thread_isolation(_config: SecurityConfig) -> Result<(), ThreadError> {
448    unsafe {
449        THREAD_ISOLATION = Some(ThreadIsolation::new());
450    }
451    
452    // Initialization completed
453    Ok(())
454}
455
456/// Create isolation domain for thread.
457pub fn create_isolation_domain(
458    thread_id: ThreadId,
459    config: IsolationConfig,
460) -> Result<(), ThreadError> {
461    unsafe {
462        if let Some(isolation) = &mut THREAD_ISOLATION {
463            isolation.create_domain(thread_id, config)
464        } else {
465            Err(ThreadError::InvalidState())
466        }
467    }
468}
469
470/// Check cross-domain access permission.
471pub fn check_cross_domain_access(
472    accessor_id: ThreadId,
473    target_id: ThreadId,
474    access_type: AccessType,
475) -> bool {
476    unsafe {
477        if let Some(isolation) = &THREAD_ISOLATION {
478            isolation.check_access(accessor_id, target_id, access_type)
479        } else {
480            true // No isolation active, allow access
481        }
482    }
483}
484
485/// Check memory access permission for domain.
486pub fn check_memory_access(
487    domain_id: ThreadId,
488    address: usize,
489    size: usize,
490    write: bool,
491) -> bool {
492    unsafe {
493        if let Some(isolation) = &THREAD_ISOLATION {
494            if let Some(domain) = isolation.domains.get(&domain_id) {
495                domain.check_memory_access(address, size, write)
496            } else {
497                true // No domain restrictions
498            }
499        } else {
500            true // No isolation active
501        }
502    }
503}
504
505/// Remove thread from isolation system.
506pub fn remove_isolation_domain(thread_id: ThreadId) {
507    unsafe {
508        if let Some(isolation) = &mut THREAD_ISOLATION {
509            isolation.remove_domain(thread_id);
510        }
511    }
512}
513
514/// Thread isolation statistics.
515#[derive(Debug, Clone)]
516pub struct IsolationStats {
517    pub domains_active: usize,
518    pub violations_detected: usize,
519    pub boundary_crosses: u64,
520    pub isolation_enabled: bool,
521}
522
523/// Get thread isolation statistics.
524pub fn get_isolation_stats() -> IsolationStats {
525    unsafe {
526        if let Some(isolation) = &THREAD_ISOLATION {
527            IsolationStats {
528                domains_active: isolation.domains.len(),
529                violations_detected: isolation.violations_detected.load(Ordering::Relaxed),
530                boundary_crosses: isolation.boundary_crosses.load(Ordering::Relaxed),
531                isolation_enabled: true,
532            }
533        } else {
534            IsolationStats {
535                domains_active: 0,
536                violations_detected: 0,
537                boundary_crosses: 0,
538                isolation_enabled: false,
539            }
540        }
541    }
542}
543
544/// Macro for creating isolated thread domain.
545#[macro_export]
546macro_rules! isolated_thread {
547    ($thread_id:expr, $security_level:expr) => {{
548        use crate::security::isolation::{IsolationConfig, SecurityLevel, create_isolation_domain};
549        let config = IsolationConfig {
550            security_level: $security_level,
551            ..Default::default()
552        };
553        create_isolation_domain($thread_id, config)
554    }};
555}
556
557/// Macro for safe cross-domain access.
558#[macro_export]
559macro_rules! cross_domain_access {
560    ($accessor:expr, $target:expr, $access_type:expr, $operation:expr) => {{
561        use crate::security::isolation::check_cross_domain_access;
562        if check_cross_domain_access($accessor, $target, $access_type) {
563            Some($operation)
564        } else {
565            None
566        }
567    }};
568}