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