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:
Andrew Boie 2018-06-22 14:29:57 -07:00 committed by Andrew Boie
commit 9d3cdb3568
2 changed files with 65 additions and 1 deletions

View file

@ -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 */

View file

@ -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,