1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
pub mod asan_rt;
pub mod helper;

/// A representation of the various Frida options
#[derive(Clone, Copy, Debug)]
#[allow(clippy::struct_excessive_bools)]
pub struct FridaOptions {
    enable_asan: bool,
    enable_asan_leak_detection: bool,
    enable_asan_continue_after_error: bool,
    enable_asan_allocation_backtraces: bool,
    enable_coverage: bool,
    enable_drcov: bool,
}

impl FridaOptions {
    /// Parse the frida options from the LIBAFL_FRIDA_OPTIONS environment variable.
    ///
    /// Options are ':' separated, and each options is a 'name=value' string.
    pub fn parse_env_options() -> Self {
        let mut options = Self::default();

        if let Ok(env_options) = std::env::var("LIBAFL_FRIDA_OPTIONS") {
            for option in env_options.trim().to_lowercase().split(':') {
                let (name, mut value) =
                    option.split_at(option.find('=').expect("Expected a '=' in option string"));
                value = value.get(1..).unwrap();
                match name {
                    "asan" => {
                        options.enable_asan = value.parse().unwrap();

                        #[cfg(not(target_arch = "aarch64"))]
                        if options.enable_asan {
                            panic!("ASAN is not currently supported on targets other than aarch64");
                        }
                    }
                    "asan-detect-leaks" => {
                        options.enable_asan_leak_detection = value.parse().unwrap();
                    }
                    "asan-continue-after-error" => {
                        options.enable_asan_continue_after_error = value.parse().unwrap();
                    }
                    "asan-allocation-backtraces" => {
                        options.enable_asan_allocation_backtraces = value.parse().unwrap();
                    }
                    "coverage" => {
                        options.enable_coverage = value.parse().unwrap();
                    }
                    "drcov" => {
                        options.enable_drcov = value.parse().unwrap();
                        #[cfg(not(target_arch = "aarch64"))]
                        if options.enable_drcov {
                            panic!(
                                "DrCov is not currently supported on targets other than aarch64"
                            );
                        }
                    }
                    _ => {
                        panic!("unknown FRIDA option: '{}'", option);
                    }
                }
            }
        }

        options
    }

    /// Is ASAN enabled?
    #[inline]
    pub fn asan_enabled(self) -> bool {
        self.enable_asan
    }

    /// Is coverage enabled?
    #[inline]
    pub fn coverage_enabled(self) -> bool {
        self.enable_coverage
    }

    /// Is DrCov enabled?
    #[inline]
    pub fn drcov_enabled(self) -> bool {
        self.enable_drcov
    }

    /// Should ASAN detect leaks
    #[inline]
    pub fn asan_detect_leaks(self) -> bool {
        self.enable_asan_leak_detection
    }

    /// Should ASAN continue after a memory error is detected
    #[inline]
    pub fn asan_continue_after_error(self) -> bool {
        self.enable_asan_continue_after_error
    }

    /// Should ASAN gather (and report) allocation-/free-site backtraces
    #[inline]
    pub fn asan_allocation_backtraces(self) -> bool {
        self.enable_asan_allocation_backtraces
    }

    /// Whether stalker should be enabled. I.e. whether at least one stalker requiring option is
    /// enabled.
    #[inline]
    pub fn stalker_enabled(self) -> bool {
        self.enable_asan || self.enable_coverage || self.enable_drcov
    }
}

impl Default for FridaOptions {
    fn default() -> Self {
        Self {
            enable_asan: false,
            enable_asan_leak_detection: false,
            enable_asan_continue_after_error: false,
            enable_asan_allocation_backtraces: true,
            enable_coverage: true,
            enable_drcov: false,
        }
    }
}