1use crate::analysis::ffi_function_resolver::{get_global_ffi_resolver, ResolvedFfiFunction};
9use crate::core::types::{AllocationInfo, TrackingError, TrackingResult};
10use crate::core::{get_global_call_stack_normalizer, CallStackRef};
11use serde::{Deserialize, Serialize};
12use std::collections::HashMap;
13use std::sync::{Arc, Mutex, OnceLock};
14
15#[derive(Debug, Clone, Serialize, Deserialize)]
17pub enum AllocationSource {
18 RustSafe,
20 UnsafeRust {
22 unsafe_block_location: String,
24 call_stack: CallStackRef,
26 risk_assessment: RiskAssessment,
28 },
29 FfiC {
31 resolved_function: ResolvedFfiFunction,
33 call_stack: CallStackRef,
35 libc_hook_info: LibCHookInfo,
37 },
38 CrossBoundary {
40 from: Box<AllocationSource>,
42 to: Box<AllocationSource>,
44 transfer_timestamp: u128,
46 transfer_metadata: TransferMetadata,
48 },
49}
50
51#[derive(Debug, Clone, Serialize, Deserialize, Hash, PartialEq, Eq)]
53pub struct StackFrame {
54 pub function_name: String,
56 pub file_name: Option<String>,
58 pub line_number: Option<u32>,
60 pub is_unsafe: bool,
62}
63
64#[derive(Debug, Clone, Serialize, Deserialize)]
66pub enum SafetyViolation {
67 DoubleFree {
69 first_free_stack: CallStackRef,
71 second_free_stack: CallStackRef,
73 timestamp: u128,
75 },
76 InvalidFree {
78 attempted_pointer: usize,
80 stack: CallStackRef,
82 timestamp: u128,
84 },
85 PotentialLeak {
87 allocation_stack: CallStackRef,
89 allocation_timestamp: u128,
91 leak_detection_timestamp: u128,
93 },
94 CrossBoundaryRisk {
96 risk_level: RiskLevel,
98 description: String,
100 stack: CallStackRef,
102 },
103}
104
105#[derive(Debug, Clone, Serialize, Deserialize)]
107pub enum RiskLevel {
108 Low,
110 Medium,
112 High,
114 Critical,
116}
117
118#[derive(Debug, Clone, Serialize, Deserialize)]
120pub struct RiskAssessment {
121 pub risk_level: RiskLevel,
123 pub risk_factors: Vec<RiskFactor>,
125 pub mitigation_suggestions: Vec<String>,
127 pub confidence_score: f64,
129 pub assessment_timestamp: u128,
131}
132
133#[derive(Debug, Clone, Serialize, Deserialize)]
135pub struct RiskFactor {
136 pub factor_type: RiskFactorType,
138 pub severity: f64,
140 pub description: String,
142 pub source_location: Option<String>,
144}
145
146#[derive(Debug, Clone, Serialize, Deserialize)]
148pub enum RiskFactorType {
149 RawPointerDeref,
151 ManualMemoryManagement,
153 CrossBoundaryTransfer,
155 UncheckedCast,
157 LifetimeViolation,
159 UseAfterFree,
161 BufferOverflow,
163 DataRace,
165}
166
167#[derive(Debug, Clone, Serialize, Deserialize)]
169pub struct LibCHookInfo {
170 pub hook_method: HookMethod,
172 pub original_function: String,
174 pub hook_timestamp: u128,
176 pub allocation_metadata: AllocationMetadata,
178 pub hook_overhead_ns: Option<u64>,
180}
181
182#[derive(Debug, Clone, Serialize, Deserialize)]
184pub enum HookMethod {
185 LdPreload,
187 DynamicLinker,
189 StaticInterposition,
191 RuntimePatching,
193}
194
195#[derive(Debug, Clone, Serialize, Deserialize)]
197pub struct AllocationMetadata {
198 pub requested_size: usize,
200 pub actual_size: usize,
202 pub alignment: usize,
204 pub allocator_info: String,
206 pub protection_flags: Option<MemoryProtectionFlags>,
208}
209
210#[derive(Debug, Clone, Serialize, Deserialize)]
212pub struct MemoryProtectionFlags {
213 pub readable: bool,
215 pub writable: bool,
217 pub executable: bool,
219 pub shared: bool,
221}
222
223#[derive(Debug, Clone, Serialize, Deserialize)]
225pub struct MemoryPassport {
226 pub passport_id: String,
228 pub origin: AllocationOrigin,
230 pub journey: Vec<PassportStamp>,
232 pub current_owner: OwnershipInfo,
234 pub validity_status: ValidityStatus,
236 pub security_clearance: SecurityClearance,
238}
239
240#[derive(Debug, Clone, Serialize, Deserialize)]
242pub struct AllocationOrigin {
243 pub context: String,
245 pub allocator_function: String,
247 pub timestamp: u128,
249 pub call_stack: CallStackRef,
251}
252
253#[derive(Debug, Clone, Serialize, Deserialize)]
255pub struct PassportStamp {
256 pub timestamp: u128,
258 pub location: String,
260 pub operation: String,
262 pub authority: String,
264 pub verification_hash: String,
266}
267
268#[derive(Debug, Clone, Serialize, Deserialize)]
270pub struct OwnershipInfo {
271 pub owner_context: String,
273 pub owner_function: String,
275 pub transfer_timestamp: u128,
277 pub expected_lifetime: Option<u128>,
279}
280
281#[derive(Debug, Clone, Serialize, Deserialize)]
283pub enum ValidityStatus {
284 Valid,
286 Expired,
288 Revoked,
290 Suspicious,
292}
293
294#[derive(Debug, Clone, Serialize, Deserialize)]
296pub enum SecurityClearance {
297 Public,
299 Restricted,
301 Confidential,
303 Secret,
305}
306
307#[derive(Debug, Clone, Serialize, Deserialize)]
309pub struct TransferMetadata {
310 pub transfer_reason: String,
312 pub expected_return: Option<String>,
314 pub validation_method: ValidationMethod,
316 pub transfer_overhead_ns: Option<u64>,
318}
319
320#[derive(Debug, Clone, Serialize, Deserialize)]
322pub enum ValidationMethod {
323 None,
325 PointerCheck,
327 BoundsCheck,
329 IntegrityCheck,
331 CryptographicCheck,
333}
334
335#[derive(Debug, Clone, Serialize, Deserialize)]
337pub struct EnhancedAllocationInfo {
338 pub base: AllocationInfo,
340 pub source: AllocationSource,
342 pub call_stack: CallStackRef,
344 pub cross_boundary_events: Vec<BoundaryEvent>,
346 pub safety_violations: Vec<SafetyViolation>,
348 pub ffi_tracked: bool,
350 pub memory_passport: Option<MemoryPassport>,
352 pub ownership_history: Option<Vec<OwnershipTransferEvent>>,
354}
355
356#[derive(Debug, Clone, Serialize, Deserialize)]
358pub struct BoundaryEvent {
359 pub event_type: BoundaryEventType,
361 pub timestamp: u128,
363 pub from_context: String,
365 pub to_context: String,
367 pub stack: CallStackRef,
369}
370
371#[derive(Debug, Clone, Serialize, Deserialize)]
373pub enum BoundaryEventType {
374 RustToFfi,
376 FfiToRust,
378 OwnershipTransfer,
380 SharedAccess,
382}
383
384#[derive(Debug, Clone, Serialize, Deserialize)]
386pub struct BoundaryEventAnalysis {
387 pub event_id: String,
389 pub ptr: usize,
391 pub event_type: BoundaryEventType,
393 pub from_context: String,
395 pub to_context: String,
397 pub transfer_size: usize,
399 pub timestamp: u128,
401 pub risk_assessment: BoundaryRiskAssessment,
403 pub ownership_chain: Vec<OwnershipRecord>,
405 pub security_implications: Vec<SecurityImplication>,
407 pub performance_impact: PerformanceImpact,
409 pub mitigation_recommendations: Vec<String>,
411}
412
413#[derive(Debug, Clone, Serialize, Deserialize)]
415pub struct BoundaryRiskAssessment {
416 pub overall_risk_level: RiskLevel,
418 pub risk_score: f64,
420 pub risk_factors: Vec<BoundaryRiskFactor>,
422 pub confidence_score: f64,
424 pub assessment_timestamp: u128,
426}
427
428#[derive(Debug, Clone, Serialize, Deserialize)]
430pub struct BoundaryRiskFactor {
431 pub factor_type: BoundaryRiskFactorType,
433 pub severity: f64,
435 pub description: String,
437 pub mitigation: String,
439}
440
441#[derive(Debug, Clone, Serialize, Deserialize)]
443pub enum BoundaryRiskFactorType {
444 RustToForeignTransfer,
446 ForeignToRustTransfer,
448 OwnershipTransfer,
450 SharedAccess,
452 LargeTransfer,
454 FrequentTransfers,
456 UnvalidatedTransfer,
458 PrivilegeBoundary,
460}
461
462#[derive(Debug, Clone, Serialize, Deserialize)]
464pub struct OwnershipTransferEvent {
465 pub transfer_id: String,
467 pub ptr: usize,
469 pub from_context: String,
471 pub to_context: String,
473 pub transfer_timestamp: u128,
475 pub transfer_reason: String,
477 pub validation_status: OwnershipValidationStatus,
479}
480
481#[derive(Debug, Clone, Serialize, Deserialize)]
483pub enum OwnershipValidationStatus {
484 Valid,
486 Pending,
488 Warning,
490 Invalid,
492 Failed,
494}
495
496#[derive(Debug, Clone, Serialize, Deserialize)]
498pub struct OwnershipRecord {
499 pub context: String,
501 pub timestamp: u128,
503 pub transfer_reason: String,
505 pub validation_status: OwnershipValidationStatus,
507}
508
509#[derive(Debug, Clone, Serialize, Deserialize)]
511pub struct SecurityImplication {
512 pub implication_type: SecurityImplicationType,
514 pub severity: RiskLevel,
516 pub description: String,
518 pub potential_impact: String,
520 pub recommended_action: String,
522}
523
524#[derive(Debug, Clone, Serialize, Deserialize)]
526pub enum SecurityImplicationType {
527 PrivilegeEscalation,
529 DataExposure,
531 InjectionRisk,
533 BufferOverflow,
535 UseAfterFree,
537 RaceCondition,
539 InformationDisclosure,
541}
542
543#[derive(Debug, Clone, Serialize, Deserialize)]
545pub struct PerformanceImpact {
546 pub impact_level: PerformanceImpactLevel,
548 pub estimated_overhead_ns: u64,
550 pub memory_overhead_bytes: usize,
552 pub cpu_overhead_percent: f64,
554 pub recommendations: Vec<String>,
556}
557
558#[derive(Debug, Clone, Serialize, Deserialize)]
560pub enum PerformanceImpactLevel {
561 Low,
563 Medium,
565 High,
567 Critical,
569}
570
571#[derive(Debug, Clone, Serialize, Deserialize)]
573pub struct BoundaryEventStatistics {
574 pub total_events: usize,
576 pub events_by_type: std::collections::HashMap<String, usize>,
578 pub risk_distribution: std::collections::HashMap<String, usize>,
580 pub average_transfer_size: f64,
582 pub total_transfer_volume: usize,
584 pub most_active_contexts: Vec<(String, usize)>,
586 pub security_incidents: usize,
588 pub performance_issues: usize,
590 pub analysis_timestamp: u128,
592}
593
594pub struct UnsafeFFITracker {
596 enhanced_allocations: Mutex<HashMap<usize, EnhancedAllocationInfo>>,
598 freed_pointers: Mutex<HashMap<usize, (CallStackRef, u128)>>,
600 violations: Mutex<Vec<SafetyViolation>>,
602 c_libraries: Mutex<HashMap<String, CLibraryInfo>>,
604 libc_hooks: Mutex<HashMap<String, EnhancedLibCHookInfo>>,
606 memory_passports: Mutex<HashMap<usize, MemoryPassport>>,
608}
609
610impl UnsafeFFITracker {
611 pub fn new() -> Self {
613 Self {
614 enhanced_allocations: Mutex::new(HashMap::new()),
615 freed_pointers: Mutex::new(HashMap::new()),
616 violations: Mutex::new(Vec::new()),
617 c_libraries: Mutex::new(HashMap::new()),
618 libc_hooks: Mutex::new(HashMap::new()),
619 memory_passports: Mutex::new(HashMap::new()),
620 }
621 }
622
623 fn create_default_unsafe_risk_assessment(&self, unsafe_location: &str) -> RiskAssessment {
625 let current_time = std::time::SystemTime::now()
626 .duration_since(std::time::UNIX_EPOCH)
627 .unwrap_or_default()
628 .as_nanos();
629
630 let risk_factors = vec![RiskFactor {
631 factor_type: RiskFactorType::ManualMemoryManagement,
632 severity: 5.0,
633 description: "Manual memory management in unsafe block".to_string(),
634 source_location: Some(unsafe_location.to_string()),
635 }];
636
637 RiskAssessment {
638 risk_level: RiskLevel::Medium,
639 risk_factors,
640 mitigation_suggestions: vec![
641 "Ensure proper memory cleanup".to_string(),
642 "Use RAII patterns where possible".to_string(),
643 ],
644 confidence_score: 0.7,
645 assessment_timestamp: current_time,
646 }
647 }
648
649 fn create_default_libc_hook_info(&self, function_name: &str, size: usize) -> LibCHookInfo {
651 let current_time = std::time::SystemTime::now()
652 .duration_since(std::time::UNIX_EPOCH)
653 .unwrap_or_default()
654 .as_nanos();
655
656 LibCHookInfo {
657 hook_method: HookMethod::DynamicLinker,
658 original_function: function_name.to_string(),
659 hook_timestamp: current_time,
660 allocation_metadata: AllocationMetadata {
661 requested_size: size,
662 actual_size: size,
663 alignment: 8, allocator_info: "libc malloc".to_string(),
665 protection_flags: Some(MemoryProtectionFlags {
666 readable: true,
667 writable: true,
668 executable: false,
669 shared: false,
670 }),
671 },
672 hook_overhead_ns: Some(100), }
674 }
675
676 fn create_memory_passport(&self, ptr: usize, origin_context: &str) -> MemoryPassport {
678 let current_time = std::time::SystemTime::now()
679 .duration_since(std::time::UNIX_EPOCH)
680 .unwrap_or_default()
681 .as_nanos();
682
683 MemoryPassport {
684 passport_id: format!("passport_{ptr:x}_{current_time}"),
685 origin: AllocationOrigin {
686 context: origin_context.to_string(),
687 allocator_function: "unknown".to_string(),
688 timestamp: current_time,
689 call_stack: {
690 let normalizer = get_global_call_stack_normalizer();
691 let empty_frames = vec![];
692 let id = normalizer.normalize_call_stack(&empty_frames).unwrap_or(0);
693 CallStackRef::new(id, Some(0))
694 },
695 },
696 journey: Vec::new(),
697 current_owner: OwnershipInfo {
698 owner_context: origin_context.to_string(),
699 owner_function: "unknown".to_string(),
700 transfer_timestamp: current_time,
701 expected_lifetime: None,
702 },
703 validity_status: ValidityStatus::Valid,
704 security_clearance: SecurityClearance::Public,
705 }
706 }
707
708 pub fn track_unsafe_allocation(
710 &self,
711 ptr: usize,
712 size: usize,
713 unsafe_location: String,
714 ) -> TrackingResult<()> {
715 let call_stack = self.capture_call_stack()?;
716 let base_allocation = AllocationInfo::new(ptr, size);
717 let risk_assessment = self.create_default_unsafe_risk_assessment(&unsafe_location);
718
719 let enhanced = EnhancedAllocationInfo {
720 base: base_allocation,
721 source: AllocationSource::UnsafeRust {
722 unsafe_block_location: unsafe_location,
723 call_stack: call_stack.clone(),
724 risk_assessment,
725 },
726 call_stack,
727 cross_boundary_events: Vec::new(),
728 safety_violations: Vec::new(),
729 ffi_tracked: false,
730 memory_passport: None,
731 ownership_history: None,
732 };
733
734 if let Ok(mut allocations) = self.enhanced_allocations.lock() {
735 allocations.insert(ptr, enhanced);
736 tracing::info!("Tracked unsafe allocation at {:x} (size: {})", ptr, size);
737 }
738
739 Ok(())
740 }
741
742 pub fn track_ffi_allocation(
744 &self,
745 ptr: usize,
746 size: usize,
747 library_name: String,
748 function_name: String,
749 ) -> TrackingResult<()> {
750 let call_stack = self.capture_call_stack()?;
751 let base_allocation = AllocationInfo::new(ptr, size);
752 let libc_hook_info = self.create_default_libc_hook_info(&function_name, size);
753
754 let resolver = get_global_ffi_resolver();
756 let resolved_function = resolver
757 .resolve_function(&function_name, Some(&library_name))
758 .unwrap_or_else(|_| {
759 tracing::warn!(
760 "Failed to resolve FFI function: {}::{}",
761 library_name,
762 function_name
763 );
764 ResolvedFfiFunction {
766 library_name: library_name.clone(),
767 function_name: function_name.clone(),
768 signature: None,
769 category: crate::analysis::FfiFunctionCategory::Unknown,
770 risk_level: crate::analysis::FfiRiskLevel::Medium,
771 metadata: std::collections::HashMap::new(),
772 }
773 });
774
775 let enhanced = EnhancedAllocationInfo {
776 base: base_allocation,
777 source: AllocationSource::FfiC {
778 resolved_function,
779 call_stack: call_stack.clone(),
780 libc_hook_info,
781 },
782 call_stack,
783 cross_boundary_events: Vec::new(),
784 safety_violations: Vec::new(),
785 ffi_tracked: true,
786 memory_passport: None,
787 ownership_history: None,
788 };
789
790 if let Ok(mut allocations) = self.enhanced_allocations.lock() {
791 allocations.insert(ptr, enhanced);
792 tracing::info!("Tracked FFI allocation at {:x} (size: {})", ptr, size);
793 }
794
795 Ok(())
796 }
797
798 pub fn track_enhanced_deallocation(&self, ptr: usize) -> TrackingResult<()> {
800 let call_stack = self.capture_call_stack()?;
801 let timestamp = std::time::SystemTime::now()
802 .duration_since(std::time::UNIX_EPOCH)
803 .unwrap_or_default()
804 .as_millis();
805
806 if let Ok(freed) = self.freed_pointers.lock() {
808 if let Some((first_free_stack, _first_timestamp)) = freed.get(&ptr) {
809 let violation = SafetyViolation::DoubleFree {
810 first_free_stack: first_free_stack.clone(),
811 second_free_stack: call_stack.clone(),
812 timestamp,
813 };
814
815 if let Ok(mut violations) = self.violations.lock() {
816 violations.push(violation);
817 }
818
819 tracing::error!("Double free detected at {:x}", ptr);
820 return Err(TrackingError::MemoryCorruption(
821 "Memory corruption detected".to_string(),
822 ));
823 }
824 }
825
826 if let Ok(mut allocations) = self.enhanced_allocations.lock() {
828 if let Some(mut allocation) = allocations.remove(&ptr) {
829 allocation.base.mark_deallocated();
830
831 if let Ok(mut freed) = self.freed_pointers.lock() {
833 freed.insert(ptr, (call_stack, timestamp));
834 }
835
836 tracing::info!("Tracked enhanced deallocation at {:x}", ptr);
837 } else {
838 let violation = SafetyViolation::InvalidFree {
840 attempted_pointer: ptr,
841 stack: call_stack,
842 timestamp,
843 };
844
845 if let Ok(mut violations) = self.violations.lock() {
846 violations.push(violation);
847 }
848
849 tracing::error!("Invalid free detected at {:x}", ptr);
850 return Err(TrackingError::InvalidPointer(format!(
851 "Invalid pointer: 0x{ptr:x}"
852 )));
853 }
854 }
855
856 Ok(())
857 }
858
859 pub fn record_boundary_event(
861 &self,
862 ptr: usize,
863 event_type: BoundaryEventType,
864 from_context: String,
865 to_context: String,
866 ) -> TrackingResult<()> {
867 let call_stack = self.capture_call_stack()?;
868 let timestamp = std::time::SystemTime::now()
869 .duration_since(std::time::UNIX_EPOCH)
870 .unwrap_or_default()
871 .as_millis();
872
873 let event = BoundaryEvent {
874 event_type,
875 timestamp,
876 from_context,
877 to_context,
878 stack: call_stack,
879 };
880
881 if let Ok(mut allocations) = self.enhanced_allocations.lock() {
882 if let Some(allocation) = allocations.get_mut(&ptr) {
883 allocation.cross_boundary_events.push(event);
884 tracing::info!("Recorded boundary event for {:x}", ptr);
885 }
886 }
887
888 Ok(())
889 }
890
891 pub fn create_or_update_passport(
893 &self,
894 ptr: usize,
895 operation: &str,
896 context: &str,
897 ) -> TrackingResult<()> {
898 if let Ok(mut allocations) = self.enhanced_allocations.lock() {
899 if let Some(allocation) = allocations.get_mut(&ptr) {
900 let current_time = std::time::SystemTime::now()
901 .duration_since(std::time::UNIX_EPOCH)
902 .unwrap_or_default()
903 .as_nanos();
904
905 if allocation.memory_passport.is_none() {
906 allocation.memory_passport = Some(self.create_memory_passport(ptr, context));
907 }
908
909 if let Some(passport) = &mut allocation.memory_passport {
910 let stamp = PassportStamp {
911 timestamp: current_time,
912 location: context.to_string(),
913 operation: operation.to_string(),
914 authority: "UnsafeFFITracker".to_string(),
915 verification_hash: format!("{:x}", ptr ^ current_time as usize),
916 };
917 passport.journey.push(stamp);
918 }
919 }
920 }
921
922 Ok(())
923 }
924
925 pub fn update_ownership(
927 &self,
928 ptr: usize,
929 new_owner_context: String,
930 new_owner_function: String,
931 ) -> TrackingResult<()> {
932 if let Ok(mut allocations) = self.enhanced_allocations.lock() {
933 if let Some(allocation) = allocations.get_mut(&ptr) {
934 let current_time = std::time::SystemTime::now()
935 .duration_since(std::time::UNIX_EPOCH)
936 .unwrap_or_default()
937 .as_nanos();
938
939 if let Some(passport) = &mut allocation.memory_passport {
940 passport.current_owner = OwnershipInfo {
941 owner_context: new_owner_context,
942 owner_function: new_owner_function,
943 transfer_timestamp: current_time,
944 expected_lifetime: None,
945 };
946 }
947 }
948 }
949
950 Ok(())
951 }
952
953 pub fn validate_passport(&self, ptr: usize) -> TrackingResult<bool> {
955 if let Ok(allocations) = self.enhanced_allocations.lock() {
956 if let Some(allocation) = allocations.get(&ptr) {
957 if let Some(passport) = &allocation.memory_passport {
958 match passport.validity_status {
960 ValidityStatus::Valid => Ok(true),
961 ValidityStatus::Expired
962 | ValidityStatus::Revoked
963 | ValidityStatus::Suspicious => Ok(false),
964 }
965 } else {
966 Ok(false) }
968 } else {
969 Ok(false) }
971 } else {
972 Err(TrackingError::LockError(
973 "Failed to acquire allocations lock".to_string(),
974 ))
975 }
976 }
977
978 pub fn get_safety_violations(&self) -> TrackingResult<Vec<SafetyViolation>> {
980 self.violations
981 .lock()
982 .map(|v| v.clone())
983 .map_err(|e| TrackingError::LockError(e.to_string()))
984 }
985
986 pub fn get_enhanced_allocations(&self) -> TrackingResult<Vec<EnhancedAllocationInfo>> {
988 self.enhanced_allocations
989 .lock()
990 .map(|allocations| allocations.values().cloned().collect())
991 .map_err(|e| TrackingError::LockError(e.to_string()))
992 }
993
994 fn capture_call_stack(&self) -> TrackingResult<CallStackRef> {
996 let frames = vec![StackFrame {
999 function_name: "current_function".to_string(),
1000 file_name: Some("src/unsafe_ffi_tracker.rs".to_string()),
1001 line_number: Some(42),
1002 is_unsafe: true,
1003 }];
1004
1005 let normalizer = get_global_call_stack_normalizer();
1006 let id = normalizer.normalize_call_stack(&frames)?;
1007 Ok(CallStackRef::new(id, Some(frames.len())))
1008 }
1009
1010 pub fn detect_leaks(&self, threshold_ms: u128) -> TrackingResult<Vec<SafetyViolation>> {
1012 let current_time = std::time::SystemTime::now()
1013 .duration_since(std::time::UNIX_EPOCH)
1014 .unwrap_or_default()
1015 .as_millis();
1016
1017 let mut leaks = Vec::new();
1018
1019 if let Ok(allocations) = self.enhanced_allocations.lock() {
1020 for allocation in allocations.values() {
1021 let alloc_time = allocation.base.timestamp_alloc as u128;
1022 let age = current_time.saturating_sub(alloc_time);
1023 if age > threshold_ms && allocation.base.is_active() {
1024 leaks.push(SafetyViolation::PotentialLeak {
1025 allocation_stack: allocation.call_stack.clone(),
1026 allocation_timestamp: allocation.base.timestamp_alloc as u128,
1027 leak_detection_timestamp: current_time,
1028 });
1029 }
1030 }
1031 }
1032
1033 Ok(leaks)
1034 }
1035}
1036
1037impl Default for UnsafeFFITracker {
1038 fn default() -> Self {
1039 Self::new()
1040 }
1041}
1042
1043static GLOBAL_UNSAFE_FFI_TRACKER: std::sync::OnceLock<std::sync::Arc<UnsafeFFITracker>> =
1045 std::sync::OnceLock::new();
1046
1047pub fn get_global_unsafe_ffi_tracker() -> std::sync::Arc<UnsafeFFITracker> {
1049 GLOBAL_UNSAFE_FFI_TRACKER
1050 .get_or_init(|| std::sync::Arc::new(UnsafeFFITracker::new()))
1051 .clone()
1052}
1053
1054#[macro_export]
1056macro_rules! track_unsafe_alloc {
1057 ($ptr:expr, $size:expr) => {{
1058 let tracker = $crate::unsafe_ffi_tracker::get_global_unsafe_ffi_tracker();
1059 let location = format!("{}:{}:{}", file!(), line!(), column!());
1060 let _ = tracker.track_unsafe_allocation($ptr as usize, $size, location);
1061 }};
1062}
1063
1064#[macro_export]
1066macro_rules! track_ffi_alloc {
1067 ($ptr:expr, $size:expr, $lib:expr, $func:expr) => {{
1068 let tracker = $crate::unsafe_ffi_tracker::get_global_unsafe_ffi_tracker();
1069 let _ =
1070 tracker.track_ffi_allocation($ptr as usize, $size, $lib.to_string(), $func.to_string());
1071 }};
1072}
1073
1074#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1076pub struct UnsafeFFIStats {
1077 pub total_operations: usize,
1079 pub unsafe_blocks: usize,
1081 pub ffi_calls: usize,
1083 pub raw_pointer_operations: usize,
1085 pub memory_violations: usize,
1087 pub risk_score: f64,
1089 pub operations: Vec<UnsafeOperation>,
1091}
1092
1093#[derive(Debug, Clone, Serialize, Deserialize)]
1095pub struct UnsafeOperation {
1096 pub operation_type: UnsafeOperationType,
1098 pub location: String,
1100 pub risk_level: RiskLevel,
1102 pub timestamp: u128,
1104 pub description: String,
1106}
1107
1108#[derive(Debug, Clone, Serialize, Deserialize)]
1110pub enum UnsafeOperationType {
1111 RawPointerDeref,
1113 FfiCall,
1115 UnsafeBlock,
1117 MemoryViolation,
1119 CrossBoundaryTransfer,
1121}
1122
1123#[derive(Debug, Clone, Serialize, Deserialize)]
1125pub struct CLibraryInfo {
1126 pub library_name: String,
1128 pub library_version: Option<String>,
1130 pub library_path: Option<String>,
1132 pub functions_called: HashMap<String, CFunctionInfo>,
1134 pub total_allocations: usize,
1136 pub total_bytes_allocated: usize,
1138 pub load_timestamp: u128,
1140 pub metadata: LibraryMetadata,
1142}
1143
1144#[derive(Debug, Clone, Serialize, Deserialize)]
1146pub struct CFunctionInfo {
1147 pub function_name: String,
1149 pub function_signature: Option<String>,
1151 pub call_count: usize,
1153 pub bytes_allocated: usize,
1155 pub average_allocation_size: f64,
1157 pub risk_assessment: RiskAssessment,
1159 pub performance_metrics: FunctionPerformanceMetrics,
1161 pub first_call_timestamp: u128,
1163 pub last_call_timestamp: u128,
1165}
1166
1167#[derive(Debug, Clone, Serialize, Deserialize)]
1169pub struct FunctionPerformanceMetrics {
1170 pub avg_execution_time_ns: u64,
1172 pub min_execution_time_ns: u64,
1174 pub max_execution_time_ns: u64,
1176 pub total_execution_time_ns: u64,
1178 pub tracking_overhead_ns: u64,
1180}
1181
1182#[derive(Debug, Clone, Serialize, Deserialize)]
1184pub struct LibraryMetadata {
1185 pub architecture: String,
1187 pub operating_system: String,
1189 pub compiler_info: Option<String>,
1191 pub has_debug_symbols: bool,
1193 pub security_features: Vec<String>,
1195}
1196
1197#[derive(Debug, Clone, Serialize, Deserialize)]
1199pub struct EnhancedLibCHookInfo {
1200 pub base_info: LibCHookInfo,
1202 pub function_tracking: CFunctionInfo,
1204 pub installation_details: HookInstallationDetails,
1206 pub runtime_analysis: RuntimeBehaviorAnalysis,
1208 pub security_analysis: SecurityAnalysis,
1210}
1211
1212#[derive(Debug, Clone, Serialize, Deserialize)]
1214pub struct HookInstallationDetails {
1215 pub installation_method: HookInstallationMethod,
1217 pub installation_success: bool,
1219 pub installation_error: Option<String>,
1221 pub installation_timestamp: u128,
1223 pub process_id: u32,
1225 pub thread_id: u64,
1227}
1228
1229#[derive(Debug, Clone, Serialize, Deserialize)]
1231pub enum HookInstallationMethod {
1232 Preload,
1234 SymbolInterposition,
1236 BinaryPatching,
1238 DebuggerHook,
1240 KernelHook,
1242}
1243
1244#[derive(Debug, Clone, Serialize, Deserialize)]
1246pub struct RuntimeBehaviorAnalysis {
1247 pub memory_patterns: Vec<MemoryAccessPattern>,
1249 pub size_distribution: SizeDistribution,
1251 pub temporal_patterns: TemporalPatterns,
1253 pub error_patterns: Vec<ErrorPattern>,
1255}
1256
1257#[derive(Debug, Clone, Serialize, Deserialize)]
1259pub struct MemoryAccessPattern {
1260 pub pattern_type: MemoryPatternType,
1262 pub frequency: usize,
1264 pub average_size: usize,
1266 pub risk_level: RiskLevel,
1268}
1269
1270#[derive(Debug, Clone, Serialize, Deserialize)]
1272pub enum MemoryPatternType {
1273 Sequential,
1275 Random,
1277 Bulk,
1279 Fragmented,
1281 Reallocation,
1283}
1284
1285#[derive(Debug, Clone, Serialize, Deserialize)]
1287pub struct SizeDistribution {
1288 pub small_allocations: usize,
1290 pub medium_allocations: usize,
1292 pub large_allocations: usize,
1294 pub average_size: f64,
1296 pub size_std_dev: f64,
1298}
1299
1300#[derive(Debug, Clone, Serialize, Deserialize)]
1302pub struct TemporalPatterns {
1303 pub allocation_rate: f64,
1305 pub peak_periods: Vec<PeakPeriod>,
1307 pub burst_count: usize,
1309 pub avg_time_between_allocs_ms: f64,
1311}
1312
1313#[derive(Debug, Clone, Serialize, Deserialize)]
1315pub struct PeakPeriod {
1316 pub start_timestamp: u128,
1318 pub end_timestamp: u128,
1320 pub allocation_count: usize,
1322 pub bytes_allocated: usize,
1324}
1325
1326#[derive(Debug, Clone, Serialize, Deserialize)]
1328pub struct ErrorPattern {
1329 pub error_type: ErrorType,
1331 pub frequency: usize,
1333 pub context: String,
1335 pub mitigation: String,
1337}
1338
1339#[derive(Debug, Clone, Serialize, Deserialize)]
1341pub enum ErrorType {
1342 AllocationFailure,
1344 InvalidFree,
1346 DoubleFree,
1348 MemoryLeak,
1350 BufferOverflow,
1352 UseAfterFree,
1354}
1355
1356#[derive(Debug, Clone, Serialize, Deserialize)]
1358pub struct SecurityAnalysis {
1359 pub vulnerabilities: Vec<SecurityVulnerability>,
1361 pub security_score: f64,
1363 pub recommendations: Vec<String>,
1365 pub compliance_status: ComplianceStatus,
1367}
1368
1369#[derive(Debug, Clone, Serialize, Deserialize)]
1371pub struct SecurityVulnerability {
1372 pub vulnerability_type: VulnerabilityType,
1374 pub severity: RiskLevel,
1376 pub description: String,
1378 pub location: String,
1380 pub potential_impact: String,
1382 pub remediation: Vec<String>,
1384}
1385
1386#[derive(Debug, Clone, Serialize, Deserialize)]
1388pub enum VulnerabilityType {
1389 BufferOverflow,
1391 UseAfterFree,
1393 DoubleFree,
1395 MemoryLeak,
1397 IntegerOverflow,
1399 FormatString,
1401 RaceCondition,
1403}
1404
1405#[derive(Debug, Clone, Serialize, Deserialize)]
1407pub struct ComplianceStatus {
1408 pub memory_safety: bool,
1410 pub thread_safety: bool,
1412 pub api_usage: bool,
1414 pub security_practices: bool,
1416 pub overall_score: f64,
1418}
1419
1420impl UnsafeFFITracker {
1421 pub fn register_c_library(
1423 &self,
1424 library_name: String,
1425 library_path: Option<String>,
1426 library_version: Option<String>,
1427 ) -> TrackingResult<()> {
1428 let current_time = std::time::SystemTime::now()
1429 .duration_since(std::time::UNIX_EPOCH)
1430 .unwrap_or_default()
1431 .as_nanos();
1432
1433 let library_info = CLibraryInfo {
1434 library_name: library_name.clone(),
1435 library_version,
1436 library_path,
1437 functions_called: HashMap::new(),
1438 total_allocations: 0,
1439 total_bytes_allocated: 0,
1440 load_timestamp: current_time,
1441 metadata: LibraryMetadata {
1442 architecture: std::env::consts::ARCH.to_string(),
1443 operating_system: std::env::consts::OS.to_string(),
1444 compiler_info: None,
1445 has_debug_symbols: false,
1446 security_features: Vec::new(),
1447 },
1448 };
1449
1450 if let Ok(mut libraries) = self.c_libraries.lock() {
1451 libraries.insert(library_name.clone(), library_info);
1452 tracing::info!("Registered C library: {}", library_name);
1453 }
1454
1455 Ok(())
1456 }
1457
1458 pub fn track_c_function_call(
1460 &self,
1461 library_name: &str,
1462 function_name: &str,
1463 allocation_size: usize,
1464 execution_time_ns: u64,
1465 ) -> TrackingResult<()> {
1466 let current_time = std::time::SystemTime::now()
1467 .duration_since(std::time::UNIX_EPOCH)
1468 .unwrap_or_default()
1469 .as_nanos();
1470
1471 if let Ok(mut libraries) = self.c_libraries.lock() {
1472 let library = libraries
1473 .entry(library_name.to_string())
1474 .or_insert_with(|| CLibraryInfo {
1475 library_name: library_name.to_string(),
1476 library_version: None,
1477 library_path: None,
1478 functions_called: HashMap::new(),
1479 total_allocations: 0,
1480 total_bytes_allocated: 0,
1481 load_timestamp: current_time,
1482 metadata: LibraryMetadata {
1483 architecture: std::env::consts::ARCH.to_string(),
1484 operating_system: std::env::consts::OS.to_string(),
1485 compiler_info: None,
1486 has_debug_symbols: false,
1487 security_features: Vec::new(),
1488 },
1489 });
1490
1491 library.total_allocations += 1;
1493 library.total_bytes_allocated += allocation_size;
1494
1495 let function_info = library
1497 .functions_called
1498 .entry(function_name.to_string())
1499 .or_insert_with(|| CFunctionInfo {
1500 function_name: function_name.to_string(),
1501 function_signature: None,
1502 call_count: 0,
1503 bytes_allocated: 0,
1504 average_allocation_size: 0.0,
1505 risk_assessment: RiskAssessment {
1506 risk_level: RiskLevel::Low,
1507 risk_factors: Vec::new(),
1508 mitigation_suggestions: Vec::new(),
1509 confidence_score: 0.5,
1510 assessment_timestamp: current_time,
1511 },
1512 performance_metrics: FunctionPerformanceMetrics {
1513 avg_execution_time_ns: 0,
1514 min_execution_time_ns: u64::MAX,
1515 max_execution_time_ns: 0,
1516 total_execution_time_ns: 0,
1517 tracking_overhead_ns: 0,
1518 },
1519 first_call_timestamp: current_time,
1520 last_call_timestamp: current_time,
1521 });
1522
1523 function_info.call_count += 1;
1525 function_info.bytes_allocated += allocation_size;
1526 function_info.average_allocation_size =
1527 function_info.bytes_allocated as f64 / function_info.call_count as f64;
1528 function_info.last_call_timestamp = current_time;
1529
1530 let metrics = &mut function_info.performance_metrics;
1532 metrics.total_execution_time_ns += execution_time_ns;
1533 metrics.avg_execution_time_ns =
1534 metrics.total_execution_time_ns / function_info.call_count as u64;
1535 metrics.min_execution_time_ns = metrics.min_execution_time_ns.min(execution_time_ns);
1536 metrics.max_execution_time_ns = metrics.max_execution_time_ns.max(execution_time_ns);
1537
1538 tracing::debug!(
1539 "Tracked C function call: {}::{} (size: {}, time: {}ns)",
1540 library_name,
1541 function_name,
1542 allocation_size,
1543 execution_time_ns
1544 );
1545 }
1546
1547 Ok(())
1548 }
1549
1550 pub fn install_enhanced_libc_hook(
1552 &self,
1553 function_name: String,
1554 hook_method: HookInstallationMethod,
1555 ) -> TrackingResult<()> {
1556 let current_time = std::time::SystemTime::now()
1557 .duration_since(std::time::UNIX_EPOCH)
1558 .unwrap_or_default()
1559 .as_nanos();
1560
1561 let installation_details = HookInstallationDetails {
1562 installation_method: hook_method,
1563 installation_success: true, installation_error: None,
1565 installation_timestamp: current_time,
1566 process_id: std::process::id(),
1567 thread_id: 0, };
1569
1570 let enhanced_hook = EnhancedLibCHookInfo {
1571 base_info: LibCHookInfo {
1572 hook_method: HookMethod::DynamicLinker,
1573 original_function: function_name.clone(),
1574 hook_timestamp: current_time,
1575 allocation_metadata: AllocationMetadata {
1576 requested_size: 0,
1577 actual_size: 0,
1578 alignment: 8,
1579 allocator_info: format!("hooked_{function_name}"),
1580 protection_flags: Some(MemoryProtectionFlags {
1581 readable: true,
1582 writable: true,
1583 executable: false,
1584 shared: false,
1585 }),
1586 },
1587 hook_overhead_ns: Some(50),
1588 },
1589 function_tracking: CFunctionInfo {
1590 function_name: function_name.clone(),
1591 function_signature: None,
1592 call_count: 0,
1593 bytes_allocated: 0,
1594 average_allocation_size: 0.0,
1595 risk_assessment: RiskAssessment {
1596 risk_level: RiskLevel::Medium,
1597 risk_factors: Vec::new(),
1598 mitigation_suggestions: vec![
1599 "Monitor for memory leaks".to_string(),
1600 "Validate all pointer operations".to_string(),
1601 ],
1602 confidence_score: 0.7,
1603 assessment_timestamp: current_time,
1604 },
1605 performance_metrics: FunctionPerformanceMetrics {
1606 avg_execution_time_ns: 0,
1607 min_execution_time_ns: u64::MAX,
1608 max_execution_time_ns: 0,
1609 total_execution_time_ns: 0,
1610 tracking_overhead_ns: 50,
1611 },
1612 first_call_timestamp: current_time,
1613 last_call_timestamp: current_time,
1614 },
1615 installation_details,
1616 runtime_analysis: RuntimeBehaviorAnalysis {
1617 memory_patterns: Vec::new(),
1618 size_distribution: SizeDistribution {
1619 small_allocations: 0,
1620 medium_allocations: 0,
1621 large_allocations: 0,
1622 average_size: 0.0,
1623 size_std_dev: 0.0,
1624 },
1625 temporal_patterns: TemporalPatterns {
1626 allocation_rate: 0.0,
1627 peak_periods: Vec::new(),
1628 burst_count: 0,
1629 avg_time_between_allocs_ms: 0.0,
1630 },
1631 error_patterns: Vec::new(),
1632 },
1633 security_analysis: SecurityAnalysis {
1634 vulnerabilities: Vec::new(),
1635 security_score: 5.0,
1636 recommendations: vec![
1637 "Enable memory protection".to_string(),
1638 "Use safe allocation patterns".to_string(),
1639 ],
1640 compliance_status: ComplianceStatus {
1641 memory_safety: false,
1642 thread_safety: false,
1643 api_usage: true,
1644 security_practices: false,
1645 overall_score: 0.25,
1646 },
1647 },
1648 };
1649
1650 if let Ok(mut hooks) = self.libc_hooks.lock() {
1651 hooks.insert(function_name.clone(), enhanced_hook);
1652 tracing::info!("Installed enhanced LibC hook for: {}", function_name);
1653 }
1654
1655 Ok(())
1656 }
1657
1658 pub fn create_and_register_passport(
1660 &self,
1661 ptr: usize,
1662 origin_context: &str,
1663 security_clearance: SecurityClearance,
1664 ) -> TrackingResult<String> {
1665 let passport = self.create_memory_passport(ptr, origin_context);
1666 let passport_id = passport.passport_id.clone();
1667
1668 let mut passport = passport;
1670 passport.security_clearance = security_clearance;
1671
1672 if let Ok(mut passports) = self.memory_passports.lock() {
1673 passports.insert(ptr, passport);
1674 tracing::info!("Created memory passport {} for ptr {:x}", passport_id, ptr);
1675 }
1676
1677 Ok(passport_id)
1678 }
1679
1680 pub fn stamp_passport(
1682 &self,
1683 ptr: usize,
1684 operation: &str,
1685 location: &str,
1686 authority: &str,
1687 ) -> TrackingResult<()> {
1688 let current_time = std::time::SystemTime::now()
1689 .duration_since(std::time::UNIX_EPOCH)
1690 .unwrap_or_default()
1691 .as_nanos();
1692
1693 if let Ok(mut passports) = self.memory_passports.lock() {
1694 if let Some(passport) = passports.get_mut(&ptr) {
1695 let stamp = PassportStamp {
1696 timestamp: current_time,
1697 location: location.to_string(),
1698 operation: operation.to_string(),
1699 authority: authority.to_string(),
1700 verification_hash: format!("{:x}", ptr ^ current_time as usize),
1701 };
1702
1703 passport.journey.push(stamp);
1704 tracing::debug!("Stamped passport for ptr {:x}: {}", ptr, operation);
1705 } else {
1706 return Err(TrackingError::InvalidPointer(format!(
1707 "No passport found for pointer: 0x{ptr:x}",
1708 )));
1709 }
1710 }
1711
1712 Ok(())
1713 }
1714
1715 pub fn transfer_passport_ownership(
1717 &self,
1718 ptr: usize,
1719 new_owner_context: &str,
1720 new_owner_function: &str,
1721 ) -> TrackingResult<()> {
1722 let current_time = std::time::SystemTime::now()
1723 .duration_since(std::time::UNIX_EPOCH)
1724 .unwrap_or_default()
1725 .as_nanos();
1726
1727 if let Ok(mut passports) = self.memory_passports.lock() {
1728 if let Some(passport) = passports.get_mut(&ptr) {
1729 passport.current_owner = OwnershipInfo {
1730 owner_context: new_owner_context.to_string(),
1731 owner_function: new_owner_function.to_string(),
1732 transfer_timestamp: current_time,
1733 expected_lifetime: None,
1734 };
1735
1736 let stamp = PassportStamp {
1738 timestamp: current_time,
1739 location: new_owner_context.to_string(),
1740 operation: "ownership_transfer".to_string(),
1741 authority: "UnsafeFFITracker".to_string(),
1742 verification_hash: format!("{:x}", ptr ^ current_time as usize),
1743 };
1744
1745 passport.journey.push(stamp);
1746 tracing::info!(
1747 "Transferred passport ownership for ptr {:x} to {}::{}",
1748 ptr,
1749 new_owner_context,
1750 new_owner_function
1751 );
1752 } else {
1753 return Err(TrackingError::InvalidPointer(format!(
1754 "No passport found for pointer: 0x{ptr:x}",
1755 )));
1756 }
1757 }
1758
1759 Ok(())
1760 }
1761
1762 pub fn revoke_passport(&self, ptr: usize, reason: &str) -> TrackingResult<()> {
1764 if let Ok(mut passports) = self.memory_passports.lock() {
1765 if let Some(passport) = passports.get_mut(&ptr) {
1766 passport.validity_status = ValidityStatus::Revoked;
1767
1768 let current_time = std::time::SystemTime::now()
1770 .duration_since(std::time::UNIX_EPOCH)
1771 .unwrap_or_default()
1772 .as_nanos();
1773
1774 let stamp = PassportStamp {
1775 timestamp: current_time,
1776 location: "memory_freed".to_string(),
1777 operation: format!("revoked: {reason}"),
1778 authority: "UnsafeFFITracker".to_string(),
1779 verification_hash: format!("{:x}", ptr ^ current_time as usize),
1780 };
1781
1782 passport.journey.push(stamp);
1783 tracing::info!("Revoked passport for ptr {ptr:x}: {reason}");
1784 }
1785 }
1786
1787 Ok(())
1788 }
1789
1790 pub fn get_c_library_stats(&self) -> TrackingResult<HashMap<String, CLibraryInfo>> {
1792 self.c_libraries
1793 .lock()
1794 .map(|libs| libs.clone())
1795 .map_err(|e| TrackingError::LockError(e.to_string()))
1796 }
1797
1798 pub fn get_libc_hook_info(&self) -> TrackingResult<HashMap<String, EnhancedLibCHookInfo>> {
1800 self.libc_hooks
1801 .lock()
1802 .map(|hooks| hooks.clone())
1803 .map_err(|e| TrackingError::LockError(e.to_string()))
1804 }
1805
1806 pub fn get_memory_passports(&self) -> TrackingResult<HashMap<usize, MemoryPassport>> {
1808 self.memory_passports
1809 .lock()
1810 .map(|passports| passports.clone())
1811 .map_err(|e| TrackingError::LockError(e.to_string()))
1812 }
1813
1814 pub fn analyze_cross_boundary_risks(&self) -> TrackingResult<Vec<SafetyViolation>> {
1816 let mut risks = Vec::new();
1817
1818 if let Ok(passports) = self.memory_passports.lock() {
1819 for (ptr, passport) in passports.iter() {
1820 if passport.journey.len() > 10 {
1822 risks.push(SafetyViolation::CrossBoundaryRisk {
1823 risk_level: RiskLevel::Medium,
1824 description: format!(
1825 "Memory at {ptr:x} has crossed boundaries {} times",
1826 passport.journey.len()
1827 ),
1828 stack: {
1829 let normalizer = get_global_call_stack_normalizer();
1830 let empty_frames = vec![];
1831 let id = normalizer.normalize_call_stack(&empty_frames).unwrap_or(0);
1832 CallStackRef::new(id, Some(0))
1833 },
1834 });
1835 }
1836
1837 if matches!(passport.validity_status, ValidityStatus::Expired) {
1839 risks.push(SafetyViolation::CrossBoundaryRisk {
1840 risk_level: RiskLevel::High,
1841 description: format!("Expired passport detected for memory at {ptr:x}"),
1842 stack: {
1843 let normalizer = get_global_call_stack_normalizer();
1844 let empty_frames = vec![];
1845 let id = normalizer.normalize_call_stack(&empty_frames).unwrap_or(0);
1846 CallStackRef::new(id, Some(0))
1847 },
1848 });
1849 }
1850 }
1851 }
1852
1853 Ok(risks)
1854 }
1855
1856 pub fn process_boundary_event(
1858 &self,
1859 ptr: usize,
1860 event_type: BoundaryEventType,
1861 from_context: &str,
1862 to_context: &str,
1863 transfer_size: usize,
1864 ) -> TrackingResult<BoundaryEventAnalysis> {
1865 let current_time = std::time::SystemTime::now()
1866 .duration_since(std::time::UNIX_EPOCH)
1867 .unwrap_or_default()
1868 .as_nanos();
1869
1870 self.record_boundary_event(
1872 ptr,
1873 event_type.clone(),
1874 from_context.to_string(),
1875 to_context.to_string(),
1876 )?;
1877
1878 let risk_analysis = self.assess_boundary_transfer_risk(
1880 ptr,
1881 &event_type,
1882 from_context,
1883 to_context,
1884 transfer_size,
1885 )?;
1886
1887 self.track_ownership_transfer(ptr, from_context, to_context)?;
1889
1890 let analysis = BoundaryEventAnalysis {
1892 event_id: format!("boundary_{ptr}_{current_time}"),
1893 ptr,
1894 event_type: event_type.clone(),
1895 from_context: from_context.to_string(),
1896 to_context: to_context.to_string(),
1897 transfer_size,
1898 timestamp: current_time,
1899 risk_assessment: risk_analysis.clone(),
1900 ownership_chain: self.get_ownership_chain(ptr)?,
1901 security_implications: self.analyze_security_implications(
1902 ptr,
1903 from_context,
1904 to_context,
1905 )?,
1906 performance_impact: self.estimate_performance_impact(&event_type, transfer_size),
1907 mitigation_recommendations: self.generate_mitigation_recommendations(&risk_analysis),
1908 };
1909
1910 Ok(analysis)
1911 }
1912
1913 fn assess_boundary_transfer_risk(
1915 &self,
1916 ptr: usize,
1917 event_type: &BoundaryEventType,
1918 _from_context: &str,
1919 _to_context: &str,
1920 transfer_size: usize,
1921 ) -> TrackingResult<BoundaryRiskAssessment> {
1922 let mut risk_factors = Vec::new();
1923 let mut risk_score = 0.0;
1924
1925 match event_type {
1927 BoundaryEventType::RustToFfi => {
1928 risk_factors.push(BoundaryRiskFactor {
1929 factor_type: BoundaryRiskFactorType::RustToForeignTransfer,
1930 severity: 6.0,
1931 description: "Memory allocated in Rust being passed to foreign code"
1932 .to_string(),
1933 mitigation: "Ensure foreign code doesn't free Rust-allocated memory"
1934 .to_string(),
1935 });
1936 risk_score += 6.0;
1937 }
1938 BoundaryEventType::FfiToRust => {
1939 risk_factors.push(BoundaryRiskFactor {
1940 factor_type: BoundaryRiskFactorType::ForeignToRustTransfer,
1941 severity: 7.0,
1942 description: "Foreign-allocated memory being passed to Rust".to_string(),
1943 mitigation: "Validate memory layout and lifetime guarantees".to_string(),
1944 });
1945 risk_score += 7.0;
1946 }
1947 BoundaryEventType::OwnershipTransfer => {
1948 risk_factors.push(BoundaryRiskFactor {
1949 factor_type: BoundaryRiskFactorType::OwnershipTransfer,
1950 severity: 8.0,
1951 description: "Memory ownership being transferred across language boundary"
1952 .to_string(),
1953 mitigation: "Clearly document ownership transfer and cleanup responsibilities"
1954 .to_string(),
1955 });
1956 risk_score += 8.0;
1957 }
1958 BoundaryEventType::SharedAccess => {
1959 risk_factors.push(BoundaryRiskFactor {
1960 factor_type: BoundaryRiskFactorType::SharedAccess,
1961 severity: 5.0,
1962 description: "Memory being shared between Rust and foreign code".to_string(),
1963 mitigation: "Implement proper synchronization mechanisms".to_string(),
1964 });
1965 risk_score += 5.0;
1966 }
1967 }
1968
1969 if transfer_size > 1024 * 1024 {
1971 risk_factors.push(BoundaryRiskFactor {
1972 factor_type: BoundaryRiskFactorType::LargeTransfer,
1973 severity: 4.0,
1974 description: format!("Large memory transfer: {transfer_size} bytes"),
1975 mitigation: "Consider streaming or chunked transfer for large data".to_string(),
1976 });
1977 risk_score += 4.0;
1978 }
1979
1980 if let Ok(allocations) = self.enhanced_allocations.lock() {
1982 if let Some(allocation) = allocations.get(&ptr) {
1983 if allocation.cross_boundary_events.len() > 5 {
1984 risk_factors.push(BoundaryRiskFactor {
1985 factor_type: BoundaryRiskFactorType::FrequentTransfers,
1986 severity: 3.0,
1987 description: format!(
1988 "Memory has crossed boundaries {} times",
1989 allocation.cross_boundary_events.len()
1990 ),
1991 mitigation: "Consider reducing boundary crossings or caching".to_string(),
1992 });
1993 risk_score += 3.0;
1994 }
1995 }
1996 }
1997
1998 let risk_level = if risk_score >= 15.0 {
2000 RiskLevel::Critical
2001 } else if risk_score >= 10.0 {
2002 RiskLevel::High
2003 } else if risk_score >= 5.0 {
2004 RiskLevel::Medium
2005 } else {
2006 RiskLevel::Low
2007 };
2008
2009 Ok(BoundaryRiskAssessment {
2010 overall_risk_level: risk_level,
2011 risk_score,
2012 risk_factors,
2013 confidence_score: 0.8, assessment_timestamp: std::time::SystemTime::now()
2015 .duration_since(std::time::UNIX_EPOCH)
2016 .unwrap_or_default()
2017 .as_nanos(),
2018 })
2019 }
2020
2021 fn track_ownership_transfer(
2023 &self,
2024 ptr: usize,
2025 from_context: &str,
2026 to_context: &str,
2027 ) -> TrackingResult<()> {
2028 let current_time = std::time::SystemTime::now()
2029 .duration_since(std::time::UNIX_EPOCH)
2030 .unwrap_or_default()
2031 .as_nanos();
2032
2033 if let Ok(mut passports) = self.memory_passports.lock() {
2035 if let Some(passport) = passports.get_mut(&ptr) {
2036 let stamp = PassportStamp {
2038 timestamp: current_time,
2039 location: to_context.to_string(),
2040 operation: format!("ownership_transfer_from_{from_context}"),
2041 authority: "BoundaryEventProcessor".to_string(),
2042 verification_hash: format!("{:x}", ptr ^ current_time as usize),
2043 };
2044 passport.journey.push(stamp);
2045
2046 passport.current_owner = OwnershipInfo {
2048 owner_context: to_context.to_string(),
2049 owner_function: "unknown".to_string(),
2050 transfer_timestamp: current_time,
2051 expected_lifetime: None,
2052 };
2053 }
2054 }
2055
2056 if let Ok(mut allocations) = self.enhanced_allocations.lock() {
2058 if let Some(allocation) = allocations.get_mut(&ptr) {
2059 let ownership_event = OwnershipTransferEvent {
2061 transfer_id: format!("transfer_{ptr}_{current_time}"),
2062 ptr,
2063 from_context: from_context.to_string(),
2064 to_context: to_context.to_string(),
2065 transfer_timestamp: current_time,
2066 transfer_reason: "boundary_crossing".to_string(),
2067 validation_status: OwnershipValidationStatus::Pending,
2068 };
2069
2070 if allocation.ownership_history.is_none() {
2072 allocation.ownership_history = Some(Vec::new());
2073 }
2074 if let Some(ref mut history) = allocation.ownership_history {
2075 history.push(ownership_event);
2076 }
2077 }
2078 }
2079
2080 Ok(())
2081 }
2082
2083 fn get_ownership_chain(&self, ptr: usize) -> TrackingResult<Vec<OwnershipRecord>> {
2085 let mut chain = Vec::new();
2086
2087 if let Ok(allocations) = self.enhanced_allocations.lock() {
2088 if let Some(allocation) = allocations.get(&ptr) {
2089 if let Some(ref history) = allocation.ownership_history {
2090 for transfer in history {
2091 chain.push(OwnershipRecord {
2092 context: transfer.to_context.clone(),
2093 timestamp: transfer.transfer_timestamp,
2094 transfer_reason: transfer.transfer_reason.clone(),
2095 validation_status: transfer.validation_status.clone(),
2096 });
2097 }
2098 }
2099 }
2100 }
2101
2102 Ok(chain)
2103 }
2104
2105 fn analyze_security_implications(
2107 &self,
2108 _ptr: usize,
2109 from_context: &str,
2110 to_context: &str,
2111 ) -> TrackingResult<Vec<SecurityImplication>> {
2112 let mut implications = Vec::new();
2113
2114 if from_context.contains("user") && to_context.contains("system") {
2116 implications.push(SecurityImplication {
2117 implication_type: SecurityImplicationType::PrivilegeEscalation,
2118 severity: RiskLevel::High,
2119 description: "Memory transfer from user context to system context".to_string(),
2120 potential_impact: "Potential privilege escalation vulnerability".to_string(),
2121 recommended_action: "Validate and sanitize all data before system context access"
2122 .to_string(),
2123 });
2124 }
2125
2126 if from_context.contains("secure") || to_context.contains("secure") {
2128 implications.push(SecurityImplication {
2129 implication_type: SecurityImplicationType::DataExposure,
2130 severity: RiskLevel::Medium,
2131 description: "Memory transfer involving secure context".to_string(),
2132 potential_impact: "Potential sensitive data exposure".to_string(),
2133 recommended_action: "Ensure proper data sanitization and access controls"
2134 .to_string(),
2135 });
2136 }
2137
2138 if to_context.contains("interpreter") || to_context.contains("eval") {
2140 implications.push(SecurityImplication {
2141 implication_type: SecurityImplicationType::InjectionRisk,
2142 severity: RiskLevel::Critical,
2143 description: "Memory transfer to code interpretation context".to_string(),
2144 potential_impact: "Potential code injection vulnerability".to_string(),
2145 recommended_action: "Validate and sanitize all input data before interpretation"
2146 .to_string(),
2147 });
2148 }
2149
2150 Ok(implications)
2151 }
2152
2153 fn estimate_performance_impact(
2155 &self,
2156 event_type: &BoundaryEventType,
2157 transfer_size: usize,
2158 ) -> PerformanceImpact {
2159 let base_overhead_ns = match event_type {
2160 BoundaryEventType::RustToFfi => 100,
2161 BoundaryEventType::FfiToRust => 150,
2162 BoundaryEventType::OwnershipTransfer => 200,
2163 BoundaryEventType::SharedAccess => 50,
2164 };
2165
2166 let size_overhead_ns = (transfer_size / 1024) as u64 * 10; let total_overhead_ns = base_overhead_ns + size_overhead_ns;
2168
2169 let impact_level = if total_overhead_ns > 10000 {
2170 PerformanceImpactLevel::High
2171 } else if total_overhead_ns > 1000 {
2172 PerformanceImpactLevel::Medium
2173 } else {
2174 PerformanceImpactLevel::Low
2175 };
2176
2177 PerformanceImpact {
2178 impact_level,
2179 estimated_overhead_ns: total_overhead_ns,
2180 memory_overhead_bytes: transfer_size / 10, cpu_overhead_percent: if total_overhead_ns > 5000 { 5.0 } else { 1.0 },
2182 recommendations: vec![
2183 "Consider batching small transfers".to_string(),
2184 "Use memory mapping for large transfers".to_string(),
2185 "Implement caching for frequently accessed data".to_string(),
2186 ],
2187 }
2188 }
2189
2190 fn generate_mitigation_recommendations(
2192 &self,
2193 risk_assessment: &BoundaryRiskAssessment,
2194 ) -> Vec<String> {
2195 let mut recommendations = Vec::new();
2196
2197 match risk_assessment.overall_risk_level {
2198 RiskLevel::Critical => {
2199 recommendations
2200 .push("URGENT: Review and redesign boundary crossing strategy".to_string());
2201 recommendations.push("Implement comprehensive input validation".to_string());
2202 recommendations.push("Add runtime safety checks".to_string());
2203 recommendations
2204 .push("Consider using safer alternatives to raw pointers".to_string());
2205 }
2206 RiskLevel::High => {
2207 recommendations.push("Implement additional safety checks".to_string());
2208 recommendations.push("Add comprehensive logging and monitoring".to_string());
2209 recommendations.push("Review memory ownership patterns".to_string());
2210 }
2211 RiskLevel::Medium => {
2212 recommendations.push("Monitor boundary crossing frequency".to_string());
2213 recommendations.push("Consider performance optimizations".to_string());
2214 recommendations.push("Document ownership transfer clearly".to_string());
2215 }
2216 RiskLevel::Low => {
2217 recommendations.push("Continue current practices".to_string());
2218 recommendations.push("Periodic review recommended".to_string());
2219 }
2220 }
2221
2222 for factor in &risk_assessment.risk_factors {
2224 recommendations.push(factor.mitigation.clone());
2225 }
2226
2227 recommendations.dedup();
2228 recommendations
2229 }
2230
2231 pub fn get_boundary_event_statistics(&self) -> TrackingResult<BoundaryEventStatistics> {
2233 let mut stats = BoundaryEventStatistics {
2234 total_events: 0,
2235 events_by_type: std::collections::HashMap::new(),
2236 risk_distribution: std::collections::HashMap::new(),
2237 average_transfer_size: 0.0,
2238 total_transfer_volume: 0,
2239 most_active_contexts: Vec::new(),
2240 security_incidents: 0,
2241 performance_issues: 0,
2242 analysis_timestamp: std::time::SystemTime::now()
2243 .duration_since(std::time::UNIX_EPOCH)
2244 .unwrap_or_default()
2245 .as_nanos(),
2246 };
2247
2248 if let Ok(allocations) = self.enhanced_allocations.lock() {
2249 let mut context_activity: std::collections::HashMap<String, usize> =
2250 std::collections::HashMap::new();
2251 let mut total_size = 0usize;
2252 let mut event_count = 0usize;
2253
2254 for allocation in allocations.values() {
2255 for event in &allocation.cross_boundary_events {
2256 stats.total_events += 1;
2257 event_count += 1;
2258
2259 *stats
2261 .events_by_type
2262 .entry(format!("{:?}", event.event_type))
2263 .or_insert(0) += 1;
2264
2265 *context_activity
2267 .entry(event.from_context.clone())
2268 .or_insert(0) += 1;
2269 *context_activity
2270 .entry(event.to_context.clone())
2271 .or_insert(0) += 1;
2272
2273 let estimated_size = allocation.base.size;
2275 total_size += estimated_size;
2276 }
2277 }
2278
2279 if event_count > 0 {
2280 stats.average_transfer_size = total_size as f64 / event_count as f64;
2281 }
2282 stats.total_transfer_volume = total_size;
2283
2284 let mut context_vec: Vec<_> = context_activity.into_iter().collect();
2286 context_vec.sort_by(|a, b| b.1.cmp(&a.1));
2287 stats.most_active_contexts = context_vec.into_iter().take(10).collect();
2288 }
2289
2290 Ok(stats)
2291 }
2292
2293 pub fn get_stats(&self) -> UnsafeFFIStats {
2295 let allocations = self
2296 .enhanced_allocations
2297 .lock()
2298 .unwrap_or_else(|poisoned| poisoned.into_inner());
2299 let violations = self
2300 .violations
2301 .lock()
2302 .unwrap_or_else(|poisoned| poisoned.into_inner());
2303
2304 let mut stats = UnsafeFFIStats::default();
2305
2306 for allocation in allocations.values() {
2308 match &allocation.source {
2309 AllocationSource::UnsafeRust { .. } => {
2310 stats.unsafe_blocks += 1;
2311 stats.total_operations += 1;
2312 }
2313 AllocationSource::FfiC { .. } => {
2314 stats.ffi_calls += 1;
2315 stats.total_operations += 1;
2316 }
2317 AllocationSource::CrossBoundary { .. } => {
2318 stats.total_operations += 1;
2319 }
2320 _ => {}
2321 }
2322
2323 stats.memory_violations += allocation.safety_violations.len();
2325 }
2326
2327 stats.memory_violations += violations.len();
2329
2330 stats.risk_score = if stats.total_operations > 0 {
2332 let base_risk = (stats.unsafe_blocks as f64 * 1.0)
2333 + (stats.ffi_calls as f64 * 2.0)
2334 + (stats.memory_violations as f64 * 5.0);
2335 (base_risk / stats.total_operations as f64).min(10.0)
2336 } else {
2337 0.0
2338 };
2339
2340 for allocation in allocations.values() {
2342 let (op_type, risk_level, description) = match &allocation.source {
2343 AllocationSource::UnsafeRust {
2344 unsafe_block_location,
2345 ..
2346 } => (
2347 UnsafeOperationType::UnsafeBlock,
2348 RiskLevel::Medium,
2349 format!("Unsafe block at {unsafe_block_location}"),
2350 ),
2351 AllocationSource::FfiC {
2352 resolved_function, ..
2353 } => (
2354 UnsafeOperationType::FfiCall,
2355 RiskLevel::High,
2356 format!(
2357 "FFI call to {}::{}",
2358 resolved_function.library_name, resolved_function.function_name
2359 ),
2360 ),
2361 AllocationSource::CrossBoundary { .. } => (
2362 UnsafeOperationType::CrossBoundaryTransfer,
2363 RiskLevel::Medium,
2364 "Cross-boundary memory transfer".to_string(),
2365 ),
2366 _ => continue,
2367 };
2368
2369 stats.operations.push(UnsafeOperation {
2370 operation_type: op_type,
2371 location: "unknown".to_string(), risk_level,
2373 timestamp: allocation.base.timestamp_alloc as u128,
2374 description,
2375 });
2376 }
2377
2378 stats.operations.truncate(50);
2380
2381 stats
2382 }
2383
2384 pub fn integrate_with_safety_analyzer(
2386 &self,
2387 safety_analyzer: &crate::analysis::SafetyAnalyzer,
2388 ) -> TrackingResult<()> {
2389 let violations = if let Ok(violations) = self.violations.lock() {
2391 violations.clone()
2392 } else {
2393 return Err(TrackingError::LockContention(
2394 "Failed to lock violations".to_string(),
2395 ));
2396 };
2397
2398 let allocations: Vec<crate::core::types::AllocationInfo> =
2400 if let Ok(enhanced_allocations) = self.enhanced_allocations.lock() {
2401 enhanced_allocations
2402 .values()
2403 .map(|ea| ea.base.clone())
2404 .collect()
2405 } else {
2406 return Err(TrackingError::LockContention(
2407 "Failed to lock allocations".to_string(),
2408 ));
2409 };
2410
2411 for violation in &violations {
2413 let source = match violation {
2414 SafetyViolation::DoubleFree { .. } => crate::analysis::UnsafeSource::RawPointer {
2415 operation: "double_free".to_string(),
2416 location: "memory_violation".to_string(),
2417 },
2418 SafetyViolation::InvalidFree {
2419 attempted_pointer, ..
2420 } => crate::analysis::UnsafeSource::RawPointer {
2421 operation: "invalid_free".to_string(),
2422 location: format!("0x{attempted_pointer:x}"),
2423 },
2424 SafetyViolation::PotentialLeak { .. } => {
2425 crate::analysis::UnsafeSource::RawPointer {
2426 operation: "potential_leak".to_string(),
2427 location: "memory_leak".to_string(),
2428 }
2429 }
2430 SafetyViolation::CrossBoundaryRisk { description, .. } => {
2431 crate::analysis::UnsafeSource::FfiFunction {
2432 library: "unknown".to_string(),
2433 function: "cross_boundary".to_string(),
2434 call_site: description.clone(),
2435 }
2436 }
2437 };
2438
2439 let _report_id =
2440 safety_analyzer.generate_unsafe_report(source, &allocations, &violations)?;
2441 }
2442
2443 tracing::info!(
2444 "🔗 Integrated {} violations with SafetyAnalyzer",
2445 violations.len()
2446 );
2447 Ok(())
2448 }
2449
2450 pub fn integrate_with_passport_tracker(
2452 &self,
2453 passport_tracker: &crate::analysis::MemoryPassportTracker,
2454 ) -> TrackingResult<()> {
2455 if let Ok(enhanced_allocations) = self.enhanced_allocations.lock() {
2456 for (ptr, allocation) in enhanced_allocations.iter() {
2457 if allocation.ffi_tracked {
2459 let _passport_id = passport_tracker.create_passport(
2460 *ptr,
2461 allocation.base.size,
2462 "ffi_integration".to_string(),
2463 )?;
2464
2465 for event in &allocation.cross_boundary_events {
2467 let event_type = match event.event_type {
2468 BoundaryEventType::RustToFfi => {
2469 crate::analysis::PassportEventType::HandoverToFfi
2470 }
2471 BoundaryEventType::FfiToRust => {
2472 crate::analysis::PassportEventType::ReclaimedByRust
2473 }
2474 BoundaryEventType::OwnershipTransfer => {
2475 crate::analysis::PassportEventType::OwnershipTransfer
2476 }
2477 BoundaryEventType::SharedAccess => {
2478 crate::analysis::PassportEventType::BoundaryAccess
2479 }
2480 };
2481
2482 passport_tracker.record_passport_event(
2483 *ptr,
2484 event_type,
2485 event.to_context.clone(),
2486 std::collections::HashMap::new(),
2487 )?;
2488 }
2489 }
2490 }
2491 }
2492
2493 tracing::info!("🔗 Integrated FFI allocations with MemoryPassportTracker");
2494 Ok(())
2495 }
2496
2497 pub fn perform_comprehensive_safety_analysis(
2499 &self,
2500 ) -> TrackingResult<crate::analysis::ComprehensiveSafetyReport> {
2501 let safety_analyzer = crate::analysis::SafetyAnalyzer::default();
2503 let passport_tracker = crate::analysis::get_global_passport_tracker();
2504
2505 self.integrate_with_safety_analyzer(&safety_analyzer)?;
2507 self.integrate_with_passport_tracker(&passport_tracker)?;
2508
2509 let leak_detection = passport_tracker.detect_leaks_at_shutdown();
2511
2512 let unsafe_reports = safety_analyzer.get_unsafe_reports();
2514 let memory_passports = passport_tracker.get_all_passports();
2515 let safety_stats = safety_analyzer.get_stats();
2516 let passport_stats = passport_tracker.get_stats();
2517
2518 let report = crate::analysis::ComprehensiveSafetyReport {
2519 unsafe_reports,
2520 memory_passports,
2521 leak_detection,
2522 safety_stats,
2523 passport_stats,
2524 analysis_timestamp: std::time::SystemTime::now()
2525 .duration_since(std::time::UNIX_EPOCH)
2526 .unwrap_or_default()
2527 .as_secs(),
2528 };
2529
2530 tracing::info!("📊 Generated comprehensive safety analysis report");
2531 Ok(report)
2532 }
2533}
2534
2535#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
2537pub struct ComprehensiveSafetyReport {
2538 pub unsafe_reports: std::collections::HashMap<String, crate::analysis::UnsafeReport>,
2540 pub memory_passports: std::collections::HashMap<usize, crate::analysis::MemoryPassport>,
2542 pub leak_detection: crate::analysis::LeakDetectionResult,
2544 pub safety_stats: crate::analysis::SafetyAnalysisStats,
2546 pub passport_stats: crate::analysis::PassportTrackerStats,
2548 pub analysis_timestamp: u64,
2550}
2551
2552static GLOBAL_UNSAFE_TRACKER: OnceLock<Arc<UnsafeFFITracker>> = OnceLock::new();
2554
2555pub fn get_global_unsafe_tracker() -> Option<Arc<UnsafeFFITracker>> {
2557 GLOBAL_UNSAFE_TRACKER.get().cloned()
2558}
2559
2560pub fn init_global_unsafe_tracker() -> Arc<UnsafeFFITracker> {
2562 GLOBAL_UNSAFE_TRACKER
2563 .get_or_init(|| Arc::new(UnsafeFFITracker::new()))
2564 .clone()
2565}
2566
2567#[cfg(test)]
2568mod tests {
2569 use super::*;
2570 use std::sync::Arc;
2571
2572 fn create_test_tracker() -> UnsafeFFITracker {
2574 UnsafeFFITracker::new()
2575 }
2576
2577 #[test]
2578 fn test_unsafe_ffi_tracker_creation() {
2579 let tracker = create_test_tracker();
2580
2581 assert!(tracker
2583 .get_enhanced_allocations()
2584 .expect("Should get enhanced allocations")
2585 .is_empty());
2586 assert!(tracker
2587 .get_safety_violations()
2588 .expect("Should get safety violations")
2589 .is_empty());
2590 assert!(tracker
2591 .get_c_library_stats()
2592 .expect("Should get C library stats")
2593 .is_empty());
2594 }
2595
2596 #[test]
2597 fn test_unsafe_ffi_tracker_default() {
2598 let tracker = UnsafeFFITracker::default();
2599
2600 assert!(tracker
2602 .get_enhanced_allocations()
2603 .expect("Should get enhanced allocations after reset")
2604 .is_empty());
2605 assert!(tracker
2606 .get_safety_violations()
2607 .expect("Should get safety violations after reset")
2608 .is_empty());
2609 }
2610
2611 #[test]
2612 fn test_track_unsafe_allocation() {
2613 let tracker = create_test_tracker();
2614 let ptr = 0x1000;
2615 let size = 1024;
2616 let location = "test_file.rs:42:10".to_string();
2617
2618 let result = tracker.track_unsafe_allocation(ptr, size, location.clone());
2619 assert!(result.is_ok());
2620
2621 let allocations = tracker.get_enhanced_allocations().unwrap();
2623 assert_eq!(allocations.len(), 1);
2624
2625 let allocation = &allocations[0];
2626 assert_eq!(allocation.base.ptr, ptr);
2627 assert_eq!(allocation.base.size, size);
2628
2629 match &allocation.source {
2631 AllocationSource::UnsafeRust {
2632 unsafe_block_location,
2633 ..
2634 } => {
2635 assert_eq!(unsafe_block_location, &location);
2636 }
2637 _ => panic!("Expected UnsafeRust allocation source"),
2638 }
2639 }
2640
2641 #[test]
2642 fn test_track_ffi_allocation() {
2643 let tracker = create_test_tracker();
2644 let ptr = 0x2000;
2645 let size = 512;
2646 let library_name = "libc".to_string();
2647 let function_name = "malloc".to_string();
2648
2649 let result =
2650 tracker.track_ffi_allocation(ptr, size, library_name.clone(), function_name.clone());
2651 assert!(result.is_ok());
2652
2653 let allocations = tracker.get_enhanced_allocations().unwrap();
2655 assert_eq!(allocations.len(), 1);
2656
2657 let allocation = &allocations[0];
2658 assert_eq!(allocation.base.ptr, ptr);
2659 assert_eq!(allocation.base.size, size);
2660 assert!(allocation.ffi_tracked);
2661
2662 match &allocation.source {
2664 AllocationSource::FfiC {
2665 resolved_function, ..
2666 } => {
2667 assert_eq!(resolved_function.library_name, library_name);
2668 assert_eq!(resolved_function.function_name, function_name);
2669 }
2670 _ => panic!("Expected FfiC allocation source"),
2671 }
2672 }
2673
2674 #[test]
2675 fn test_track_enhanced_deallocation_valid() {
2676 let tracker = create_test_tracker();
2677 let ptr = 0x3000;
2678 let size = 256;
2679
2680 tracker
2682 .track_unsafe_allocation(ptr, size, "test_location".to_string())
2683 .unwrap();
2684
2685 let result = tracker.track_enhanced_deallocation(ptr);
2687 assert!(result.is_ok());
2688
2689 let allocations = tracker.get_enhanced_allocations().unwrap();
2691 assert!(allocations.is_empty());
2692 }
2693
2694 #[test]
2695 fn test_track_enhanced_deallocation_invalid_free() {
2696 let tracker = create_test_tracker();
2697 let ptr = 0x4000;
2698
2699 let result = tracker.track_enhanced_deallocation(ptr);
2701 assert!(result.is_err());
2702
2703 let violations = tracker.get_safety_violations().unwrap();
2705 assert_eq!(violations.len(), 1);
2706
2707 match &violations[0] {
2708 SafetyViolation::InvalidFree {
2709 attempted_pointer, ..
2710 } => {
2711 assert_eq!(*attempted_pointer, ptr);
2712 }
2713 _ => panic!("Expected InvalidFree violation"),
2714 }
2715 }
2716
2717 #[test]
2718 fn test_track_enhanced_deallocation_double_free() {
2719 let tracker = create_test_tracker();
2720 let ptr = 0x5000;
2721 let size = 128;
2722
2723 tracker
2725 .track_unsafe_allocation(ptr, size, "test_location".to_string())
2726 .unwrap();
2727
2728 let result1 = tracker.track_enhanced_deallocation(ptr);
2730 assert!(result1.is_ok());
2731
2732 let result2 = tracker.track_enhanced_deallocation(ptr);
2734 assert!(result2.is_err());
2735
2736 let violations = tracker.get_safety_violations().unwrap();
2738 assert_eq!(violations.len(), 1);
2739
2740 match &violations[0] {
2741 SafetyViolation::DoubleFree { .. } => {
2742 }
2744 _ => panic!("Expected DoubleFree violation"),
2745 }
2746 }
2747
2748 #[test]
2749 fn test_record_boundary_event() {
2750 let tracker = create_test_tracker();
2751 let ptr = 0x6000;
2752 let size = 1024;
2753
2754 tracker
2756 .track_unsafe_allocation(ptr, size, "test_location".to_string())
2757 .unwrap();
2758
2759 let result = tracker.record_boundary_event(
2761 ptr,
2762 BoundaryEventType::RustToFfi,
2763 "rust_context".to_string(),
2764 "ffi_context".to_string(),
2765 );
2766 assert!(result.is_ok());
2767
2768 let allocations = tracker.get_enhanced_allocations().unwrap();
2770 assert_eq!(allocations.len(), 1);
2771
2772 let allocation = &allocations[0];
2773 assert_eq!(allocation.cross_boundary_events.len(), 1);
2774
2775 let event = &allocation.cross_boundary_events[0];
2776 assert!(matches!(event.event_type, BoundaryEventType::RustToFfi));
2777 assert_eq!(event.from_context, "rust_context");
2778 assert_eq!(event.to_context, "ffi_context");
2779 }
2780
2781 #[test]
2782 fn test_register_c_library() {
2783 let tracker = create_test_tracker();
2784 let library_name = "test_lib".to_string();
2785 let library_path = Some("/usr/lib/libtest.so".to_string());
2786 let library_version = Some("1.0.0".to_string());
2787
2788 let result = tracker.register_c_library(
2789 library_name.clone(),
2790 library_path.clone(),
2791 library_version.clone(),
2792 );
2793 assert!(result.is_ok());
2794
2795 let libraries = tracker.get_c_library_stats().unwrap();
2797 assert_eq!(libraries.len(), 1);
2798
2799 let library = libraries.get(&library_name).unwrap();
2800 assert_eq!(library.library_name, library_name);
2801 assert_eq!(library.library_path, library_path);
2802 assert_eq!(library.library_version, library_version);
2803 assert_eq!(library.total_allocations, 0);
2804 assert_eq!(library.total_bytes_allocated, 0);
2805 }
2806
2807 #[test]
2808 fn test_track_c_function_call() {
2809 let tracker = create_test_tracker();
2810 let library_name = "libc";
2811 let function_name = "malloc";
2812 let allocation_size = 1024;
2813 let execution_time_ns = 500;
2814
2815 let result = tracker.track_c_function_call(
2816 library_name,
2817 function_name,
2818 allocation_size,
2819 execution_time_ns,
2820 );
2821 assert!(result.is_ok());
2822
2823 let libraries = tracker.get_c_library_stats().unwrap();
2825 assert_eq!(libraries.len(), 1);
2826
2827 let library = libraries.get(library_name).unwrap();
2828 assert_eq!(library.total_allocations, 1);
2829 assert_eq!(library.total_bytes_allocated, allocation_size);
2830
2831 let function = library.functions_called.get(function_name).unwrap();
2832 assert_eq!(function.call_count, 1);
2833 assert_eq!(function.bytes_allocated, allocation_size);
2834 assert_eq!(function.average_allocation_size, allocation_size as f64);
2835 assert_eq!(
2836 function.performance_metrics.avg_execution_time_ns,
2837 execution_time_ns
2838 );
2839 }
2840
2841 #[test]
2842 fn test_install_enhanced_libc_hook() {
2843 let tracker = create_test_tracker();
2844 let function_name = "malloc".to_string();
2845 let hook_method = HookInstallationMethod::Preload;
2846
2847 let result = tracker.install_enhanced_libc_hook(function_name.clone(), hook_method);
2848 assert!(result.is_ok());
2849
2850 let hooks = tracker.get_libc_hook_info().unwrap();
2852 assert_eq!(hooks.len(), 1);
2853
2854 let hook = hooks.get(&function_name).unwrap();
2855 assert_eq!(hook.base_info.original_function, function_name);
2856 assert!(matches!(
2857 hook.installation_details.installation_method,
2858 HookInstallationMethod::Preload
2859 ));
2860 assert!(hook.installation_details.installation_success);
2861 }
2862
2863 #[test]
2864 fn test_create_and_register_passport() {
2865 let tracker = create_test_tracker();
2866 let ptr = 0x7000;
2867 let origin_context = "rust_main";
2868 let security_clearance = SecurityClearance::Public;
2869
2870 let result = tracker.create_and_register_passport(ptr, origin_context, security_clearance);
2871 assert!(result.is_ok());
2872
2873 let passport_id = result.unwrap();
2874 assert!(!passport_id.is_empty());
2875
2876 let passports = tracker.get_memory_passports().unwrap();
2878 assert_eq!(passports.len(), 1);
2879
2880 let passport = passports.get(&ptr).unwrap();
2881 assert_eq!(passport.passport_id, passport_id);
2882 assert_eq!(passport.origin.context, origin_context);
2883 assert!(matches!(
2884 passport.security_clearance,
2885 SecurityClearance::Public
2886 ));
2887 assert!(matches!(passport.validity_status, ValidityStatus::Valid));
2888 }
2889
2890 #[test]
2891 fn test_stamp_passport() {
2892 let tracker = create_test_tracker();
2893 let ptr = 0x8000;
2894
2895 tracker
2897 .create_and_register_passport(ptr, "rust_main", SecurityClearance::Public)
2898 .unwrap();
2899
2900 let result =
2902 tracker.stamp_passport(ptr, "memory_access", "ffi_boundary", "UnsafeFFITracker");
2903 assert!(result.is_ok());
2904
2905 let passports = tracker.get_memory_passports().unwrap();
2907 let passport = passports.get(&ptr).unwrap();
2908 assert_eq!(passport.journey.len(), 1);
2909
2910 let stamp = &passport.journey[0];
2911 assert_eq!(stamp.operation, "memory_access");
2912 assert_eq!(stamp.location, "ffi_boundary");
2913 assert_eq!(stamp.authority, "UnsafeFFITracker");
2914 }
2915
2916 #[test]
2917 fn test_transfer_passport_ownership() {
2918 let tracker = create_test_tracker();
2919 let ptr = 0x9000;
2920
2921 tracker
2923 .create_and_register_passport(ptr, "rust_main", SecurityClearance::Public)
2924 .unwrap();
2925
2926 let result = tracker.transfer_passport_ownership(ptr, "ffi_context", "malloc");
2928 assert!(result.is_ok());
2929
2930 let passports = tracker.get_memory_passports().unwrap();
2932 let passport = passports.get(&ptr).unwrap();
2933 assert_eq!(passport.current_owner.owner_context, "ffi_context");
2934 assert_eq!(passport.current_owner.owner_function, "malloc");
2935
2936 assert_eq!(passport.journey.len(), 1);
2938 assert_eq!(passport.journey[0].operation, "ownership_transfer");
2939 }
2940
2941 #[test]
2942 fn test_revoke_passport() {
2943 let tracker = create_test_tracker();
2944 let ptr = 0xa000;
2945
2946 tracker
2948 .create_and_register_passport(ptr, "rust_main", SecurityClearance::Public)
2949 .unwrap();
2950
2951 let result = tracker.revoke_passport(ptr, "memory_freed");
2953 assert!(result.is_ok());
2954
2955 let passports = tracker.get_memory_passports().unwrap();
2957 let passport = passports.get(&ptr).unwrap();
2958 assert!(matches!(passport.validity_status, ValidityStatus::Revoked));
2959
2960 assert_eq!(passport.journey.len(), 1);
2962 assert!(passport.journey[0].operation.contains("revoked"));
2963 }
2964
2965 #[test]
2966 fn test_validate_passport() {
2967 let tracker = create_test_tracker();
2968 let ptr = 0xb000;
2969
2970 tracker
2972 .track_unsafe_allocation(ptr, 1024, "test_location".to_string())
2973 .unwrap();
2974
2975 tracker
2977 .create_or_update_passport(ptr, "create", "rust_main")
2978 .unwrap();
2979
2980 let result = tracker.validate_passport(ptr);
2982 assert!(result.is_ok());
2983 let is_valid = result.unwrap();
2984 assert!(is_valid);
2985
2986 let allocations = tracker.get_enhanced_allocations().unwrap();
2988 assert_eq!(allocations.len(), 1);
2989 let allocation = &allocations[0];
2990 assert!(allocation.memory_passport.is_some());
2991 let passport = allocation.memory_passport.as_ref().unwrap();
2992 assert!(matches!(passport.validity_status, ValidityStatus::Valid));
2993
2994 let result = tracker.validate_passport(0xdead);
2996 assert!(result.is_ok());
2997 assert!(!result.unwrap()); let ptr2 = 0xc000;
3001 tracker
3002 .create_and_register_passport(ptr2, "rust_main", SecurityClearance::Public)
3003 .unwrap();
3004
3005 let passports = tracker.get_memory_passports().unwrap();
3007 assert_eq!(passports.len(), 1);
3008 let passport = passports.get(&ptr2).unwrap();
3009 assert!(matches!(passport.validity_status, ValidityStatus::Valid));
3010
3011 tracker.revoke_passport(ptr2, "test_revocation").unwrap();
3013 let passports = tracker.get_memory_passports().unwrap();
3014 let passport = passports.get(&ptr2).unwrap();
3015 assert!(matches!(passport.validity_status, ValidityStatus::Revoked));
3016 }
3017
3018 #[test]
3019 fn test_detect_leaks() {
3020 let tracker = create_test_tracker();
3021 let ptr = 0xc000;
3022 let size = 1024;
3023
3024 tracker
3026 .track_unsafe_allocation(ptr, size, "test_location".to_string())
3027 .unwrap();
3028
3029 std::thread::sleep(std::time::Duration::from_millis(10));
3031
3032 let result = tracker.detect_leaks(1); assert!(result.is_ok());
3035
3036 let leaks = result.unwrap();
3037 if !leaks.is_empty() {
3040 match &leaks[0] {
3041 SafetyViolation::PotentialLeak { .. } => {
3042 }
3044 _ => panic!("Expected PotentialLeak violation"),
3045 }
3046 } else {
3047 let allocations = tracker.get_enhanced_allocations().unwrap();
3049 assert_eq!(allocations.len(), 1);
3050 assert!(allocations[0].base.is_active());
3051 }
3052 }
3053
3054 #[test]
3055 fn test_analyze_cross_boundary_risks() {
3056 let tracker = create_test_tracker();
3057 let ptr = 0xd000;
3058
3059 tracker
3061 .create_and_register_passport(ptr, "rust_main", SecurityClearance::Public)
3062 .unwrap();
3063
3064 for i in 0..15 {
3066 tracker
3067 .stamp_passport(ptr, &format!("operation_{i}"), "boundary", "test")
3068 .unwrap();
3069 }
3070
3071 let result = tracker.analyze_cross_boundary_risks();
3073 assert!(result.is_ok());
3074
3075 let risks = result.unwrap();
3076 assert!(!risks.is_empty());
3077
3078 let has_boundary_risk = risks
3080 .iter()
3081 .any(|risk| matches!(risk, SafetyViolation::CrossBoundaryRisk { .. }));
3082 assert!(has_boundary_risk);
3083 }
3084
3085 #[test]
3086 fn test_get_stats() {
3087 let tracker = create_test_tracker();
3088
3089 tracker
3091 .track_unsafe_allocation(0x1000, 1024, "unsafe_block".to_string())
3092 .unwrap();
3093 tracker
3094 .track_ffi_allocation(0x2000, 512, "libc".to_string(), "malloc".to_string())
3095 .unwrap();
3096
3097 let stats = tracker.get_stats();
3099
3100 assert_eq!(stats.total_operations, 2);
3101 assert_eq!(stats.unsafe_blocks, 1);
3102 assert_eq!(stats.ffi_calls, 1);
3103 assert_eq!(stats.memory_violations, 0);
3104 assert!(stats.risk_score > 0.0);
3105 assert_eq!(stats.operations.len(), 2);
3106 }
3107
3108 #[test]
3109 fn test_boundary_event_statistics() {
3110 let tracker = create_test_tracker();
3111 let ptr = 0xe000;
3112
3113 tracker
3115 .track_unsafe_allocation(ptr, 1024, "test_location".to_string())
3116 .unwrap();
3117 tracker
3118 .record_boundary_event(
3119 ptr,
3120 BoundaryEventType::RustToFfi,
3121 "rust".to_string(),
3122 "ffi".to_string(),
3123 )
3124 .unwrap();
3125 tracker
3126 .record_boundary_event(
3127 ptr,
3128 BoundaryEventType::FfiToRust,
3129 "ffi".to_string(),
3130 "rust".to_string(),
3131 )
3132 .unwrap();
3133
3134 let result = tracker.get_boundary_event_statistics();
3136 assert!(result.is_ok());
3137
3138 let stats = result.unwrap();
3139 assert_eq!(stats.total_events, 2);
3140 assert!(stats.events_by_type.contains_key("RustToFfi"));
3141 assert!(stats.events_by_type.contains_key("FfiToRust"));
3142 assert!(stats.average_transfer_size > 0.0);
3143 assert!(stats.total_transfer_volume > 0);
3144 }
3145
3146 #[test]
3147 fn test_risk_level_serialization() {
3148 let risk_levels = vec![
3149 RiskLevel::Low,
3150 RiskLevel::Medium,
3151 RiskLevel::High,
3152 RiskLevel::Critical,
3153 ];
3154
3155 for risk_level in risk_levels {
3156 let serialized = serde_json::to_string(&risk_level).expect("Failed to serialize");
3157 let _deserialized: RiskLevel =
3158 serde_json::from_str(&serialized).expect("Failed to deserialize");
3159 }
3160 }
3161
3162 #[test]
3163 fn test_boundary_event_type_serialization() {
3164 let event_types = vec![
3165 BoundaryEventType::RustToFfi,
3166 BoundaryEventType::FfiToRust,
3167 BoundaryEventType::OwnershipTransfer,
3168 BoundaryEventType::SharedAccess,
3169 ];
3170
3171 for event_type in event_types {
3172 let serialized = serde_json::to_string(&event_type).expect("Failed to serialize");
3173 let _deserialized: BoundaryEventType =
3174 serde_json::from_str(&serialized).expect("Failed to deserialize");
3175 }
3176 }
3177
3178 #[test]
3179 fn test_security_clearance_serialization() {
3180 let clearances = vec![
3181 SecurityClearance::Public,
3182 SecurityClearance::Restricted,
3183 SecurityClearance::Confidential,
3184 SecurityClearance::Secret,
3185 ];
3186
3187 for clearance in clearances {
3188 let serialized = serde_json::to_string(&clearance).expect("Failed to serialize");
3189 let _deserialized: SecurityClearance =
3190 serde_json::from_str(&serialized).expect("Failed to deserialize");
3191 }
3192 }
3193
3194 #[test]
3195 fn test_global_tracker_initialization() {
3196 let tracker1 = init_global_unsafe_tracker();
3197 let tracker2 = init_global_unsafe_tracker();
3198
3199 assert!(Arc::ptr_eq(&tracker1, &tracker2));
3201 }
3202
3203 #[test]
3204 fn test_memory_protection_flags() {
3205 let flags = MemoryProtectionFlags {
3206 readable: true,
3207 writable: true,
3208 executable: false,
3209 shared: false,
3210 };
3211
3212 assert!(flags.readable);
3213 assert!(flags.writable);
3214 assert!(!flags.executable);
3215 assert!(!flags.shared);
3216 }
3217
3218 #[test]
3219 fn test_allocation_metadata() {
3220 let metadata = AllocationMetadata {
3221 requested_size: 1024,
3222 actual_size: 1024,
3223 alignment: 8,
3224 allocator_info: "test_allocator".to_string(),
3225 protection_flags: Some(MemoryProtectionFlags {
3226 readable: true,
3227 writable: true,
3228 executable: false,
3229 shared: false,
3230 }),
3231 };
3232
3233 assert_eq!(metadata.requested_size, 1024);
3234 assert_eq!(metadata.actual_size, 1024);
3235 assert_eq!(metadata.alignment, 8);
3236 assert!(metadata.protection_flags.is_some());
3237 }
3238
3239 #[test]
3240 fn test_comprehensive_workflow() {
3241 let tracker = create_test_tracker();
3242
3243 tracker
3245 .register_c_library(
3246 "test_lib".to_string(),
3247 Some("/lib/libtest.so".to_string()),
3248 Some("1.0".to_string()),
3249 )
3250 .unwrap();
3251
3252 let ptr1 = 0x10000;
3254 let ptr2 = 0x20000;
3255
3256 tracker
3257 .track_unsafe_allocation(ptr1, 1024, "unsafe_block".to_string())
3258 .unwrap();
3259 tracker
3260 .track_ffi_allocation(ptr2, 512, "test_lib".to_string(), "test_malloc".to_string())
3261 .unwrap();
3262
3263 tracker
3265 .create_and_register_passport(ptr1, "rust_main", SecurityClearance::Public)
3266 .unwrap();
3267 tracker
3268 .create_and_register_passport(ptr2, "ffi_lib", SecurityClearance::Restricted)
3269 .unwrap();
3270
3271 tracker
3273 .record_boundary_event(
3274 ptr1,
3275 BoundaryEventType::RustToFfi,
3276 "rust".to_string(),
3277 "ffi".to_string(),
3278 )
3279 .unwrap();
3280
3281 tracker
3283 .track_c_function_call("test_lib", "test_malloc", 512, 1000)
3284 .unwrap();
3285
3286 tracker
3288 .install_enhanced_libc_hook("malloc".to_string(), HookInstallationMethod::Preload)
3289 .unwrap();
3290
3291 let allocations = tracker.get_enhanced_allocations().unwrap();
3293 assert_eq!(allocations.len(), 2);
3294
3295 let libraries = tracker.get_c_library_stats().unwrap();
3296 assert_eq!(libraries.len(), 1);
3297
3298 let passports = tracker.get_memory_passports().unwrap();
3299 assert_eq!(passports.len(), 2);
3300
3301 let hooks = tracker.get_libc_hook_info().unwrap();
3302 assert_eq!(hooks.len(), 1);
3303
3304 let stats = tracker.get_stats();
3305 assert_eq!(stats.total_operations, 2);
3306 assert_eq!(stats.unsafe_blocks, 1);
3307 assert_eq!(stats.ffi_calls, 1);
3308
3309 tracker.track_enhanced_deallocation(ptr1).unwrap();
3311 tracker.track_enhanced_deallocation(ptr2).unwrap();
3312
3313 let final_allocations = tracker.get_enhanced_allocations().unwrap();
3314 assert!(final_allocations.is_empty());
3315 }
3316}