Add sodium_{malloc,allocarray,free}() and sodium_mprotect_*()
ptr = sodium_malloc(size) returns a pointer from which exactly "size" bytes can be accessed. ptr = sodium_allocarray(count, size) allocates enough storage space for "count" pointers or scalars of unit size "size". In both cases, the region is immediately followed by a guard page. As a result, any attempt to access a memory location after ptr[size - 1] will immediately trigger a segmentation fault. The allocated region is mlock()ed and filled with 0xd0 bytes. A read-only page with the size, a guard page, as well as a canary are placed before the returned pointer. The canary is checked by sodium_free(); as a result, altering data right before ptr is likely to cause sodium_free() to kill the process. sodium_free() munlock()s the region and fills it with zeros before actually calling free(). sodium_mprotect_noaccess(), sodium_mprotect_readonly() and sodium_mprotect_readwrite() can be used to change the protection on the set of allocated pages. Reverting the protection to read+write is not required before calling sodium_free().
This commit is contained in:
parent
729a54f4a2
commit
473e1718cc
2
.gitignore
vendored
2
.gitignore
vendored
@ -100,6 +100,8 @@ test/default/shorthash
|
|||||||
test/default/sign
|
test/default/sign
|
||||||
test/default/sodium_core
|
test/default/sodium_core
|
||||||
test/default/sodium_utils
|
test/default/sodium_utils
|
||||||
|
test/default/sodium_utils2
|
||||||
|
test/default/sodium_utils3
|
||||||
test/default/sodium_version
|
test/default/sodium_version
|
||||||
test/default/stream
|
test/default/stream
|
||||||
test/default/stream2
|
test/default/stream2
|
||||||
|
@ -187,6 +187,12 @@
|
|||||||
<ClCompile Include="..\..\..\..\test\default\sodium_utils.c">
|
<ClCompile Include="..\..\..\..\test\default\sodium_utils.c">
|
||||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\..\test\default\sodium_utils2.c">
|
||||||
|
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\..\test\default\sodium_utils3.c">
|
||||||
|
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\..\..\test\default\sodium_version.c">
|
<ClCompile Include="..\..\..\..\test\default\sodium_version.c">
|
||||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -118,6 +118,12 @@
|
|||||||
<ClCompile Include="..\..\..\..\test\default\sodium_utils.c">
|
<ClCompile Include="..\..\..\..\test\default\sodium_utils.c">
|
||||||
<Filter>src</Filter>
|
<Filter>src</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\..\test\default\sodium_utils2.c">
|
||||||
|
<Filter>src</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\..\test\default\sodium_utils3.c">
|
||||||
|
<Filter>src</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\..\..\test\default\sodium_version.c">
|
<ClCompile Include="..\..\..\..\test\default\sodium_version.c">
|
||||||
<Filter>src</Filter>
|
<Filter>src</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -187,6 +187,12 @@
|
|||||||
<ClCompile Include="..\..\..\..\test\default\sodium_utils.c">
|
<ClCompile Include="..\..\..\..\test\default\sodium_utils.c">
|
||||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\..\test\default\sodium_utils2.c">
|
||||||
|
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\..\test\default\sodium_utils3.c">
|
||||||
|
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\..\..\test\default\sodium_version.c">
|
<ClCompile Include="..\..\..\..\test\default\sodium_version.c">
|
||||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -118,6 +118,12 @@
|
|||||||
<ClCompile Include="..\..\..\..\test\default\sodium_utils.c">
|
<ClCompile Include="..\..\..\..\test\default\sodium_utils.c">
|
||||||
<Filter>src</Filter>
|
<Filter>src</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\..\test\default\sodium_utils2.c">
|
||||||
|
<Filter>src</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\..\test\default\sodium_utils3.c">
|
||||||
|
<Filter>src</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\..\..\test\default\sodium_version.c">
|
<ClCompile Include="..\..\..\..\test\default\sodium_version.c">
|
||||||
<Filter>src</Filter>
|
<Filter>src</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -187,6 +187,12 @@
|
|||||||
<ClCompile Include="..\..\..\..\test\default\sodium_utils.c">
|
<ClCompile Include="..\..\..\..\test\default\sodium_utils.c">
|
||||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\..\test\default\sodium_utils2.c">
|
||||||
|
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\..\test\default\sodium_utils3.c">
|
||||||
|
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\..\..\test\default\sodium_version.c">
|
<ClCompile Include="..\..\..\..\test\default\sodium_version.c">
|
||||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -118,6 +118,12 @@
|
|||||||
<ClCompile Include="..\..\..\..\test\default\sodium_utils.c">
|
<ClCompile Include="..\..\..\..\test\default\sodium_utils.c">
|
||||||
<Filter>src</Filter>
|
<Filter>src</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\..\test\default\sodium_utils2.c">
|
||||||
|
<Filter>src</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\..\test\default\sodium_utils3.c">
|
||||||
|
<Filter>src</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\..\..\test\default\sodium_version.c">
|
<ClCompile Include="..\..\..\..\test\default\sodium_version.c">
|
||||||
<Filter>src</Filter>
|
<Filter>src</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -412,7 +412,7 @@ dnl Checks for functions and headers
|
|||||||
AS_IF([test "x$EMSCRIPTEN" = "x"],[
|
AS_IF([test "x$EMSCRIPTEN" = "x"],[
|
||||||
AC_CHECK_FUNCS([arc4random arc4random_buf])
|
AC_CHECK_FUNCS([arc4random arc4random_buf])
|
||||||
])
|
])
|
||||||
AC_CHECK_FUNCS([mlock explicit_bzero posix_memalign])
|
AC_CHECK_FUNCS([mlock mprotect explicit_bzero posix_memalign])
|
||||||
|
|
||||||
AC_SUBST([LIBTOOL_EXTRA_FLAGS])
|
AC_SUBST([LIBTOOL_EXTRA_FLAGS])
|
||||||
|
|
||||||
|
@ -43,6 +43,55 @@ int sodium_mlock(void * const addr, const size_t len);
|
|||||||
SODIUM_EXPORT
|
SODIUM_EXPORT
|
||||||
int sodium_munlock(void * const addr, const size_t len);
|
int sodium_munlock(void * const addr, const size_t len);
|
||||||
|
|
||||||
|
/* WARNING: sodium_malloc() and sodium_allocarray() are not general-purpose
|
||||||
|
* allocation functions.
|
||||||
|
*
|
||||||
|
* They return a pointer to a region filled with 0xd0 bytes and immediately
|
||||||
|
* followed by a guard page.
|
||||||
|
* As a result, accessing a single byte after the requested allocation size
|
||||||
|
* will intentionally trigger a segmentation fault.
|
||||||
|
*
|
||||||
|
* A canary and an additional guard page placed before the beginning of the
|
||||||
|
* region may also kill the process if a buffer underflow is detected.
|
||||||
|
*
|
||||||
|
* The memory layout is:
|
||||||
|
* [unprotected region size (read only)][guard page (no access)][unprotected pages (read/write)][guard page (no access)]
|
||||||
|
* With the layout of the unprotected pages being:
|
||||||
|
* [optional padding][16-bytes canary][user region]
|
||||||
|
*
|
||||||
|
* However:
|
||||||
|
* - These functions are significantly slower than standard functions
|
||||||
|
* - Each allocation requires 3 or 4 additional pages
|
||||||
|
* - The returned address will not be aligned if the allocation size is not
|
||||||
|
* a multiple of the required alignment. For this reason, these functions
|
||||||
|
* are designed to store data, such as secret keys and messages.
|
||||||
|
* They should not be used to store pointers mixed with other types
|
||||||
|
* in portable code unless extreme care is taken to ensure correct
|
||||||
|
* pointers alignment.
|
||||||
|
*/
|
||||||
|
|
||||||
|
SODIUM_EXPORT
|
||||||
|
void *sodium_malloc(const size_t size);
|
||||||
|
|
||||||
|
SODIUM_EXPORT
|
||||||
|
void *sodium_allocarray(size_t count, size_t size);
|
||||||
|
|
||||||
|
SODIUM_EXPORT
|
||||||
|
void sodium_free(void *ptr);
|
||||||
|
|
||||||
|
SODIUM_EXPORT
|
||||||
|
int sodium_mprotect_noaccess(void *ptr);
|
||||||
|
|
||||||
|
SODIUM_EXPORT
|
||||||
|
int sodium_mprotect_readonly(void *ptr);
|
||||||
|
|
||||||
|
SODIUM_EXPORT
|
||||||
|
int sodium_mprotect_readwrite(void *ptr);
|
||||||
|
|
||||||
|
/* -------- */
|
||||||
|
|
||||||
|
int _sodium_alloc_init(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include "crypto_onetimeauth.h"
|
#include "crypto_onetimeauth.h"
|
||||||
#include "randombytes.h"
|
#include "randombytes.h"
|
||||||
#include "runtime.h"
|
#include "runtime.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
static int initialized;
|
static int initialized;
|
||||||
|
|
||||||
@ -17,6 +18,7 @@ sodium_init(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
randombytes_stir();
|
randombytes_stir();
|
||||||
|
_sodium_alloc_init();
|
||||||
initialized = 1;
|
initialized = 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
#ifndef __STDC_WANT_LIB_EXT1__
|
#ifndef __STDC_WANT_LIB_EXT1__
|
||||||
# define __STDC_WANT_LIB_EXT1__ 1
|
# define __STDC_WANT_LIB_EXT1__ 1
|
||||||
#endif
|
#endif
|
||||||
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -17,8 +19,32 @@
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
# include <wincrypt.h>
|
# include <wincrypt.h>
|
||||||
|
#else
|
||||||
|
# include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define CANARY_SIZE 16U
|
||||||
|
#define GARBAGE_VALUE 0xd0
|
||||||
|
|
||||||
|
#ifndef MAP_NOCORE
|
||||||
|
# define MAP_NOCORE 0
|
||||||
|
#endif
|
||||||
|
#if !defined(MAP_ANON) && defined(MAP_ANONYMOUS)
|
||||||
|
# define MAP_ANON MAP_ANONYMOUS
|
||||||
|
#endif
|
||||||
|
#if defined(_WIN32) || defined(MAP_ANON) || defined(HAVE_POSIX_MEMALIGN)
|
||||||
|
# define HAVE_ALIGNED_MALLOC
|
||||||
|
#endif
|
||||||
|
#if defined(HAVE_MPROTECT) && !(defined(PROT_NONE) && defined(PROT_READ) && defined(PROT_WRITE))
|
||||||
|
# undef HAVE_MPROTECT
|
||||||
|
#endif
|
||||||
|
#if defined(HAVE_ALIGNED_MALLOC) && (defined(_WIN32) || defined(HAVE_MPROTECT))
|
||||||
|
# define HAVE_PAGE_PROTECTION
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static size_t page_size;
|
||||||
|
static unsigned char canary[CANARY_SIZE];
|
||||||
|
|
||||||
#ifdef HAVE_WEAK_SYMBOLS
|
#ifdef HAVE_WEAK_SYMBOLS
|
||||||
__attribute__((weak)) void
|
__attribute__((weak)) void
|
||||||
__sodium_dummy_symbol_to_prevent_lto(void * const pnt, const size_t len)
|
__sodium_dummy_symbol_to_prevent_lto(void * const pnt, const size_t len)
|
||||||
@ -174,3 +200,280 @@ sodium_munlock(void * const addr, const size_t len)
|
|||||||
return -1;
|
return -1;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
_sodium_alloc_init(void)
|
||||||
|
{
|
||||||
|
#if defined(_SC_PAGESIZE)
|
||||||
|
long page_size_ = sysconf(_SC_PAGESIZE);
|
||||||
|
if (page_size_ > 0L) {
|
||||||
|
page_size = (size_t) page_size_;
|
||||||
|
}
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
SYSTEM_INFO si;
|
||||||
|
GetSystemInfo(&si);
|
||||||
|
page_size = (size_t) si.dwPageSize;
|
||||||
|
#endif
|
||||||
|
if (page_size < CANARY_SIZE) {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
randombytes_buf(canary, sizeof canary);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline size_t
|
||||||
|
_page_round(const size_t size)
|
||||||
|
{
|
||||||
|
const size_t page_mask = page_size - 1U;
|
||||||
|
|
||||||
|
return (size + page_mask) & ~page_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_mprotect_noaccess(void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
#if defined(HAVE_MPROTECT) && defined(HAVE_PAGE_PROTECTION)
|
||||||
|
return mprotect(ptr, size, PROT_NONE);
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
{
|
||||||
|
DWORD old;
|
||||||
|
return -(VirtualProtect(ptr, size, PAGE_NOACCESS, &old) == 0);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
errno = ENOSYS;
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_mprotect_readonly(void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
#if defined(HAVE_MPROTECT) && defined(HAVE_PAGE_PROTECTION)
|
||||||
|
return mprotect(ptr, size, PROT_READ);
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
{
|
||||||
|
DWORD old;
|
||||||
|
return -(VirtualProtect(ptr, size, PAGE_READONLY, &old) == 0);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
errno = ENOSYS;
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_mprotect_readwrite(void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
#if defined(HAVE_MPROTECT) && defined(HAVE_PAGE_PROTECTION)
|
||||||
|
return mprotect(ptr, size, PROT_READ | PROT_WRITE);
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
{
|
||||||
|
DWORD old;
|
||||||
|
return -(VirtualProtect(ptr, size, PAGE_READWRITE, &old) == 0);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
errno = ENOSYS;
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_out_of_bounds(void)
|
||||||
|
{
|
||||||
|
#ifdef SIGSEGV
|
||||||
|
raise(SIGSEGV);
|
||||||
|
#elif defined(SIGKILL)
|
||||||
|
raise(SIGKILL);
|
||||||
|
#endif
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
static __attribute__((malloc)) unsigned char *
|
||||||
|
_alloc_aligned(const size_t size)
|
||||||
|
{
|
||||||
|
void *ptr;
|
||||||
|
|
||||||
|
#ifdef MAP_ANON
|
||||||
|
if ((ptr = mmap(NULL, size, PROT_READ | PROT_WRITE,
|
||||||
|
MAP_ANON | MAP_PRIVATE | MAP_NOCORE, -1, 0)) == MAP_FAILED) {
|
||||||
|
ptr = NULL;
|
||||||
|
}
|
||||||
|
#elif defined(HAVE_POSIX_MEMALIGN)
|
||||||
|
if (posix_memalign(&ptr, page_size, size) != 0) {
|
||||||
|
ptr = NULL;
|
||||||
|
}
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
ptr = VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||||
|
#elif !defined(HAVE_ALIGNED_MALLOC)
|
||||||
|
ptr = malloc(size);
|
||||||
|
#else
|
||||||
|
# error Bug
|
||||||
|
#endif
|
||||||
|
return (unsigned char *) ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_free_aligned(unsigned char * const ptr, const size_t size)
|
||||||
|
{
|
||||||
|
#ifdef MAP_ANON
|
||||||
|
(void) munmap(ptr, size);
|
||||||
|
#elif defined(HAVE_POSIX_MEMALIGN)
|
||||||
|
free(ptr);
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
VirtualFree(ptr, 0U, MEM_RELEASE);
|
||||||
|
#else
|
||||||
|
free(ptr);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned char *
|
||||||
|
_unprotected_ptr_from_user_ptr(const void *ptr)
|
||||||
|
{
|
||||||
|
uintptr_t unprotected_ptr_u;
|
||||||
|
unsigned char *canary_ptr;
|
||||||
|
unsigned char *unprotected_ptr;
|
||||||
|
size_t page_mask;
|
||||||
|
|
||||||
|
canary_ptr = ((unsigned char *) ptr) - sizeof canary;
|
||||||
|
page_mask = page_size - 1U;
|
||||||
|
unprotected_ptr_u = ((uintptr_t) canary_ptr & (uintptr_t) ~page_mask);
|
||||||
|
if (unprotected_ptr_u <= page_size * 2U) {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return (unsigned char *) unprotected_ptr_u;
|
||||||
|
}
|
||||||
|
|
||||||
|
static __attribute__((malloc)) void *
|
||||||
|
_sodium_malloc(const size_t size)
|
||||||
|
{
|
||||||
|
void *user_ptr;
|
||||||
|
unsigned char *base_ptr;
|
||||||
|
unsigned char *canary_ptr;
|
||||||
|
unsigned char *unprotected_ptr;
|
||||||
|
size_t page_mask;
|
||||||
|
size_t size_with_canary;
|
||||||
|
size_t total_size;
|
||||||
|
size_t unprotected_size;
|
||||||
|
|
||||||
|
if (size >= SIZE_MAX - page_size * 4U) {
|
||||||
|
errno = ENOMEM;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (page_size <= sizeof canary || page_size < sizeof unprotected_size) {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
size_with_canary = (sizeof canary) + size;
|
||||||
|
unprotected_size = _page_round(size_with_canary);
|
||||||
|
total_size = page_size + page_size + unprotected_size + page_size;
|
||||||
|
if ((base_ptr = _alloc_aligned(total_size)) == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
unprotected_ptr = base_ptr + page_size * 2U;
|
||||||
|
_mprotect_noaccess(base_ptr + page_size, page_size);
|
||||||
|
#ifndef HAVE_PAGE_PROTECTION
|
||||||
|
memcpy(unprotected_ptr + unprotected_size, canary, sizeof canary);
|
||||||
|
#endif
|
||||||
|
_mprotect_noaccess(unprotected_ptr + unprotected_size, page_size);
|
||||||
|
sodium_mlock(unprotected_ptr, unprotected_size);
|
||||||
|
page_mask = page_size - 1U;
|
||||||
|
canary_ptr = unprotected_ptr + _page_round(size_with_canary) -
|
||||||
|
size_with_canary;
|
||||||
|
user_ptr = canary_ptr + sizeof canary;
|
||||||
|
memcpy(canary_ptr, canary, sizeof canary);
|
||||||
|
memcpy(base_ptr, &unprotected_size, sizeof unprotected_size);
|
||||||
|
_mprotect_readonly(base_ptr, page_size);
|
||||||
|
assert(_unprotected_ptr_from_user_ptr(user_ptr) == unprotected_ptr);
|
||||||
|
|
||||||
|
return user_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((malloc)) void *
|
||||||
|
sodium_malloc(const size_t size)
|
||||||
|
{
|
||||||
|
void *ptr;
|
||||||
|
|
||||||
|
if ((ptr = _sodium_malloc(size)) == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memset(ptr, (int) GARBAGE_VALUE, size);
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((malloc)) void *
|
||||||
|
sodium_allocarray(size_t count, size_t size)
|
||||||
|
{
|
||||||
|
size_t total_size;
|
||||||
|
|
||||||
|
if (size >= SIZE_MAX / count) {
|
||||||
|
errno = ENOMEM;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
total_size = count * size;
|
||||||
|
|
||||||
|
return sodium_malloc(total_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
sodium_free(void *ptr)
|
||||||
|
{
|
||||||
|
unsigned char *base_ptr;
|
||||||
|
unsigned char *canary_ptr;
|
||||||
|
unsigned char *unprotected_ptr;
|
||||||
|
size_t total_size;
|
||||||
|
size_t unprotected_size;
|
||||||
|
|
||||||
|
if (ptr == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
canary_ptr = ((unsigned char *) ptr) - sizeof canary;
|
||||||
|
if (sodium_memcmp(canary_ptr, canary, sizeof canary) != 0) {
|
||||||
|
_out_of_bounds();
|
||||||
|
}
|
||||||
|
unprotected_ptr = _unprotected_ptr_from_user_ptr(ptr);
|
||||||
|
base_ptr = unprotected_ptr - page_size * 2U;
|
||||||
|
memcpy(&unprotected_size, base_ptr, sizeof unprotected_size);
|
||||||
|
total_size = page_size + page_size + unprotected_size + page_size;
|
||||||
|
_mprotect_readwrite(base_ptr, total_size);
|
||||||
|
#ifndef HAVE_PAGE_PROTECTION
|
||||||
|
if (sodium_memcmp(unprotected_ptr + unprotected_size,
|
||||||
|
canary, sizeof canary) != 0) {
|
||||||
|
_out_of_bounds();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
sodium_munlock(unprotected_ptr, unprotected_size);
|
||||||
|
_free_aligned(base_ptr, total_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_sodium_mprotect(void *ptr, int (*cb)(void *ptr, size_t size))
|
||||||
|
{
|
||||||
|
unsigned char *base_ptr;
|
||||||
|
unsigned char *unprotected_ptr;
|
||||||
|
size_t unprotected_size;
|
||||||
|
|
||||||
|
unprotected_ptr = _unprotected_ptr_from_user_ptr(ptr);
|
||||||
|
base_ptr = unprotected_ptr - page_size * 2U;
|
||||||
|
memcpy(&unprotected_size, base_ptr, sizeof unprotected_size);
|
||||||
|
|
||||||
|
return cb(unprotected_ptr, unprotected_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
sodium_mprotect_noaccess(void *ptr)
|
||||||
|
{
|
||||||
|
return _sodium_mprotect(ptr, _mprotect_noaccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
sodium_mprotect_readonly(void *ptr)
|
||||||
|
{
|
||||||
|
return _sodium_mprotect(ptr, _mprotect_readonly);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
sodium_mprotect_readwrite(void *ptr)
|
||||||
|
{
|
||||||
|
return _sodium_mprotect(ptr, _mprotect_readwrite);
|
||||||
|
}
|
||||||
|
@ -49,6 +49,8 @@ EXTRA_DIST = \
|
|||||||
sign.exp \
|
sign.exp \
|
||||||
sodium_core.exp \
|
sodium_core.exp \
|
||||||
sodium_utils.exp \
|
sodium_utils.exp \
|
||||||
|
sodium_utils2.exp \
|
||||||
|
sodium_utils3.exp \
|
||||||
sodium_version.exp \
|
sodium_version.exp \
|
||||||
stream.exp \
|
stream.exp \
|
||||||
stream2.exp \
|
stream2.exp \
|
||||||
@ -104,6 +106,8 @@ DISTCLEANFILES = \
|
|||||||
sign.res \
|
sign.res \
|
||||||
sodium_core.res \
|
sodium_core.res \
|
||||||
sodium_utils.res \
|
sodium_utils.res \
|
||||||
|
sodium_utils2.res \
|
||||||
|
sodium_utils3.res \
|
||||||
sodium_version.res \
|
sodium_version.res \
|
||||||
stream.res \
|
stream.res \
|
||||||
stream2.res \
|
stream2.res \
|
||||||
@ -167,6 +171,8 @@ TESTS_TARGETS = \
|
|||||||
sign \
|
sign \
|
||||||
sodium_core \
|
sodium_core \
|
||||||
sodium_utils \
|
sodium_utils \
|
||||||
|
sodium_utils2 \
|
||||||
|
sodium_utils3 \
|
||||||
sodium_version \
|
sodium_version \
|
||||||
stream \
|
stream \
|
||||||
stream2 \
|
stream2 \
|
||||||
@ -322,6 +328,12 @@ sodium_core_LDADD = $(TESTS_LDADD)
|
|||||||
sodium_utils_SOURCE = cmptest.h sodium_utils.c
|
sodium_utils_SOURCE = cmptest.h sodium_utils.c
|
||||||
sodium_utils_LDADD = $(TESTS_LDADD)
|
sodium_utils_LDADD = $(TESTS_LDADD)
|
||||||
|
|
||||||
|
sodium_utils2_SOURCE = cmptest.h sodium_utils2.c
|
||||||
|
sodium_utils2_LDADD = $(TESTS_LDADD)
|
||||||
|
|
||||||
|
sodium_utils3_SOURCE = cmptest.h sodium_utils3.c
|
||||||
|
sodium_utils3_LDADD = $(TESTS_LDADD)
|
||||||
|
|
||||||
sodium_version_SOURCE = cmptest.h sodium_version.c
|
sodium_version_SOURCE = cmptest.h sodium_version.c
|
||||||
sodium_version_LDADD = $(TESTS_LDADD)
|
sodium_version_LDADD = $(TESTS_LDADD)
|
||||||
|
|
||||||
|
70
test/default/sodium_utils2.c
Normal file
70
test/default/sodium_utils2.c
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define TEST_NAME "sodium_utils2"
|
||||||
|
#include "cmptest.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
segv_handler(int sig)
|
||||||
|
{
|
||||||
|
printf("Intentional segfault / bus error caught\n");
|
||||||
|
printf("OK\n");
|
||||||
|
#ifdef SIGSEGV
|
||||||
|
signal(SIGSEGV, SIG_DFL);
|
||||||
|
#endif
|
||||||
|
#ifdef SIGBUS
|
||||||
|
signal(SIGBUS, SIG_DFL);
|
||||||
|
#endif
|
||||||
|
#ifdef SIGABRT
|
||||||
|
signal(SIGABRT, SIG_DFL);
|
||||||
|
#endif
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
|
void *buf;
|
||||||
|
size_t size;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
if (sodium_allocarray(SIZE_MAX / 2U + 1U, SIZE_MAX / 2U) != NULL) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
sodium_free(sodium_malloc(0U));
|
||||||
|
sodium_free(NULL);
|
||||||
|
for (i = 0U; i < 10000U; i++) {
|
||||||
|
size = randombytes_uniform(100000U);
|
||||||
|
buf = sodium_malloc(size);
|
||||||
|
memset(buf, i, size);
|
||||||
|
sodium_mprotect_readonly(buf);
|
||||||
|
sodium_free(buf);
|
||||||
|
}
|
||||||
|
printf("OK\n");
|
||||||
|
|
||||||
|
#ifdef SIGSEGV
|
||||||
|
signal(SIGSEGV, segv_handler);
|
||||||
|
#endif
|
||||||
|
#ifdef SIGBUS
|
||||||
|
signal(SIGBUS, segv_handler);
|
||||||
|
#endif
|
||||||
|
#ifdef SIGABRT
|
||||||
|
signal(SIGABRT, segv_handler);
|
||||||
|
#endif
|
||||||
|
size = randombytes_uniform(100000U);
|
||||||
|
buf = sodium_malloc(size);
|
||||||
|
sodium_mprotect_readonly(buf);
|
||||||
|
sodium_mprotect_readwrite(buf);
|
||||||
|
sodium_memzero(((unsigned char *) buf) + size, 1U);
|
||||||
|
sodium_mprotect_noaccess(buf);
|
||||||
|
sodium_free(buf);
|
||||||
|
printf("Overflow not caught\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
3
test/default/sodium_utils2.exp
Normal file
3
test/default/sodium_utils2.exp
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
OK
|
||||||
|
Intentional segfault / bus error caught
|
||||||
|
OK
|
55
test/default/sodium_utils3.c
Normal file
55
test/default/sodium_utils3.c
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define TEST_NAME "sodium_utils3"
|
||||||
|
#include "cmptest.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
segv_handler(int sig)
|
||||||
|
{
|
||||||
|
printf("Intentional segfault / bus error caught\n");
|
||||||
|
printf("OK\n");
|
||||||
|
#ifdef SIGSEGV
|
||||||
|
signal(SIGSEGV, SIG_DFL);
|
||||||
|
#endif
|
||||||
|
#ifdef SIGBUS
|
||||||
|
signal(SIGBUS, SIG_DFL);
|
||||||
|
#endif
|
||||||
|
#ifdef SIGABRT
|
||||||
|
signal(SIGABRT, SIG_DFL);
|
||||||
|
#endif
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
|
void *buf;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
#ifdef SIGSEGV
|
||||||
|
signal(SIGSEGV, segv_handler);
|
||||||
|
#endif
|
||||||
|
#ifdef SIGBUS
|
||||||
|
signal(SIGBUS, segv_handler);
|
||||||
|
#endif
|
||||||
|
#ifdef SIGABRT
|
||||||
|
signal(SIGABRT, segv_handler);
|
||||||
|
#endif
|
||||||
|
size = randombytes_uniform(100000U);
|
||||||
|
buf = sodium_malloc(size);
|
||||||
|
sodium_mprotect_noaccess(buf);
|
||||||
|
sodium_mprotect_readwrite(buf);
|
||||||
|
sodium_memzero(((unsigned char *) buf) - 8, 8U);
|
||||||
|
sodium_mprotect_readonly(buf);
|
||||||
|
sodium_free(buf);
|
||||||
|
printf("Underflow not caught\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
2
test/default/sodium_utils3.exp
Normal file
2
test/default/sodium_utils3.exp
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
Intentional segfault / bus error caught
|
||||||
|
OK
|
Loading…
Reference in New Issue
Block a user