Kernel, libc: Implement mprotect() and use proper PROT_* values
This commit is contained in:
parent
62d631f1b4
commit
613f8170b6
@ -17,6 +17,7 @@
|
|||||||
#define SYS_seek 12
|
#define SYS_seek 12
|
||||||
#define SYS_exec 13
|
#define SYS_exec 13
|
||||||
#define SYS_fcntl 14
|
#define SYS_fcntl 14
|
||||||
|
#define SYS_mprotect 15
|
||||||
|
|
||||||
namespace Syscall
|
namespace Syscall
|
||||||
{
|
{
|
||||||
@ -32,7 +33,7 @@ void sys_write(Context* context, int fd, size_t size, const char* addr);
|
|||||||
void sys_paint(Context* context, uint64_t x, uint64_t y, uint64_t w, uint64_t h, uint64_t col);
|
void sys_paint(Context* context, uint64_t x, uint64_t y, uint64_t w, uint64_t h, uint64_t col);
|
||||||
void sys_rand(Context* context);
|
void sys_rand(Context* context);
|
||||||
void sys_gettid(Context* context);
|
void sys_gettid(Context* context);
|
||||||
void sys_mmap(Context* context, void* address, size_t size, int flags);
|
void sys_mmap(Context* context, void* address, size_t size, int prot);
|
||||||
void sys_munmap(Context* context, void* address, size_t size);
|
void sys_munmap(Context* context, void* address, size_t size);
|
||||||
void sys_open(Context* context, const char* filename, int flags);
|
void sys_open(Context* context, const char* filename, int flags);
|
||||||
void sys_read(Context* context, int fd, size_t size, char* buffer);
|
void sys_read(Context* context, int fd, size_t size, char* buffer);
|
||||||
@ -40,3 +41,4 @@ void sys_close(Context* context, int fd);
|
|||||||
void sys_seek(Context* context, int fd, long offset, int whence);
|
void sys_seek(Context* context, int fd, long offset, int whence);
|
||||||
void sys_exec(Context* context, const char* pathname);
|
void sys_exec(Context* context, const char* pathname);
|
||||||
void sys_fcntl(Context* context, int fd, int command, uintptr_t arg);
|
void sys_fcntl(Context* context, int fd, int command, uintptr_t arg);
|
||||||
|
void sys_mprotect(Context* context, void* address, size_t size, int prot);
|
@ -26,6 +26,7 @@ void Syscall::entry(Context* context)
|
|||||||
case SYS_seek: sys_seek(context, (int)context->rdi, (long)context->rsi, (int)context->rdx); break;
|
case SYS_seek: sys_seek(context, (int)context->rdi, (long)context->rsi, (int)context->rdx); break;
|
||||||
case SYS_exec: sys_exec(context, (const char*)context->rdi); break;
|
case SYS_exec: sys_exec(context, (const char*)context->rdi); break;
|
||||||
case SYS_fcntl: sys_fcntl(context, (int)context->rdi, (int)context->rsi, context->rdx); break;
|
case SYS_fcntl: sys_fcntl(context, (int)context->rdi, (int)context->rsi, context->rdx); break;
|
||||||
|
case SYS_mprotect: sys_mprotect(context, (void*)context->rdi, context->rsi, (int)context->rdx); break;
|
||||||
default: context->rax = -ENOSYS; break;
|
default: context->rax = -ENOSYS; break;
|
||||||
}
|
}
|
||||||
VMM::exit_syscall_context();
|
VMM::exit_syscall_context();
|
||||||
|
@ -8,9 +8,30 @@
|
|||||||
#include "misc/utils.h"
|
#include "misc/utils.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#define MAP_READ 1
|
||||||
|
#define MAP_WRITE 2
|
||||||
|
#define MAP_NONE 0
|
||||||
|
|
||||||
#define MAP_FAIL(errno) 0xffffffffffffff00 | (unsigned char)(errno)
|
#define MAP_FAIL(errno) 0xffffffffffffff00 | (unsigned char)(errno)
|
||||||
|
|
||||||
void sys_mmap(Context* context, void* address, size_t size, int flags)
|
static const char* format_prot(int prot)
|
||||||
|
{
|
||||||
|
static char prot_string[3];
|
||||||
|
prot_string[2] = 0;
|
||||||
|
prot_string[0] = ((prot & MAP_READ) > 0) ? 'r' : '-';
|
||||||
|
prot_string[1] = ((prot & MAP_WRITE) > 0) ? 'w' : '-';
|
||||||
|
return prot_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mman_flags_from_prot(int prot)
|
||||||
|
{
|
||||||
|
prot &= 0b11;
|
||||||
|
if (prot == MAP_NONE) return 0;
|
||||||
|
if ((prot & MAP_WRITE) > 0) return MAP_USER | MAP_READ_WRITE;
|
||||||
|
return MAP_USER;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sys_mmap(Context* context, void* address, size_t size, int prot)
|
||||||
{
|
{
|
||||||
if (size < PAGE_SIZE)
|
if (size < PAGE_SIZE)
|
||||||
{
|
{
|
||||||
@ -24,12 +45,10 @@ void sys_mmap(Context* context, void* address, size_t size, int flags)
|
|||||||
context->rax = MAP_FAIL(EINVAL);
|
context->rax = MAP_FAIL(EINVAL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int real_flags = MAP_USER;
|
int real_flags = mman_flags_from_prot(prot);
|
||||||
if (flags & MAP_READ_WRITE) real_flags |= MAP_READ_WRITE;
|
|
||||||
if (address)
|
if (address)
|
||||||
{
|
{
|
||||||
kdbgln("mmap(): %ld pages at address %p, %s", size / PAGE_SIZE, address,
|
kdbgln("mmap(): %ld pages at address %p, %s", size / PAGE_SIZE, address, format_prot(prot));
|
||||||
real_flags & MAP_READ_WRITE ? "rw" : "ro");
|
|
||||||
if (VMM::get_physical((uint64_t)address) != (uint64_t)-1) // Address is already used.
|
if (VMM::get_physical((uint64_t)address) != (uint64_t)-1) // Address is already used.
|
||||||
{
|
{
|
||||||
kwarnln("attempt to map an already mapped address");
|
kwarnln("attempt to map an already mapped address");
|
||||||
@ -52,8 +71,7 @@ void sys_mmap(Context* context, void* address, size_t size, int flags)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
kdbgln("mmap(): %ld pages at any address, %s", Utilities::get_blocks_from_size(PAGE_SIZE, size),
|
kdbgln("mmap(): %ld pages at any address, %s", Utilities::get_blocks_from_size(PAGE_SIZE, size), format_prot(prot));
|
||||||
real_flags & MAP_READ_WRITE ? "rw" : "ro");
|
|
||||||
void* result = MemoryManager::get_pages(Utilities::get_blocks_from_size(PAGE_SIZE, size), real_flags);
|
void* result = MemoryManager::get_pages(Utilities::get_blocks_from_size(PAGE_SIZE, size), real_flags);
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
@ -103,3 +121,42 @@ void sys_munmap(Context* context, void* address, size_t size)
|
|||||||
context->rax = 0;
|
context->rax = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sys_mprotect(Context* context, void* address, size_t size, int prot)
|
||||||
|
{
|
||||||
|
kdbgln("mprotect(): attempting to protect %p with %s", address, format_prot(prot));
|
||||||
|
|
||||||
|
if (size < PAGE_SIZE)
|
||||||
|
{
|
||||||
|
kwarnln("mprotect() failed: size is too small");
|
||||||
|
context->rax = -EINVAL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (size % PAGE_SIZE)
|
||||||
|
{
|
||||||
|
kwarnln("mprotect() failed: size is not a multiple of PAGE_SIZE");
|
||||||
|
context->rax = -EINVAL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!address)
|
||||||
|
{
|
||||||
|
kwarnln("mprotect() failed: attempted to unmap page 0");
|
||||||
|
context->rax = -EINVAL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t flags = VMM::get_flags((uint64_t)address);
|
||||||
|
if (!(flags & MAP_USER))
|
||||||
|
{
|
||||||
|
kwarnln("mprotect() failed: attempted to protect a non-existent or kernel page");
|
||||||
|
context->rax = -EINVAL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t offset = (uint64_t)address % PAGE_SIZE;
|
||||||
|
MemoryManager::protect((void*)((uint64_t)address - offset), Utilities::get_blocks_from_size(PAGE_SIZE, size),
|
||||||
|
mman_flags_from_prot(prot));
|
||||||
|
kdbgln("mprotect() succeeded");
|
||||||
|
context->rax = 0;
|
||||||
|
return;
|
||||||
|
}
|
@ -7,7 +7,9 @@
|
|||||||
/* Address returned by mmap when it fails. */
|
/* Address returned by mmap when it fails. */
|
||||||
#define MAP_FAILED (void*)-1
|
#define MAP_FAILED (void*)-1
|
||||||
|
|
||||||
#define PROT_READ_WRITE 1
|
#define PROT_NONE 0
|
||||||
|
#define PROT_READ 1
|
||||||
|
#define PROT_WRITE 2
|
||||||
|
|
||||||
#define PAGE_SIZE 4096
|
#define PAGE_SIZE 4096
|
||||||
|
|
||||||
@ -24,6 +26,9 @@ extern "C"
|
|||||||
* address space. */
|
* address space. */
|
||||||
int munmap(void* addr, size_t size);
|
int munmap(void* addr, size_t size);
|
||||||
|
|
||||||
|
/* Protects size bytes of memory according to the prot argument. */
|
||||||
|
int mprotect(void* addr, size_t size, int prot);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -13,7 +13,7 @@ int liballoc_unlock()
|
|||||||
|
|
||||||
void* liballoc_alloc(size_t size)
|
void* liballoc_alloc(size_t size)
|
||||||
{
|
{
|
||||||
void* result = mmap(NULL, size * PAGE_SIZE, PROT_READ_WRITE, 0, 0, 0);
|
void* result = mmap(NULL, size * PAGE_SIZE, PROT_READ | PROT_WRITE, 0, 0, 0);
|
||||||
if (result == MAP_FAILED) return 0;
|
if (result == MAP_FAILED) return 0;
|
||||||
return (void*)result;
|
return (void*)result;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user