monster/
lib.rs

1#[macro_use]
2pub mod util;
3
4pub mod disassemble;
5pub mod engine;
6pub mod path_exploration;
7pub mod solver;
8
9use anyhow::Context;
10pub use engine::{
11    BugFinder, RaritySimulation, RaritySimulationBug, RaritySimulationError,
12    RaritySimulationOptions, SymbolicExecutionBug, SymbolicExecutionEngine, SymbolicExecutionError,
13    SymbolicExecutionOptions,
14};
15use riscu::{load_object_file, Program};
16pub use solver::{SmtGenerationOptions, SmtType};
17use std::{fs::File, io::Write, path::Path};
18use thiserror::Error;
19
20#[derive(Debug, Error)]
21pub enum MonsterError {
22    #[error("I/O error")]
23    IoError(anyhow::Error),
24
25    #[error("preprocessing failed with error")]
26    Preprocessing(anyhow::Error),
27
28    #[error("symbolic execution stopped with error, {0}")]
29    SymbolicExecution(SymbolicExecutionError),
30
31    #[error("rarity simulation stopped with error")]
32    RaritySimulation(RaritySimulationError),
33}
34
35pub fn load_elf<P>(input: P) -> Result<Program, MonsterError>
36where
37    P: AsRef<Path>,
38{
39    load_object_file(input).map_err(|e| {
40        MonsterError::IoError(anyhow::Error::new(e).context("Failed to load object file"))
41    })
42}
43
44pub fn symbolically_execute(
45    program: &Program,
46) -> Result<Option<SymbolicExecutionBug>, MonsterError> {
47    let options = SymbolicExecutionOptions::default();
48    let solver = solver::MonsterSolver::default();
49    let strategy = path_exploration::ShortestPathStrategy::compute_for(program)
50        .map_err(MonsterError::Preprocessing)?;
51
52    symbolically_execute_with(program, &options, &strategy, &solver)
53}
54
55pub fn symbollically_execute_elf<P: AsRef<Path>>(
56    input: P,
57) -> Result<Option<SymbolicExecutionBug>, MonsterError> {
58    let program = load_elf(input)?;
59
60    symbolically_execute(&program)
61}
62
63pub fn symbolically_execute_with<Solver, Strategy>(
64    program: &Program,
65    options: &SymbolicExecutionOptions,
66    strategy: &Strategy,
67    solver: &Solver,
68) -> Result<Option<SymbolicExecutionBug>, MonsterError>
69where
70    Strategy: path_exploration::ExplorationStrategy,
71    Solver: solver::Solver,
72{
73    SymbolicExecutionEngine::new(&options, strategy, solver)
74        .search_for_bugs(&program)
75        .map_err(MonsterError::SymbolicExecution)
76}
77
78pub fn symbolically_execute_elf_with<P, Solver, Strategy>(
79    input: P,
80    options: &SymbolicExecutionOptions,
81    strategy: &Strategy,
82    solver: &Solver,
83) -> Result<Option<SymbolicExecutionBug>, MonsterError>
84where
85    P: AsRef<Path>,
86    Strategy: path_exploration::ExplorationStrategy,
87    Solver: solver::Solver,
88{
89    let program = load_elf(input)?;
90
91    symbolically_execute_with(&program, options, strategy, solver)
92}
93
94pub fn generate_smt<Strategy, W, P>(
95    input: P,
96    write: W,
97    options: &SmtGenerationOptions,
98    strategy: &Strategy,
99) -> Result<Option<SymbolicExecutionBug>, MonsterError>
100where
101    W: Write + Send + 'static,
102    Strategy: path_exploration::ExplorationStrategy,
103    P: AsRef<Path>,
104{
105    let sym_options = SymbolicExecutionOptions {
106        memory_size: options.memory_size,
107        max_exection_depth: options.max_execution_depth,
108        optimistically_prune_search_space: false,
109    };
110
111    match options.smt_type {
112        SmtType::Generic => {
113            let solver = solver::SmtWriter::new::<W>(write)
114                .context("failed to generate SMT file writer backend")
115                .map_err(MonsterError::Preprocessing)?;
116
117            symbolically_execute_elf_with(input, &sym_options, strategy, &solver)
118        }
119        #[cfg(feature = "boolector")]
120        SmtType::Boolector => {
121            let solver = solver::SmtWriter::new_for_solver::<solver::Boolector, W>(write)
122                .context("failed to generate SMT file writer backend")
123                .map_err(MonsterError::Preprocessing)?;
124
125            symbolically_execute_elf_with(input, &sym_options, strategy, &solver)
126        }
127        #[cfg(feature = "z3")]
128        SmtType::Z3 => {
129            let solver = solver::SmtWriter::new_for_solver::<solver::Z3, W>(write)
130                .context("failed to generate SMT file writer backend")
131                .map_err(MonsterError::Preprocessing)?;
132
133            symbolically_execute_elf_with(input, &sym_options, strategy, &solver)
134        }
135    }
136}
137
138pub fn generate_smt_to_file<Strategy, P>(
139    input: P,
140    output: P,
141    options: &SmtGenerationOptions,
142    strategy: &Strategy,
143) -> Result<Option<SymbolicExecutionBug>, MonsterError>
144where
145    Strategy: path_exploration::ExplorationStrategy,
146    P: AsRef<Path> + Send,
147{
148    let file = File::create(output)
149        .context("failed to generate SMT file writer")
150        .map_err(MonsterError::IoError)?;
151
152    generate_smt(input, file, options, strategy)
153}
154
155pub fn rarity_simulate(program: &Program) -> Result<Option<RaritySimulationBug>, MonsterError> {
156    rarity_simulate_with(program, &RaritySimulationOptions::default())
157}
158
159pub fn rarity_simulate_elf<P: AsRef<Path>>(
160    input: P,
161) -> Result<Option<RaritySimulationBug>, MonsterError> {
162    let program = load_elf(input)?;
163
164    rarity_simulate(&program)
165}
166
167pub fn rarity_simulate_with(
168    program: &Program,
169    options: &RaritySimulationOptions,
170) -> Result<Option<RaritySimulationBug>, MonsterError> {
171    RaritySimulation::new(&options)
172        .search_for_bugs(program)
173        .map_err(MonsterError::RaritySimulation)
174}
175
176pub fn rarity_simulate_elf_with<P>(
177    input: P,
178    options: &RaritySimulationOptions,
179) -> Result<Option<RaritySimulationBug>, MonsterError>
180where
181    P: AsRef<Path>,
182{
183    let program = load_elf(input)?;
184
185    rarity_simulate_with(&program, options)
186}