kernel: Initial try at actual user buffer validation

This commit is contained in:
K. Lange 2021-09-29 14:07:32 +09:00
parent ebd86b1a3f
commit 1f0d982240
4 changed files with 54 additions and 8 deletions

12
apps/test-badwrite.c Normal file
View File

@ -0,0 +1,12 @@
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char * argv[]) {
int fd = open("/dev/dsp",O_WRONLY);
if (fd < 0) {
fprintf(stderr, "failed to open dsp\n");
return 1;
}
return write(fd, &fd, -1);
}

View File

@ -12,6 +12,9 @@
#define MMU_GET_MAKE 0x01
#define MMU_PTR_NULL 1
#define MMU_PTR_WRITE 2
void mmu_frame_set(uintptr_t frame_addr);
void mmu_frame_clear(uintptr_t frame_addr);
int mmu_frame_test(uintptr_t frame_addr);
@ -40,3 +43,5 @@ size_t mmu_total_memory(void);
size_t mmu_used_memory(void);
void * sbrk(size_t);
int mmu_validate_user_pointer(void * addr, size_t size, int flags);

View File

@ -899,3 +899,26 @@ void * mmu_map_module(size_t size) {
}
int mmu_validate_user_pointer(void * addr, size_t size, int flags) {
if (addr == NULL && !(flags & MMU_PTR_NULL)) return 0;
if (size > 0x800000000000) return 0;
uintptr_t base = (uintptr_t)addr;
uintptr_t end = size ? (base + (size - 1)) : base;
/* Get start page, end page */
uintptr_t page_base = base >> 12;
uintptr_t page_end = end >> 12;
for (uintptr_t page = page_base; page <= page_end; ++page) {
if ((page & 0xffff800000000) != 0 && (page & 0xffff800000000) != 0xffff800000000) return 0;
union PML * page_entry = mmu_get_page_other(this_core->current_process->thread.page_directory->directory, page << 12);
if (!page_entry) return 0;
if (!page_entry->bits.present) return 0;
if (!page_entry->bits.user) return 0;
if (!page_entry->bits.writable && (flags & MMU_PTR_WRITE)) return 0;
}
return 1;
}

View File

@ -25,14 +25,20 @@
static char hostname[256];
static size_t hostname_len = 0;
extern union PML * mmu_get_page_other(union PML * root, uintptr_t virtAddr);
int ptr_validate(void * ptr, const char * syscall) {
if (ptr && !PTR_INRANGE(ptr)) {
send_signal(this_core->current_process->id, SIGSEGV, 1);
return 1;
if (ptr) {
if (!PTR_INRANGE(ptr)) {
send_signal(this_core->current_process->id, SIGSEGV, 1);
return 1;
}
if (!mmu_validate_user_pointer(ptr,1,0)) return 1;
}
return 0;
}
#define PTRCHECK(addr,size,flags) do { if (!mmu_validate_user_pointer(addr,size,flags)) return -EFAULT; } while (0)
static long sys_sbrk(ssize_t size) {
if (size & 0xFFF) return -EINVAL;
volatile process_t * volatile proc = this_core->current_process;
@ -97,7 +103,7 @@ static long sys_sysfunc(long fn, char ** args) {
* the stuff in the middle to be mapped necessarily... */
PTR_VALIDATE(args);
if (!args) return -EFAULT;
PTR_VALIDATE(args[0]);
if (!PTR_INRANGE(args[0])) return -EFAULT;
if (!args[0]) return -EFAULT;
volatile process_t * volatile proc = this_core->current_process;
if (proc->group != 0) proc = process_from_pid(proc->group);
@ -119,8 +125,8 @@ static long sys_sysfunc(long fn, char ** args) {
/* Align inputs */
uintptr_t start = ((uintptr_t)args[0]) & 0xFFFFffffFFFFf000UL;
uintptr_t end = ((uintptr_t)args[0] + (size_t)args[1] + 0xFFF) & 0xFFFFffffFFFFf000UL;
PTR_VALIDATE(start);
PTR_VALIDATE(end);
if (!PTR_INRANGE(start)) return -EFAULT;
if (!PTR_INRANGE(end)) return -EFAULT;
for (uintptr_t i = start; i < end; i += 0x1000) {
union PML * page = mmu_get_page(i, MMU_GET_MAKE);
mmu_frame_allocate(page, MMU_FLAG_WRITABLE);
@ -177,7 +183,7 @@ static long sys_exit(long exitcode) {
static long sys_write(int fd, char * ptr, unsigned long len) {
if (FD_CHECK(fd)) {
PTR_VALIDATE(ptr);
PTRCHECK(ptr,len,MMU_PTR_NULL);
fs_node_t * node = FD_ENTRY(fd);
if (!(FD_MODE(fd) & 2)) return -EACCES;
if (len && !ptr) {
@ -394,7 +400,7 @@ static long sys_seek(int fd, long offset, long whence) {
static long sys_read(int fd, char * ptr, unsigned long len) {
if (FD_CHECK(fd)) {
PTR_VALIDATE(ptr);
PTRCHECK(ptr,len,MMU_PTR_NULL|MMU_PTR_WRITE);
if (len && !ptr) {
return -EFAULT;
}