From d9051ea59c7253b2bb081fbede09017c59f7926b Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Sun, 4 Feb 2024 21:42:29 +0100 Subject: [PATCH] Propagate page fault to ressource handler Fix mmap arguments handling --- arch/x86/exception.c | 28 +++++++++++++++++++--------- arch/x86/exception_wrappers.S | 2 +- core/syscall.c | 20 ++++++++++++++++---- core/uaccess.c | 11 +++++++++++ core/uaccess.h | 1 + core/uaddrspace.c | 29 +++++++++++++++++++++++++++-- core/uaddrspace.h | 3 ++- userspace/libc.c | 9 +++++++-- 8 files changed, 84 insertions(+), 19 deletions(-) diff --git a/arch/x86/exception.c b/arch/x86/exception.c index 68e5cee..ec8c0ef 100644 --- a/arch/x86/exception.c +++ b/arch/x86/exception.c @@ -45,9 +45,9 @@ int exceptionSetRoutine(int exception, exception_handler handler) void print_handler(struct cpu_state *frame, ulong intr) { - int intNbInt = intr; - VGAPrintf(RED, BLACK, 0, VGA_HEIGHT - 1, "EXCEPTION %d", intNbInt); + VGAPrintf(RED, BLACK, 0, VGA_HEIGHT - 1, "EXCEPTION %lu", intr); printf("Exception %lu at 0x%p\n", intr, (void *)cpu_context_get_PC(frame)); + asm("hlt"); } @@ -55,17 +55,26 @@ void pagefault_handler(struct cpu_state *frame, ulong intr) { struct thread *current = getCurrentThread(); - struct uAddrSpace *as = processGetAddrSpace(current->process); - vaddr_t faultAddr = cpu_context_get_EX_faulting_vaddr(frame); + assert(frame == current->cpuState); + if (cpu_context_is_in_user_mode(current->cpuState)) { + struct uAddrSpace *as = processGetAddrSpace(current->process); + vaddr_t faultAddr = cpu_context_get_EX_faulting_vaddr(frame); - if(!uAddrSpaceCheckNAlloc(as, faultAddr)) - return; + if (!uAddrSpaceHeapCheckNAlloc(as, faultAddr)) + return; - printf("page fault while in thread [%s] at 0x%p when trying to access 0x%p err_code 0x%x\n", current->name, - (void *)cpu_context_get_PC(frame), (void *)faultAddr, cpu_context_get_EX_err(frame)); - if (cpu_context_is_in_user_mode(frame)) { + // PAGE_FAULT is a interrupt with an error code (see exception_wrapper.S) + uint32_t error_code = cpu_context_get_EX_err(frame); + + if (!uAddrSpaceSolvePageFault(as, faultAddr, error_code & 0x2)) + return; + + printf( + "page fault while in thread [%s] at 0x%p when trying to access 0x%p err_code 0x%x\n", + current->name, (void *)cpu_context_get_PC(frame), (void *)faultAddr, error_code); printf("Killing User Thread\n"); threadExit(); + return; } VGAPrintf(RED, BLACK, 0, VGA_HEIGHT - 1, "PAGE FAULT %d", intr); (void)intr; @@ -79,5 +88,6 @@ int exceptionSetup() exceptionSetRoutine(i, print_handler); } exceptionSetRoutine(EXCEPTION_PAGE_FAULT, pagefault_handler); + return 0; } diff --git a/arch/x86/exception_wrappers.S b/arch/x86/exception_wrappers.S index 52f6a09..c490e13 100644 --- a/arch/x86/exception_wrappers.S +++ b/arch/x86/exception_wrappers.S @@ -165,7 +165,7 @@ iret .endm -/*List of exception w or w/o err codehttps://wiki.osdev.org/Exceptions*/ +/* List of exception w or w/o err code https://wiki.osdev.org/Exceptions */ .irp exception_id, 8, 10, 11, 12, 13, 14, 17, 30 exception_mac_with_errcode exception_id .endr diff --git a/core/syscall.c b/core/syscall.c index aeb8184..0cbdf25 100644 --- a/core/syscall.c +++ b/core/syscall.c @@ -61,6 +61,7 @@ int syscallExecute(int syscallId, const struct cpu_state *userCtx) case SYSCALL_ID_MMAP: { struct uAddrSpace *as; uaddr_t uaddr; + uaddr_t uaddr_ptr; size_t size; uint32_t rights; uint32_t flags; @@ -69,15 +70,26 @@ int syscallExecute(int syscallId, const struct cpu_state *userCtx) char path[256]; as = processGetAddrSpace(getCurrentThread()->process); - ret = syscallGet5args(userCtx, (unsigned int *)&uaddr, (unsigned int *)&size, (unsigned int *)&rights, + ret = syscallGet5args(userCtx, (unsigned int *)&uaddr_ptr, (unsigned int *)&size, (unsigned int *)&rights, (unsigned int *)&flags, (unsigned int *)&userPath); + + if (memcpyFromUser((vaddr_t)&uaddr, uaddr_ptr, sizeof(uaddr)) != sizeof(uaddr)) { + ret = -EFAULT; + break; + } + strzcpyFromUser((vaddr_t *)path, (uaddr_t *)userPath, sizeof(path)); - printf("Trying mmap for device %s\n", path); + + printf("Trying mmap for device %s at %lu\n", path, (vaddr_t)uaddr); if(strcmp(path, "/dev/zero") == 0){ ret = zeroMmap(as, &uaddr, size, rights,flags); } - printf("ret %d\n", ret); - (void)as; + if(!ret){ + if(memcpyToUser(uaddr_ptr, (vaddr_t)&uaddr, sizeof(uaddr)) != sizeof(uaddr)){ + ret = -EFAULT; + break; + } + } break; } default: diff --git a/core/uaccess.c b/core/uaccess.c index 023a591..1548faf 100644 --- a/core/uaccess.c +++ b/core/uaccess.c @@ -44,6 +44,17 @@ static int memcpyUserMemNoCheck(vaddr_t dest, vaddr_t src, size_t size) return size; } +int memcpyToUser(uaddr_t to, vaddr_t from, size_t size) +{ + + if ((uint)to < PAGING_BASE_USER_ADDRESS) + return -EPERM; + if ((uint)to > PAGING_TOP_USER_ADDRESS - size) + return -EPERM; + + return memcpyUserMemNoCheck(to, from, size); +} + int memcpyFromUser(vaddr_t to, uaddr_t from, size_t size) { diff --git a/core/uaccess.h b/core/uaccess.h index 53b619f..03d7685 100644 --- a/core/uaccess.h +++ b/core/uaccess.h @@ -4,4 +4,5 @@ #include "stdarg.h" int memcpyFromUser(vaddr_t to, uaddr_t from, size_t size); +int memcpyToUser(uaddr_t to, vaddr_t from, size_t size); int strzcpyFromUser(vaddr_t *to, uaddr_t *from, size_t size); diff --git a/core/uaddrspace.c b/core/uaddrspace.c index 4eebbd6..80f5ead 100644 --- a/core/uaddrspace.c +++ b/core/uaddrspace.c @@ -250,7 +250,7 @@ uaddr_t sysBrk(struct uAddrSpace *as, uaddr_t newHeapTop) incSize = ALIGN(newHeapTop - (as->heapStart + as->heapSize), PAGE_SIZE); if (incSize < 0){ - //TODO how to free allocated page by uAddrSpaceCheckNAlloc + //TODO how to free allocated page by uAddrSpaceHeapCheckNAlloc return as->heapStart + as->heapSize; } @@ -259,7 +259,7 @@ uaddr_t sysBrk(struct uAddrSpace *as, uaddr_t newHeapTop) return as->heapStart + as->heapSize; } -int uAddrSpaceCheckNAlloc(struct uAddrSpace *as, vaddr_t addr) +int uAddrSpaceHeapCheckNAlloc(struct uAddrSpace *as, vaddr_t addr) { struct uAddrVirtualReg *newReg; int right = PAGING_MEM_USER | PAGING_MEM_WRITE | PAGING_MEM_READ; @@ -372,3 +372,28 @@ free_reg: free(reg); return ret; } + +/** + * Check if @param faultAddr could be managed by the uAddrVirtualReg from @param as + **/ +int uAddrSpaceSolvePageFault(struct uAddrSpace *as, vaddr_t faultAddr, int isWriteAccess) +{ + struct uAddrVirtualReg *reg; + int rights = PAGING_MEM_READ; + + reg = findVirtualRegionFromAddr(as, faultAddr, 1); + + if (reg == NULL) + return -EFAULT; + + if (isWriteAccess && !(reg->right & PAGING_MEM_WRITE)) + return -EFAULT; + + if (isWriteAccess) + rights |= PAGING_MEM_WRITE; + + if (reg->res->ops->nopage(reg, faultAddr, rights)) + return -EFAULT; + + return 0; +} diff --git a/core/uaddrspace.h b/core/uaddrspace.h index 77f49e6..fa34190 100644 --- a/core/uaddrspace.h +++ b/core/uaddrspace.h @@ -43,9 +43,10 @@ struct uAddrSpace * uAddrSpaceCreate(struct process *proc); int uAddrSpaceDelete(struct uAddrSpace *addr); struct mmu_context * uAddrSpaceGetMMUContext(struct uAddrSpace *addr); int uAddrSpaceSetHeap(struct uAddrSpace *as, uaddr_t addr, size_t size); -int uAddrSpaceCheckNAlloc(struct uAddrSpace *as, vaddr_t addr); +int uAddrSpaceHeapCheckNAlloc(struct uAddrSpace *as, vaddr_t addr); uaddr_t sysBrk(struct uAddrSpace *as, uaddr_t newHeapTop); int uAddrSpaceMmap(struct uAddrSpace *as, uaddr_t *uaddr, size_t size, uint32_t rights, uint32_t flags, struct mappedRessource *res, uint32_t offset); int uAddrSpaceUnmap(struct uAddrSpace *as, uaddr_t uaddr, size_t size); +int uAddrSpaceSolvePageFault(struct uAddrSpace *as, vaddr_t faultAddr, int isWriteAccess); diff --git a/userspace/libc.c b/userspace/libc.c index bbc1ff4..5269949 100644 --- a/userspace/libc.c +++ b/userspace/libc.c @@ -4,6 +4,7 @@ #include "swintr.h" #include "syscall.h" +int errno = 0; int memcmp(const void *aptr, const void *bptr, size_t size) { const unsigned char *a = (const unsigned char *)aptr; @@ -725,7 +726,11 @@ void *realloc(void *ptr, size_t size) return new_ptr; } -void *mmap(void *addr, size_t len, int prot, int flags, char *path){ +void *mmap(void *addr, size_t len, int prot, int flags, char *path) { - return (void *)syscall5(SYSCALL_ID_MMAP, (unsigned int)addr, len, prot, flags, (unsigned int)path); + int ret = syscall5(SYSCALL_ID_MMAP, (unsigned int)&addr, len, prot, flags, (unsigned int)path); + if(!ret) + return addr; + errno = ret; + return (void *)-1; }