swage_core/victim.rs
1//! Victim orchestration for Rowhammer attacks.
2//!
3//! This module provides the infrastructure for managing victim applications or memory
4//! regions that are targeted by Rowhammer attacks. A victim can be:
5//! - A memory region checked for bit flips ([`MemCheck`](crate::MemCheck))
6//! - A process or application being attacked
7//! - Other custom victim implementations
8//!
9//! The [`VictimOrchestrator`] trait defines the lifecycle and interface for all victims.
10
11use crate::memory::BitFlip;
12use crate::memory::FlippyPage;
13use crate::memory::LinuxPageMapError;
14use core::panic;
15use serde::Serialize;
16use thiserror::Error;
17
18/// Errors that can occur during victim operations.
19#[derive(Error, Debug)]
20pub enum HammerVictimError {
21 /// No bit flips were detected during the check operation.
22 #[error("No flips detected")]
23 NoFlips,
24 /// An I/O error occurred during victim operations.
25 #[error(transparent)]
26 IoError(#[from] std::io::Error),
27 /// The victim is not currently running.
28 #[error("Victim is not running")]
29 NotRunning,
30 /// Failed to construct the victim with the given configuration.
31 #[error("Failed to construct victim: {0}")]
32 ConstructionError(Box<dyn std::error::Error>),
33 /// The expected flippy page was not found.
34 #[error("Flippy page not found")]
35 FlippyPageNotFound,
36 /// The flippy page offset does not match the expected value.
37 #[error("Flippy page offset mismatch: expected {expected}, actual {actual:?}")]
38 FlippyPageOffsetMismatch {
39 /// Expected page offset
40 expected: usize,
41 /// Actual flippy page information
42 actual: FlippyPage,
43 },
44 /// An error occurred while accessing Linux pagemap.
45 #[error(transparent)]
46 LinuxPageMapError(#[from] LinuxPageMapError),
47 /// A protocol-level error occurred in victim communication.
48 #[error("Protocol Error: {0}")]
49 ProtocolError(String),
50}
51
52/// Result type returned by victim check operations.
53///
54/// This enum represents the different types of results that can be returned
55/// when checking if a Rowhammer attack was successful.
56#[derive(Debug, Serialize)]
57pub enum VictimResult {
58 /// One or more bit flips were detected at specific memory locations.
59 BitFlips(Vec<BitFlip>),
60 /// A string result describing the attack outcome.
61 String(String),
62 /// Multiple string results describing attack outcome.
63 Strings(Vec<String>),
64 /// No meaningful result to report.
65 Nothing,
66}
67
68impl VictimResult {
69 /// Extracts the bit flips from this result.
70 ///
71 /// # Panics
72 ///
73 /// Panics if this result is not the `BitFlips` variant.
74 pub fn bit_flips(self) -> Vec<BitFlip> {
75 match self {
76 VictimResult::BitFlips(flips) => flips,
77 _ => panic!("Invalid variant. Expected BitFlips, got {:?}", self),
78 }
79 }
80}
81
82/// Trait for orchestrating victim applications or memory regions targeted by Rowhammer attacks.
83///
84/// Implementors of this trait define how to initialize, monitor, and check victim
85/// memory regions or processes for the effects of Rowhammer attacks (e.g., bit flips).
86/// The trait provides a lifecycle for victim management: start, initialize, check, and stop.
87///
88/// # Lifecycle
89///
90/// The typical victim lifecycle is:
91/// 1. [`start()`](VictimOrchestrator::start) - Initialize victim resources (called once)
92/// 2. [`init()`](VictimOrchestrator::init) - Prepare victim state before hammering
93/// 3. Hammering occurs (external to victim)
94/// 4. [`check()`](VictimOrchestrator::check) - Verify if attack succeeded
95/// 5. [`stop()`](VictimOrchestrator::stop) - Clean up victim resources
96///
97/// Steps 2-4 may be repeated multiple times between start and stop.
98///
99/// # Examples
100///
101/// See `swage-victim-dev-memcheck` or the [`MemCheck`](crate::MemCheck) implementation
102/// for concrete usage examples.
103pub trait VictimOrchestrator {
104 /// Starts the victim and allocates required resources.
105 ///
106 /// This method is called once at the beginning of an experiment to set up
107 /// the victim environment. It may involve starting processes, mapping memory,
108 /// or establishing communication channels.
109 ///
110 /// # Errors
111 ///
112 /// Returns [`HammerVictimError`] if initialization fails.
113 fn start(&mut self) -> Result<(), HammerVictimError>;
114
115 /// Initializes the victim state before a hammering round.
116 ///
117 /// This method is called before each hammering operation to prepare the
118 /// victim memory or process to a known state. For memory-based victims,
119 /// this typically involves writing specific patterns to memory.
120 /// For process-based victims, this might involve triggering an operation
121 /// or sending a signal to the victim process.
122 fn init(&mut self);
123
124 /// Checks if the hammering attack was successful.
125 ///
126 /// This method examines the victim to detect any effects of the Rowhammer
127 /// attack, typically by checking for bit flips in memory or unexpected
128 /// behavior in victim processes.
129 ///
130 /// # Returns
131 ///
132 /// Returns `Ok(VictimResult)` with attack results if effects are detected,
133 /// or [`HammerVictimError::NoFlips`] if no effects are found.
134 ///
135 /// # Errors
136 ///
137 /// Returns an error if:
138 /// * No bit flips or effects are detected ([`HammerVictimError::NoFlips`])
139 /// * I/O operations fail
140 /// * The victim is not in a valid state
141 fn check(&mut self) -> Result<VictimResult, HammerVictimError>;
142
143 /// Stops the victim and releases resources.
144 ///
145 /// This method is called at the end of an experiment to clean up the victim
146 /// environment, stop processes, and release any allocated resources.
147 fn stop(&mut self);
148
149 /// Optionally serializes victim-specific data to JSON.
150 ///
151 /// This method allows victims to provide additional metadata or state
152 /// information that can be included in experiment results.
153 ///
154 /// # Returns
155 ///
156 /// Returns `Some(Value)` with serialized data, or `None` if no additional
157 /// data is available.
158 fn serialize(&self) -> Option<serde_json::Value> {
159 None
160 }
161}