From 604c781c9c42e9ae814476f21b53067bad8ac4f9 Mon Sep 17 00:00:00 2001 From: Liviu Chircu Date: Tue, 6 Jan 2015 19:09:15 +0200 Subject: [PATCH] F_MALLOC: add extra safety checks at runtime The F_MALLOC allocator now properly reports any free() or realloc() operations which are performed on bogus memory regions, making OpenSIPS immediately abort. These checks may be skipped by defining F_MALLOC_OPTIMIZATIONS at compile time. --- Makefile.conf.template | 1 + error.h | 2 +- mem/common.h | 45 ++++++++++++++++++++++++++++++++++ mem/mem.h | 55 ++++++++++++++++++++++++++++++------------ mem/shm_mem.h | 30 +++++++++++++++++++---- 5 files changed, 111 insertions(+), 22 deletions(-) create mode 100644 mem/common.h diff --git a/Makefile.conf.template b/Makefile.conf.template index 78421da85d4..a80d7b7d7c1 100644 --- a/Makefile.conf.template +++ b/Makefile.conf.template @@ -65,6 +65,7 @@ DEFS+= -DSTATISTICS #Enables the statistics manager DEFS+= -DHAVE_RESOLV_RES #Support for changing some of the resolver parameters #DEFS+= -DHP_MALLOC #High performance allocator with fine-grained locking DEFS+= -DF_MALLOC #An even faster allocator. Not recommended for debugging +#DEFS+= -DF_MALLOC_OPTIMIZATIONS #Remove all internal checks in F_MALLOC DEFS+= -DUSE_TCP #Compiles in TCP support #DEFS+= -DUSE_TLS #Compiles in TLS support #DEFS+= -DUSE_SCTP #Compiles in SCTP support diff --git a/error.h b/error.h index de9fee1612f..87854ca4367 100644 --- a/error.h +++ b/error.h @@ -61,7 +61,7 @@ #define E_BAD_SERVER -500 /*!< error in server */ #define report_programming_bug(format, args...) \ - LM_CRIT("\n!!! " format " !!!\nIt seems you have hit a programming bug.\n" \ + LM_CRIT("\n>>> " format"\nIt seems you have hit a programming bug.\n" \ "Please help us make OpenSIPS better by reporting it at " \ "https://github.com/OpenSIPS/opensips/issues\n\n", ##args); #define LM_BUG report_programming_bug diff --git a/mem/common.h b/mem/common.h new file mode 100644 index 00000000000..a787b12b7c7 --- /dev/null +++ b/mem/common.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2014 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * -------- + */ + +#ifndef mem_common_h +#define mem_common_h + +# ifdef VQ_MALLOC +# include "vq_malloc.h" + extern struct vqm_block* mem_block; + extern struct vqm_block* shm_block; +# elif defined F_MALLOC +# include "f_malloc.h" + extern struct fm_block* mem_block; + extern struct fm_block* shm_block; +# elif defined HP_MALLOC +# include "hp_malloc.h" + extern struct hp_block* mem_block; + extern struct hp_block* shm_block; +# else +# include "q_malloc.h" + extern struct qm_block* mem_block; + extern struct qm_block* shm_block; +# endif + +#endif diff --git a/mem/mem.h b/mem/mem.h index 38d6b0f9f32..7952553cfc9 100644 --- a/mem/mem.h +++ b/mem/mem.h @@ -37,6 +37,7 @@ #include "../config.h" #include "../dprint.h" +#include "../stdlib.h" /* fix debug defines, DBG_F_MALLOC <=> DBG_QM_MALLOC */ #ifdef F_MALLOC @@ -50,22 +51,9 @@ #endif #ifdef PKG_MALLOC -# ifdef VQ_MALLOC -# include "vq_malloc.h" - extern struct vqm_block* mem_block; -# elif defined F_MALLOC -# include "f_malloc.h" - extern struct fm_block* mem_block; -# elif defined HP_MALLOC -# include "hp_malloc.h" - extern struct hp_block* mem_block; -# else -# include "q_malloc.h" - extern struct qm_block* mem_block; -# endif - - extern char *mem_pool; +#include "common.h" +extern char *mem_pool; #ifdef STATISTICS #define PKG_TOTAL_SIZE_IDX 0 @@ -114,11 +102,46 @@ void set_pkg_stats(pkg_status_holder*); # ifdef VQ_MALLOC # define pkg_malloc(s) vqm_malloc(mem_block, (s)) # define pkg_free(p) vqm_free(mem_block, (p)) + # elif defined F_MALLOC # include "../error.h" # define pkg_malloc(s) fm_malloc(mem_block, (s)) +# ifdef F_MALLOC_OPTIMIZATIONS # define pkg_realloc(p, s) fm_realloc(mem_block, (p), (s)) -# define pkg_free(p) fm_free(mem_block, (p)) +# define pkg_free(p) fm_free(mem_block, (p)) +# else +# define pkg_free(p) \ + do { \ + if (shm_block && \ + ((void *)p >= (void *)shm_block->first_frag && \ + (void *)p <= (void *)shm_block->last_frag)) { \ + LM_BUG("pkg_free() on shm ptr %p - aborting!\n", p); \ + abort(); \ + } else if (p && ((void *)p < (void *)mem_block->first_frag || \ + (void *)p > (void *)mem_block->last_frag)) { \ + LM_BUG("pkg_free() on non-pkg ptr %p - aborting!\n", p); \ + abort(); \ + } \ + fm_free(mem_block, (p)); \ + } while (0) + +# define pkg_realloc(p, s) \ + ({ \ + if (shm_block && \ + ((void *)p >= (void *)shm_block->first_frag && \ + (void *)p <= (void *)shm_block->last_frag)) { \ + LM_BUG("pkg_realloc(%lu) on shm ptr %p - aborting!\n", \ + (unsigned long)s, p); \ + abort(); \ + } else if (p && ((void *)p < (void *)mem_block->first_frag || \ + (void *)p > (void *)mem_block->last_frag)) { \ + LM_BUG("pkg_realloc(%lu) on non-pkg ptr %p - abort!\n", \ + (unsigned long)s, p); \ + abort(); \ + } \ + fm_realloc(mem_block, (p), (s)); \ + }) +# endif # define pkg_info(i) fm_info(mem_block,i) # elif defined HP_MALLOC # define pkg_malloc(s) hp_pkg_malloc(mem_block, (s)) diff --git a/mem/shm_mem.h b/mem/shm_mem.h index 41162693bcf..21c45dc073b 100644 --- a/mem/shm_mem.h +++ b/mem/shm_mem.h @@ -31,10 +31,12 @@ #ifdef SHM_MEM #include "../statistics.h" +#include "../error.h" #ifndef shm_mem_h #define shm_mem_h +#include #include #include #include @@ -65,10 +67,10 @@ #include "../dprint.h" #include "../lock_ops.h" /* we don't include locking.h on purpose */ +#include "common.h" #ifdef VQ_MALLOC # include "vq_malloc.h" - extern struct vqm_block* shm_block; # define MY_MALLOC vqm_malloc # define MY_FREE vqm_free # define MY_STATUS vqm_status @@ -76,7 +78,6 @@ # warn "no proper vq_realloc implementation, try another memory allocator" #elif defined F_MALLOC # include "f_malloc.h" - extern struct fm_block* shm_block; # define MY_MALLOC fm_malloc # define MY_FREE fm_free # define MY_REALLOC fm_realloc @@ -96,7 +97,6 @@ # define MY_REALLOC_UNSAFE MY_REALLOC #elif defined HP_MALLOC # include "hp_malloc.h" - extern struct hp_block* shm_block; # define MY_MALLOC hp_shm_malloc # define MY_MALLOC_UNSAFE hp_shm_malloc_unsafe # define MY_FREE hp_shm_free @@ -118,7 +118,6 @@ # define update_mem_pattern_file hp_update_mem_pattern_file #else # include "q_malloc.h" - extern struct qm_block* shm_block; # define MY_MALLOC qm_malloc # define MY_FREE qm_free # define MY_REALLOC qm_realloc @@ -315,7 +314,6 @@ void* _shm_resize(void* ptr, unsigned int size, const char* f, const char* fn, #else /*DBQ_QM_MALLOC*/ - inline static void* shm_malloc_unsafe(unsigned int size) { void *p; @@ -351,6 +349,17 @@ inline static void* shm_realloc(void *ptr, unsigned int size) #ifndef HP_MALLOC shm_lock(); +#if (defined F_MALLOC) && !(defined F_MALLOC_OPTIMIZATIONS) + if (ptr >= (void *)mem_block->first_frag && + ptr <= (void *)mem_block->last_frag) { + LM_BUG("shm_realloc(%u) on pkg ptr %p - aborting!\n", size, ptr); + abort(); + } else if (ptr && (ptr < (void *)shm_block->first_frag || + ptr > (void *)shm_block->last_frag)) { + LM_BUG("shm_realloc(%u) on non-shm ptr %p - aborting!\n", size, ptr); + abort(); + } +#endif #endif p = MY_REALLOC(shm_block, ptr, size); @@ -386,6 +395,17 @@ inline static void shm_free(void *_p) { #ifndef HP_MALLOC shm_lock(); +#if defined(F_MALLOC) && !defined(F_MALLOC_OPTIMIZATIONS) + if (_p >= (void *)mem_block->first_frag && + _p <= (void *)mem_block->last_frag) { + LM_BUG("shm_free() on pkg ptr %p - aborting!\n", _p); + abort(); + } else if (_p && (_p < (void *)shm_block->first_frag || + _p > (void *)shm_block->last_frag)) { + LM_BUG("shm_free() on non-shm ptr %p - aborting!\n", _p); + abort(); + } +#endif #endif #ifdef HP_MALLOC