x86: add z_arch_user_string_nlen
Uses fixup infrastructure to safely abort if we get a page fault while measuring a string passed in from user mode. Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
parent
1f2eedff18
commit
9d3cdb3568
2 changed files with 65 additions and 1 deletions
|
@ -21,6 +21,7 @@
|
|||
#include <arch/x86/segmentation.h>
|
||||
#include <exception.h>
|
||||
#include <inttypes.h>
|
||||
#include <exc_handle.h>
|
||||
|
||||
__weak void _debug_fatal_hook(const NANO_ESF *esf) { ARG_UNUSED(esf); }
|
||||
|
||||
|
@ -315,10 +316,28 @@ static void dump_mmu_flags(void *addr)
|
|||
}
|
||||
#endif
|
||||
|
||||
FUNC_NORETURN void page_fault_handler(const NANO_ESF *pEsf)
|
||||
#ifdef CONFIG_USERSPACE
|
||||
Z_EXC_DECLARE(z_arch_user_string_nlen);
|
||||
|
||||
static const struct z_exc_handle exceptions[] = {
|
||||
Z_EXC_HANDLE(z_arch_user_string_nlen)
|
||||
};
|
||||
#endif
|
||||
|
||||
void page_fault_handler(NANO_ESF *pEsf)
|
||||
{
|
||||
u32_t err, cr2;
|
||||
|
||||
#ifdef CONFIG_USERSPACE
|
||||
for (int i = 0; i < ARRAY_SIZE(exceptions); i++) {
|
||||
if ((void *)pEsf->eip >= exceptions[i].start &&
|
||||
(void *)pEsf->eip < exceptions[i].end) {
|
||||
pEsf->eip = (unsigned int)(exceptions[i].fixup);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* See Section 6.15 of the IA32 Software Developer's Manual vol 3 */
|
||||
__asm__ ("mov %%cr2, %0" : "=r" (cr2));
|
||||
|
||||
|
@ -335,6 +354,7 @@ FUNC_NORETURN void page_fault_handler(const NANO_ESF *pEsf)
|
|||
#endif
|
||||
|
||||
_NanoFatalErrorHandler(_NANO_ERR_CPU_EXCEPTION, pEsf);
|
||||
CODE_UNREACHABLE;
|
||||
}
|
||||
_EXCEPTION_CONNECT_CODE(page_fault_handler, IV_PAGE_FAULT);
|
||||
#endif /* CONFIG_EXCEPTION_DEBUG */
|
||||
|
|
|
@ -13,6 +13,10 @@
|
|||
/* Exports */
|
||||
GTEXT(_x86_syscall_entry_stub)
|
||||
GTEXT(_x86_userspace_enter)
|
||||
GTEXT(z_arch_user_string_nlen)
|
||||
GTEXT(z_arch_user_string_nlen_fault_start)
|
||||
GTEXT(z_arch_user_string_nlen_fault_end)
|
||||
GTEXT(z_arch_user_string_nlen_fixup)
|
||||
|
||||
/* Imports */
|
||||
GTEXT(_k_syscall_table)
|
||||
|
@ -83,6 +87,46 @@ _bad_syscall:
|
|||
jmp _id_ok
|
||||
|
||||
|
||||
/*
|
||||
* size_t z_arch_user_string_nlen(const char *s, size_t maxsize, int *err_arg)
|
||||
*/
|
||||
SECTION_FUNC(TEXT, z_arch_user_string_nlen)
|
||||
push %ebp
|
||||
mov %esp, %ebp
|
||||
|
||||
/* error value, set to -1 initially. This location is -4(%ebp) */
|
||||
push $-1
|
||||
|
||||
/* Do the strlen operation, based on disassembly of minimal libc */
|
||||
xor %eax, %eax /* EAX = 0, length count */
|
||||
mov 0x8(%ebp), %edx /* EDX base of string */
|
||||
|
||||
/* This code might page fault */
|
||||
strlen_loop:
|
||||
z_arch_user_string_nlen_fault_start:
|
||||
cmpb $0x0, (%edx, %eax, 1) /* *(EDX + EAX) == 0? Could fault. */
|
||||
|
||||
z_arch_user_string_nlen_fault_end:
|
||||
je strlen_done
|
||||
cmp 0xc(%ebp), %eax /* Max length reached? */
|
||||
je strlen_done
|
||||
inc %eax /* EAX++ and loop again */
|
||||
jmp strlen_loop
|
||||
|
||||
strlen_done:
|
||||
/* Set error value to 0 since we succeeded */
|
||||
movl $0, -4(%ebp)
|
||||
|
||||
z_arch_user_string_nlen_fixup:
|
||||
/* Write error value to err pointer parameter */
|
||||
movl 0x10(%ebp), %ecx
|
||||
pop %edx
|
||||
movl %edx, (%ecx)
|
||||
|
||||
pop %ebp
|
||||
ret
|
||||
|
||||
|
||||
/* FUNC_NORETURN void _x86_userspace_enter(k_thread_entry_t user_entry,
|
||||
* void *p1, void *p2, void *p3,
|
||||
* u32_t stack_end,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue