Kernel: Improve strdup_from_user and add copy to and from user
Still a bit funky, that's why we're not using it in read() and write() yet.
This commit is contained in:
parent
67f536cf91
commit
b63a9f5ba9
@ -16,6 +16,9 @@ bool validate_user_writable_page(uintptr_t address);
|
|||||||
bool validate_user_read(uintptr_t address, size_t size);
|
bool validate_user_read(uintptr_t address, size_t size);
|
||||||
bool validate_user_write(uintptr_t address, size_t size);
|
bool validate_user_write(uintptr_t address, size_t size);
|
||||||
|
|
||||||
|
bool copy_from_user(const void* user_ptr, void* ptr, size_t size);
|
||||||
|
bool copy_to_user(void* user_ptr, const void* ptr, size_t size);
|
||||||
|
|
||||||
// FIXME: Map the physical addresses into kernel address space. Right now, something overwrites KernelHeap and crashes
|
// FIXME: Map the physical addresses into kernel address space. Right now, something overwrites KernelHeap and crashes
|
||||||
// it, so that's not really possible. But it should be done in the future.
|
// it, so that's not really possible. But it should be done in the future.
|
||||||
|
|
||||||
|
@ -1,14 +1,44 @@
|
|||||||
#include "sys/UserMemory.h"
|
#include "sys/UserMemory.h"
|
||||||
#include "memory/Memory.h"
|
#include "memory/Memory.h"
|
||||||
|
#include "memory/MemoryManager.h"
|
||||||
|
#include "std/stdlib.h"
|
||||||
#include "std/string.h"
|
#include "std/string.h"
|
||||||
#include "utils/Addresses.h"
|
#include "utils/Addresses.h"
|
||||||
|
|
||||||
char* strdup_from_user(
|
struct dynamic_string
|
||||||
const char* user_string) // FIXME: This function is a little hacky. Use the obtain_user_ref and similar functions.
|
|
||||||
{
|
{
|
||||||
uint64_t phys = VMM::get_physical((uint64_t)user_string);
|
char* buf;
|
||||||
if (phys == (uint64_t)-1) { return nullptr; }
|
long capacity;
|
||||||
return strdup((const char*)phys);
|
long size;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool dynamic_expand(dynamic_string* str, long new_capacity)
|
||||||
|
{
|
||||||
|
char* buffer = (char*)krealloc(str->buf, new_capacity);
|
||||||
|
if (!buffer) { return false; }
|
||||||
|
str->buf = buffer;
|
||||||
|
str->capacity = new_capacity;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dynamic_push(dynamic_string* str, char c)
|
||||||
|
{
|
||||||
|
if (str->size == str->capacity)
|
||||||
|
{
|
||||||
|
if (!dynamic_expand(str, str->capacity + 16)) return false;
|
||||||
|
}
|
||||||
|
str->buf[str->size] = c;
|
||||||
|
str->size++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dynamic_init(dynamic_string* str)
|
||||||
|
{
|
||||||
|
str->buf = (char*)kmalloc(10);
|
||||||
|
if (!str->buf) return false;
|
||||||
|
str->capacity = 10;
|
||||||
|
str->size = 0;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool validate_user_readable_page(uintptr_t address)
|
bool validate_user_readable_page(uintptr_t address)
|
||||||
@ -29,6 +59,54 @@ bool validate_user_writable_page(uintptr_t address)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char* strdup_from_user(const char* user_string)
|
||||||
|
{
|
||||||
|
uintptr_t user_ptr = (uintptr_t)user_string;
|
||||||
|
auto aligned = round_down_to_nearest_page(user_ptr);
|
||||||
|
char* ptr = nullptr;
|
||||||
|
uintptr_t index = 0;
|
||||||
|
if (aligned != user_ptr) // Otherwise, we already do this check below.
|
||||||
|
{
|
||||||
|
if (!validate_user_readable_page(aligned)) return nullptr;
|
||||||
|
ptr = (char*)MemoryManager::get_mapping((void*)VMM::get_physical(aligned), 0);
|
||||||
|
index = user_ptr - aligned;
|
||||||
|
}
|
||||||
|
dynamic_string str;
|
||||||
|
if (!dynamic_init(&str))
|
||||||
|
{
|
||||||
|
if (ptr) MemoryManager::release_mapping(ptr);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
while (true) // FIXME: set a limit for this and fail with ENAMETOOLONG otherwise.
|
||||||
|
{
|
||||||
|
if (user_ptr % PAGE_SIZE == 0)
|
||||||
|
{
|
||||||
|
index = 0;
|
||||||
|
if (ptr) MemoryManager::release_mapping(ptr);
|
||||||
|
if (!validate_user_readable_page(user_ptr))
|
||||||
|
{
|
||||||
|
kfree(str.buf);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
ptr = (char*)MemoryManager::get_mapping((void*)VMM::get_physical(user_ptr), 0);
|
||||||
|
}
|
||||||
|
char c = ptr[index];
|
||||||
|
if (!dynamic_push(&str, c))
|
||||||
|
{
|
||||||
|
MemoryManager::release_mapping(ptr);
|
||||||
|
kfree(str.buf);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (!c) // We reached the null terminator!!
|
||||||
|
{
|
||||||
|
MemoryManager::release_mapping(ptr);
|
||||||
|
return str.buf;
|
||||||
|
}
|
||||||
|
user_ptr++;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool validate_user_read(uintptr_t address, size_t size)
|
bool validate_user_read(uintptr_t address, size_t size)
|
||||||
{
|
{
|
||||||
auto aligned = round_down_to_nearest_page(address);
|
auto aligned = round_down_to_nearest_page(address);
|
||||||
@ -64,3 +142,71 @@ bool validate_user_write(uintptr_t address, size_t size)
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool do_copy_from_user(const char* uptr, char* ptr, size_t size)
|
||||||
|
{
|
||||||
|
uintptr_t user_ptr = (uintptr_t)uptr;
|
||||||
|
auto aligned = round_down_to_nearest_page(user_ptr);
|
||||||
|
char* mapping = nullptr;
|
||||||
|
uintptr_t index = 0;
|
||||||
|
if (aligned != user_ptr) // Otherwise, we already do this check below.
|
||||||
|
{
|
||||||
|
if (!validate_user_readable_page(aligned)) return false;
|
||||||
|
mapping = (char*)MemoryManager::get_mapping((void*)VMM::get_physical(aligned), 0);
|
||||||
|
index = user_ptr - aligned;
|
||||||
|
}
|
||||||
|
while (size--)
|
||||||
|
{
|
||||||
|
if (user_ptr % PAGE_SIZE == 0)
|
||||||
|
{
|
||||||
|
if (mapping) MemoryManager::release_mapping(mapping);
|
||||||
|
index = 0;
|
||||||
|
if (!validate_user_readable_page(user_ptr)) return false;
|
||||||
|
mapping = (char*)MemoryManager::get_mapping((void*)VMM::get_physical(user_ptr), 0);
|
||||||
|
}
|
||||||
|
*ptr = mapping[index];
|
||||||
|
user_ptr++;
|
||||||
|
ptr++;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool do_copy_to_user(char* uptr, const char* ptr, size_t size)
|
||||||
|
{
|
||||||
|
uintptr_t user_ptr = (uintptr_t)uptr;
|
||||||
|
auto aligned = round_down_to_nearest_page(user_ptr);
|
||||||
|
char* mapping = nullptr;
|
||||||
|
uintptr_t index = 0;
|
||||||
|
if (aligned != user_ptr) // Otherwise, we already do this check below.
|
||||||
|
{
|
||||||
|
if (!validate_user_writable_page(aligned)) return false;
|
||||||
|
mapping = (char*)MemoryManager::get_mapping((void*)VMM::get_physical(aligned));
|
||||||
|
index = user_ptr - aligned;
|
||||||
|
}
|
||||||
|
while (size--)
|
||||||
|
{
|
||||||
|
if (user_ptr % PAGE_SIZE == 0)
|
||||||
|
{
|
||||||
|
if (mapping) MemoryManager::release_mapping(mapping);
|
||||||
|
index = 0;
|
||||||
|
if (!validate_user_writable_page(user_ptr)) return false;
|
||||||
|
mapping = (char*)MemoryManager::get_mapping((void*)VMM::get_physical(user_ptr));
|
||||||
|
}
|
||||||
|
mapping[index] = *ptr;
|
||||||
|
user_ptr++;
|
||||||
|
ptr++;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool copy_from_user(const void* user_ptr, void* ptr, size_t size)
|
||||||
|
{
|
||||||
|
return do_copy_from_user((const char*)user_ptr, (char*)ptr, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool copy_to_user(void* user_ptr, const void* ptr, size_t size)
|
||||||
|
{
|
||||||
|
return do_copy_to_user((char*)user_ptr, (const char*)ptr, size);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user