📄 pgpmemorymgrwin32.c
字号:
/*____________________________________________________________________________
Copyright (C) 1997 Network Associates Inc. and affiliated companies.
All rights reserved.
Win32-specific functions to plug into the PGPMemoryMgr:
pgpCreateStandardMemoryMgr
pgpDisposeStandardMemoryMgrUserValue
$Id: pgpMemoryMgrWin32.c,v 1.13 1999/03/10 02:53:26 heller Exp $
____________________________________________________________________________*/
#include "pgpPFLErrors.h"
#include "pgpMem.h"
#include "pgpMemoryMgrPriv.h"
#define INTEGRITY_CHECKS PGP_DEBUG
#if PGP_WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
/* header containing device driver definitions */
#include "pgpMemLockWin32.h"
/* names of device drivers used for memory locking */
static const char kPGPMemLockDriver95Name[] = "\\\\.\\PGPMemLock.vxd";
static const char kPGPMemLockDriverNTName[] = "\\\\.\\PGPMEMLOCK";
#else
typedef void * HANDLE;
#endif
/*____________________________________________________________________________
[Secure memory only]
kPageSize page size suitable for VM allocation and locking
kMinHeapSize minimum size of heap we'll create
kChunkSize granularity of allocation and alignment value
nothing smaller can be allocated and therefore,
every allocation is aligned to this value.
kMinLeftoverBytes dont create a free block with fewer bytes than this
____________________________________________________________________________*/
#define kPageSize ( (PGPSize)4096 )
#define kMinHeapSizeBytes ( kPageSize * 2 )
#define kChunkSize ( 32 )
#define kMinLeftoverBytes pgpMax( kChunkSize, sizeof( ChunkHeader ) )
/*____________________________________________________________________________
[Secure memory only]
Free space is linked together in a list in each heap.
'numChunks' contains the total size of the block, in chunks, which
includes the ChunkHeader itself.
____________________________________________________________________________*/
typedef struct ChunkHeader
{
struct ChunkHeader * next;
struct ChunkHeader * prev;
PGPUInt32 numChunks;
} ChunkHeader;
/*____________________________________________________________________________
[Secure memory only]
A PageHeap keeps a memory heap on a contiguous range of pages.
Free space is maintained in a free list; there is no overhead to
allocated items other than our chunk size requirement.
____________________________________________________________________________*/
typedef struct PageHeap
{
struct PageHeap * next;
struct PageHeap * prev;
HANDLE hDriver;
void * pages;
PGPUInt32 numPages;
PGPBoolean isNonPageable;
PGPUInt32 numFreeChunks;
ChunkHeader * freeList;
} PageHeap;
/*____________________________________________________________________________
[Secure memory only]
A pointer to this struct is stored as the customValue of the MemoryMgr.
____________________________________________________________________________*/
typedef struct MyData
{
/* handle of loaded driver; NULL=>no driver loaded */
HANDLE hDriver;
PageHeap * heapList;
PageHeap * lastHeapUsed;
} MyData;
static PageHeap * sCreateHeap( HANDLE hDriver, PGPSize heapSize );
static void sDisposeHeap( HANDLE hDriver, PageHeap *heap );
static PageHeap * sCreateAndAddHeap( MyData * myData, PGPSize heapSize );
static void sRemoveAndDisposeHeap( MyData *myData, PageHeap *heap );
static PGPBoolean sHeapOwnsAllocation( PageHeap const *heap,
void const *allocation );
static PGPBoolean sHeapIsEmpty( PageHeap const *heap );
static void * sAllocateBytes( MyData *myData,
PGPSize requestSize, PGPBoolean *isNonPageable );
static void sFreeBytes( MyData *myData,
void *allocation, PGPSize allocationSize );
static void * sHeapAllocateChunks( PageHeap *heap,
PGPUInt32 allocChunks, PGPBoolean *isNonPageable );
static void sHeapFreeChunks( PageHeap *heap,
void *ptr, PGPUInt32 numChunks );
#if INTEGRITY_CHECKS /* [ */
static void sHeapValidate( PageHeap const *heap );
#else
#define sHeapValidate( heap ) /* nothing */
#endif
static PGPError sInitMyData( MyData *myData );
static PGPError sCleanupMyData( MyData *myData );
static void sLockMemory( HANDLE hDriver, void *mem, PGPSize numBytes,
PGPBoolean *isNonPageable );
static void sUnlockMemory( HANDLE hDriver, void *mem, PGPSize numBytes );
static void *
sInternalAlloc( PGPSize numBytes )
{
void * result = malloc( numBytes );
if ( IsntNull( result ) )
{
pgpClearMemory( result, numBytes );
}
return( result );
}
static void
sInternalFree( void *ptr )
{
if ( IsntNull( ptr ) )
free( ptr );
}
/*____________________________________________________________________________
For non-secure memory allocation, we just use standard malloc/realloc/free
____________________________________________________________________________*/
static void *
sWin32MemoryAllocationProc(
PGPMemoryMgrRef mgr,
PGPUserValue customValue,
PGPSize allocationSize,
PGPMemoryMgrFlags flags )
{
(void) mgr;
(void) flags;
(void) customValue;
return( malloc( allocationSize ) );
}
static PGPError
sWin32MemoryDeallocationProc(
PGPMemoryMgrRef mgr,
PGPUserValue customValue,
void * allocation,
PGPSize allocationSize )
{
(void) mgr;
(void) allocationSize;
(void) customValue;
free( allocation );
return( kPGPError_NoErr );
}
static PGPError
sWin32MemoryReallocationProc(
PGPMemoryMgrRef mgr,
PGPUserValue customValue,
void ** allocation,
PGPSize newAllocationSize,
PGPMemoryMgrFlags flags,
PGPSize existingSize )
{
PGPError err;
void * oldPtr = *allocation;
void * newPtr = NULL;
(void) mgr;
(void) flags;
(void) existingSize;
(void) customValue;
newPtr = realloc( oldPtr, newAllocationSize );
if ( IsNull( newPtr ) )
{
err = kPGPError_OutOfMemory;
}
else
{
err = kPGPError_NoErr;
*allocation = newPtr;
}
return( err );
}
/*____________________________________________________________________________
Win32 version
Under Win32 we can lock individual pages or ranges of pages by using
APIs which are available only to device drivers. In order to avoid any
potential problems derived from locking pages in the process heaps,
we restrict ourselves to locking pages which are directly assigned to
us from the OS using the Win32 API function VirtualAlloc. Using
VirtualAlloc we can obtain virtual pages of memory from our process's
private address space and which are outside the process heaps. Also,
VirtualAlloc gives us committed and page-aligned memory, two other
requirements for pagelocking.
Memory is allocated with a granularity of 4K bytes (the page size
in Win32).
____________________________________________________________________________*/
static void *
sWin32SecureMemoryAllocationProc(
PGPMemoryMgrRef mgr,
PGPUserValue customValue,
PGPSize allocationSize,
PGPMemoryMgrFlags flags,
PGPBoolean * isNonPageable )
{
void * result;
MyData * myData = (MyData *)customValue;
(void) mgr;
(void) flags;
*isNonPageable = FALSE;
result = sAllocateBytes( myData, allocationSize, isNonPageable );
return( result );
}
/*____________________________________________________________________________
Win32 secure memory deallocator.
____________________________________________________________________________*/
static PGPError
sWin32SecureMemoryDeallocationProc(
PGPMemoryMgrRef mgr,
PGPUserValue customValue,
void * allocation,
PGPSize allocationSize,
PGPBoolean nonPageable)
{
MyData * myData = (MyData *)customValue;
(void) mgr;
(void) allocationSize;
(void) nonPageable;
sFreeBytes( myData, allocation, allocationSize );
return( kPGPError_NoErr );
}
static HANDLE
sGetMyDriver( void )
{
HANDLE hDriver = NULL;
#if PGP_WIN32
OSVERSIONINFO osid;
osid.dwOSVersionInfoSize = sizeof ( osid );
GetVersionEx ( &osid );
/* load correct memory-locking driver on basis of which
OS we're running under */
switch ( osid.dwPlatformId ) {
/* Windows 95 */
case VER_PLATFORM_WIN32_WINDOWS :
hDriver =
CreateFile ( kPGPMemLockDriver95Name,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_FLAG_DELETE_ON_CLOSE,
NULL );
// pgpFixBeforeShip ("Need to do something if driver load fails");
/// pgpAssertMsg ( hDriver != INVALID_HANDLE_VALUE,
/// "Could not load page-locking driver" );
if ( hDriver == INVALID_HANDLE_VALUE )
{
hDriver = NULL;
}
break;
/* Windows NT */
case VER_PLATFORM_WIN32_NT :
hDriver =
CreateFile ( kPGPMemLockDriverNTName,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL );
// pgpFixBeforeShip ("Need to do something if driver load fails");
/// pgpAssertMsg ( hDriver != INVALID_HANDLE_VALUE,
/// "Could not load page-locking driver" );
if ( hDriver == INVALID_HANDLE_VALUE )
{
hDriver = NULL;
}
break;
/* all other OSes */
default :
pgpDebugMsg( "unknown platform" );
break;
}
#endif
return( hDriver );
}
/*____________________________________________________________________________
Initialize MyData data structure. It has already been allocated.
____________________________________________________________________________*/
static PGPError
sInitMyData( MyData *myData )
{
PGPError err = kPGPError_NoErr;
PGPValidatePtr( myData );
myData->hDriver = sGetMyDriver();
myData->heapList = NULL;
myData->lastHeapUsed = NULL;
return err;
}
/*____________________________________________________________________________
Dispose MyData data structure contents and free it.
____________________________________________________________________________*/
static PGPError
sCleanupMyData( MyData *myData )
{
PageHeap * heap = NULL;
pgpAssertMsg( IsNull( myData->heapList ),
"sCleanupMyData(): WARNING: secure memory is being leaked" );
while ( IsntNull( myData->heapList ) )
{
sRemoveAndDisposeHeap( myData, myData->heapList );
}
#if PGP_WIN32
if ( myData->hDriver != NULL )
{
CloseHandle ( myData->hDriver );
myData->hDriver = NULL;
}
#endif
sInternalFree( myData );
return kPGPError_NoErr;
}
PGPError
pgpCreateStandardMemoryMgr( PGPMemoryMgrRef *newMemoryMgr )
{
PGPError err = kPGPError_NoErr;
MyData * pmyData = NULL;
PGPValidatePtr( newMemoryMgr );
*newMemoryMgr = NULL;
/* allocate private data which we will store as the customValue */
pmyData = (MyData *)sInternalAlloc( sizeof( MyData ) );
if ( IsntNull( pmyData ) )
{
PGPNewMemoryMgrStruct custom;
pgpClearMemory( pmyData, sizeof( MyData ) );
err = sInitMyData( pmyData );
if ( IsntPGPError( err ) )
{
pgpClearMemory( &custom, sizeof( custom ) );
custom.customValue = (PGPUserValue)pmyData;
custom.sizeofStruct = sizeof( custom );
custom.allocProc = sWin32MemoryAllocationProc;
custom.reallocProc = sWin32MemoryReallocationProc;
custom.deallocProc = sWin32MemoryDeallocationProc;
custom.secureAllocProc = sWin32SecureMemoryAllocationProc;
custom.secureDeallocProc = sWin32SecureMemoryDeallocationProc;
err = PGPNewMemoryMgrCustom( &custom, newMemoryMgr );
if ( IsPGPError( err ) )
{
sCleanupMyData( pmyData );
}
}
if ( IsPGPError( err ) )
{
/* creation failed...dispose our private data */
sInternalFree( pmyData );
}
}
else
{
err = kPGPError_OutOfMemory;
}
return( err );
}
PGPError
pgpDisposeStandardMemoryMgrUserValue( PGPUserValue customValue )
{
MyData * pmyData = (MyData *)customValue;
sCleanupMyData( pmyData );
return( kPGPError_NoErr );
}
/*____________________________________________________________________________
Allocate a page of memory from the VM system and make it non-pageable
if possible.
____________________________________________________________________________*/
static void *
sAllocatePages(
HANDLE hDriver, /* may be NULL */
PGPUInt32 numPages,
PGPBoolean * isNonPageable )
{
void * result = NULL;
pgpAssert( IsntNull( isNonPageable ) );
*isNonPageable = FALSE;
#if PGP_WIN32
/* since the first parameter to VirtualAlloc is NULL, it automatically
rounds allocation size up to next page boundary */
result = VirtualAlloc ( NULL,
numPages * kPageSize, MEM_COMMIT, PAGE_READWRITE );
if ( IsntNull( result ) )
{
sLockMemory( hDriver, result, numPages * kPageSize, isNonPageable );
}
#else
(void)hDriver;
result = sInternalAlloc( numPages * kPageSize );
#endif
return( result );
}
/*____________________________________________________________________________
Free pages allocated with sAllocatePages()
____________________________________________________________________________*/
static void
sFreePages(
HANDLE hDriver, /* may be NULL */
void * pages,
PGPUInt32 numPages,
PGPBoolean nonPageable )
{
#if PGP_WIN32
/* we can assume it has already been safely cleared */
if ( nonPageable )
{
sUnlockMemory( hDriver, pages, numPages * kPageSize );
}
VirtualFree( pages, 0, MEM_RELEASE );
#else
(void)hDriver;
(void)numPages;
(void)nonPageable;
sInternalFree( (Ptr)pages );
#endif
}
/*____________________________________________________________________________
Create a heap of the specified size.
____________________________________________________________________________*/
static PageHeap *
sCreateHeap(
HANDLE hDriver,
PGPSize heapSize)
{
PGPError err = kPGPError_NoErr;
PageHeap * heap = NULL;
PGPUInt32 numPages;
PGPUInt32 numChunks;
numPages = heapSize / kPageSize;
if ( ( heapSize % kPageSize ) != 0 )
numPages += 1;
numChunks = ( numPages * kPageSize ) / kChunkSize;
heap = (PageHeap *)sInternalAlloc( sizeof( *heap ) );
if ( IsntNull( heap ) )
{
heap->hDriver = hDriver;
heap->numPages = numPages;
heap->numFreeChunks = numChunks;
heap->pages = sAllocatePages( hDriver,
numPages, &heap->isNonPageable );
if ( IsntNull( heap->pages ) )
{
ChunkHeader * chunkHeader = (ChunkHeader *)heap->pages;
chunkHeader->next = NULL;
chunkHeader->prev = NULL;
chunkHeader->numChunks = numChunks;
heap->freeList = chunkHeader;
}
else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -