/* SAMHAIN file system integrity testing */ /* Copyright (C) 1999, 2000 Rainer Wichmann */ /* */ /* This program 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. */ /* */ /* This program 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "config_xor.h" /* With glibc, _XOPEN_SOURCE 500 is required for * pthread_mutexattr_settype/PTHREAD_MUTEX_RECURSIVE */ #if defined(HAVE_PTHREAD) && defined(MEM_DEBUG) #define _XOPEN_SOURCE 500 #endif #include #include #include #include #include #ifdef HAVE_MEMORY_H #include #endif #define SH_REAL_SET #include "samhain.h" #include "sh_error.h" #include "sh_utils.h" #include "sh_mem.h" #include "sh_pthread.h" extern int safe_logger (int signal, int method, char * details); #undef FIL__ #define FIL__ _("sh_mem.c") static int eblock = 0; #ifdef MEM_DEBUG #define CHECKBYTE 0x7F /* Memory alignment; should be 16 bytes on 64 bit machines. * -> 32 bytes overhead/allocation */ #define SH_MEMMULT 16 typedef struct mem_struct { struct mem_struct *next; /* link to next struct */ char * real_address; /* address assigned */ char * address; /* address returned */ unsigned long size; /* size allocated */ char file[20]; /* Allocation file name */ int line; /* Allocation line number */ } memlist_t; memlist_t * memlist = NULL; int Free_Count = 0, Alloc_Count = 0; int Now_Alloc_Count = 0, Max_Alloc_Count = 0; unsigned long Mem_Current = 0, Mem_Max = 0; #if 0 #define MEM_DETAILS #endif #ifdef MEM_DETAILS int max_upto_032 = 0; int max_upto_064 = 0; int max_upto_128 = 0; int max_upto_256 = 0; int max_upto_512 = 0; int max_upto_1024 = 0; int max_upto_4096 = 0; int max_upto_inf = 0; int now_upto_032 = 0; int now_upto_064 = 0; int now_upto_128 = 0; int now_upto_256 = 0; int now_upto_512 = 0; int now_upto_1024 = 0; int now_upto_4096 = 0; int now_upto_inf = 0; int tot_upto_032 = 0; int tot_upto_064 = 0; int tot_upto_128 = 0; int tot_upto_256 = 0; int tot_upto_512 = 0; int tot_upto_1024 = 0; int tot_upto_4096 = 0; int tot_upto_inf = 0; #endif #ifdef HAVE_PTHREAD static pthread_once_t mem_is_initialized = PTHREAD_ONCE_INIT; static pthread_mutex_t mutex_mem; static void initialize_mem(void) { pthread_mutexattr_t mta; pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&mutex_mem, &mta); pthread_mutexattr_destroy(&mta); return; } #define MEM_MUTEX_INIT (void) pthread_once(&mem_is_initialized, initialize_mem) #else #define MEM_MUTEX_INIT ((void)0) #endif #ifdef MEM_LOG void sh_mem_dump () { memlist_t * this = memlist; FILE * fd; MEM_MUTEX_INIT; SH_MUTEX_LOCK(mutex_mem); fd = fopen(MEM_LOG, "w"); while (this != NULL) { fprintf (fd, "%20s %5d %ld\n", this->file, this->line, this->size); this = this->next; } fclose(fd); SH_MUTEX_UNLOCK(mutex_mem); return; } #else void sh_mem_dump () { return; } #endif void sh_mem_stat () { memlist_t * this; SL_ENTER(_("sh_mem_stat")); MEM_MUTEX_INIT; SH_MUTEX_LOCK(mutex_mem); if (Alloc_Count == Free_Count) { sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_MSTAMP, Mem_Max, Mem_Current); goto out; } sh_error_handle (SH_ERR_INFO, FIL__, __LINE__, 0, MSG_MSTAMP2, Alloc_Count, Free_Count, Max_Alloc_Count); sh_error_handle (SH_ERR_INFO, FIL__, __LINE__, 0, MSG_MSTAMP, Mem_Max, Mem_Current); #ifdef MEM_DETAILS fprintf(stderr, "\n"); fprintf(stderr, "__SIZE_____TOTAL___MAXIMUM___\n"); fprintf(stderr, " 32 %6d %6d\n", tot_upto_032, max_upto_032); fprintf(stderr, " 64 %6d %6d\n", tot_upto_064, max_upto_064); fprintf(stderr, " 128 %6d %6d\n", tot_upto_128, max_upto_128); fprintf(stderr, " 256 %6d %6d\n", tot_upto_256, max_upto_256); fprintf(stderr, " 512 %6d %6d\n", tot_upto_512, max_upto_512); fprintf(stderr, " 1024 %6d %6d\n", tot_upto_1024, max_upto_1024); fprintf(stderr, " 4096 %6d %6d\n", tot_upto_4096, max_upto_4096); fprintf(stderr, " inf %6d %6d\n", tot_upto_inf, max_upto_inf); fprintf(stderr, "\n"); #endif this = memlist; while (this != NULL) { sh_error_handle (SH_ERR_WARN, FIL__, __LINE__, 0, MSG_E_NOTFREE, this->size, this->file, this->line); this = this->next; } out: SH_MUTEX_UNLOCK(mutex_mem); SL_RET0(_("sh_mem_stat")); } void sh_mem_check () { memlist_t * this; long nerr = 0; SL_ENTER(_("sh_mem_check")); MEM_MUTEX_INIT; SH_MUTEX_LOCK(mutex_mem); sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_MSTAMP, Mem_Max, Mem_Current); this = memlist; while (this != NULL) { if ( this->address == NULL ) { sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_MNULL); ++nerr; } else { if ( this->address[this->size] != CHECKBYTE ) { sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_MOVER, this->file, this->line, FIL__, __LINE__); ++nerr; } if ( this->real_address[SH_MEMMULT-1] != CHECKBYTE ) { sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_MUNDER, this->file, this->line, FIL__, __LINE__); ++nerr; } } this = this->next; } /* if (nerr > 0) abort(); */ SH_MUTEX_UNLOCK(mutex_mem); SL_RET0(_("sh_mem_check")); } void * sh_mem_malloc (size_t size, char * file, int line) { void * the_realAddress; void * theAddress; memlist_t * this; SL_ENTER(_("sh_mem_malloc")); MEM_MUTEX_INIT; SH_MUTEX_LOCK(mutex_mem); the_realAddress = malloc(size + 2 * SH_MEMMULT); if ( the_realAddress == NULL ) { if (eblock == 0) { eblock = 1; (void) safe_logger (0, 0, NULL); /* sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_MMEM, file, line); */ eblock = 0; } /* use _exit() rather than exit() - we malloc() in atexit() functions */ _exit (42); } /* --- Set check bytes. --- */ theAddress = ((char *) the_realAddress + SH_MEMMULT); memset(the_realAddress, CHECKBYTE, SH_MEMMULT); memset(theAddress, CHECKBYTE, size + 1); memset(theAddress, 0, 1); ++Alloc_Count; ++Now_Alloc_Count; if (Max_Alloc_Count < Now_Alloc_Count) Max_Alloc_Count = Now_Alloc_Count; #ifdef MEM_DETAILS if (size <= 32) { ++now_upto_032; ++tot_upto_032; if (now_upto_032 > max_upto_032) max_upto_032 = now_upto_032; } else if (size <= 64) { ++now_upto_064; ++tot_upto_064; if (now_upto_064 > max_upto_064) max_upto_064 = now_upto_064; } else if (size <= 128) { ++now_upto_128; ++tot_upto_128; if (now_upto_128 > max_upto_128) max_upto_128 = now_upto_128; } else if (size <= 256) { ++now_upto_256; ++tot_upto_256; if (now_upto_256 > max_upto_256) max_upto_256 = now_upto_256; } else if (size <= 512) { ++now_upto_512; ++tot_upto_512; if (now_upto_512 > max_upto_512) max_upto_512 = now_upto_512; } else if (size <= 1024) { ++now_upto_1024; ++tot_upto_1024; if (now_upto_1024 > max_upto_1024) max_upto_1024 = now_upto_1024; } else if (size <= 4096) { ++now_upto_4096; ++tot_upto_4096; if (now_upto_4096 > max_upto_4096) max_upto_4096 = now_upto_4096; } else { ++now_upto_inf; ++tot_upto_inf; if (now_upto_inf > max_upto_inf) max_upto_inf = now_upto_inf; fprintf(stderr, "\n___BIGSIZE___"); fprintf(stderr, " %6d -> %16s %10d \n", size, file, line); fprintf(stderr, "\n"); } #endif Mem_Current += size; Mem_Max = ( (Mem_Current > Mem_Max) ? Mem_Current : Mem_Max); this = (memlist_t *) malloc (sizeof(memlist_t)); if ( this == NULL) { if (eblock == 0) { eblock = 1; (void) safe_logger(0, 0, NULL); /* sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_MMEM, file, line); */ eblock = 0; } _exit(42); } /* make list entry */ this->real_address = the_realAddress; this->address = theAddress; this->size = size; this->line = line; sl_strlcpy(this->file, file, 20); this->next = memlist; memlist = this; SH_MUTEX_UNLOCK(mutex_mem); SL_RETURN( theAddress, _("sh_mem_malloc")); } void sh_mem_free (void * a, char * file, int line) { memlist_t * this = memlist; memlist_t * before = memlist; unsigned long size = 0; SL_ENTER(_("sh_mem_free")); MEM_MUTEX_INIT; SH_MUTEX_LOCK(mutex_mem); if ( a == NULL ) { sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_MNULL, file, line); goto out; } /* -- Find record. -- */ while (this != NULL) { if (this->address == a) break; before = this; this = this->next; } if (this == NULL) { sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_MREC, file, line); goto out; } else { a = this->real_address; if ( this->address[this->size] != CHECKBYTE ) { sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_MOVER, this->file, this->line, file, line); } if ( this->real_address[SH_MEMMULT-1] != CHECKBYTE ) sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_MUNDER, this->file, this->line, file, line); size = this->size; if (this == memlist) memlist = this->next; else before->next = this->next; } free(a); if (this) free(this); ++Free_Count; --Now_Alloc_Count; #ifdef MEM_DETAILS if (size <= 32) --now_upto_032; else if (size <= 64) --now_upto_064; else if (size <= 128) --now_upto_128; else if (size <= 256) --now_upto_256; else if (size <= 512) --now_upto_512; else if (size <= 1024) --now_upto_1024; else if (size <= 4096) --now_upto_4096; else --now_upto_inf; #endif Mem_Current -= size; out: SH_MUTEX_UNLOCK(mutex_mem); SL_RET0(_("sh_mem_free")); } #else void sh_mem_free (void * a) { SL_ENTER(_("sh_mem_free")); if (a) { free(a); } else { sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_MNULL); } SL_RET0(_("sh_mem_free")); } void * sh_mem_malloc (size_t size) { void * theAddress; SL_ENTER(_("sh_mem_malloc")); theAddress = malloc(size); if ( theAddress == NULL ) { if (eblock == 0) { eblock = 1; (void) safe_logger(0, 0, NULL); /* sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_MMEM); */ eblock = 0; } /* use _exit() rather than exit() - we malloc() in atexit() */ _exit (42); } /* memset (theAddress, 0, 1); *//* needs testing */ SL_RETURN( theAddress, _("sh_mem_malloc")); } #endif