Skip to content

Instantly share code, notes, and snippets.

@brant-ruan
Last active January 9, 2023 04:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save brant-ruan/779f824939606ba7a6db5e4af6f92af2 to your computer and use it in GitHub Desktop.
Save brant-ruan/779f824939606ba7a6db5e4af6f92af2 to your computer and use it in GitHub Desktop.
Pawnyable LK04
#define _GNU_SOURCE
#include <assert.h>
#include <fcntl.h>
#include <linux/userfaultfd.h>
#include <poll.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
void fatal(const char *msg) {
perror(msg);
exit(1);
}
static void *fault_handler_thread(void *arg) {
char *dummy_page;
static struct uffd_msg msg;
struct uffdio_copy copy;
struct pollfd pollfd;
long uffd;
static int fault_cnt = 0;
uffd = (long)arg;
puts("[t][*] mmaping one dummy page");
dummy_page = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (dummy_page == MAP_FAILED)
fatal("mmap(dummy)");
puts("[t][*] waiting for page fault");
pollfd.fd = uffd;
pollfd.events = POLLIN;
while (poll(&pollfd, 1, -1) > 0) {
if (pollfd.revents & POLLERR || pollfd.revents & POLLHUP)
fatal("poll");
// block until triggered
if (read(uffd, &msg, sizeof(msg)) <= 0)
fatal("read(uffd)");
assert(msg.event == UFFD_EVENT_PAGEFAULT);
puts("[t][+] caught page fault");
printf("[t][+] uffd: flag=0x%llx, addr=0x%llx\n", msg.arg.pagefault.flags, msg.arg.pagefault.address);
// craft data and copy
puts("[t][*] writing hello world into dummy page");
if (fault_cnt++ == 0)
strcpy(dummy_page, "Hello, world! (1)");
else
strcpy(dummy_page, "Hello, world! (2)");
puts("[t][*] copying data from dummy page to faulted page");
copy.src = (unsigned long)dummy_page;
copy.dst = (unsigned long)msg.arg.pagefault.address & ~0xfff;
copy.len = 0x1000;
copy.mode = 0;
copy.copy = 0;
if (ioctl(uffd, UFFDIO_COPY, &copy) == -1)
fatal("ioctl(UFFDIO_COPY)");
}
return NULL;
}
int register_uffd(void *addr, size_t len) {
struct uffdio_api uffdio_api;
struct uffdio_register uffdio_register;
long uffd;
pthread_t th;
puts("[*] registering userfaultfd");
uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK);
if (uffd == -1)
fatal("userfaultfd");
uffdio_api.api = UFFD_API;
uffdio_api.features = 0;
if (ioctl(uffd, UFFDIO_API, &uffdio_api) == -1)
fatal("ioctl(UFFDIO_API)");
uffdio_register.range.start = (unsigned long)addr;
uffdio_register.range.len = len;
uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING;
if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register) == -1)
fatal("UFFDIO_REGISTER");
puts("[*] spawning a fault handler thread");
if (pthread_create(&th, NULL, fault_handler_thread, (void *)uffd))
fatal("pthread_create");
return 0;
}
int main() {
void *page;
page = mmap(NULL, 0x2000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (page == MAP_FAILED)
fatal("mmap");
printf("[+] mmap two pages at 0x%llx\n", (long long unsigned int)page);
register_uffd(page, 0x2000);
char buf[0x100];
puts("[*] reading from page#1");
strcpy(buf, (char *)(page));
printf("[+] 0x0000: %s\n", buf);
puts("[*] reading from page#2");
strcpy(buf, (char *)(page + 0x1000));
printf("[+] 0x1000: %s\n", buf);
puts("[*] reading from page#1");
strcpy(buf, (char *)(page));
printf("[+] 0x0000: %s\n", buf);
puts("[*] reading from page#2");
strcpy(buf, (char *)(page + 0x1000));
printf("[+] 0x1000: %s\n", buf);
getchar();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment