2020-10-22 14:38:41 +02:00
#![ feature(unsafe_block_in_unsafe_fn) ]
#![ deny(unsafe_op_in_unsafe_fn) ]
use turn_lock ::TurnLock ;
const PAGE_SIZE : usize = 1 < < 12 ; // FIXME Magic
// design docs
// Build a channel using x pages + one synchronisation primitive.
// F+R only use one line per page
// F+F should use several line per page
// Each page has 1<<12 bytes / 1<<6 bytes per line, hence 64 lines (or 6 bits of info).
// General structure : two threads, a transmitter and a reciever. Transmitter generates bytes, Reciever reads bytes, then on join compare results for accuracy.
// Alos time in order to determine duration, in rdtsc and seconds.
use bit_field ::BitField ;
2020-11-20 10:52:58 +01:00
use cache_side_channel ::{ restore_affinity , set_affinity , CoreSpec } ;
2020-10-22 14:38:41 +02:00
use cache_utils ::mmap ::MMappedMemory ;
use cache_utils ::rdtsc_fence ;
2020-11-20 10:52:58 +01:00
use nix ::sched ::sched_getaffinity ;
use nix ::unistd ::Pid ;
2020-10-22 14:38:41 +02:00
use std ::any ::Any ;
use std ::collections ::VecDeque ;
2020-11-20 10:52:58 +01:00
use std ::fmt ::Debug ;
2020-10-22 14:38:41 +02:00
use std ::sync ::Arc ;
use std ::thread ;
/**
* Safety considerations : Not ensure thread safety , need proper locking as needed .
* /
2020-11-20 10:52:58 +01:00
pub trait CovertChannel : Send + Sync + CoreSpec + Debug {
2020-10-22 14:38:41 +02:00
const BIT_PER_PAGE : usize ;
unsafe fn transmit ( & self , page : * const u8 , bits : & mut BitIterator ) ;
unsafe fn receive ( & self , page : * const u8 ) -> Vec < bool > ;
2020-11-20 10:52:58 +01:00
unsafe fn ready_page ( & mut self , page : * const u8 ) ;
2020-10-22 14:38:41 +02:00
}
2020-11-20 10:52:58 +01:00
#[ derive(Debug) ]
2020-10-22 14:38:41 +02:00
pub struct CovertChannelBenchmarkResult {
pub num_bytes_transmitted : usize ,
pub num_bit_errors : usize ,
pub error_rate : f64 ,
pub time_rdtsc : u64 ,
2020-11-24 10:25:32 +01:00
pub time_seconds : std ::time ::Duration ,
}
impl CovertChannelBenchmarkResult {
pub fn capacity ( & self ) -> f64 {
( self . num_bytes_transmitted * 8 ) as f64 / self . time_seconds . as_secs_f64 ( )
}
pub fn true_capacity ( & self ) -> f64 {
let p = self . error_rate ;
self . capacity ( ) * ( 1.0 + ( ( 1.0 - p ) * f64 ::log2 ( 1.0 - p ) + p * f64 ::log2 ( p ) ) )
}
2020-10-22 14:38:41 +02:00
}
pub struct BitIterator < ' a > {
bytes : & ' a Vec < u8 > ,
byte_index : usize ,
bit_index : u8 ,
}
impl < ' a > BitIterator < ' a > {
pub fn new ( bytes : & ' a Vec < u8 > ) -> BitIterator < ' a > {
BitIterator {
bytes ,
byte_index : 0 ,
bit_index : 0 ,
}
}
pub fn atEnd ( & self ) -> bool {
self . byte_index > = self . bytes . len ( )
}
}
impl Iterator for BitIterator < '_ > {
type Item = bool ;
fn next ( & mut self ) -> Option < Self ::Item > {
if let Some ( b ) = self . bytes . get ( self . byte_index ) {
let r = ( b > > ( u8 ::BIT_LENGTH - 1 - self . bit_index as usize ) ) & 1 ! = 0 ;
self . bit_index + = 1 ;
self . byte_index + = self . bit_index as usize / u8 ::BIT_LENGTH ;
self . bit_index = self . bit_index % u8 ::BIT_LENGTH as u8 ;
Some ( r )
} else {
None
}
}
}
struct CovertChannelPage {
pub turn : TurnLock ,
pub addr : * const u8 ,
}
struct CovertChannelParams < T : CovertChannel + Send > {
pages : Vec < CovertChannelPage > ,
covert_channel : Arc < T > ,
}
unsafe impl < T : 'static + CovertChannel + Send > Send for CovertChannelParams < T > { }
fn transmit_thread < T : CovertChannel > (
num_bytes : usize ,
mut params : CovertChannelParams < T > ,
2020-11-24 10:25:32 +01:00
) -> ( u64 , std ::time ::Instant , Vec < u8 > ) {
2020-11-20 10:52:58 +01:00
let old_affinity = set_affinity ( & ( * params . covert_channel ) . helper_core ( ) ) ;
2020-10-22 14:38:41 +02:00
let mut result = Vec ::new ( ) ;
result . reserve ( num_bytes ) ;
for _ in 0 .. num_bytes {
let byte = rand ::random ( ) ;
result . push ( byte ) ;
}
2020-11-20 10:52:58 +01:00
let mut bit_sent = 0 ;
2020-10-22 14:38:41 +02:00
let mut bit_iter = BitIterator ::new ( & result ) ;
2020-11-24 10:25:32 +01:00
let start_time = std ::time ::Instant ::now ( ) ;
2020-10-22 14:38:41 +02:00
let start = unsafe { rdtsc_fence ( ) } ;
while ! bit_iter . atEnd ( ) {
for page in params . pages . iter_mut ( ) {
page . turn . wait ( ) ;
unsafe { params . covert_channel . transmit ( page . addr , & mut bit_iter ) } ;
2020-11-20 10:52:58 +01:00
bit_sent + = T ::BIT_PER_PAGE ;
2020-10-22 14:38:41 +02:00
page . turn . next ( ) ;
2020-11-20 10:52:58 +01:00
if bit_iter . atEnd ( ) {
break ;
}
2020-10-22 14:38:41 +02:00
}
}
2020-11-24 10:25:32 +01:00
( start , start_time , result )
2020-10-22 14:38:41 +02:00
}
pub fn benchmark_channel < T : 'static + Send + CovertChannel > (
2020-11-20 10:52:58 +01:00
mut channel : T ,
2020-10-22 14:38:41 +02:00
num_pages : usize ,
num_bytes : usize ,
) -> CovertChannelBenchmarkResult {
// Allocate pages
2020-11-20 10:52:58 +01:00
let old_affinity = set_affinity ( & channel . main_core ( ) ) ;
2020-10-22 14:38:41 +02:00
let size = num_pages * PAGE_SIZE ;
2020-11-20 10:52:58 +01:00
let mut m = MMappedMemory ::new ( size , false ) ;
2020-10-22 14:38:41 +02:00
let mut pages_transmit = Vec ::new ( ) ;
let mut pages_receive = Vec ::new ( ) ;
2020-11-20 10:52:58 +01:00
for i in 0 .. num_pages {
m . slice_mut ( ) [ i * PAGE_SIZE ] = i as u8 ;
}
2020-10-22 14:38:41 +02:00
let array : & [ u8 ] = m . slice ( ) ;
for i in 0 .. num_pages {
let addr = & array [ i * PAGE_SIZE ] as * const u8 ;
let mut turns = TurnLock ::new ( 2 ) ;
let mut t_iter = turns . drain ( 0 .. ) ;
let transmit_lock = t_iter . next ( ) . unwrap ( ) ;
2020-11-20 10:52:58 +01:00
let receive_lock = t_iter . next ( ) . unwrap ( ) ;
2020-10-22 14:38:41 +02:00
assert! ( t_iter . next ( ) . is_none ( ) ) ;
2020-11-20 10:52:58 +01:00
unsafe { channel . ready_page ( addr ) } ;
2020-10-22 14:38:41 +02:00
pages_transmit . push ( CovertChannelPage {
turn : transmit_lock ,
addr ,
} ) ;
pages_receive . push ( CovertChannelPage {
turn : receive_lock ,
addr ,
} ) ;
}
2020-11-20 10:52:58 +01:00
2020-10-22 14:38:41 +02:00
let covert_channel_arc = Arc ::new ( channel ) ;
let params = CovertChannelParams {
pages : pages_transmit ,
covert_channel : covert_channel_arc . clone ( ) ,
} ;
let helper = thread ::spawn ( move | | transmit_thread ( num_bytes , params ) ) ;
// Create the thread parameters
let mut received_bytes : Vec < u8 > = Vec ::new ( ) ;
let mut received_bits = VecDeque ::< bool > ::new ( ) ;
while received_bytes . len ( ) < num_bytes {
for page in pages_receive . iter_mut ( ) {
page . turn . wait ( ) ;
let mut bits = unsafe { covert_channel_arc . receive ( page . addr ) } ;
page . turn . next ( ) ;
received_bits . extend ( & mut bits . iter ( ) ) ;
while received_bits . len ( ) > = u8 ::BIT_LENGTH {
let mut byte = 0 ;
for i in 0 .. u8 ::BIT_LENGTH {
byte < < = 1 ;
let bit = received_bits . pop_front ( ) . unwrap ( ) ;
byte | = bit as u8 ;
}
received_bytes . push ( byte ) ;
}
2020-11-20 10:52:58 +01:00
if received_bytes . len ( ) > = num_bytes {
break ;
}
2020-10-22 14:38:41 +02:00
}
// TODO
// receiver thread
}
2020-11-20 10:52:58 +01:00
2020-10-22 14:38:41 +02:00
let stop = unsafe { rdtsc_fence ( ) } ;
2020-11-24 10:25:32 +01:00
let stop_time = std ::time ::Instant ::now ( ) ;
2020-10-22 14:38:41 +02:00
let r = helper . join ( ) ;
2020-11-24 10:25:32 +01:00
let ( start , start_time , sent_bytes ) = match r {
2020-10-22 14:38:41 +02:00
Ok ( r ) = > r ,
Err ( e ) = > panic! ( " Join Error: {:?#} " ) ,
} ;
assert_eq! ( sent_bytes . len ( ) , received_bytes . len ( ) ) ;
assert_eq! ( num_bytes , received_bytes . len ( ) ) ;
2020-11-20 10:52:58 +01:00
restore_affinity ( & old_affinity ) ;
2020-10-22 14:38:41 +02:00
let mut num_bit_error = 0 ;
for i in 0 .. num_bytes {
num_bit_error + = ( sent_bytes [ i ] ^ received_bytes [ i ] ) . count_ones ( ) as usize ;
}
let error_rate = ( num_bit_error as f64 ) / ( ( num_bytes * u8 ::BIT_LENGTH ) as f64 ) ;
2020-11-20 10:52:58 +01:00
2020-10-22 14:38:41 +02:00
CovertChannelBenchmarkResult {
num_bytes_transmitted : num_bytes ,
num_bit_errors : num_bit_error ,
error_rate ,
time_rdtsc : stop - start ,
2020-11-24 10:25:32 +01:00
time_seconds : stop_time - start_time ,
2020-10-22 14:38:41 +02:00
}
}
#[ cfg(test) ]
mod tests {
use crate ::BitIterator ;
#[ test ]
fn it_works ( ) {
assert_eq! ( 2 + 2 , 4 ) ;
}
#[ test ]
fn test_bit_vec ( ) {
let bit_iter = BitIterator ::new ( vec! [ 0x55 , 0xf ] ) ;
let results = vec! [
false , true , false , true , false , true , false , true , false , false , false , false , true ,
true , true , true ,
] ;
for ( i , bit ) in bit_iter . enumerate ( ) {
assert_eq! ( results [ i ] , bit ) ;
}
}
}