| Crates.io | swage |
| lib.rs | swage |
| version | 0.2.0 |
| created_at | 2023-09-28 15:35:56.307239+00 |
| updated_at | 2026-01-22 14:42:54.362783+00 |
| description | The Swage Rowhammer framework. |
| homepage | |
| repository | https://github.com/UzL-ITS/swage |
| max_upload_size | |
| id | 986037 |
| size | 76,312 |
SWAGE is a Rust-based framework for conducting end-to-end Rowhammer attacks in a modular and composable way. The framework separates the attack pipeline into three core components: allocators, hammerers, and victims, each defined by a trait that can be independently implemented and combined.
Rowhammer is a hardware vulnerability in DRAM where repeated accesses to memory rows can cause bit flips in adjacent rows. SWAGE provides a structured approach to researching and executing such attacks by breaking down the attack into modular components.
SWAGE is built around three main traits defined in [swage_core]:
allocator::ConsecAllocator] - Strategies for allocating consecutive physical memory blockshammerer::Hammering] - Implementations of memory hammering patterns and techniquesvictim::VictimOrchestrator] - Management of target memory regions or applicationsThese components are orchestrated by the [Swage] struct, which coordinates the complete
attack pipeline from memory allocation through hammering to result verification.
Creating a custom Rowhammer attack pipeline with SWAGE involves three main steps:
Allocators provide consecutive physical memory blocks required for effective Rowhammer attacks. SWAGE includes several built-in allocators:
Spoiler - Uses SPOILER timing side-channel attack to infer physical addressesPfn - Uses /proc/self/pagemap to obtain physical frame numbers (requires root)THP - Uses Transparent Huge Pages for 2MB blocksHugepage - Uses 1GB hugepages (requires system configuration)use swage::memory::MemConfiguration;
use swage::allocator::{ConsecAllocator, Spoiler, ConflictThreshold};
use swage::util::Size;
// Example: Create a Spoiler allocator
let mut allocator = Spoiler::new(MemConfiguration::default(), ConflictThreshold::from(190), None);
let memory = allocator.alloc_consec_blocks(Size::MB(256)).unwrap();
To create a custom allocator, implement the [allocator::ConsecAllocator] trait:
use swage::allocator::ConsecAllocator;
use swage::memory::ConsecBlocks;
use swage::util::Size;
struct MyAllocator;
impl ConsecAllocator for MyAllocator {
type Error = std::io::Error;
fn block_size(&self) -> Size {
Size::MB(2) // 2MB blocks
}
fn alloc_consec_blocks(&mut self, size: Size) -> Result<ConsecBlocks, Self::Error> {
// Your allocation logic here
todo!()
}
}
Hammerers define the memory access patterns used to trigger bit flips. SWAGE provides:
Blacksmith - Implements the Blacksmith fuzzing-based hammering techniqueDevMem - Direct memory access via /dev/mem (requires root)Dummy - A no-op hammerer for testingThe Blacksmith hammerer requires specific configuration including DRAM addressing
parameters and hammering patterns. See the swage-blacksmith crate documentation
for configuration details.
Note: Hammerers are typically created via factory functions in the builder pattern. See Step 4 for usage examples.
To create a custom hammerer, implement the [hammerer::Hammering] trait:
use swage::hammerer::Hammering;
struct MyHammerer {
// Your hammerer state
}
impl Hammering for MyHammerer {
type Error = std::io::Error;
fn hammer(&self) -> Result<(), Self::Error> {
// Perform memory accesses to trigger Rowhammer
todo!()
}
}
Victims define what is being targeted and how to check for successful attacks:
MemCheck - Checks memory regions for bit flipsNote: MemCheck is typically created by the victim factory in the builder pattern.
See Step 4 for usage examples.
To create a custom victim, implement the [victim::VictimOrchestrator] trait:
use swage::victim::{VictimOrchestrator, HammerVictimError, VictimResult};
use swage::memory::ConsecBlocks;
struct MyVictim;
impl VictimOrchestrator for MyVictim {
fn start(&mut self) -> Result<(), HammerVictimError> {
// Initialize victim
Ok(())
}
fn init(&mut self) {
// Prepare victim state before hammering
}
fn check(&mut self) -> Result<VictimResult, HammerVictimError> {
// Check if attack succeeded
Ok(VictimResult::Nothing)
}
fn stop(&mut self) {
// Cleanup
}
}
SWAGE uses the builder pattern to construct and configure attack pipelines. The [Swage::builder()]
method provides a fluent interface for assembling the components:
use swage::{Swage, SwageConfig, MemCheck, DataPatternKind};
use swage::allocator::{Spoiler, ConflictThreshold};
use swage::memory::{MemConfiguration, DataPattern, ConsecBlocks};
use swage::util::Size;
use swage::victim::VictimOrchestrator;
use swage::blacksmith::Blacksmith;
// Configure the attack
let config = SwageConfig {
profiling_rounds: 10,
reproducibility_threshold: 0.8,
repetitions: Some(1),
..Default::default()
};
let allocator = Spoiler::new(
MemConfiguration::default(),
300.into(),
None
);
let pattern_size = Size::MB(256).bytes();
let swage = Swage::<Blacksmith, _, std::io::Error, std::io::Error>::builder()
.allocator(allocator)
.profile_hammerer_factory(|memory| {
todo!("Build blacksmith hammerer");
})
.victim_factory(|memory, profiling| {
todo!("Build your victim")
})
.pattern_size(todo!("pattern size"))
.config(config)
.build()
.unwrap();
let experiments = swage.run();
SWAGE uses automatic module discovery. To add a new module:
Create a new crate in the appropriate directory:
crates/allocators/swage-myallocator/ for allocatorscrates/hammerers/swage-myhammerer/ for hammererscrates/victims/swage-myvictim/ for victimsImplement the corresponding trait from swage-core
Run the module discovery script:
./update_modules.sh
The script will automatically register your module in the workspace.
/proc/self/pagemapEnable specific non-core modules via Cargo features:
spoiler - SPOILER allocatorpfn - PFN allocatorhugepage - Hugepage allocatorthp - Transparent Huge Pages allocatorblacksmith - Blacksmith hammererdev-mem - /dev/mem hammererThis framework is intended for security research and education. Users must:
License: MIT