⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sec_mem.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 3 页
字号:
/****************************************************************************
*																			*
*							Secure Memory Management						*
*						Copyright Peter Gutmann 1995-2007					*
*																			*
****************************************************************************/

#if defined( INC_ALL )
  #include "crypt.h"
  #include "acl.h"
  #include "kernel.h"
#else
  #include "crypt.h"
  #include "kernel/acl.h"
  #include "kernel/kernel.h"
#endif /* Compiler-specific includes */

/* A pointer to the kernel data block */

static KERNEL_DATA *krnlData = NULL;

/* The minimum and maximum amount of secure memory that we can ever allocate.
   A more normal upper bound is 8K, however the SSL session cache constitutes
   a single large chunk of secure memory that goes way over this limit */

#define MIN_ALLOC_SIZE		8
#ifdef __MSDOS__
  #define MAX_ALLOC_SIZE	8192
#else
  #define MAX_ALLOC_SIZE	32768L
#endif /* 16 vs. 32-bit systems */

/* To support page locking we need to store some additional information with
   the memory block.  We do this by reserving an extra memory block at the
   start of the allocated block and saving the information there.

   The information stored in the extra block is a flag indicating whether the
   block is pagelocked (so we can call the unlock function when we free it),
   the size of the block, and pointers to the next and previous pointers in
   the list of allocated blocks (this is used by the thread that walks the
   block list touching each one) */

#if INT_MAX <= 32767
  #define MEMLOCK_HEADERSIZE	16
#elif INT_MAX <= 0xFFFFFFFFUL
  #define MEMLOCK_HEADERSIZE	32
#else
  #define MEMLOCK_HEADERSIZE	64
#endif /* 16/32/64-bit systems */

/* If it's a debug build we also insert a canary at the start and end of each
   block to detect memory overwrites, the block size is adjusted accordingly
   to handle this extra data */

#define CANARY_STARTVALUE	"\xC0\xED\xBA\xBE"	/* More fun than dead beef */
#define CANARY_ENDVALUE		"\x36\xDD\x24\x36"

#ifndef NDEBUG
  #define adjustMemCanary( size ) \
		  size += CANARY_SIZE
  #define insertMemCanary( memBlockPtr, memPtr ) \
		  memcpy( memBlockPtr->canary, CANARY_STARTVALUE, CANARY_SIZE ); \
		  memcpy( memPtr + memBlockPtr->size - CANARY_SIZE, CANARY_ENDVALUE, \
				  CANARY_SIZE )
  #define checkMemCanary( memBlockPtr, memPtr ) \
		  assert( !memcmp( memBlockPtr->canary, CANARY_STARTVALUE, CANARY_SIZE ) ); \
		  assert( !memcmp( memPtr + memBlockPtr->size - CANARY_SIZE, \
						   CANARY_ENDVALUE, CANARY_SIZE ) );
#else
  #define adjustMemCanary( size )
  #define insertMemCanary( memBlockPtr, memPtr )
  #define checkMemCanary( memBlockPtr, memPtr )
#endif /* NDEBUG */

/****************************************************************************
*																			*
*								Misc Functions								*
*																			*
****************************************************************************/

/* Prepare to allocate/free a block of secure memory */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int checkInitAlloc( OUT void **allocPtrPtr, 
						   IN_RANGE( MIN_ALLOC_SIZE, MAX_ALLOC_SIZE ) \
							const int size )
	{
	/* Make sure that the parameters are in order */
	if( !isWritePtr( allocPtrPtr, sizeof( void * ) ) )
		retIntError();
	
	REQUIRES( size >= MIN_ALLOC_SIZE && size <= MAX_ALLOC_SIZE );

	return( CRYPT_OK );
	}

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
static int checkInitFree( void **freePtrPtr, OUT_PTR BYTE **memPtrPtr, 
						  OUT_PTR MEMLOCK_INFO **memBlockPtrPtr )
	{
	MEMLOCK_INFO *memBlockPtr;
	BYTE *memPtr;

	PRE( isWritePtr( memPtrPtr, sizeof( BYTE * ) ) );
	PRE( isWritePtr( memBlockPtrPtr, sizeof( MEMLOCK_INFO * ) ) );

	/* Make sure that the parameters are in order */
	if( !isReadPtr( freePtrPtr, sizeof( void * ) ) || \
		!isReadPtr( *freePtrPtr, sizeof( MIN_ALLOC_SIZE ) ) )
		retIntError();

	/* Recover the actual allocated memory block data from the pointer */
	memPtr = ( ( BYTE * ) *freePtrPtr ) - MEMLOCK_HEADERSIZE;
	if( !isReadPtr( memPtr, sizeof( MEMLOCK_INFO ) ) )
		retIntError();
	memBlockPtr = ( MEMLOCK_INFO * ) memPtr;
	REQUIRES( memBlockPtr->size >= sizeof( MEMLOCK_INFO ) + MIN_ALLOC_SIZE && \
			  memBlockPtr->size <= sizeof( MEMLOCK_INFO ) + MAX_ALLOC_SIZE && \
			  ( memBlockPtr->isLocked == FALSE || \
				memBlockPtr->isLocked == TRUE ) );

	*memPtrPtr = memPtr;
	*memBlockPtrPtr = memBlockPtr;
	return( CRYPT_OK );
	}

/* Insert and unlink a memory block from a list of memory blocks.  We can't 
   use insertDoubleListElements()/deleteDoubleListElement() for this because 
   they don't handle the end-of-list pointer, since they're intended for 
   random-access lists rather than append-only lists */

STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
static void insertMemBlock( INOUT MEMLOCK_INFO **allocatedListHeadPtr, 
							INOUT MEMLOCK_INFO **allocatedListTailPtr, 
							INOUT MEMLOCK_INFO *memBlockPtr )
	{
	MEMLOCK_INFO *allocatedListHead = *allocatedListHeadPtr;
	MEMLOCK_INFO *allocatedListTail = *allocatedListTailPtr;

	assert( isWritePtr( allocatedListHeadPtr, sizeof( MEMLOCK_INFO * ) ) );
	assert( allocatedListHead == NULL || \
			isWritePtr( allocatedListHead, sizeof( MEMLOCK_INFO ) ) );
	assert( isWritePtr( allocatedListTailPtr, sizeof( MEMLOCK_INFO * ) ) );
	assert( allocatedListTail == NULL || \
			isWritePtr( allocatedListTail, sizeof( MEMLOCK_INFO ) ) );
	assert( isWritePtr( memBlockPtr, sizeof( MEMLOCK_INFO * ) ) );

	/* If it's a new list, set up the head and tail pointers and return */
	if( allocatedListHead == NULL )
		{
		*allocatedListHeadPtr = *allocatedListTailPtr = memBlockPtr;
		return;
		}

	/* It's an existing list, add the new element to the end */
	allocatedListTail->next = memBlockPtr;
	memBlockPtr->prev = allocatedListTail;
	*allocatedListTailPtr = memBlockPtr;
	}

STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
static void unlinkMemBlock( INOUT MEMLOCK_INFO **allocatedListHeadPtr, 
							INOUT MEMLOCK_INFO **allocatedListTailPtr, 
							INOUT MEMLOCK_INFO *memBlockPtr )
	{
	MEMLOCK_INFO *allocatedListHead = *allocatedListHeadPtr;
	MEMLOCK_INFO *allocatedListTail = *allocatedListTailPtr;
	MEMLOCK_INFO *nextBlockPtr = memBlockPtr->next;
	MEMLOCK_INFO *prevBlockPtr = memBlockPtr->prev;

	assert( isWritePtr( allocatedListHeadPtr, sizeof( MEMLOCK_INFO * ) ) );
	assert( allocatedListHead == NULL || \
			isWritePtr( allocatedListHead, sizeof( MEMLOCK_INFO ) ) );
	assert( isWritePtr( allocatedListTailPtr, sizeof( MEMLOCK_INFO * ) ) );
	assert( allocatedListTail == NULL || \
			isWritePtr( allocatedListTail, sizeof( MEMLOCK_INFO ) ) );
	assert( isWritePtr( memBlockPtr, sizeof( MEMLOCK_INFO * ) ) );

	/* If we're removing the block from the start of the list, make the
	   start the next block */
	if( memBlockPtr == allocatedListHead )
		*allocatedListHeadPtr = nextBlockPtr;
	else
		{
		assert( prevBlockPtr != NULL );

		/* Delete from the middle or end of the list */
		prevBlockPtr->next = nextBlockPtr;
		}
	if( nextBlockPtr != NULL )
		nextBlockPtr->prev = prevBlockPtr;

	/* If we're removed the last element, update the end pointer */
	if( memBlockPtr == allocatedListTail )
		*allocatedListTailPtr = prevBlockPtr;

	/* Clear the current block's pointers, just to be clean */
	memBlockPtr->next = memBlockPtr->prev = NULL;
	}

#if 0	/* Currently unused, in practice would be called from a worker thread
		   that periodically touches all secure-data pages */

/* Walk the allocated block list touching each page.  In most cases we don't
   need to explicitly touch the page since the allocated blocks are almost
   always smaller than the MMU's page size and simply walking the list
   touches them, but in some rare cases we need to explicitly touch each
   page */

static void touchAllocatedPages( void )
	{
	MEMLOCK_INFO *memBlockPtr;

	/* Lock the allocation object to ensure that other threads don't try to
	   access them */
	MUTEX_LOCK( allocation );

	/* Walk down the list (which implicitly touches each page).  If the
	   allocated region is larger than 4K, explicitly touch each 4K page.
	   This assumes a page size of 4K which is usually true (and difficult
	   to determine otherwise), in any case it doesn't make much difference
	   since nothing ever allocates more than two 4K pages */
	for( memBlockPtr = krnlData->allocatedListHead; memBlockPtr != NULL;
		 memBlockPtr = memBlockPtr->next )
		{
		const int pageSize = getSysVar( SYSVAR_PAGESIZE );

		/* If the allocated region has pages beyond the first one (which 
		   we've already touched by accessing the header), explicitly
		   touch those pages as well */
		if( memBlockPtr->size > pageSize )
			{
			BYTE *memPtr = ( BYTE * ) memBlockPtr + pageSize;
			int memSize = memBlockPtr->size;

			/* Touch each page.  The rather convoluted expression is to try
			   and stop it from being optimised away - it always evaluates to
			   true since we only get here if allocatedListHead != NULL, but
			   hopefully the compiler won't be able to figure that out */
			while( memSize > pageSize )
				{
				if( *memPtr || krnlData->allocatedListHead != NULL )
					memPtr += pageSize;
				memSize -= pageSize;
				}
			}
		}

	/* Unlock the allocation object to allow access by other threads */
	MUTEX_UNLOCK( allocation );
	}
#endif /* 0 */

/****************************************************************************
*																			*
*							Init/Shutdown Functions							*
*																			*
****************************************************************************/

/* Create and destroy the secure allocation information */

int initAllocation( KERNEL_DATA *krnlDataPtr )
	{
	int status;

	PRE( isWritePtr( krnlDataPtr, sizeof( KERNEL_DATA ) ) );

	/* Set up the reference to the kernel data block */
	krnlData = krnlDataPtr;

	/* Clear the list head and tail pointers */
	krnlData->allocatedListHead = krnlData->allocatedListTail = NULL;

	/* Initialize any data structures required to make the allocation thread-
	   safe */
	MUTEX_CREATE( allocation, status );
	ENSURES( cryptStatusOK( status ) );

	return( CRYPT_OK );
	}

void endAllocation( void )
	{
	/* Destroy any data structures required to make the allocation thread-
	   safe */
	MUTEX_DESTROY( allocation );

	krnlData = NULL;
	}

/****************************************************************************
*																			*
*					Windows Secure Memory Allocation Functions				*
*																			*
****************************************************************************/

#if defined( __WIN32__ )

#if !defined( NDEBUG ) && !defined( NT_DRIVER ) && !defined( __BORLANDC__ )
  #define USE_HEAP_CHECKING
#endif /* Win32 debug version */

#ifdef USE_HEAP_CHECKING
  #include <crtdbg.h>	/* For heap checking in debug version */
#endif /* USE_HEAP_CHECKING */

/* Get the start address of a page and, given an address in a page and a
   size, determine on which page the data ends.  These are used to determine
   which pages a memory block covers */

#if defined( _MSC_VER ) && ( _MSC_VER >= 1400 )
  #define PTR_TYPE	INT_PTR 
#else
  #define PTR_TYPE	long

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -