Made the {debug,user}_{mem,strl}cpy() and user_memset() functions deal with

address overflows. Apparently at least the x86 string instructions generate
a general protection fault instead of a page fault, and we only use the fault
handler in the latter case (maybe we should change that, too). Fixes #4714.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@33436 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2009-10-05 09:54:40 +00:00
parent 4401e83384
commit 8a71915a9d
2 changed files with 48 additions and 2 deletions

View File

@ -13,6 +13,8 @@
#include "blue_screen.h"
#include <algorithm>
#include <cpu.h>
#include <debug.h>
#include <debug_heap.h>
@ -1529,6 +1531,10 @@ debug_call_with_fault_handler(jmp_buf jumpBuffer, void (*function)(void*),
status_t
debug_memcpy(void* to, const void* from, size_t size)
{
// don't allow address overflows
if ((addr_t)from + size < (addr_t)from || (addr_t)to + size < (addr_t)to)
return B_BAD_ADDRESS;
debug_memcpy_parameters parameters = {to, from, size};
if (debug_call_with_fault_handler(gCPU[sDebuggerOnCPU].fault_jump_buffer,
@ -1545,12 +1551,26 @@ debug_memcpy(void* to, const void* from, size_t size)
ssize_t
debug_strlcpy(char* to, const char* from, size_t size)
{
debug_strlcpy_parameters parameters = {to, from, size};
if (size == 0)
return 0;
if (from == NULL || to == NULL)
return B_BAD_ADDRESS;
// limit size to avoid address overflows
size_t maxSize = std::min(size,
~(addr_t)0 - std::max((addr_t)from, (addr_t)to) + 1);
debug_strlcpy_parameters parameters = {to, from, maxSize};
if (debug_call_with_fault_handler(gCPU[sDebuggerOnCPU].fault_jump_buffer,
&debug_strlcpy_trampoline, &parameters) != 0) {
return B_BAD_ADDRESS;
}
// If we hit the address overflow boundary, fail.
if (parameters.result == maxSize && maxSize < size)
return B_BAD_ADDRESS;
return parameters.result;
}

View File

@ -16,6 +16,8 @@
#include <string.h>
#include <sys/mman.h>
#include <algorithm>
#include <OS.h>
#include <KernelExport.h>
@ -5457,6 +5459,10 @@ vm_memcpy_physical_page(addr_t to, addr_t from)
status_t
user_memcpy(void* to, const void* from, size_t size)
{
// don't allow address overflows
if ((addr_t)from + size < (addr_t)from || (addr_t)to + size < (addr_t)to)
return B_BAD_ADDRESS;
if (arch_cpu_user_memcpy(to, from, size,
&thread_get_current_thread()->fault_handler) < B_OK)
return B_BAD_ADDRESS;
@ -5477,14 +5483,34 @@ user_memcpy(void* to, const void* from, size_t size)
ssize_t
user_strlcpy(char* to, const char* from, size_t size)
{
return arch_cpu_user_strlcpy(to, from, size,
if (size == 0)
return 0;
if (from == NULL || to == NULL)
return B_BAD_ADDRESS;
// limit size to avoid address overflows
size_t maxSize = std::min(size,
~(addr_t)0 - std::max((addr_t)from, (addr_t)to) + 1);
ssize_t result = arch_cpu_user_strlcpy(to, from, maxSize,
&thread_get_current_thread()->fault_handler);
// If we hit the address overflow boundary, fail.
if (result >= 0 && (size_t)result == maxSize && maxSize < size)
return B_BAD_ADDRESS;
return result;
}
status_t
user_memset(void* s, char c, size_t count)
{
// don't allow address overflows
if ((addr_t)s + count < (addr_t)s)
return B_BAD_ADDRESS;
if (arch_cpu_user_memset(s, c, count,
&thread_get_current_thread()->fault_handler) < B_OK)
return B_BAD_ADDRESS;