1use std::collections::VecDeque;
4use std::sync::{Arc, Mutex};
5use std::time::{Duration, SystemTime};
6
7use serde::{Serialize, Deserialize};
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
11pub enum AuditSeverity {
12 Info,
14
15 Warning,
17
18 Error,
20
21 Critical,
23}
24
25#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
27pub enum AuditEventType {
28 ModuleLoaded {
30 id: String,
32
33 size: usize
35 },
36
37 InstanceCreated {
39 id: String
41 },
42
43 InstanceTerminated {
45 id: String,
47
48 exit_code: Option<i32>
50 },
51
52 FunctionCall {
54 instance_id: String,
56
57 function_name: String
59 },
60
61 ResourceLimit {
63 instance_id: String,
65
66 resource: String,
68
69 limit_type: String,
71
72 limit: u64,
74
75 attempted: u64
77 },
78
79 CapabilityViolation {
81 instance_id: String,
83
84 domain: String,
86
87 operation: String
89 },
90
91 HostFunctionCall {
93 instance_id: String,
95
96 function_name: String
98 },
99
100 MemoryAccess {
102 instance_id: String,
104
105 access_type: String,
107
108 address: u32,
110
111 size: usize
113 },
114
115 Custom {
117 event_type: String,
119
120 data: String
122 },
123}
124
125#[derive(Debug, Clone, Serialize, Deserialize)]
127pub struct AuditEvent {
128 pub timestamp: SystemTime,
130
131 pub severity: AuditSeverity,
133
134 pub event_type: AuditEventType,
136
137 pub message: String,
139}
140
141#[derive(Debug, Clone)]
143pub struct AuditLogger {
144 events: Arc<Mutex<VecDeque<AuditEvent>>>,
146
147 max_events: usize,
149
150 log_to_stdout: bool,
152
153 log_to_file: bool,
155
156 file_path: Option<String>,
158}
159
160impl AuditLogger {
161 pub fn new(max_events: usize) -> Self {
163 Self {
164 events: Arc::new(Mutex::new(VecDeque::with_capacity(max_events))),
165 max_events,
166 log_to_stdout: false,
167 log_to_file: false,
168 file_path: None,
169 }
170 }
171
172 pub fn with_stdout(mut self) -> Self {
174 self.log_to_stdout = true;
175 self
176 }
177
178 pub fn with_file(mut self, file_path: &str) -> Self {
180 self.log_to_file = true;
181 self.file_path = Some(file_path.to_string());
182 self
183 }
184
185 pub fn log(&self, severity: AuditSeverity, event_type: AuditEventType, message: &str) {
187 let event = AuditEvent {
188 timestamp: SystemTime::now(),
189 severity,
190 event_type,
191 message: message.to_string(),
192 };
193
194 if self.log_to_stdout {
196 let timestamp = chrono::DateTime::<chrono::Utc>::from(event.timestamp)
197 .format("%Y-%m-%d %H:%M:%S%.3f")
198 .to_string();
199
200 let level = match event.severity {
201 AuditSeverity::Info => "INFO",
202 AuditSeverity::Warning => "WARN",
203 AuditSeverity::Error => "ERROR",
204 AuditSeverity::Critical => "CRITICAL",
205 };
206
207 println!("[{}] {} - {} - {:?}", timestamp, level, event.message, event.event_type);
208 }
209
210 if self.log_to_file {
212 if let Some(file_path) = &self.file_path {
213 let json = serde_json::to_string(&event).unwrap_or_else(|_| "{}".to_string());
215
216 std::fs::OpenOptions::new()
218 .create(true)
219 .append(true)
220 .open(file_path)
221 .map(|mut file| {
222 use std::io::Write;
223 let _ = writeln!(file, "{}", json);
224 })
225 .ok();
226 }
227 }
228
229 let mut events = self.events.lock().unwrap();
231 events.push_back(event);
232
233 while events.len() > self.max_events {
235 events.pop_front();
236 }
237 }
238
239 pub fn info(&self, event_type: AuditEventType, message: &str) {
241 self.log(AuditSeverity::Info, event_type, message);
242 }
243
244 pub fn warning(&self, event_type: AuditEventType, message: &str) {
246 self.log(AuditSeverity::Warning, event_type, message);
247 }
248
249 pub fn error(&self, event_type: AuditEventType, message: &str) {
251 self.log(AuditSeverity::Error, event_type, message);
252 }
253
254 pub fn critical(&self, event_type: AuditEventType, message: &str) {
256 self.log(AuditSeverity::Critical, event_type, message);
257 }
258
259 pub fn get_events(&self) -> Vec<AuditEvent> {
261 self.events.lock().unwrap().iter().cloned().collect()
262 }
263
264 pub fn get_events_by_severity(&self, severity: AuditSeverity) -> Vec<AuditEvent> {
266 self.events.lock().unwrap()
267 .iter()
268 .filter(|e| e.severity == severity)
269 .cloned()
270 .collect()
271 }
272
273 pub fn get_events_in_range(&self, start: SystemTime, end: SystemTime) -> Vec<AuditEvent> {
275 self.events.lock().unwrap()
276 .iter()
277 .filter(|e| e.timestamp >= start && e.timestamp <= end)
278 .cloned()
279 .collect()
280 }
281
282 pub fn clear(&self) {
284 self.events.lock().unwrap().clear();
285 }
286}
287
288#[derive(Debug, Clone)]
290pub struct AuditConfig {
291 pub enabled: bool,
293
294 pub log_to_stdout: bool,
296
297 pub log_to_file: bool,
299
300 pub file_path: Option<String>,
302
303 pub max_events: usize,
305
306 pub min_severity: AuditSeverity,
308
309 pub log_module_loads: bool,
311
312 pub log_instance_creation: bool,
314
315 pub log_function_calls: bool,
317
318 pub log_resource_limits: bool,
320
321 pub log_capability_violations: bool,
323}
324
325impl Default for AuditConfig {
326 fn default() -> Self {
327 Self {
328 enabled: true,
329 log_to_stdout: false,
330 log_to_file: false,
331 file_path: None,
332 max_events: 1000,
333 min_severity: AuditSeverity::Info,
334 log_module_loads: true,
335 log_instance_creation: true,
336 log_function_calls: true,
337 log_resource_limits: true,
338 log_capability_violations: true,
339 }
340 }
341}
342
343#[derive(Debug, Clone, Copy, PartialEq, Eq)]
345pub enum ThreatLevel {
346 None,
348
349 Low,
351
352 Medium,
354
355 High,
357
358 Critical,
360}
361
362pub struct SecurityScanner {
364 logger: AuditLogger,
366
367 config: ScanConfig,
369}
370
371#[derive(Debug, Clone)]
373pub struct ScanConfig {
374 pub capability_violation_threshold: usize,
376
377 pub resource_limit_threshold: usize,
379
380 pub scan_interval: Duration,
382
383 pub detect_memory_access_patterns: bool,
385
386 pub detect_network_access_patterns: bool,
388
389 pub detect_filesystem_access_patterns: bool,
391}
392
393impl Default for ScanConfig {
394 fn default() -> Self {
395 Self {
396 capability_violation_threshold: 3,
397 resource_limit_threshold: 5,
398 scan_interval: Duration::from_secs(60),
399 detect_memory_access_patterns: true,
400 detect_network_access_patterns: true,
401 detect_filesystem_access_patterns: true,
402 }
403 }
404}
405
406impl SecurityScanner {
407 pub fn new(logger: AuditLogger, config: ScanConfig) -> Self {
409 Self {
410 logger,
411 config,
412 }
413 }
414
415 pub fn scan(&self) -> Vec<SecurityThreat> {
417 let mut threats = Vec::new();
418 let events = self.logger.get_events();
419
420 let capability_violations = events.iter()
422 .filter(|e| matches!(e.event_type, AuditEventType::CapabilityViolation { .. }))
423 .count();
424
425 if capability_violations >= self.config.capability_violation_threshold {
426 threats.push(SecurityThreat {
427 level: ThreatLevel::Medium,
428 description: format!(
429 "High number of capability violations detected: {} (threshold: {})",
430 capability_violations,
431 self.config.capability_violation_threshold
432 ),
433 events: events.iter()
434 .filter(|e| matches!(e.event_type, AuditEventType::CapabilityViolation { .. }))
435 .cloned()
436 .collect(),
437 });
438 }
439
440 let resource_violations = events.iter()
442 .filter(|e| matches!(e.event_type, AuditEventType::ResourceLimit { .. }))
443 .count();
444
445 if resource_violations >= self.config.resource_limit_threshold {
446 threats.push(SecurityThreat {
447 level: ThreatLevel::Medium,
448 description: format!(
449 "High number of resource limit violations detected: {} (threshold: {})",
450 resource_violations,
451 self.config.resource_limit_threshold
452 ),
453 events: events.iter()
454 .filter(|e| matches!(e.event_type, AuditEventType::ResourceLimit { .. }))
455 .cloned()
456 .collect(),
457 });
458 }
459
460 if self.config.detect_memory_access_patterns {
462 let memory_accesses = events.iter()
463 .filter(|e| matches!(e.event_type, AuditEventType::MemoryAccess { .. }))
464 .collect::<Vec<_>>();
465
466 let mut suspicious_addresses = std::collections::HashSet::new();
469 for event in &memory_accesses {
470 if let AuditEventType::MemoryAccess {
471 address, size, access_type, ..
472 } = &event.event_type {
473 if access_type == "write" && *size > 1024 && *address > 0xFFFF0000 {
474 suspicious_addresses.insert(*address);
475 }
476 }
477 }
478
479 if suspicious_addresses.len() > 2 {
480 threats.push(SecurityThreat {
481 level: ThreatLevel::High,
482 description: format!(
483 "Potential buffer overflow attempt detected: {} suspicious memory writes",
484 suspicious_addresses.len()
485 ),
486 events: memory_accesses.into_iter().cloned().collect(),
487 });
488 }
489 }
490
491 threats
492 }
493
494 pub fn start_scanner(&self) -> std::thread::JoinHandle<()> {
496 let logger = self.logger.clone();
497 let config = self.config.clone();
498
499 std::thread::spawn(move || {
500 let scanner = SecurityScanner::new(logger.clone(), config);
501
502 loop {
503 std::thread::sleep(scanner.config.scan_interval);
505
506 let threats = scanner.scan();
508
509 for threat in threats {
511 logger.log(
512 match threat.level {
513 ThreatLevel::None | ThreatLevel::Low => AuditSeverity::Info,
514 ThreatLevel::Medium => AuditSeverity::Warning,
515 ThreatLevel::High | ThreatLevel::Critical => AuditSeverity::Critical,
516 },
517 AuditEventType::Custom {
518 event_type: "security_threat".to_string(),
519 data: threat.description.clone(),
520 },
521 &format!("Security threat detected: {}", threat.description),
522 );
523 }
524 }
525 })
526 }
527}
528
529#[derive(Debug, Clone)]
531pub struct SecurityThreat {
532 pub level: ThreatLevel,
534
535 pub description: String,
537
538 pub events: Vec<AuditEvent>,
540}