├── Makefile ├── README.md ├── cache ├── evict.c ├── evict.h ├── set.c ├── set.h ├── slice.c └── slice.h ├── cjag.c ├── cjag.h ├── cs ├── Makefile ├── README.md ├── cachespeed.c ├── cachespeed.h └── util │ ├── cache.c │ ├── cache.h │ ├── colorprint.c │ ├── colorprint.h │ ├── getopt_helper.c │ └── getopt_helper.h ├── detection ├── cache.c ├── cache.h ├── cpu.c ├── cpu.h ├── paging.c └── paging.h ├── jag ├── common.c ├── common.h ├── receive.c ├── receive.h ├── send.c └── send.h └── util ├── colorprint.c ├── colorprint.h ├── error.c ├── error.h ├── getopt_helper.c ├── getopt_helper.h ├── timing.c ├── timing.h ├── watchdog.c └── watchdog.h /Makefile: -------------------------------------------------------------------------------- 1 | OBJECTS = detection/paging.o \ 2 | detection/cache.o \ 3 | detection/cpu.o \ 4 | util/error.o \ 5 | util/timing.o \ 6 | util/colorprint.o \ 7 | util/getopt_helper.o \ 8 | util/watchdog.o \ 9 | cache/evict.o \ 10 | cache/set.o \ 11 | cache/slice.o \ 12 | jag/send.o \ 13 | jag/common.o \ 14 | jag/receive.o 15 | 16 | FLAGS = -Wall -g -O3 -march=native -std=gnu11 -pthread 17 | 18 | all: cjag 19 | 20 | cjag: cjag.c $(OBJECTS) cjag.h 21 | gcc $(OBJECTS) $(FLAGS) -o $@ $@.c -lm 22 | 23 | %.o: %.c 24 | gcc $(FLAGS) -c $^ -o $@ 25 | 26 | .PHONY: clean 27 | clean: 28 | rm -f $(OBJECTS) cjag 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CJAG 2 | 3 | CJAG is an open-source implementation of our cache-based jamming agreement. 4 | The CJAG implementation can be used to establish a cross-VM cache covert channel. The CJAG test application in this repository is used to test a cache-based communication between two co-located virtual machines. It can also be used locally for test and research purposes. 5 | 6 | A thorough description can be found in our whitepaper 7 | 8 | * [CJAG: Cache-based Jamming Agreement](https://www.blackhat.com/docs/asia-17/materials/asia-17-Schwarz-Hello-From-The-Other-Side-SSH-Over-Robust-Cache-Covert-Channels-In-The-Cloud-wp.pdf) (Michael Schwarz, Manuel Weber) 9 | 10 | A cache-based, robust covert channel based on CJAG can be found in our NDSS'17 paper 11 | 12 | * [Hello from the Other Side: SSH over Robust Cache Covert Channels in the Cloud](https://cmaurice.fr/pdf/ndss17_maurice.pdf) (Clémentine Maurice, Manuel Weber, Michael Schwarz, Lukas Giner, Daniel Gruss, Carlo Alberto Boano, Stefan Mangard, Kay Römer) 13 | 14 | ## Table of contents 15 | 16 | * [Prerequisites](#prerequisites) 17 | * [Building CJAG from source](#building-cjag-from-source) 18 | * [Using CJAG](#using-cjag) 19 | * [FAQ](#faq) 20 | 21 | ## Prerequisites 22 | 23 | CJAG consists of multiple C files. There is no dependency on any external library, thus the only required packages are 24 | 25 | * gcc 26 | * make 27 | 28 | On Ubuntu, they can be installed using the package manager: 29 | 30 | sudo apt-get install gcc make 31 | 32 | As the program explicitly requests huge pages from the operating system, it requires support of the `mmap` flag `MAP_HUGETLB`. This is the case for any Linux kernel >= 2.6.32. 33 | 34 | Furthermore, if huge pages are not configured, they have to be enabled. 35 | This can either be done temporarily by running 36 | 37 | sudo sysctl -w vm.nr_hugepages=32 38 | 39 | or permanently by running 40 | 41 | echo "vm.nr_hugepages = 32" | sudo tee >> /etc/sysctl.conf 42 | 43 | and rebooting afterwards. 44 | 45 | ## Building CJAG from source 46 | 47 | If all prerequisites are fulfilled, CJAG can be simply built by executing 48 | 49 | make 50 | 51 | This results in a `cjag` binary. 52 | 53 | ## Using CJAG 54 | 55 | The `cjag` binary includes both the sender and the receiver side. 56 | The sender side runs `./cjag`whereas the receiver side runs `./cjag -r`. 57 | 58 | If you test CJAG locally, the parameter auto detection should be able to figure out all parameters and CJAG will just work. If, however, it does not work, you have to manually tweak the parameters. Run `./cjag --help` to get a list and explanation of all parameters. The most important ones are: 59 | 60 | * **--cache-size**: The size of the last-level cache (also called LLC or L3) in bytes. 61 | * **--ways**: The number of cache ways. Will usually be something like 12 or 16. 62 | * **--slices**: Usually the number of CPU cores (real cores, not hyperthreads). On modern CPUs it might sometimes also be the number of hyperthreads. 63 | * **--threshold**: The minimum number of cycles it takes to access data which is not cached. You can find this number by running the tool `cachespeed` from the subfolder `cachespeed`. Take the value in row "L3 miss" and column "+ mfence". 64 | * **--delay**: If your computer (or VM) is slow, try to increase this value. This gives CJAG more time to react on. Important: this value has to be the same for the sender and the receiver. 65 | 66 | The whitepaper contains a table for these parameters for all environments we used to test CJAG (including Amazon EC2). 67 | If CJAG was successful, the sender will display `Done. 100.00% of the channels are established, your system [ V U L N E R A B L E ].` 68 | For a thorough explanation of the program's output please refer to the whitepaper. 69 | 70 | ## FAQ 71 | 72 | * **I really like the auto detection/eviction set generation/eviction strategy/< insert any part here >. Can I use it in my own project?** 73 | 74 | Yes, all parts of CJAG are open source and you are free to use it in your projects. 75 | 76 | * **I get `*[ERROR] Could not retrieve cache sets, please try to restart*`** 77 | 78 | Most likely some cache parameters are wrong. Maybe the auto detection did not work (happens on virtual machines) or you messed up some numbers. Check the specifications of your **host** CPU and try again. 79 | 80 | * **It does not work!** 81 | 82 | Did you check that all the parameters are correct? Try to play around with the threshold and delay parameter. You should also check the whitepaper, section 4.3 "Common Errors". 83 | 84 | * **My cloud provider only has CPUs where the number of slices is not a power of 2.** 85 | 86 | Currently, the cache slice functions for such CPUs are not known. As soon as someone reverse engineers the functions (or Intel releases them), we will update the program. 87 | 88 | * **This is nice, but can you release your full covert channel?** 89 | 90 | We will not release the full covert channel. However, using CJAG as a base, the remaining covert channel is just (a lot of) engineering work. 91 | -------------------------------------------------------------------------------- /cache/evict.c: -------------------------------------------------------------------------------- 1 | #include "evict.h" 2 | #include "../util/timing.h" 3 | 4 | //haswell + 5 | void evict_set(volatile uint8_t **addresses, int kill_count) { 6 | for (size_t i = 0; i < kill_count; ++i) { 7 | *addresses[i]; 8 | *addresses[i + 1]; 9 | *addresses[i]; 10 | *addresses[i + 1]; 11 | } 12 | } 13 | 14 | void access_set(volatile uint8_t **addresses, int probe_count) { 15 | for (size_t i = 0; i < probe_count; ++i) { 16 | *addresses[i]; 17 | *addresses[i + 1]; 18 | *addresses[i + 2]; 19 | *addresses[i]; 20 | *addresses[i + 1]; 21 | *addresses[i + 2]; 22 | } 23 | } 24 | 25 | //sandy only 26 | size_t 27 | test_evict_set(volatile uint8_t **probe_set, volatile uint8_t **eviction_set, volatile uint8_t **test_eviction_set, 28 | int probe_count, int es_size, int tes_size) // not cached 29 | { 30 | if (es_size != 0) { 31 | for (size_t i = 0; i < es_size - 1; ++i) { 32 | *eviction_set[i]; 33 | *eviction_set[i + 1]; 34 | } 35 | } 36 | if (tes_size != 0) { 37 | for (size_t i = 0; i < tes_size - 1; ++i) { 38 | *test_eviction_set[i]; 39 | *test_eviction_set[i + 1]; 40 | } 41 | } 42 | 43 | size_t time = rdtsc(); 44 | for (size_t i = 0; i < probe_count; ++i) { 45 | *probe_set[i]; 46 | } 47 | size_t delta = rdtsc() - time; 48 | return delta; 49 | } -------------------------------------------------------------------------------- /cache/evict.h: -------------------------------------------------------------------------------- 1 | #ifndef BLACKHAT_EVICT_H 2 | #define BLACKHAT_EVICT_H 3 | 4 | #include 5 | #include 6 | 7 | void evict_set(volatile uint8_t **addresses, int kill_count); 8 | void access_set(volatile uint8_t **addresses, int probe_count); 9 | size_t test_evict_set(volatile uint8_t **probe_set, volatile uint8_t **eviction_set, volatile uint8_t **test_eviction_set, 10 | int probe_count, int es_size, int tes_size); 11 | 12 | #endif //BLACKHAT_EVICT_H 13 | -------------------------------------------------------------------------------- /cache/set.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by mschwarz on 2/19/17. 3 | // 4 | 5 | #include "set.h" 6 | #include 7 | 8 | uint32_t get_cache_set_index(uint64_t phys_addr) { 9 | uint64_t mask = ((uint64_t) 1 << 17) - 1; 10 | return (phys_addr & mask) >> 6; 11 | } -------------------------------------------------------------------------------- /cache/set.h: -------------------------------------------------------------------------------- 1 | #ifndef BLACKHAT_SET_H 2 | #define BLACKHAT_SET_H 3 | 4 | #include 5 | uint32_t get_cache_set_index(uint64_t phys_addr); 6 | 7 | #endif //BLACKHAT_SET_H 8 | -------------------------------------------------------------------------------- /cache/slice.c: -------------------------------------------------------------------------------- 1 | #include "slice.h" 2 | 3 | // ----------------------------------------------------------------------------- 4 | int get_cache_slice(uint64_t phys_addr, int slices) { 5 | static const int h0[] = {6, 10, 12, 14, 16, 17, 18, 20, 22, 24, 25, 26, 27, 28, 30, 32, 33, 35, 36}; 6 | static const int h1[] = {7, 11, 13, 15, 17, 19, 20, 21, 22, 23, 24, 26, 28, 29, 31, 33, 34, 35, 37}; 7 | static const int h2[] = {8, 12, 13, 16, 19, 22, 23, 26, 27, 30, 31, 34, 35, 36, 37}; 8 | int slice; 9 | 10 | int count = sizeof(h0) / sizeof(h0[0]); 11 | int hash0 = 0; 12 | for (int i = 0; i < count; i++) { 13 | hash0 ^= (phys_addr >> h0[i]) & 1; 14 | } 15 | slice = hash0; 16 | 17 | int hash1 = 0; 18 | count = sizeof(h1) / sizeof(h1[0]); 19 | if (slices > 2) { 20 | for (int i = 0; i < count; i++) { 21 | hash1 ^= (phys_addr >> h1[i]) & 1; 22 | } 23 | slice = hash1 << 1 | hash0; 24 | } 25 | 26 | int hash2 = 0; 27 | count = sizeof(h2) / sizeof(h2[0]); 28 | if (slices > 4) { 29 | for (int i = 0; i < count; i++) { 30 | hash2 ^= (phys_addr >> h2[i]) & 1; 31 | } 32 | slice = (hash2 << 2) | (hash1 << 1) | hash0; 33 | } 34 | return slice; 35 | } 36 | -------------------------------------------------------------------------------- /cache/slice.h: -------------------------------------------------------------------------------- 1 | #ifndef BLACKHAT_SLICE_H 2 | #define BLACKHAT_SLICE_H 3 | 4 | #include 5 | 6 | int get_cache_slice(uint64_t phys_addr, int slices); 7 | 8 | #endif //BLACKHAT_SLICE_H 9 | -------------------------------------------------------------------------------- /cjag.c: -------------------------------------------------------------------------------- 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 | 15 | #include "detection/paging.h" 16 | #include "util/error.h" 17 | #include "util/colorprint.h" 18 | 19 | #include "cjag.h" 20 | #include "jag/common.h" 21 | #include "jag/send.h" 22 | #include "jag/receive.h" 23 | #include "detection/cache.h" 24 | #include "detection/cpu.h" 25 | #include "util/getopt_helper.h" 26 | 27 | static size_t *usable_sets; 28 | 29 | static getopt_arg_t options[] = 30 | { 31 | {"receive", no_argument, NULL, 'r', "Start in [c]receive mode[/c] (default: [m]send mode[/m])", NULL}, 32 | {"threshold", required_argument, NULL, 't', "Set the cache-miss threshold to [y]THRESHOLD[/y] (default: 280)", "THRESHOLD"}, 33 | {"delay", required_argument, NULL, 'd', "Increase the [m]jamming[/m] and [c]listening[/c] delays by factor [y]DELAY[/y] (default: 1)", "DELAY"}, 34 | {"patience", required_argument, NULL, 'p', "Sets the watchdog timeout to [y]SECONDS[/y] seconds (default: 10)", "SECONDS"}, 35 | {"cache-size", required_argument, NULL, 'c', "Set the size of the L3 cache to [y]SIZE[/y] bytes (default: auto detect)", "SIZE"}, 36 | {"ways", required_argument, NULL, 'w', "Set the number of cache ways to [y]WAYS[/y] ways (default: auto detect)", "WAYS"}, 37 | {"slices", required_argument, NULL, 's', "Set the number of cache slices to [y]SLICES[/y] slices (default: auto detect)", "SLICES"}, 38 | {"no-color", no_argument, NULL, 'n', "Disable color output.", NULL}, 39 | {"verbose", no_argument, NULL, 'v', "Verbose mode", NULL}, 40 | {"help", no_argument, NULL, 'h', "Show this help.", NULL}, 41 | {NULL, 0, NULL, 0, NULL, NULL} 42 | }; 43 | 44 | 45 | int main(int argc, char **argv) { 46 | int verbose = 0; 47 | watchdog_t watchdog_settings; 48 | cjag_config_t config = { 49 | .send = 1, 50 | .color_output = 1, 51 | .channels = 6, 52 | .cache_miss_threshold = 280, 53 | .cache_probe_count = 3, 54 | .jag_send_count = 5000 * 3, 55 | .jag_recv_count = 15000 * 3, 56 | .set_offset = 10, 57 | .timeout = 10, 58 | .watchdog = &watchdog_settings 59 | }; 60 | 61 | cache_config_l3_t l3 = get_l3_info(); 62 | config.cache_size = l3.size; 63 | config.cache_ways = l3.ways; 64 | config.cache_kill_count = config.cache_ways - 1; 65 | config.cache_slices = get_slices(); 66 | 67 | 68 | struct option *long_options = getopt_get_long_options((getopt_arg_t *) options); 69 | ERROR_ON(!long_options, ERROR_OOM, config.color_output); 70 | 71 | int c; 72 | while ((c = getopt_long(argc, argv, ":c:t:w:rs:nhd:p:v", long_options, NULL)) != EOF) { 73 | switch (c) { 74 | case 'r': 75 | config.send = 0; 76 | break; 77 | case 'c': 78 | config.cache_size = atoi(optarg); 79 | break; 80 | case 't': 81 | config.cache_miss_threshold = atoi(optarg); 82 | break; 83 | case 'w': 84 | config.cache_ways = atoi(optarg); 85 | config.cache_kill_count = config.cache_ways - 1; 86 | break; 87 | case 's': 88 | config.cache_slices = atoi(optarg); 89 | break; 90 | case 'n': 91 | config.color_output = 0; 92 | break; 93 | case 'd': 94 | config.jag_send_count = (int) (config.jag_send_count * atof(optarg)); 95 | config.jag_recv_count = (int) (config.jag_recv_count * atof(optarg)); 96 | break; 97 | case 'p': 98 | config.timeout = atoi(optarg); 99 | break; 100 | case 'v': 101 | verbose = 1; 102 | break; 103 | case 'h': 104 | show_usage(argv[0], &config); 105 | return 0; 106 | case ':': 107 | printf_color(config.color_output, ERROR_TAG "Option [c]-%c[/c] requires an [y]argument[/y].\n", 108 | optopt); 109 | printf("\n"); 110 | show_usage(argv[0], &config); 111 | return 1; 112 | case '?': 113 | if (isprint(optopt)) { 114 | printf_color(config.color_output, ERROR_TAG "[y]Unknown[/y] option [c]-%c[/c].\n", optopt); 115 | } else { 116 | printf_color(config.color_output, ERROR_TAG "[y]Unknown[/y] option character [c]\\x%x[/c].\n", 117 | optopt); 118 | } 119 | printf("\n"); 120 | show_usage(argv[0], &config); 121 | return 1; 122 | default: 123 | show_usage(argv[0], &config); 124 | return 0; 125 | } 126 | } 127 | 128 | free(long_options); 129 | 130 | show_welcome(&config); 131 | show_parameters(&config); 132 | 133 | ERROR_ON(config.cache_slices > 16, ERROR_TOO_MANY_CPUS, config.color_output); 134 | ERROR_ON(config.cache_slices < 1 || config.cache_slices > 8 || (config.cache_slices & (config.cache_slices - 1)), 135 | ERROR_SLICES_NOT_SUPPORTED, config.color_output); 136 | ERROR_ON(config.cache_ways < 2, ERROR_INVALID_WAYS, config.color_output); 137 | ERROR_ON(config.timeout <= 1, ERROR_TIMEOUT_TOO_LOW, config.color_output); 138 | 139 | ERROR_ON(config.jag_send_count <= 0 || config.jag_recv_count <= 0, ERROR_INVALID_SPEED, config.color_output); 140 | 141 | ERROR_ON(!has_huge_pages(), ERROR_NO_HUGEPAGES, config.color_output); 142 | 143 | int init = jag_init(&config); 144 | ERROR_ON(!init, ERROR_NO_CACHE_SETS, config.color_output); 145 | 146 | usable_sets = calloc(config.channels, sizeof(size_t)); 147 | ERROR_ON(!usable_sets, ERROR_OOM, config.color_output); 148 | 149 | watchdog_start(config.watchdog, config.timeout, timeout, (void *) &config); 150 | 151 | void **addrs = malloc(config.cache_ways * config.channels * sizeof(void *)); 152 | if (config.send) { 153 | printf_color(config.color_output, "[y]Send mode[/y]: start [m]jamming[/m]...\n\n"); 154 | printf_color(config.color_output, "[g][ # ][/g] Jamming set...\n"); 155 | watchdog_reset(config.watchdog); 156 | jag_send(&config, send_callback); 157 | if(verbose) { 158 | printf_color(config.color_output, "[y]Eviction sets[/y]:\n"); 159 | print_eviction_sets(config.addr, &config); 160 | } 161 | 162 | printf_color(config.color_output, "\n[y]Verification mode[/y]: start [c]receiving[/c]...\n\n"); 163 | watchdog_reset(config.watchdog); 164 | sleep(1); 165 | watchdog_reset(config.watchdog); 166 | sleep(1); 167 | for (int i = 0; i < 15; i++) { 168 | watchdog_reset(config.watchdog); 169 | sched_yield(); 170 | } 171 | 172 | printf_color(config.color_output, "[g][ # ][/g] Checking sets...\n"); 173 | watchdog_reset(config.watchdog); 174 | jag_receive(addrs, usable_sets, &config, watch_callback); 175 | watchdog_done(config.watchdog); 176 | if(verbose) { 177 | printf_color(config.color_output, "[y]Eviction sets[/y]:\n"); 178 | print_eviction_sets(addrs, &config); 179 | } 180 | 181 | int correct = 0; 182 | for (int i = 0; i < config.channels; i++) { 183 | if (i == usable_sets[i] - config.set_offset) { 184 | correct++; 185 | } 186 | } 187 | 188 | printf_color(config.color_output, 189 | "\n[g][ # ][/g] Done. [g]%.2f%%[/g] of the channels are established, your system is [r]%s[/r][y]%s[/y].\n\n", 190 | (correct * 100.0 / config.channels), correct ? "[ V U L N E R A B L E ]" : "", 191 | correct ? "" : "[ maybe not vulnerable ]"); 192 | } else { 193 | printf_color(config.color_output, "[y]Receive mode[/y]: start [c]listening[/c]...\n\n"); 194 | printf_color(config.color_output, "[g][ # ][/g] Receiving sets...\n"); 195 | watchdog_reset(config.watchdog); 196 | jag_receive(addrs, usable_sets, &config, receive_callback); 197 | if(verbose) { 198 | printf_color(config.color_output, "[y]Eviction sets[/y]:\n"); 199 | print_eviction_sets(addrs, &config); 200 | } 201 | 202 | printf_color(config.color_output, "\n[g][ # ][/g] Reconstructing mapping...\n"); 203 | for (int i = 0; i < config.channels; i++) { 204 | printf_color(config.color_output, "[g][ + ][/g] Sender[[m]%d[/m]] -> Receiver[[c]%zd[/c]]\n", i, 205 | usable_sets[i]); 206 | } 207 | 208 | printf_color(config.color_output, "\n[y]Test mode[/y]: start [m]probing[/m]...\n\n"); 209 | watchdog_reset(config.watchdog); 210 | sleep(1); 211 | for (int i = 0; i < 15; i++) { 212 | watchdog_reset(config.watchdog); 213 | sched_yield(); 214 | } 215 | 216 | watchdog_reset(config.watchdog); 217 | void *old_addr = config.addr; 218 | config.addr = addrs; // send back the received addresses 219 | jag_send(&config, probe_callback); 220 | config.addr = old_addr; // bit of a hack to prevent double free and memory leak... 221 | watchdog_done(config.watchdog); 222 | printf_color(config.color_output, "\n[g][ # ][/g] Done!\n\n"); 223 | } 224 | 225 | ERROR_ON(!jag_free(&config), ERROR_UNMAP_FAILED, config.color_output); 226 | free(usable_sets); 227 | free(addrs); 228 | 229 | return 0; 230 | } 231 | 232 | 233 | void show_welcome(cjag_config_t *config) { 234 | printf_color(config->color_output, 235 | "\n___[y]/\\/\\/\\/\\/\\[/y]__________[r]/\\/\\[/r]______[r]/\\/\\[/r]________[r]/\\/\\/\\/\\/\\[/r]_\n"); 236 | printf_color(config->color_output, 237 | "_[y]/\\/\\[/y]__________________[r]/\\/\\[/r]____[r]/\\/\\/\\/\\[/r]____[r]/\\/\\[/r]_________\n"); 238 | printf_color(config->color_output, 239 | "_[y]/\\/\\[/y]__________________[r]/\\/\\[/r]__[r]/\\/\\[/r]____[r]/\\/\\[/r]__[r]/\\/\\[/r]__[r]/\\/\\/\\[/r]_\n"); 240 | printf_color(config->color_output, 241 | "_[y]/\\/\\[/y]__________[r]/\\/\\[/r]____[r]/\\/\\[/r]__[r]/\\/\\/\\/\\/\\/\\[/r]__[r]/\\/\\[/r]____[r]/\\/\\[/r]_\n"); 242 | printf_color(config->color_output, 243 | "___[y]/\\/\\/\\/\\/\\[/y]____[r]/\\/\\/\\/\\[/r]____[r]/\\/\\[/r]____[r]/\\/\\[/r]____[r]/\\/\\/\\/\\/\\[/r]_\n"); 244 | printf_color(config->color_output, "________________________________________________________\n\n"); 245 | } 246 | 247 | void show_parameters(cjag_config_t *config) { 248 | int size = config->cache_size / 1024; 249 | const char *unit = "KB"; 250 | if (size >= 1024 && size % 1024 == 0) { 251 | size /= 1024; 252 | unit = "MB"; 253 | } 254 | printf_color(config->color_output, " %10s %10s %10s %10s\n", "Size", "Ways", "Slices", "Threshold"); 255 | printf_color(config->color_output, "L3 [g]%7d %s[/g] [g]%9d[/g] [g]%7d[/g] [g]%9d[/g]\n\n", size, unit, 256 | config->cache_ways, config->cache_slices, config->cache_miss_threshold); 257 | } 258 | 259 | void show_usage(char *binary, cjag_config_t *config) { 260 | printf_color(config->color_output, "[y]USAGE[/y]\n %s [g][options][/g] \n\n", binary); 261 | getopt_arg_t null_option = {0}; 262 | size_t count = 0; 263 | printf_color(config->color_output, "\n[y]OPTIONS[/y]\n"); 264 | do { 265 | if (!memcmp((void *) &options[count], (void *) &null_option, sizeof(getopt_arg_t))) { 266 | break; 267 | } else if (options[count].description) { 268 | printf_color(config->color_output, " [g]-%c[/g]%s[y]%s[/y]%s [g]%s%s%s[/g][y]%s[/y]\n ", 269 | options[count].val, 270 | options[count].has_arg != no_argument ? " " : "", 271 | options[count].has_arg != no_argument ? options[count].arg_name : "", 272 | options[count].name ? "," : "", options[count].name ? "--" : "", options[count].name, 273 | options[count].has_arg != no_argument ? "=" : "", 274 | options[count].has_arg != no_argument ? options[count].arg_name : ""); 275 | printf_color(config->color_output, options[count].description); 276 | printf_color(config->color_output, "\n\n"); 277 | } 278 | count++; 279 | } while (1); 280 | printf("\n"); 281 | printf_color(config->color_output, 282 | "[y]EXAMPLE[/y]\n Start [m]%s[/m] and [c]%s --receive[/c] in two different terminals (or on two co-located VMs).\n\n\n", 283 | binary, binary); 284 | printf_color(config->color_output, 285 | "[y]AUTHORS[/y]\n Written by Michael Schwarz, Lukas Giner, Daniel Gruss, Clémentine Maurice and Manuel Weber.\n\n"); 286 | 287 | } 288 | 289 | void send_callback(cjag_config_t *config, int set) { 290 | watchdog_reset(config->watchdog); 291 | printf_color(config->color_output, "[g][ + ][/g] ...set #%d\n", set); 292 | } 293 | 294 | void probe_callback(cjag_config_t *config, int set) { 295 | watchdog_reset(config->watchdog); 296 | printf_color(config->color_output, "[g][ + ][/g] Probing set #%d ([[c]%d[/c]] -> [[m]%d[/m]])\n", set, 297 | usable_sets[set - 1], set - 1); 298 | } 299 | 300 | void receive_callback(cjag_config_t *config, int set) { 301 | watchdog_reset(config->watchdog); 302 | printf_color(config->color_output, "[g][ + ][/g] ...set #%d\n", set); 303 | } 304 | 305 | void watch_callback(cjag_config_t *config, int set) { 306 | watchdog_reset(config->watchdog); 307 | printf_color(config->color_output, "[g][ + ][/g] Sender[[m]%d[/m]] <-> Sender[[c]%zd[/c]] [g]%s[/g][r]%s[/r]\n", 308 | set - 1, usable_sets[set - 1] - config->set_offset, 309 | (set - 1 == usable_sets[set - 1] - config->set_offset) ? "[ OK ]" : "", 310 | (set - 1 != usable_sets[set - 1] - config->set_offset) ? "[FAIL]" : ""); 311 | } 312 | 313 | void timeout(void *arg) { 314 | cjag_config_t *config = (cjag_config_t *) arg; 315 | 316 | printf_color(config->color_output, 317 | ERROR_TAG "Timeout after [g]%d seconds[/g].\n Please [y]try to restart[/y] the application.\n\n", 318 | config->timeout); 319 | exit(1); 320 | } 321 | 322 | void print_eviction_sets(void** addr, cjag_config_t* config) { 323 | for (int i = 0; i < config->channels; i++) { 324 | printf_color(config->color_output, "[g][ . ] Set #%d[/g]\n", i + 1); 325 | for (int j = 0; j < config->cache_ways; j++) { 326 | void* v_addr = GET_EVICTION_SET(addr, i, config)[j]; 327 | printf_color(config->color_output, " %p\n", v_addr); 328 | } 329 | } 330 | } 331 | -------------------------------------------------------------------------------- /cjag.h: -------------------------------------------------------------------------------- 1 | #ifndef BLACKHAT_CJAG_H 2 | #define BLACKHAT_CJAG_H 3 | 4 | #include "util/watchdog.h" 5 | 6 | typedef struct _cjag_config_t { 7 | int send; 8 | int color_output; 9 | int channels; 10 | int cache_size; 11 | int cache_ways; 12 | int cache_slices; 13 | int cache_miss_threshold; 14 | int cache_kill_count; 15 | int cache_probe_count; 16 | int jag_send_count; 17 | int jag_recv_count; 18 | int set_offset; 19 | int timeout; 20 | 21 | watchdog_t *watchdog; 22 | void *addresses; 23 | volatile void **cache_sets; 24 | int n_addr_per_set; 25 | int n_pages; 26 | void **addr; 27 | } cjag_config_t; 28 | 29 | 30 | void show_welcome(cjag_config_t *config); 31 | 32 | void show_parameters(cjag_config_t *config); 33 | 34 | void show_usage(char *binary, cjag_config_t *config); 35 | 36 | void send_callback(cjag_config_t *config, int set); 37 | 38 | void probe_callback(cjag_config_t *config, int set); 39 | 40 | void receive_callback(cjag_config_t *config, int set); 41 | 42 | void watch_callback(cjag_config_t *config, int set); 43 | 44 | void timeout(void *arg); 45 | 46 | void print_eviction_sets(void **addr, cjag_config_t *config); 47 | 48 | 49 | #endif //BLACKHAT_CJAG_H 50 | -------------------------------------------------------------------------------- /cs/Makefile: -------------------------------------------------------------------------------- 1 | OBJECTS = util/cache.o \ 2 | util/colorprint.o \ 3 | util/getopt_helper.o 4 | 5 | FLAGS = -Wall -g -O3 -march=native -std=gnu11 6 | 7 | all: cachespeed 8 | 9 | cachespeed: cachespeed.c $(OBJECTS) cachespeed.h 10 | gcc $(OBJECTS) $(FLAGS) -o $@ $@.c -lm 11 | 12 | %.o: %.c 13 | gcc $(FLAGS) -c $^ -o $@ 14 | 15 | .PHONY: clean 16 | clean: 17 | rm -f $(OBJECTS) cachespeed 18 | -------------------------------------------------------------------------------- /cs/README.md: -------------------------------------------------------------------------------- 1 | # CacheSpeed 2 | 3 | CacheSpeed is a simple tool to measure certain parameters required for cache attacks. 4 | 5 | ## Building CacheSpeed 6 | 7 | CacheSpeed has no dependencies on any shared library or special system calls. It should be possible to compile it on any POSIX-compliant operating system. 8 | 9 | To build CacheSpeed, simply execute 10 | 11 | make 12 | 13 | ## Running CacheSpeed 14 | 15 | To run CacheSpeed, simply execute 16 | 17 | ./cachespeed 18 | 19 | The measurement might take several seconds and yields an output similar to this. 20 | ``` 21 | ( 22 | ( ) )\ ) ( 23 | )\ ) ( /( ( (()/( ( ( )\ ) 24 | (((_) ( /( ( )\()) ))\ /(_))` ) ))\ ))\ (()/( 25 | )\___ )(_)) )\ ((_)\ /((_) (_)) /(/( /((_)/((_) ((_)) 26 | ((/ __|((_)_ ((_)| |(_)(_)) / __|((_)_\ (_)) (_)) _| | 27 | | (__ / _` |/ _| | ' \ / -_) \__ \| '_ \)/ -_)/ -_)/ _` | 28 | \___|\__,_|\__| |_||_|\___| |___/| .__/ \___|\___|\__,_| 29 | |_| 30 | [ * ] Measuring lfence overhead... 31 | [ + ] Done. 32 | [ * ] Measuring mfence overhead... 33 | [ + ] Done. 34 | [ * ] Measuring cpuid overhead... 35 | [ + ] Done. 36 | [ * ] Measuring L1 hit time... 37 | [ + ] Done. 38 | [ * ] Measuring L1 miss time... 39 | [ + ] Done. 40 | [ * ] Measuring L3 miss time... 41 | [ + ] Done. 42 | 43 | 44 | | cycles | + lfence | + mfence | + cpuid 45 | ---------+-----------+-----------+-----------+------------ 46 | L1 Hit | 8 | 64 | 96 | 102 47 | L1 Miss | 16 | 72 | 104 | 110 48 | L3 Miss | 180 | 236 | 268 | 274 49 | ---------+-----------+-----------+-----------+------------ 50 | ``` 51 | 52 | CacheSpeed measures how long it takes to access data which is stored in the L1 cache (L1 Hit), L2 cache (L1 MIss), and DRAM (L3 Miss). 53 | The first column (cycles) shows the access times. Columns "+ lfence", "+ mfence", and "+ cpuid" are the access times including the respective fence mechanisms. 54 | 55 | ### Example: CJAG 56 | 57 | CJAG exploits the timing differences in the last-level cache. 58 | The used fences are `mfence`. 59 | Thus, the value in line "L3 Miss" and column "+ mfence" is the correct threshold to use. -------------------------------------------------------------------------------- /cs/cachespeed.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "util/cache.h" 8 | #include "util/getopt_helper.h" 9 | #include "util/colorprint.h" 10 | #include "cachespeed.h" 11 | 12 | static int hit[MAX_TIME]; 13 | static int miss[MAX_TIME]; 14 | static int dummy_mem[4096]; 15 | 16 | static int l1_thrash[256 * 1024 / sizeof(int)]; 17 | 18 | static getopt_arg_t options[] = 19 | { 20 | {"repeat", required_argument, NULL, 'r', "Set the number of measurements to [y]REPEAT[/y] (default: 1000000)", "REPEAT"}, 21 | {"no-color", no_argument, NULL, 'n', "Disable color output.", NULL}, 22 | {"verbose", no_argument, NULL, 'v', "Verbose mode", NULL}, 23 | {"help", no_argument, NULL, 'h', "Show this help.", NULL}, 24 | {NULL, 0, NULL, 0, NULL, NULL} 25 | }; 26 | 27 | 28 | int main(int argc, char* argv[]) { 29 | int color = 1; 30 | int verbose = 0; 31 | size_t repeat = REPEAT; 32 | 33 | struct option *long_options = getopt_get_long_options((getopt_arg_t *) options); 34 | int c; 35 | while ((c = getopt_long(argc, argv, ":r:nhv", long_options, NULL)) != EOF) { 36 | switch (c) { 37 | case 'r': 38 | repeat = strtoul(optarg, NULL, 0); 39 | break; 40 | case 'n': 41 | color = 0; 42 | break; 43 | case 'v': 44 | verbose = 1; 45 | break; 46 | case 'h': 47 | show_usage(argv[0], color); 48 | return 0; 49 | case ':': 50 | printf_color(color, ERROR_TAG "Option [c]-%c[/c] requires an [y]argument[/y].\n", 51 | optopt); 52 | printf("\n"); 53 | show_usage(argv[0], color); 54 | return 1; 55 | case '?': 56 | if (isprint(optopt)) { 57 | printf_color(color, ERROR_TAG "[y]Unknown[/y] option [c]-%c[/c].\n", optopt); 58 | } else { 59 | printf_color(color, ERROR_TAG "[y]Unknown[/y] option character [c]\\x%x[/c].\n", 60 | optopt); 61 | } 62 | printf("\n"); 63 | show_usage(argv[0], color); 64 | return 1; 65 | default: 66 | show_usage(argv[0], color); 67 | return 0; 68 | } 69 | } 70 | 71 | free(long_options); 72 | 73 | show_splash(color); 74 | 75 | volatile int *dummy = &(dummy_mem[2048]); 76 | 77 | printf_color(color, "[g][ * ][/g] Measuring [c]lfence[/c] overhead...\n"); 78 | for (int i = 0; i < repeat; i++) { 79 | size_t start = rdtscl(); 80 | size_t end = rdtscl(); 81 | size_t diff = end - start; 82 | if (diff < 0) { 83 | diff = 0; 84 | } 85 | if (diff < MAX_TIME) { 86 | hit[diff]++; 87 | } 88 | } 89 | printf_color(color, "[g][ + ][/g] Done.\n"); 90 | if(verbose) { 91 | print_histogram(hit, NULL, 1); 92 | } 93 | int lfence = get_single_threshold(hit, 95); 94 | memset(hit, 0, sizeof(hit)); 95 | 96 | sched_yield(); 97 | sched_yield(); 98 | sched_yield(); 99 | 100 | printf_color(color, "[g][ * ][/g] Measuring [c]mfence[/c] overhead...\n"); 101 | for (int i = 0; i < repeat; i++) { 102 | size_t start = rdtsc(); 103 | size_t end = rdtsc(); 104 | size_t diff = end - start; 105 | if (diff < 0) { 106 | diff = 0; 107 | } 108 | if (diff < MAX_TIME) { 109 | hit[diff]++; 110 | } 111 | } 112 | printf_color(color, "[g][ + ][/g] Done.\n"); 113 | if(verbose) { 114 | print_histogram(hit, NULL, 1); 115 | } 116 | int mfence = get_single_threshold(hit, 95); 117 | memset(hit, 0, sizeof(hit)); 118 | 119 | sched_yield(); 120 | sched_yield(); 121 | sched_yield(); 122 | 123 | printf_color(color, "[g][ * ][/g] Measuring [c]cpuid[/c] overhead...\n"); 124 | for (int i = 0; i < repeat; i++) { 125 | size_t start = rdtscl(); 126 | asm volatile("xor %%rax, %%rax\ncpuid":: : "rax", "rbx", "rcx", "rdx"); 127 | size_t end = rdtscl(); 128 | size_t diff = end - start; 129 | if (diff < 0) { 130 | diff = 0; 131 | } 132 | if (diff < MAX_TIME) { 133 | hit[diff]++; 134 | } 135 | } 136 | printf_color(color, "[g][ + ][/g] Done.\n"); 137 | if(verbose) { 138 | print_histogram(hit, NULL, 1); 139 | } 140 | int cpuid = get_single_threshold(hit, 95) - lfence; 141 | memset(hit, 0, sizeof(hit)); 142 | 143 | sched_yield(); 144 | sched_yield(); 145 | sched_yield(); 146 | 147 | printf_color(color, "[g][ * ][/g] Measuring [c]L1[/c] hit time...\n"); 148 | // cache hit 149 | for (int i = 0; i < repeat; i++) { 150 | size_t start = rdtsc(); 151 | maccess(dummy); 152 | size_t end = rdtsc(); 153 | size_t diff = end - start; 154 | if (diff < 0) { 155 | diff = 0; 156 | } 157 | if (diff < MAX_TIME) { 158 | hit[diff]++; 159 | } 160 | } 161 | printf_color(color, "[g][ + ][/g] Done.\n"); 162 | if(verbose) { 163 | print_histogram(hit, NULL, 1); 164 | } 165 | int l1 = get_single_threshold(hit, 95) - mfence; 166 | memset(hit, 0, sizeof(hit)); 167 | 168 | sched_yield(); 169 | sched_yield(); 170 | sched_yield(); 171 | 172 | printf_color(color, "[g][ * ][/g] Measuring [c]L1[/c] miss time...\n"); 173 | for (int i = 0; i < repeat; i++) { 174 | maccess(dummy); 175 | asm volatile("xor %%rax, %%rax\ncpuid":: : "rax", "rbx", "rcx", "rdx"); 176 | memset(l1_thrash, i & 0xff, sizeof(l1_thrash)); 177 | asm volatile("xor %%rax, %%rax\ncpuid":: : "rax", "rbx", "rcx", "rdx"); 178 | size_t start = rdtsc(); 179 | maccess(dummy); 180 | size_t end = rdtsc(); 181 | size_t diff = end - start; 182 | if (diff < 0) { 183 | diff = 0; 184 | } 185 | if (diff < MAX_TIME) { 186 | hit[diff]++; 187 | } 188 | } 189 | printf_color(color, "[g][ + ][/g] Done.\n"); 190 | if(verbose) { 191 | print_histogram(hit, NULL, 1); 192 | } 193 | int l2 = get_single_threshold(hit, 95) - mfence; 194 | memset(hit, 0, sizeof(hit)); 195 | 196 | sched_yield(); 197 | sched_yield(); 198 | sched_yield(); 199 | 200 | printf_color(color, "[g][ * ][/g] Measuring [c]L3[/c] miss time...\n"); 201 | for (int i = 0; i < repeat; i++) { 202 | flush(dummy); 203 | asm volatile("xor %%rax, %%rax\ncpuid":: : "rax", "rbx", "rcx", "rdx"); 204 | uint64_t start = rdtsc(); 205 | maccess(dummy); 206 | uint64_t end = rdtsc(); 207 | asm volatile("xor %%rax, %%rax\ncpuid":: : "rax", "rbx", "rcx", "rdx"); 208 | size_t diff = end - start; 209 | if (diff < 0) { 210 | diff = 0; 211 | } 212 | if (diff < MAX_TIME) { 213 | miss[diff]++; 214 | } 215 | } 216 | printf_color(color, "[g][ + ][/g] Done.\n"); 217 | int dram = get_single_threshold(miss, 10) - mfence; 218 | 219 | printf_color(color, "\n\n | [m]cycles[/m] | [m]+ lfence[/m] | [m]+ mfence[/m] | [m]+ cpuid[/m]\n"); 220 | printf_color(color, "---------+-----------+-----------+-----------+------------\n"); 221 | printf_color(color, "[c] L1 Hit [/c]|%10d |%10d |%10d |%10d \n", l1, l1 + lfence, l1 + mfence, l1 + cpuid); 222 | printf_color(color, "[c] L1 Miss [/c]|%10d |%10d |%10d |%10d \n", l2, l2 + lfence, l2 + mfence, l2 + cpuid); 223 | printf_color(color, "[c] L3 Miss [/c]|%10d |%10d |%10d |%10d \n", dram, dram + lfence, dram + mfence, dram + cpuid); 224 | printf_color(color, "---------+-----------+-----------+-----------+------------\n"); 225 | 226 | return 0; 227 | } 228 | 229 | // --------------------------------------------------------------------------- 230 | void show_splash(int color) { 231 | printf_color(color, "[r] ( [/r]\n"); 232 | printf_color(color, "[r] ( ) )\\ ) ( [/r]\n"); 233 | printf_color(color, "[r] )\\ ) ( /( ( (()/( ( ( )\\ ) [/r]\n"); 234 | printf_color(color, "[r] (((_) ( /( ( )\\()) ))\\ /(_))` ) ))\\ ))\\ (()/( [/r]\n"); 235 | printf_color(color, 236 | "[r] )\\[y]___[/y] )(_)) )\\ ((_)\\ /((_) ([y]_[/y])) /(/( /((_)/((_) (([y]_[/y]))[/r]\n"); 237 | printf_color(color, 238 | "[r](([y]/ __|[/y](([y]_[/y])[y]_ [/y]((_)[y]| |[/y](_)([y]_[/y]))[y] / __|[/y]((_)[y]_[/y]\\ ([y]_[/y])) ([y]_[/y]))[y] _| | [/y][/r]\n"); 239 | printf_color(color, "[y] | (__ / _` |/ _| | ' \\ / -_) \\__ \\| '_ \\[r])[/r]/ -_)/ -_)/ _` | [/y]\n"); 240 | printf_color(color, "[y] \\___|\\__,_|\\__| |_||_|\\___| |___/| .__/ \\___|\\___|\\__,_| [/y]\n"); 241 | printf_color(color, "[y] |_| [/y]\n"); 242 | } 243 | 244 | // --------------------------------------------------------------------------- 245 | void show_usage(char *binary, int color) { 246 | printf_color(color, "[y]USAGE[/y]\n %s [g][options][/g] \n\n", binary); 247 | getopt_arg_t null_option = {0}; 248 | size_t count = 0; 249 | printf_color(color, "\n[y]OPTIONS[/y]\n"); 250 | do { 251 | if (!memcmp((void *) &options[count], (void *) &null_option, sizeof(getopt_arg_t))) { 252 | break; 253 | } else if (options[count].description) { 254 | printf_color(color, " [g]-%c[/g]%s[y]%s[/y]%s [g]%s%s%s[/g][y]%s[/y]\n ", 255 | options[count].val, 256 | options[count].has_arg != no_argument ? " " : "", 257 | options[count].has_arg != no_argument ? options[count].arg_name : "", 258 | options[count].name ? "," : "", options[count].name ? "--" : "", options[count].name, 259 | options[count].has_arg != no_argument ? "=" : "", 260 | options[count].has_arg != no_argument ? options[count].arg_name : ""); 261 | printf_color(color, options[count].description); 262 | printf_color(color, "\n\n"); 263 | } 264 | count++; 265 | } while (1); 266 | printf("\n"); 267 | printf_color(color, 268 | "[y]EXAMPLE[/y]\n Start [c]%s[/c].\n\n\n", binary); 269 | printf_color(color, 270 | "[y]AUTHORS[/y]\n Written by Michael Schwarz.\n\n"); 271 | 272 | } 273 | 274 | 275 | // --------------------------------------------------------------------------- 276 | void print_histogram(int *h, int *m, int perc) { 277 | int min_val = 0, max_val = MAX_TIME - 1; 278 | size_t sum_h = 0, sum_m = 0; 279 | for (int i = 0; i < MAX_TIME; i++) { 280 | if (h) { 281 | sum_h += h[i]; 282 | } 283 | if (m) { 284 | sum_m += m[i]; 285 | } 286 | } 287 | for (int i = 0; i < MAX_TIME; i++) { 288 | if ((h && h[i]) || (m && m[i])) { 289 | min_val = i; 290 | break; 291 | } 292 | } 293 | for (int i = MAX_TIME - 1; i >= 0; i--) { 294 | if ((h && h[i]) || (m && m[i])) { 295 | max_val = i + 1; 296 | break; 297 | } 298 | } 299 | 300 | size_t p_sum_h = 0, p_sum_m = 0; 301 | for (int i = min_val; i < max_val; i++) { 302 | printf("%10d: ", i); 303 | if (h) { 304 | p_sum_h += h[i]; 305 | if (perc) { 306 | printf("%10d (%f%%) ", h[i], 100.0 * p_sum_h / sum_h); 307 | } else { 308 | printf("%10d ", h[i]); 309 | } 310 | } 311 | if (m) { 312 | p_sum_m += m[i]; 313 | if (perc) { 314 | printf("%10d (%f%%) ", m[i], 100.0 * p_sum_m / sum_m); 315 | } else { 316 | printf("%10d ", m[i]); 317 | } 318 | } 319 | printf("\n"); 320 | } 321 | } 322 | 323 | // --------------------------------------------------------------------------- 324 | int get_single_threshold(int *h, double perc) { 325 | size_t sum_h = 0, p_sum_h = 0; 326 | for (int i = 0; i < MAX_TIME; i++) { 327 | sum_h += h[i]; 328 | } 329 | for (int i = 0; i < MAX_TIME; i++) { 330 | p_sum_h += h[i]; 331 | if (100.0 * p_sum_h / sum_h >= perc) { 332 | return i; 333 | } 334 | } 335 | return -1; 336 | } -------------------------------------------------------------------------------- /cs/cachespeed.h: -------------------------------------------------------------------------------- 1 | #ifndef CS_CACHESPEED_H 2 | #define CS_CACHESPEED_H 3 | 4 | #define MAX_TIME 10000 5 | #define REPEAT 1000000 6 | 7 | int get_single_threshold(int *h, double perc); 8 | void print_histogram(int *h, int *m, int perc); 9 | void show_splash(int color); 10 | void show_usage(char *binary, int color); 11 | 12 | 13 | #endif //CS_CACHESPEED_H 14 | -------------------------------------------------------------------------------- /cs/util/cache.c: -------------------------------------------------------------------------------- 1 | #include "cache.h" 2 | 3 | // --------------------------------------------------------------------------- 4 | uint64_t rdtsc() { 5 | uint64_t a, d; 6 | asm volatile ("mfence"); 7 | asm volatile ("rdtsc" : "=a" (a), "=d" (d)); 8 | asm volatile ("mfence"); 9 | return (d << 32) | a; 10 | } 11 | 12 | // --------------------------------------------------------------------------- 13 | uint64_t rdtscl() { 14 | uint64_t a, d; 15 | asm volatile ("lfence"); 16 | asm volatile ("rdtsc" : "=a" (a), "=d" (d)); 17 | asm volatile ("lfence"); 18 | return (d << 32) | a; 19 | } 20 | 21 | // --------------------------------------------------------------------------- 22 | void maccess(volatile void *p) { 23 | asm volatile ("movq (%0), %%rax\n" 24 | : 25 | : "c" (p) 26 | : "rax"); 27 | } 28 | 29 | // --------------------------------------------------------------------------- 30 | void flush(volatile void *p) { 31 | asm volatile ("clflush 0(%0)\n" 32 | : 33 | : "c" (p) 34 | : "rax"); 35 | } -------------------------------------------------------------------------------- /cs/util/cache.h: -------------------------------------------------------------------------------- 1 | #ifndef CS_CACHEUTILS_C_H 2 | #define CS_CACHEUTILS_C_H 3 | 4 | #include 5 | 6 | uint64_t rdtsc(); 7 | uint64_t rdtscl(); 8 | void maccess(volatile void *p); 9 | void flush(volatile void *p); 10 | 11 | #endif //CS_CACHEUTILS_C_H 12 | -------------------------------------------------------------------------------- /cs/util/colorprint.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "colorprint.h" 6 | 7 | #define ANSI_COLOR_RED "\x1b[31m" 8 | #define ANSI_COLOR_GREEN "\x1b[32m" 9 | #define ANSI_COLOR_YELLOW "\x1b[33m" 10 | #define ANSI_COLOR_BLUE "\x1b[34m" 11 | #define ANSI_COLOR_MAGENTA "\x1b[35m" 12 | #define ANSI_COLOR_CYAN "\x1b[36m" 13 | #define ANSI_COLOR_RESET "\x1b[0m" 14 | #define ANSI_COLOR_WHITE "\x1b[0m" 15 | 16 | 17 | typedef struct { 18 | ansi_color_t stack[16]; 19 | int ptr; 20 | } colorstack_t; 21 | 22 | static void colorstack_push(colorstack_t *stack, ansi_color_t color) { 23 | if (stack->ptr >= 16) { 24 | return; 25 | } 26 | stack->stack[stack->ptr++] = color; 27 | } 28 | 29 | static ansi_color_t colorstack_pop(colorstack_t *stack) { 30 | if (stack->ptr <= 0) { 31 | return RESET; 32 | } 33 | return stack->stack[--stack->ptr]; 34 | } 35 | 36 | static int append_color(char *str, int pos, ansi_color_t color) { 37 | const char *colors[] = { 38 | [RED] = ANSI_COLOR_RED, 39 | [GREEN] = ANSI_COLOR_GREEN, 40 | [BLUE] = ANSI_COLOR_BLUE, 41 | [CYAN] = ANSI_COLOR_CYAN, 42 | [MAGENTA] = ANSI_COLOR_MAGENTA, 43 | [YELLOW] = ANSI_COLOR_YELLOW, 44 | [WHITE] = ANSI_COLOR_WHITE, 45 | [RESET] = ANSI_COLOR_RESET 46 | }; 47 | const char *color_str = colors[color]; 48 | int len = strlen(color_str); 49 | int i; 50 | for (i = 0; i < len; i++) { 51 | str[pos + i] = color_str[i]; 52 | } 53 | return pos + len; 54 | } 55 | 56 | void printf_color(int enable, const char *fmt, ...) { 57 | colorstack_t stack = {{0}}; 58 | ansi_color_t colors[] = { 59 | ['r'] = RED, 60 | ['g'] = GREEN, 61 | ['b'] = BLUE, 62 | ['c'] = CYAN, 63 | ['m'] = MAGENTA, 64 | ['y'] = YELLOW, 65 | ['w'] = WHITE, 66 | ['/'] = RESET 67 | }; 68 | 69 | int i, len = strlen(fmt), ptr = 0; 70 | char *fmt_replace = (char *) malloc(len * 3 + 1); 71 | ansi_color_t color = RESET; 72 | for (i = 0; i < len; i++) { 73 | if (fmt[i] == '[' && 74 | ((i + 2 < len && fmt[i + 2] == ']') || (i + 3 < len && fmt[i + 1] == '/' && fmt[i + 3] == ']'))) { 75 | if (i != len - 1) { 76 | if (fmt[i + 1] == '/') { 77 | color = colorstack_pop(&stack); 78 | i++; 79 | } else { 80 | colorstack_push(&stack, color); 81 | color = colors[(int) fmt[i + 1]]; 82 | if(color == RESET) { 83 | color = colorstack_pop(&stack); 84 | fmt_replace[ptr++] = '['; 85 | i--; 86 | } 87 | } 88 | if (enable) { 89 | ptr = append_color(fmt_replace, ptr, color); 90 | } 91 | i += 2; 92 | continue; 93 | } 94 | } else { 95 | fmt_replace[ptr++] = fmt[i]; 96 | } 97 | } 98 | fmt_replace[ptr] = 0; 99 | 100 | fmt = fmt_replace; 101 | va_list ap; 102 | va_start(ap, fmt); 103 | vfprintf(stdout, fmt, ap); 104 | va_end(ap); 105 | free((char*)fmt); 106 | } 107 | -------------------------------------------------------------------------------- /cs/util/colorprint.h: -------------------------------------------------------------------------------- 1 | #ifndef CJAG_COLORPRINT 2 | #define CJAG_COLORPRINT 3 | 4 | typedef enum { 5 | RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, RESET 6 | } ansi_color_t; 7 | 8 | #define ERROR_TAG "[r][ERROR][/r] " 9 | 10 | void printf_color(int color, const char *fmt, ...); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /cs/util/getopt_helper.c: -------------------------------------------------------------------------------- 1 | #include "getopt_helper.h" 2 | #include 3 | #include 4 | #include 5 | 6 | struct option* getopt_get_long_options(getopt_arg_t* opt) { 7 | size_t count = 0; 8 | getopt_arg_t null_option = {0}; 9 | do { 10 | if(!memcmp((void*)&opt[count], (void*)&null_option, sizeof(getopt_arg_t))) { 11 | break; 12 | } else { 13 | count++; 14 | } 15 | } while(1); 16 | 17 | struct option* gopt = malloc(sizeof(struct option) * count); 18 | if(!gopt) { 19 | return NULL; 20 | } 21 | for(int i = 0; i < count; i++) { 22 | gopt[i].name = opt[i].name; 23 | gopt[i].has_arg = opt[i].has_arg; 24 | gopt[i].flag = opt[i].flag; 25 | gopt[i].val = opt[i].val; 26 | } 27 | return gopt; 28 | } -------------------------------------------------------------------------------- /cs/util/getopt_helper.h: -------------------------------------------------------------------------------- 1 | #ifndef BLACKHAT_GETOPT_HELPER_H 2 | #define BLACKHAT_GETOPT_HELPER_H 3 | 4 | #include 5 | 6 | typedef struct { 7 | const char* name; 8 | int has_arg; 9 | int* flag; 10 | int val; 11 | const char* description; 12 | const char* arg_name; 13 | } getopt_arg_t; 14 | 15 | struct option* getopt_get_long_options(getopt_arg_t* opt); 16 | 17 | #endif //BLACKHAT_GETOPT_HELPER_H 18 | -------------------------------------------------------------------------------- /detection/cache.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "cache.h" 4 | 5 | 6 | cache_config_l3_t get_l3_info() { 7 | uint32_t eax, ebx, ecx, edx; 8 | int level = 0; 9 | cache_config_l3_t config; 10 | 11 | do { 12 | asm volatile("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (4), "c" (level)); 13 | int type = eax & 0x1f; 14 | if(!type) break; 15 | level++; 16 | config.line_size = (ebx & 0xfff) + 1; 17 | config.ways = ((ebx >> 22) & 0x3ff) + 1; 18 | config.sets = ecx + 1; 19 | config.partitions = ((ebx >> 12) & 0x3ff) + 1; 20 | config.size = config.line_size * config.ways * config.sets * config.partitions; 21 | } while(1); 22 | return config; 23 | } 24 | 25 | 26 | void show_cache_info() { 27 | cache_config_l3_t l3 = get_l3_info(); 28 | printf("%d KB, %d-way L3\n", l3.size / 1024, l3.ways); 29 | } -------------------------------------------------------------------------------- /detection/cache.h: -------------------------------------------------------------------------------- 1 | #ifndef BLACKHAT_CACHE_H 2 | #define BLACKHAT_CACHE_H 3 | 4 | #include 5 | 6 | typedef struct { 7 | int size; 8 | int ways; 9 | int line_size; 10 | int sets; 11 | int partitions; 12 | int miss_threshold; 13 | } cache_config_l3_t; 14 | 15 | void show_cache_info(); 16 | cache_config_l3_t get_l3_info(); 17 | 18 | #endif //BLACKHAT_CACHE_H 19 | -------------------------------------------------------------------------------- /detection/cpu.c: -------------------------------------------------------------------------------- 1 | #include "cpu.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int get_physical_cores() { 8 | FILE *f = fopen("/proc/cpuinfo", "r"); 9 | if (!f) { 10 | return 0; 11 | } 12 | char *line = NULL; 13 | 14 | int cores[256] = {0}; 15 | size_t len = 0; 16 | while (getline(&line, &len, f) != -1) { 17 | if (strncmp(line, "core id", 7) == 0) { 18 | int id = 0; 19 | sscanf(strrchr(line, ':') + 1, "%d", &id); 20 | if (id >= 0 && id < 256) { 21 | cores[id]++; 22 | } 23 | } 24 | } 25 | free(line); 26 | fclose(f); 27 | 28 | int phys_cores = 0; 29 | for (int i = 0; i < 256; i++) { 30 | if (cores[i]) { 31 | phys_cores++; 32 | } 33 | } 34 | return phys_cores; 35 | } 36 | 37 | int get_cpu_architecture() { 38 | unsigned int model; 39 | int name[4] = {0, 0, 0, 0}; 40 | __cpuid(0, model, name[0], name[2], name[1]); 41 | 42 | if (strcmp((char *) name, "GenuineIntel") != 0) return -1; 43 | return model; 44 | } 45 | 46 | int get_slices() { 47 | int slices = get_physical_cores(); 48 | if (get_cpu_architecture() >= 0x16) { 49 | slices <<= 1; 50 | } 51 | return slices; 52 | } -------------------------------------------------------------------------------- /detection/cpu.h: -------------------------------------------------------------------------------- 1 | #ifndef BLACKHAT_CPU_H 2 | #define BLACKHAT_CPU_H 3 | 4 | int get_physical_cores(); 5 | int get_cpu_architecture(); 6 | int get_slices(); 7 | 8 | #endif //BLACKHAT_CPU_H 9 | -------------------------------------------------------------------------------- /detection/paging.c: -------------------------------------------------------------------------------- 1 | #include "paging.h" 2 | #include 3 | #include 4 | #include 5 | 6 | // ---------------------------------------------- 7 | int has_huge_pages() { 8 | FILE *f = fopen("/proc/meminfo", "r"); 9 | if (!f) { 10 | return 0; 11 | } 12 | char *line = NULL; 13 | 14 | size_t len = 0; 15 | int hp = 0; 16 | while (getline(&line, &len, f) != -1) { 17 | if (strncmp(line, "HugePages_Total", 15) == 0) { 18 | int size = 0; 19 | sscanf(&line[17], "%d", &size); 20 | if (size > 0) { 21 | hp = 1; 22 | break; 23 | } 24 | } 25 | } 26 | free(line); 27 | fclose(f); 28 | return hp; 29 | } 30 | -------------------------------------------------------------------------------- /detection/paging.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by mschwarz on 2/19/17. 3 | // 4 | 5 | #ifndef BLACKHAT_PAGING_H 6 | #define BLACKHAT_PAGING_H 7 | 8 | int has_huge_pages(); 9 | 10 | #endif //BLACKHAT_PAGING_H 11 | -------------------------------------------------------------------------------- /jag/common.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "../cache/evict.h" 7 | #include "../cache/set.h" 8 | #include "../cache/slice.h" 9 | #include "../util/timing.h" 10 | #include "../util/error.h" 11 | 12 | #define MIN(x, y) ((x) < (y) ? (x) : (y)) 13 | 14 | int jag_init(cjag_config_t* config) { 15 | config->n_addr_per_set = 16 / config->cache_slices; 16 | config->n_pages = (int) (ceil((float) config->cache_ways / config->n_addr_per_set) + 1); 17 | config->addr = NULL; 18 | 19 | config->cache_sets = jag_get_cache_sets(config); 20 | if(!config->cache_sets) { 21 | return 0; 22 | } 23 | 24 | return 1; 25 | } 26 | 27 | int jag_free(cjag_config_t* config) { 28 | free(config->cache_sets); 29 | free(config->addr); 30 | return !munmap(config->addresses, config->n_pages * 2 * 1024 * 1024); 31 | } 32 | 33 | 34 | volatile void ** 35 | jag_get_cache_sets(cjag_config_t *config) { 36 | const int n_addr_per_set = 16 / config->cache_slices; 37 | const int n_pages = (int) (ceil((float) config->cache_ways / n_addr_per_set) + 1); 38 | const int set_offset = 0; 39 | const int sub_set_offset = 64; //this should not change the process at all, but prevent interference from traffic on 4k aligned sets 40 | const int probe_count = MIN(2, n_addr_per_set); // 2 seems to be enough, but won't just work for 16 cores 41 | const int n_samples = 16 * 1024; 42 | uint8_t *cache_set[n_pages][32][config->cache_slices][n_addr_per_set]; 43 | uint8_t cache_set_counter[32][config->cache_slices]; 44 | int slice_offset[n_pages]; 45 | 46 | uint8_t *addr = mmap(NULL, n_pages * 2 * 1024 * 1024, PROT_READ | PROT_WRITE, 47 | MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB, 0, 0); 48 | if (addr == MAP_FAILED) { 49 | return NULL; 50 | } 51 | 52 | config->addresses = (void*)addr; 53 | 54 | memset(cache_set, 0, sizeof(cache_set)); 55 | memset(slice_offset, 0, sizeof(slice_offset)); 56 | 57 | for (int i = 0; i < n_pages; ++i) { 58 | memset(cache_set_counter, 0, sizeof(cache_set_counter)); 59 | for (int j = 0; j < 512; ++j) { 60 | uint8_t *cur_addr = addr + i * 2 * 1024 * 1024 + 4096 * j; 61 | int slice = get_cache_slice((uint64_t) cur_addr & ((1 << 21) - 1), config->cache_slices); 62 | int set = get_cache_set_index((uint64_t)(cur_addr)) >> 6; 63 | cache_set[i][set][slice][cache_set_counter[set][slice]++] = cur_addr + sub_set_offset; 64 | } 65 | } 66 | 67 | volatile uint8_t *test_eviction_set[config->cache_slices * n_pages * n_addr_per_set]; 68 | volatile uint8_t *eviction_set[config->cache_slices * n_pages * n_addr_per_set]; 69 | volatile uint8_t *probe_set[probe_count]; 70 | 71 | int tes_size = 0; 72 | int es_size = 0; 73 | 74 | for (int p = 1; p < n_pages; ++p) { 75 | for (int s = 0; s < config->cache_slices; ++s) { 76 | for (int i = 0; i < n_addr_per_set; ++i) { 77 | test_eviction_set[tes_size] = cache_set[p][set_offset][s][i]; 78 | tes_size++; 79 | } 80 | } 81 | } 82 | 83 | //turns out, 2 probes are enough for pretty much any stress level 84 | for (int i = 0; i < probe_count; ++i) 85 | probe_set[i] = cache_set[0][set_offset][0][i]; 86 | 87 | for (int p = n_pages - 1; p > 0; --p) { 88 | tes_size = p * config->cache_slices * n_addr_per_set; 89 | slice_offset[p] = config->cache_slices - 1; 90 | for (int i = 0; i < config->cache_slices; ++i) { 91 | int fast = 0, slow = 0; 92 | tes_size -= n_addr_per_set; 93 | for (int c = 0; c < n_samples; ++c) { 94 | uint32_t time = test_evict_set(probe_set, eviction_set, test_eviction_set, probe_count, es_size, 95 | tes_size); 96 | if (time > config->cache_miss_threshold) 97 | slow++; 98 | else 99 | fast++; 100 | } 101 | 102 | //is faster, but might have a few errors 103 | if (slow < fast) 104 | break; 105 | 106 | slice_offset[p]--; 107 | 108 | if (slice_offset[p] < 0) { 109 | return NULL; 110 | } 111 | } 112 | //a bit slower, but almost no errors 113 | for (int s = 0; s < config->cache_slices; ++s) { 114 | for (int i = 0; i < n_addr_per_set; ++i) { 115 | eviction_set[es_size] = cache_set[p][set_offset][s][i]; 116 | es_size++; 117 | } 118 | } 119 | } 120 | 121 | uint8_t *final_cache_sets[32 * config->cache_slices][config->cache_ways]; //[set][index] 122 | 123 | slice_offset[0] = 0; 124 | 125 | 126 | for (int set = 0; set < 32; ++set) { 127 | for (int slice = 0; slice < config->cache_slices; ++slice) { 128 | for (int page = 0; page < n_pages - 1; ++page) { 129 | for (int i = 0; i < n_addr_per_set; ++i) { 130 | if ((page * n_addr_per_set + i) == config->cache_ways) 131 | break; 132 | final_cache_sets[set * config->cache_slices + (slice ^ slice_offset[page])] 133 | [page * n_addr_per_set + i] = cache_set[page][set][slice][i] - sub_set_offset; 134 | } 135 | } 136 | } 137 | } 138 | 139 | volatile void **cache_set_out = malloc(sizeof(final_cache_sets)); 140 | memcpy(cache_set_out, final_cache_sets, sizeof(final_cache_sets)); 141 | 142 | return cache_set_out; 143 | } 144 | 145 | 146 | uint32_t 147 | jag_check_set(volatile uint8_t **s_addrs, uint32_t target_misses, uint32_t read_timeout, cjag_config_t *config) { 148 | uint8_t hit[500], miss[500]; 149 | uint32_t hits = 0, misses = 0, reads = 0; 150 | size_t time, delta; 151 | int window_index = 0, max_misses = 0; 152 | int i; 153 | 154 | memset(hit, 0, sizeof(hit)); 155 | memset(miss, 0, sizeof(miss)); 156 | 157 | for(i = 0; i <= config->cache_kill_count; i++) { 158 | ABORT_ON((ssize_t)s_addrs[i] <= 0, ERROR_INVALID_PARAMETERS, config->color_output); 159 | } 160 | evict_set(s_addrs, config->cache_kill_count); 161 | 162 | while (reads < read_timeout) //if the sender isn't active this could run forever otherwise 163 | { 164 | time = rdtsc(); 165 | access_set(s_addrs, config->cache_probe_count); 166 | delta = rdtsc() - time; 167 | 168 | hits -= hit[window_index]; 169 | misses -= miss[window_index]; 170 | 171 | if (delta < config->cache_miss_threshold) { 172 | hits++; 173 | hit[window_index] = 1; 174 | miss[window_index] = 0; 175 | } else { 176 | misses++; 177 | hit[window_index] = 0; 178 | miss[window_index] = 1; 179 | } 180 | 181 | if (misses > max_misses) 182 | max_misses = misses; 183 | 184 | if (misses >= target_misses) 185 | break; 186 | 187 | reads++; 188 | window_index = (window_index + 1) % 500; 189 | } 190 | 191 | return max_misses; 192 | } 193 | -------------------------------------------------------------------------------- /jag/common.h: -------------------------------------------------------------------------------- 1 | #ifndef BLACKHAT_COMMON_H 2 | #define BLACKHAT_COMMON_H 3 | 4 | #include 5 | #include "../cjag.h" 6 | 7 | int jag_init(cjag_config_t* config); 8 | 9 | int jag_free(cjag_config_t* config); 10 | 11 | #define GET_EVICTION_SET(addr, set, cfg) (void**)(((char**)(addr)) + (cfg)->cache_ways * (set)) 12 | 13 | volatile void **jag_get_cache_sets(cjag_config_t* config); 14 | 15 | uint32_t jag_check_set(volatile uint8_t **s_addrs, uint32_t target_misses, uint32_t read_timeout, cjag_config_t* config); 16 | 17 | 18 | typedef void (*jag_callback_t)(cjag_config_t*, int); 19 | 20 | 21 | #endif //BLACKHAT_COMMON_H 22 | -------------------------------------------------------------------------------- /jag/receive.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "receive.h" 4 | #include "common.h" 5 | #include "../cache/evict.h" 6 | #include "../cjag.h" 7 | 8 | void jag_receive(void **ret_addrs, size_t* recv_sets, cjag_config_t *config, jag_callback_t cb) { 9 | uint8_t received_set_count = 0; 10 | uint16_t *received_sets = calloc(32 * config->cache_slices, sizeof(uint16_t)); 11 | const int detection_threshold = 300; 12 | volatile uint8_t **all_addrs = (volatile uint8_t**)config->cache_sets; 13 | 14 | while (received_set_count != config->channels) { 15 | for (int i = 0; i < 32 * config->cache_slices; i++) { 16 | uint32_t misses = jag_check_set(all_addrs + i * config->cache_ways, detection_threshold, config->jag_send_count * 2, config); 17 | 18 | if (misses >= detection_threshold) { 19 | for (int j = 0; j < config->jag_recv_count; ++j) { 20 | evict_set(all_addrs + i * config->cache_ways, config->cache_ways); 21 | } 22 | 23 | if (!received_sets[i]) { 24 | for (int j = 0; j < config->cache_ways; ++j) { 25 | ret_addrs[(received_set_count) * config->cache_ways + j] = (void*)all_addrs[i * config->cache_ways + j]; 26 | } 27 | 28 | received_set_count++; 29 | if (cb) { 30 | if(recv_sets) { 31 | recv_sets[received_set_count - 1] = i; 32 | } 33 | cb(config, received_set_count); 34 | } 35 | } 36 | received_sets[i]++; 37 | 38 | //jam the last set some more because there is no feedback 39 | if (received_set_count == config->channels) { 40 | for (int j = 0; j < (int)(config->jag_recv_count * 1.5); ++j) { 41 | evict_set(all_addrs + i * config->cache_ways, config->cache_kill_count); 42 | } 43 | break; 44 | } 45 | 46 | } 47 | } 48 | } 49 | free(received_sets); 50 | } 51 | -------------------------------------------------------------------------------- /jag/receive.h: -------------------------------------------------------------------------------- 1 | #ifndef BLACKHAT_RECEIVE_H 2 | #define BLACKHAT_RECEIVE_H 3 | #include "../cjag.h" 4 | #include "common.h" 5 | #include 6 | 7 | void jag_receive(void **ret_addrs, size_t* recv_sets, cjag_config_t* config, jag_callback_t cb); 8 | 9 | #endif //BLACKHAT_RECEIVE_H 10 | -------------------------------------------------------------------------------- /jag/send.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "send.h" 4 | #include "common.h" 5 | #include "../cache/evict.h" 6 | #include "../cjag.h" 7 | 8 | void jag_send(cjag_config_t* config, jag_callback_t cb) { 9 | int got = 0; 10 | const int detection_threshold = 300; 11 | 12 | volatile uint8_t** addrs; 13 | if(!config->addr) { 14 | addrs = malloc(config->cache_ways * config->channels * sizeof(void*)); 15 | for (int i = 0; i < config->channels; i++) { 16 | for (int j = 0; j < config->cache_ways; j++) { 17 | addrs[i * config->cache_ways + j] = ((uint8_t**)(config->cache_sets))[(i + config->set_offset) * config->cache_ways + j]; 18 | } 19 | } 20 | config->addr = (void**)addrs; 21 | } else { 22 | addrs = (volatile uint8_t**)config->addr; 23 | } 24 | 25 | for (int i = 0; i < config->channels; i++) // 26 | { 27 | while (1) { 28 | for (int j = 0; j < config->jag_send_count; ++j) { 29 | evict_set(addrs + (i * config->cache_ways), config->cache_kill_count); 30 | } 31 | uint32_t misses = jag_check_set(addrs + (i * config->cache_ways), detection_threshold, config->jag_send_count * 2, config); 32 | if (misses >= detection_threshold) { 33 | got++; 34 | if(cb) { 35 | cb(config, got); 36 | } 37 | break; 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /jag/send.h: -------------------------------------------------------------------------------- 1 | #ifndef BLACKHAT_SEND_H 2 | #define BLACKHAT_SEND_H 3 | 4 | #include 5 | #include "../cjag.h" 6 | #include "common.h" 7 | 8 | void jag_send(cjag_config_t* config, jag_callback_t cb); 9 | 10 | #endif //BLACKHAT_SEND_H 11 | -------------------------------------------------------------------------------- /util/colorprint.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "colorprint.h" 6 | 7 | #define ANSI_COLOR_RED "\x1b[31m" 8 | #define ANSI_COLOR_GREEN "\x1b[32m" 9 | #define ANSI_COLOR_YELLOW "\x1b[33m" 10 | #define ANSI_COLOR_BLUE "\x1b[34m" 11 | #define ANSI_COLOR_MAGENTA "\x1b[35m" 12 | #define ANSI_COLOR_CYAN "\x1b[36m" 13 | #define ANSI_COLOR_RESET "\x1b[0m" 14 | #define ANSI_COLOR_WHITE "\x1b[0m" 15 | 16 | 17 | typedef struct { 18 | ansi_color_t stack[16]; 19 | int ptr; 20 | } colorstack_t; 21 | 22 | static void colorstack_push(colorstack_t *stack, ansi_color_t color) { 23 | if (stack->ptr >= 16) { 24 | return; 25 | } 26 | stack->stack[stack->ptr++] = color; 27 | } 28 | 29 | static ansi_color_t colorstack_pop(colorstack_t *stack) { 30 | if (stack->ptr <= 0) { 31 | return RESET; 32 | } 33 | return stack->stack[--stack->ptr]; 34 | } 35 | 36 | static int append_color(char *str, int pos, ansi_color_t color) { 37 | const char *colors[] = { 38 | [RED] = ANSI_COLOR_RED, 39 | [GREEN] = ANSI_COLOR_GREEN, 40 | [BLUE] = ANSI_COLOR_BLUE, 41 | [CYAN] = ANSI_COLOR_CYAN, 42 | [MAGENTA] = ANSI_COLOR_MAGENTA, 43 | [YELLOW] = ANSI_COLOR_YELLOW, 44 | [WHITE] = ANSI_COLOR_WHITE, 45 | [RESET] = ANSI_COLOR_RESET 46 | }; 47 | const char *color_str = colors[color]; 48 | int len = strlen(color_str); 49 | int i; 50 | for (i = 0; i < len; i++) { 51 | str[pos + i] = color_str[i]; 52 | } 53 | return pos + len; 54 | } 55 | 56 | void printf_color(int enable, const char *fmt, ...) { 57 | colorstack_t stack = {{0}}; 58 | ansi_color_t colors[] = { 59 | ['r'] = RED, 60 | ['g'] = GREEN, 61 | ['b'] = BLUE, 62 | ['c'] = CYAN, 63 | ['m'] = MAGENTA, 64 | ['y'] = YELLOW, 65 | ['w'] = WHITE, 66 | ['/'] = RESET 67 | }; 68 | 69 | int i, len = strlen(fmt), ptr = 0; 70 | char *fmt_replace = (char *) malloc(len * 3 + 1); 71 | ansi_color_t color = RESET; 72 | for (i = 0; i < len; i++) { 73 | if (fmt[i] == '[' && 74 | ((i + 2 < len && fmt[i + 2] == ']') || (i + 3 < len && fmt[i + 1] == '/' && fmt[i + 3] == ']'))) { 75 | if (i != len - 1) { 76 | if (fmt[i + 1] == '/') { 77 | color = colorstack_pop(&stack); 78 | i++; 79 | } else { 80 | colorstack_push(&stack, color); 81 | color = colors[(int) fmt[i + 1]]; 82 | if(color == RESET) { 83 | color = colorstack_pop(&stack); 84 | fmt_replace[ptr++] = '['; 85 | i--; 86 | } 87 | } 88 | if (enable) { 89 | ptr = append_color(fmt_replace, ptr, color); 90 | } 91 | i += 2; 92 | continue; 93 | } 94 | } else { 95 | fmt_replace[ptr++] = fmt[i]; 96 | } 97 | } 98 | fmt_replace[ptr] = 0; 99 | 100 | fmt = fmt_replace; 101 | va_list ap; 102 | va_start(ap, fmt); 103 | vfprintf(stdout, fmt, ap); 104 | va_end(ap); 105 | free((char*)fmt); 106 | } 107 | -------------------------------------------------------------------------------- /util/colorprint.h: -------------------------------------------------------------------------------- 1 | #ifndef CJAG_COLORPRINT 2 | #define CJAG_COLORPRINT 3 | 4 | typedef enum { 5 | RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, RESET 6 | } ansi_color_t; 7 | 8 | #define ERROR_TAG "[r][ERROR][/r] " 9 | 10 | void printf_color(int color, const char *fmt, ...); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /util/error.c: -------------------------------------------------------------------------------- 1 | #include "error.h" 2 | #include "colorprint.h" 3 | #include 4 | 5 | int show_error(error_code_t e, int color) { 6 | switch(e) { 7 | case ERROR_TOO_MANY_CPUS: 8 | printf_color(color, ERROR_TAG "Sorry, only CPUs with [y]up to 8 cores (4 for Skylake)[/y] are supported at the moment\n"); 9 | break; 10 | 11 | case ERROR_NO_HUGEPAGES: 12 | printf_color(color, ERROR_TAG "Huge pages are not available!\nActivate them by running\n\n [y]sudo sysctl -w vm.nr_hugepages=32[/y]\n\n"); 13 | break; 14 | 15 | case ERROR_OOM: 16 | printf_color(color, ERROR_TAG "Out of memory\n"); 17 | break; 18 | 19 | case ERROR_NO_CACHE_SETS: 20 | printf_color(color, ERROR_TAG "Could not retrieve cache sets, please [g]try to restart[/g]\n"); 21 | break; 22 | 23 | case ERROR_UNMAP_FAILED: 24 | printf_color(color, ERROR_TAG "munmap failed\n"); 25 | break; 26 | 27 | case ERROR_SLICES_NOT_SUPPORTED: 28 | printf_color(color, ERROR_TAG "Number of [y]slices[/y] must be between [y]1 and 8[/y], and a [y]power of two[/y]\n"); 29 | break; 30 | 31 | case ERROR_INVALID_WAYS: 32 | printf_color(color, ERROR_TAG "Number of [y]ways[/y] is invalid\n"); 33 | break; 34 | 35 | case ERROR_MISSING_OPTION: 36 | printf_color(color, ERROR_TAG "Parameter requires an [y]option[/y]\n"); 37 | break; 38 | 39 | case ERROR_INVALID_SPEED: 40 | printf_color(color, ERROR_TAG "Invalid [y]delay[/y] factor!\n"); 41 | break; 42 | 43 | case ERROR_TIMEOUT_TOO_LOW: 44 | printf_color(color, ERROR_TAG "[y]Timeout[/y] must be at least [y]2[/y] seconds!\n"); 45 | break; 46 | 47 | case ERROR_INVALID_PARAMETERS: 48 | printf_color(color, ERROR_TAG "The combination of [y]parameters[/y] is [y]invalid[/y]\n"); 49 | break; 50 | 51 | default: 52 | printf_color(color, ERROR_TAG "An [r]unknown[/r] error occurred\n"); 53 | break; 54 | 55 | } 56 | return 1; 57 | } 58 | -------------------------------------------------------------------------------- /util/error.h: -------------------------------------------------------------------------------- 1 | #ifndef BLACKHAT_ERROR_H 2 | #define BLACKHAT_ERROR_H 3 | 4 | typedef enum { 5 | ERROR_OOM, 6 | ERROR_NO_HUGEPAGES, 7 | ERROR_TOO_MANY_CPUS, 8 | ERROR_NO_CACHE_SETS, 9 | ERROR_UNMAP_FAILED, 10 | ERROR_SLICES_NOT_SUPPORTED, 11 | ERROR_INVALID_WAYS, 12 | ERROR_MISSING_OPTION, 13 | ERROR_INVALID_SPEED, 14 | ERROR_TIMEOUT_TOO_LOW, 15 | ERROR_INVALID_PARAMETERS 16 | } error_code_t; 17 | 18 | #define ERROR_ON(condition, error_code, color) do { if(condition) return show_error(error_code, color); } while(0) 19 | #define ABORT_ON(condition, error_code, color) do { if(condition) exit(show_error(error_code, color)); } while(0) 20 | 21 | int show_error(error_code_t e, int color); 22 | 23 | 24 | #endif //BLACKHAT_ERROR_H 25 | -------------------------------------------------------------------------------- /util/getopt_helper.c: -------------------------------------------------------------------------------- 1 | #include "getopt_helper.h" 2 | #include 3 | #include 4 | #include 5 | 6 | struct option* getopt_get_long_options(getopt_arg_t* opt) { 7 | size_t count = 0; 8 | getopt_arg_t null_option = {0}; 9 | do { 10 | if(!memcmp((void*)&opt[count], (void*)&null_option, sizeof(getopt_arg_t))) { 11 | break; 12 | } else { 13 | count++; 14 | } 15 | } while(1); 16 | 17 | struct option* gopt = malloc(sizeof(struct option) * count); 18 | if(!gopt) { 19 | return NULL; 20 | } 21 | for(int i = 0; i < count; i++) { 22 | gopt[i].name = opt[i].name; 23 | gopt[i].has_arg = opt[i].has_arg; 24 | gopt[i].flag = opt[i].flag; 25 | gopt[i].val = opt[i].val; 26 | } 27 | return gopt; 28 | } -------------------------------------------------------------------------------- /util/getopt_helper.h: -------------------------------------------------------------------------------- 1 | #ifndef BLACKHAT_GETOPT_HELPER_H 2 | #define BLACKHAT_GETOPT_HELPER_H 3 | 4 | #include 5 | 6 | typedef struct { 7 | const char* name; 8 | int has_arg; 9 | int* flag; 10 | int val; 11 | const char* description; 12 | const char* arg_name; 13 | } getopt_arg_t; 14 | 15 | struct option* getopt_get_long_options(getopt_arg_t* opt); 16 | 17 | #endif //BLACKHAT_GETOPT_HELPER_H 18 | -------------------------------------------------------------------------------- /util/timing.c: -------------------------------------------------------------------------------- 1 | #include "timing.h" 2 | 3 | uint64_t rdtsc() { 4 | uint64_t a, d; 5 | asm volatile ("mfence"); 6 | asm volatile ("rdtsc" : "=a" (a), "=d" (d)); 7 | asm volatile ("mfence"); 8 | return (d << 32) | a; 9 | } 10 | -------------------------------------------------------------------------------- /util/timing.h: -------------------------------------------------------------------------------- 1 | #ifndef BLACKHAT_TIMING_H 2 | #define BLACKHAT_TIMING_H 3 | #include 4 | 5 | uint64_t rdtsc(); 6 | 7 | #endif //BLACKHAT_TIMING_H 8 | -------------------------------------------------------------------------------- /util/watchdog.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "watchdog.h" 3 | 4 | 5 | void *watchdog(void *arg) { 6 | watchdog_t *params = (watchdog_t *) arg; 7 | while (!params->done && params->timeout) { 8 | params->timeout--; 9 | sleep(1); 10 | } 11 | if (!params->done) { 12 | params->callback(params->data); 13 | } 14 | return NULL; 15 | } 16 | 17 | void watchdog_start(watchdog_t *w, int timeout, void (*callback)(void*), void* data) { 18 | w->timeout = timeout; 19 | w->interval = timeout; 20 | w->callback = callback; 21 | w->data = data; 22 | w->done = 0; 23 | pthread_create(&w->thread, NULL, watchdog, (void *) w); 24 | } 25 | 26 | void watchdog_reset(watchdog_t *w) { 27 | if (w) { 28 | w->timeout = w->interval; 29 | } 30 | } 31 | 32 | 33 | void watchdog_done(watchdog_t *w) { 34 | if (w) { 35 | w->done = 1; 36 | w->timeout = w->interval; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /util/watchdog.h: -------------------------------------------------------------------------------- 1 | #ifndef TOOL_WATCHDOG_H 2 | #define TOOL_WATCHDOG_H 3 | 4 | #include 5 | 6 | typedef struct _watchdog_t { 7 | int done; 8 | int interval; 9 | int timeout; 10 | pthread_t thread; 11 | void (*callback)(void*); 12 | void* data; 13 | } watchdog_t; 14 | 15 | void watchdog_start(watchdog_t *w, int timeout, void (*callback)(void*), void* data); 16 | 17 | void watchdog_reset(watchdog_t *w); 18 | 19 | void watchdog_done(watchdog_t *w); 20 | 21 | 22 | #endif //TOOL_WATCHDOG_H 23 | --------------------------------------------------------------------------------