[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[libmicrohttpd] 02/02: Added custom memory poisoning for MemoryPool
From: |
gnunet |
Subject: |
[libmicrohttpd] 02/02: Added custom memory poisoning for MemoryPool |
Date: |
Sun, 10 Oct 2021 20:17:04 +0200 |
This is an automated email from the git hooks/post-receive script.
karlson2k pushed a commit to branch master
in repository libmicrohttpd.
commit 50c9e5efea6913cf97b4b1afd8c57f886f552d32
Author: Evgeny Grin (Karlson2k) <k2k@narod.ru>
AuthorDate: Sun Oct 10 21:16:25 2021 +0300
Added custom memory poisoning for MemoryPool
---
configure.ac | 111 ++++++++++++++++++++++++++++++++++++++++++-
src/include/mhd_options.h | 27 ++++++++++-
src/microhttpd/memorypool.c | 75 +++++++++++++++++++++++------
src/testcurl/test_toolarge.c | 6 +++
4 files changed, 203 insertions(+), 16 deletions(-)
diff --git a/configure.ac b/configure.ac
index f013ecb1..67b18c5f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2648,6 +2648,8 @@ AS_VAR_IF([enable_sanitizers], ["yes"],
)
AS_VAR_IF([mhd_cv_cc_sanitizer_address],["yes"],
[
+ AC_DEFINE([MHD_ASAN_ACTIVE], [1], [Define to '1' if you have
address sanitizer enabled])
+ AC_CHECK_HEADERS([sanitizer/asan_interface.h], [], [],
[AC_INCLUDES_DEFAULT])
AX_APPEND_FLAG([-fsanitize=address], [san_FLAGS])
enabled_sanitizers="${enabled_sanitizers}${enabled_sanitizers:+,
}address"
AC_CACHE_CHECK([whether leak detect is supported],
[mhd_cv_cc_sanitizer_address_leak],
@@ -2691,6 +2693,104 @@ AS_VAR_IF([enable_sanitizers], ["yes"],
enabled_sanitizers="${enabled_sanitizers}${enabled_sanitizers:+, }pointer
subtract"
]
)
+ AS_VAR_IF([ac_cv_header_sanitizer_asan_interface_h],["yes"],
+ [
+ AC_CACHE_CHECK([whether
'__attribute__((no_sanitize("pointer-compare","pointer-subtract")))' works],
[mhd_cv_func_attribute_nosanitize_ptr],
+ [
+
ASAN_OPTIONS="exitcode=88:detect_invalid_pointer_pairs=3:halt_on_error=1"
+ export ASAN_OPTIONS
+ CFLAGS="${saved_CFLAGS} ${san_CFLAGS} ${san_FLAGS}
${errattr_CFLAGS}"
+ AC_RUN_IFELSE(
+ [
+ AC_LANG_PROGRAM(
+ [[
+#include <stdlib.h>
+
+__attribute__((no_sanitize("pointer-compare","pointer-subtract")))
+int ptr_process(void *ptr1, void *ptr2)
+{
+ if ((char*)ptr1 <= (char*)ptr2)
+ return (int) ((char*)ptr2 - (char*)ptr1);
+ return (int) ((char*)ptr1 - (char*)ptr2);
+}
+ ]],
+ [[
+ int *a = (int*) malloc (sizeof(int)*4);
+ int *b = (int*) malloc (sizeof(long)*6);
+ int c = ptr_process(a, b);
+ if (c)
+ {
+ free (b);
+ free (a);
+ return 0;
+ }
+ free (a);
+ free (b);
+ ]]
+ )
+ ],
+ [mhd_cv_func_attribute_nosanitize_ptr=yes],
[mhd_cv_func_attribute_nosanitize_ptr=no],
+ [
+ # Cross-compiling with sanitizers??
+ mhd_cv_func_attribute_nosanitize_ptr=no
+ ]
+ )
+ AS_UNSET([ASAN_OPTIONS])
+ ]
+ )
+ AS_VAR_IF([mhd_cv_func_attribute_nosanitize_ptr], ["yes"],
+ [AC_DEFINE([FUNC_ATTR_PTRCOMPARE_WOKRS],[1],[Define to '1' if
'__attribute__((no_sanitize("pointer-compare","pointer-subtract")))' works])],
+ [
+ AC_CACHE_CHECK([whether
'__attribute__((no_sanitize("address")))' works for pointers compare],
[mhd_cv_func_attribute_nosanitize_addr],
+ [
+
ASAN_OPTIONS="exitcode=88:detect_invalid_pointer_pairs=3:halt_on_error=1"
+ export ASAN_OPTIONS
+ CFLAGS="${saved_CFLAGS} ${san_CFLAGS} ${san_FLAGS}
${errattr_CFLAGS}"
+ AC_RUN_IFELSE(
+ [
+ AC_LANG_PROGRAM(
+ [[
+#include <stdlib.h>
+
+__attribute__((no_sanitize("address")))
+int ptr_process(void *ptr1, void *ptr2)
+{
+ if ((char*)ptr1 <= (char*)ptr2)
+ return (int) ((char*)ptr2 - (char*)ptr1);
+ return (int) ((char*)ptr1 - (char*)ptr2);
+}
+ ]],
+ [[
+ int *a = (int*) malloc (sizeof(int)*4);
+ int *b = (int*) malloc (sizeof(long)*6);
+ int c = ptr_process(a, b);
+ if (c)
+ {
+ free (b);
+ free (a);
+ return 0;
+ }
+ free (a);
+ free (b);
+ ]]
+ )
+ ],
+ [mhd_cv_func_attribute_nosanitize_addr=yes],
[mhd_cv_func_attribute_nosanitize_addr=no],
+ [
+ # Cross-compiling with sanitizers??
+ mhd_cv_func_attribute_nosanitize_addr=no
+ ]
+ )
+ AS_UNSET([ASAN_OPTIONS])
+ ]
+ )
+ AS_VAR_IF([mhd_cv_func_attribute_nosanitize_addr], ["yes"],
+ [AC_DEFINE([FUNC_ATTR_NOSANITIZE_WORKS],[1],[Define to
'1' if '__attribute__((no_sanitize("address")))' works for pointers compare])]
+ )
+ ]
+ )
+ ]
+ )
]
)
dnl Ensure that '#' will be processed correctly
@@ -2812,6 +2912,15 @@ int main(void)
)
AS_IF([test -z "${enabled_sanitizers}"],
[AC_MSG_ERROR([cannot find any sanitizer supported by $CC])])
+ AC_MSG_CHECKING([whether to enable user memory poisoning])
+ AS_IF([test "x${mhd_cv_cc_sanitizer_address}" = "xyes" && test
"x${ac_cv_header_sanitizer_asan_interface_h}" = "xyes" && \
+ (test "x${mhd_cv_func_attribute_nosanitize_ptr}" = "xyes" || test
"x${mhd_cv_func_attribute_nosanitize_addr}" = "xyes")],
+ [
+ AC_DEFINE([MHD_ASAN_POISON_ACTIVE], [1], [Define to '1' if user
memory poison is used])
+ enabled_sanitizers="${enabled_sanitizers}${enabled_sanitizers:+,
}user-poison"
+ AC_MSG_RESULT([yes])
+ ], [AC_MSG_RESULT([no])]
+ )
AS_VAR_IF([mhd_cv_cc_sanitizer_address],["yes"],
[
AX_APPEND_FLAG([-D_FORTIFY_SOURCE=0], [san_CFLAGS])
@@ -2829,7 +2938,7 @@ int main(void)
AM_ASAN_OPTIONS="exitcode=88:strict_string_checks=1:detect_stack_use_after_return=1"
AM_ASAN_OPTIONS="${AM_ASAN_OPTIONS}:check_initialization_order=1:strict_init_order=1:redzone=64"
AM_ASAN_OPTIONS="${AM_ASAN_OPTIONS}:max_free_fill_size=1024:detect_invalid_pointer_pairs=3"
- AM_ASAN_OPTIONS="${AM_ASAN_OPTIONS}:handle_ioctl=1:halt_on_error=1"
+
AM_ASAN_OPTIONS="${AM_ASAN_OPTIONS}:handle_ioctl=1:allow_user_poisoning=1:halt_on_error=1"
AS_VAR_IF([mhd_cv_cc_sanitizer_address_leak], ["yes"],
[AM_ASAN_OPTIONS="${AM_ASAN_OPTIONS}:detect_leaks=1"])
AM_UBSAN_OPTIONS="exitcode=87:print_stacktrace=1:halt_on_error=1"
diff --git a/src/include/mhd_options.h b/src/include/mhd_options.h
index 0e803451..e405fd23 100644
--- a/src/include/mhd_options.h
+++ b/src/include/mhd_options.h
@@ -1,6 +1,6 @@
/*
This file is part of libmicrohttpd
- Copyright (C) 2016 Karlson2k (Evgeny Grin)
+ Copyright (C) 2016-2021 Karlson2k (Evgeny Grin)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@@ -142,4 +142,29 @@
#define MHD_FAVOR_FAST_CODE 1
#endif /* !MHD_FAVOR_FAST_CODE && !MHD_FAVOR_SMALL_CODE */
+#ifndef MHD_ASAN_ACTIVE
+#if (defined(__GNUC__) || defined(_MSC_VER)) && defined(__SANITIZE_ADDRESS__)
+#define MHD_ASAN_ACTIVE 1
+#elif defined(__has_feature)
+#if __has_feature (address_sanitizer)
+#define MHD_ASAN_ACTIVE 1
+#endif /* __has_feature(address_sanitizer) */
+#endif /* __has_feature */
+#endif /* MHD_ASAN_ACTIVE */
+
+#if defined(MHD_ASAN_ACTIVE) && defined(HAVE_SANITIZER_ASAN_INTERFACE_H) && \
+ (defined(FUNC_ATTR_PTRCOMPARE_WOKRS) || defined(FUNC_ATTR_NOSANITIZE_WORKS))
+#ifndef MHD_ASAN_POISON_ACTIVE
+/* Manual ASAN poisoning could be used */
+#warning User memory poisoning is not active
+#endif /* ! MHD_ASAN_POISON_ACTIVE */
+#define _MHD_USE_ASAN_POISON 1
+#else /* ! (MHD_ASAN_ACTIVE && HAVE_SANITIZER_ASAN_INTERFACE_H &&
+ (FUNC_ATTR_PTRCOMPARE_WOKRS || FUNC_ATTR_NOSANITIZE_WORKS)) */
+#ifdef MHD_ASAN_POISON_ACTIVE
+#error User memory poisoning is active, but conditions are not suitable
+#endif /* MHD_ASAN_POISON_ACTIVE */
+#endif /* ! (MHD_ASAN_ACTIVE && HAVE_SANITIZER_ASAN_INTERFACE_H &&
+ (FUNC_ATTR_PTRCOMPARE_WOKRS || FUNC_ATTR_NOSANITIZE_WORKS)) */
+
#endif /* MHD_OPTIONS_H */
diff --git a/src/microhttpd/memorypool.c b/src/microhttpd/memorypool.c
index fb6c0652..0f71ab1b 100644
--- a/src/microhttpd/memorypool.c
+++ b/src/microhttpd/memorypool.c
@@ -45,6 +45,11 @@
#define MHD_SC_PAGESIZE _SC_PAGESIZE
#endif /* _SC_PAGESIZE */
#endif /* HAVE_SYSCONF */
+#include "mhd_limits.h" /* for SIZE_MAX */
+
+#ifdef MHD_ASAN_POISON_ACTIVE
+#include <sanitizer/asan_interface.h>
+#endif /* _MHD_USE_ASAN_POISON */
/* define MAP_ANONYMOUS for Mac OS X */
#if defined(MAP_ANON) && ! defined(MAP_ANONYMOUS)
@@ -67,6 +72,28 @@
#define ROUND_TO_ALIGN(n) (((n) + (ALIGN_SIZE - 1)) \
/ (ALIGN_SIZE) *(ALIGN_SIZE))
+
+#ifndef MHD_ASAN_POISON_ACTIVE
+#define _MHD_NOSANITIZE_PTRS /**/
+#define _MHD_RED_ZONE_SIZE (0)
+#define ROUND_TO_ALIGN_PLUS_RED_ZONE(n) ROUND_TO_ALIGN(n)
+#define _MHD_POISON_MEMORY(pointer, size) /**/
+#define _MHD_UNPOISON_MEMORY(pointer, size) /**/
+#else /* MHD_ASAN_POISON_ACTIVE */
+#if defined(FUNC_ATTR_PTRCOMPARE_WOKRS)
+#define _MHD_NOSANITIZE_PTRS \
+ __attribute__((no_sanitize("pointer-compare","pointer-subtract")))
+#elif defined(FUNC_ATTR_NOSANITIZE_WORKS)
+#define _MHD_NOSANITIZE_PTRS __attribute__((no_sanitize("address")))
+#endif
+#define _MHD_RED_ZONE_SIZE (ALIGN_SIZE)
+#define ROUND_TO_ALIGN_PLUS_RED_ZONE(n) (ROUND_TO_ALIGN(n) +
_MHD_RED_ZONE_SIZE)
+#define _MHD_POISON_MEMORY(pointer, size) \
+ ASAN_POISON_MEMORY_REGION ((pointer), (size))
+#define _MHD_UNPOISON_MEMORY(pointer, size) \
+ ASAN_UNPOISON_MEMORY_REGION ((pointer), (size))
+#endif /* MHD_ASAN_POISON_ACTIVE */
+
#if defined(PAGE_SIZE) && (0 < (PAGE_SIZE + 0))
#define MHD_DEF_PAGE_SIZE_ PAGE_SIZE
#elif defined(PAGESIZE) && (0 < (PAGESIZE + 0))
@@ -205,6 +232,7 @@ MHD_pool_create (size_t max)
pool->end = alloc_size;
pool->size = alloc_size;
mhd_assert (0 < alloc_size);
+ _MHD_POISON_MEMORY (pool->memory, pool->size);
return pool;
}
@@ -222,6 +250,7 @@ MHD_pool_destroy (struct MemoryPool *pool)
mhd_assert (pool->end >= pool->pos);
mhd_assert (pool->size >= pool->end - pool->pos);
+ _MHD_POISON_MEMORY (pool->memory, pool->size);
if (! pool->is_mmap)
free (pool->memory);
else
@@ -250,7 +279,11 @@ MHD_pool_get_free (struct MemoryPool *pool)
{
mhd_assert (pool->end >= pool->pos);
mhd_assert (pool->size >= pool->end - pool->pos);
- return (pool->end - pool->pos);
+#ifdef MHD_ASAN_POISON_ACTIVE
+ if ((pool->end - pool->pos) <= _MHD_RED_ZONE_SIZE)
+ return 0;
+#endif /* _MHD_USE_ASAN_POISON */
+ return (pool->end - pool->pos) - _MHD_RED_ZONE_SIZE;
}
@@ -275,7 +308,7 @@ MHD_pool_allocate (struct MemoryPool *pool,
mhd_assert (pool->end >= pool->pos);
mhd_assert (pool->size >= pool->end - pool->pos);
- asize = ROUND_TO_ALIGN (size);
+ asize = ROUND_TO_ALIGN_PLUS_RED_ZONE (size);
if ( (0 == asize) && (0 != size) )
return NULL; /* size too close to SIZE_MAX */
if ( (pool->pos + asize > pool->end) ||
@@ -291,6 +324,7 @@ MHD_pool_allocate (struct MemoryPool *pool,
ret = &pool->memory[pool->pos];
pool->pos += asize;
}
+ _MHD_UNPOISON_MEMORY (ret, size);
return ret;
}
@@ -299,7 +333,7 @@ MHD_pool_allocate (struct MemoryPool *pool,
* Try to allocate @a size bytes memory area from the @a pool.
*
* If allocation fails, @a required_bytes is updated with size required to be
- * freed in the @a pool from relocatable area to allocate requested number
+ * freed in the @a pool from rellocatable area to allocate requested number
* of bytes.
* Allocated memory area is always not rellocatable ("from end").
*
@@ -311,7 +345,7 @@ MHD_pool_allocate (struct MemoryPool *pool,
* Cannot be NULL.
* @return the pointer to allocated memory area if succeed,
* NULL if the pool doesn't have enough space, required_bytes is
updated
- * with amount of space needed to be freed in relocatable area or
+ * with amount of space needed to be freed in rellocatable area or
* set to SIZE_MAX if requested size is too large for the pool.
*/
void *
@@ -324,7 +358,7 @@ MHD_pool_try_alloc (struct MemoryPool *pool,
mhd_assert (pool->end >= pool->pos);
mhd_assert (pool->size >= pool->end - pool->pos);
- asize = ROUND_TO_ALIGN (size);
+ asize = ROUND_TO_ALIGN_PLUS_RED_ZONE (size);
if ( (0 == asize) && (0 != size) )
{ /* size is too close to SIZE_MAX, very unlikely */
*required_bytes = SIZE_MAX;
@@ -333,6 +367,8 @@ MHD_pool_try_alloc (struct MemoryPool *pool,
if ( (pool->pos + asize > pool->end) ||
(pool->pos + asize < pool->pos))
{
+ mhd_assert ((pool->end - pool->pos) == \
+ ROUND_TO_ALIGN (pool->end - pool->pos));
if (asize <= pool->end)
*required_bytes = asize - (pool->end - pool->pos);
else
@@ -341,6 +377,7 @@ MHD_pool_try_alloc (struct MemoryPool *pool,
}
ret = &pool->memory[pool->end - asize];
pool->end -= asize;
+ _MHD_UNPOISON_MEMORY (ret, size);
return ret;
}
@@ -362,7 +399,7 @@ MHD_pool_try_alloc (struct MemoryPool *pool,
* NULL if the pool cannot support @a new_size
* bytes (old continues to be valid for @a old_size)
*/
-void *
+_MHD_NOSANITIZE_PTRS void *
MHD_pool_reallocate (struct MemoryPool *pool,
void *old,
size_t old_size,
@@ -374,11 +411,11 @@ MHD_pool_reallocate (struct MemoryPool *pool,
mhd_assert (pool->end >= pool->pos);
mhd_assert (pool->size >= pool->end - pool->pos);
mhd_assert (old != NULL || old_size == 0);
- mhd_assert (old == NULL || pool->memory <= (uint8_t*) old);
mhd_assert (pool->size >= old_size);
+ mhd_assert (old == NULL || pool->memory <= (uint8_t*) old);
/* (old == NULL || pool->memory + pool->size >= (uint8_t*) old + old_size) */
mhd_assert (old == NULL || \
- (pool->size) >= \
+ (pool->size - _MHD_RED_ZONE_SIZE) >= \
(((size_t) (((uint8_t*) old) - pool->memory)) + old_size));
/* Blocks "from the end" must not be reallocated */
/* (old == NULL || old_size == 0 || pool->memory + pool->pos > (uint8_t*)
old) */
@@ -386,7 +423,7 @@ MHD_pool_reallocate (struct MemoryPool *pool,
pool->pos > (size_t) ((uint8_t*) old - pool->memory));
mhd_assert (old == NULL || old_size == 0 || \
(size_t) (((uint8_t*) old) - pool->memory) + old_size <= \
- pool->end);
+ pool->end - _MHD_RED_ZONE_SIZE);
if (0 != old_size)
{ /* Have previously allocated data */
@@ -396,10 +433,13 @@ MHD_pool_reallocate (struct MemoryPool *pool,
if (shrinking)
{ /* Shrinking in-place, zero-out freed part */
memset ((uint8_t*) old + new_size, 0, old_size - new_size);
+ _MHD_POISON_MEMORY ((uint8_t*) old + new_size, old_size - new_size);
}
- if (pool->pos == ROUND_TO_ALIGN (old_offset + old_size))
+ if (pool->pos ==
+ ROUND_TO_ALIGN_PLUS_RED_ZONE (old_offset + old_size))
{ /* "old" block is the last allocated block */
- const size_t new_apos = ROUND_TO_ALIGN (old_offset + new_size);
+ const size_t new_apos =
+ ROUND_TO_ALIGN_PLUS_RED_ZONE (old_offset + new_size);
if (! shrinking)
{ /* Grow in-place, check for enough
space. */
if ( (new_apos > pool->end) ||
@@ -408,13 +448,14 @@ MHD_pool_reallocate (struct MemoryPool *pool,
}
/* Resized in-place */
pool->pos = new_apos;
+ _MHD_UNPOISON_MEMORY (old, new_size);
return old;
}
if (shrinking)
return old; /* Resized in-place, freed part remains allocated */
}
/* Need to allocate new block */
- asize = ROUND_TO_ALIGN (new_size);
+ asize = ROUND_TO_ALIGN_PLUS_RED_ZONE (new_size);
if ( ( (0 == asize) &&
(0 != new_size) ) || /* Value wrap, too large new_size. */
(asize > pool->end - pool->pos) ) /* Not enough space */
@@ -423,12 +464,14 @@ MHD_pool_reallocate (struct MemoryPool *pool,
new_blc = pool->memory + pool->pos;
pool->pos += asize;
+ _MHD_UNPOISON_MEMORY (new_blc, new_size);
if (0 != old_size)
{
/* Move data to new block, old block remains allocated */
memcpy (new_blc, old, old_size);
/* Zero-out old block */
memset (old, 0, old_size);
+ _MHD_POISON_MEMORY (old, old_size);
}
return new_blc;
}
@@ -447,7 +490,7 @@ MHD_pool_reallocate (struct MemoryPool *pool,
* (should be larger or equal to @a copy_bytes)
* @return addr new address of @a keep (if it had to change)
*/
-void *
+_MHD_NOSANITIZE_PTRS void *
MHD_pool_reset (struct MemoryPool *pool,
void *keep,
size_t copy_bytes,
@@ -463,6 +506,7 @@ MHD_pool_reset (struct MemoryPool *pool,
mhd_assert (keep == NULL || \
pool->size >= \
((size_t) ((uint8_t*) keep - pool->memory)) + copy_bytes);
+ _MHD_UNPOISON_MEMORY (pool->memory, new_size);
if ( (NULL != keep) &&
(keep != pool->memory) )
{
@@ -477,6 +521,7 @@ MHD_pool_reset (struct MemoryPool *pool,
size_t to_zero; /** Size of area to zero-out */
to_zero = pool->size - copy_bytes;
+ _MHD_UNPOISON_MEMORY (pool->memory + copy_bytes, to_zero);
#ifdef _WIN32
if (pool->is_mmap)
{
@@ -506,8 +551,10 @@ MHD_pool_reset (struct MemoryPool *pool,
0,
to_zero);
}
- pool->pos = ROUND_TO_ALIGN (new_size);
+ pool->pos = ROUND_TO_ALIGN_PLUS_RED_ZONE (new_size);
pool->end = pool->size;
+ _MHD_POISON_MEMORY (((uint8_t*) pool->memory) + new_size, \
+ pool->size - new_size);
return pool->memory;
}
diff --git a/src/testcurl/test_toolarge.c b/src/testcurl/test_toolarge.c
index 70b37ff9..4294010a 100644
--- a/src/testcurl/test_toolarge.c
+++ b/src/testcurl/test_toolarge.c
@@ -193,8 +193,14 @@ _mhdErrorExit_func (const char *errDesc, const char
*funcName, int lineNum)
#define BUFFER_SIZE 1024
+#define MHD_ASAN_ACTIVE 1
+
/* The size of the test element that must pass the test */
+#ifndef MHD_ASAN_POISON_ACTIVE
#define TEST_OK_SIZE (BUFFER_SIZE - 384)
+#else /* MHD_ASAN_POISON_ACTIVE */
+#define TEST_OK_SIZE (BUFFER_SIZE - 384 - 80)
+#endif /* MHD_ASAN_POISON_ACTIVE */
/* The size of the test element where tests are started */
#define TEST_START_SIZE (TEST_OK_SIZE - 16)
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.