📄 objects.c
字号:
/****************************************************************************
* *
* Kernel Object Management *
* Copyright Peter Gutmann 1997-2005 *
* *
****************************************************************************/
#include <stdlib.h>
#if defined( INC_ALL )
#include "crypt.h"
#include "acl.h"
#include "kernel.h"
#elif defined( INC_CHILD )
#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 */
/* The initial allocation size of the object table. In memory-starved
environments we limit the size, in general these are embedded systems or
single-tasking OSes that aren't going to need many objects anyway */
#ifdef CONFIG_CONSERVE_MEMORY
#define OBJECT_TABLE_ALLOCSIZE 128
#define INITIAL_LFSRPOLY 0x83
#else
#define OBJECT_TABLE_ALLOCSIZE 1024
#define INITIAL_LFSRPOLY 0x409
#endif /* Memory-starved environments */
/* A pointer to the kernel data block */
static KERNEL_DATA *krnlData = NULL;
/* A template used to initialise object table entries. Some of the entries
are either object handles that have to be set to CRYPT_ERROR or values
for which 0 is significant (so they're set to CRYPT_UNUSED), because of
this we can't just memset the entry to all zeroes */
static const OBJECT_INFO OBJECT_INFO_TEMPLATE = {
OBJECT_TYPE_NONE, 0, /* Type, subtype */
NULL, 0, /* Object data and size */
OBJECT_FLAG_INTERNAL | OBJECT_FLAG_NOTINITED, /* Flags */
0, /* Action flags */
0, 0, /* Ref.count, lock count */
#ifdef USE_THREADS
THREAD_INITIALISER, /* Lock owner */
#endif /* USE_THREADS */
0, /* Unique ID */
CRYPT_UNUSED, CRYPT_UNUSED, /* Forward count, usage count */
#ifdef USE_THREADS
THREAD_INITIALISER, /* Owner */
#endif /* USE_THREADS */
NULL, /* Message function */
CRYPT_ERROR, CRYPT_ERROR,
CRYPT_ERROR /* Owning/dependent objects */
};
/* A template used to initialise the object allocation state data */
static const OBJECT_STATE_INFO OBJECT_STATE_INFO_TEMPLATE = {
OBJECT_TABLE_ALLOCSIZE, /* Mask for LFSR output */
INITIAL_LFSRPOLY, /* LFSR polynomial */
-1 /* Initial-1'th object handle */
};
/****************************************************************************
* *
* Init/Shutdown Functions *
* *
****************************************************************************/
/* Create and destroy the object table. The destroy process is handled in
two stages, the first of which is called fairly early in the shutdown
process to destroy any remaining objects, and the second which is called
at the end of the shutdown when the kernel data is being deleted. This
is because some of the objects are tied to things like external devices,
and deleting them at the end when everything else has been shut down
isn't possible */
int initObjects( KERNEL_DATA *krnlDataPtr )
{
int i;
/* Perform a consistency check on various things that need to be set
up in a certain way for things to work properly */
assert( OBJECT_TABLE_ALLOCSIZE >= 64 );
assert( OBJECT_INFO_TEMPLATE.type == OBJECT_TYPE_NONE );
assert( OBJECT_INFO_TEMPLATE.subType == 0 );
assert( OBJECT_INFO_TEMPLATE.objectPtr == NULL );
assert( OBJECT_INFO_TEMPLATE.objectSize == 0 );
assert( OBJECT_INFO_TEMPLATE.flags == \
( OBJECT_FLAG_INTERNAL | OBJECT_FLAG_NOTINITED ) );
assert( OBJECT_INFO_TEMPLATE.actionFlags == 0 );
assert( OBJECT_INFO_TEMPLATE.forwardCount == CRYPT_UNUSED );
assert( OBJECT_INFO_TEMPLATE.usageCount == CRYPT_UNUSED );
assert( OBJECT_INFO_TEMPLATE.owner == CRYPT_ERROR );
assert( OBJECT_INFO_TEMPLATE.dependentDevice == CRYPT_ERROR );
assert( OBJECT_INFO_TEMPLATE.dependentObject == CRYPT_ERROR );
assert( SYSTEM_OBJECT_HANDLE == NO_SYSTEM_OBJECTS - 2 );
assert( DEFAULTUSER_OBJECT_HANDLE == NO_SYSTEM_OBJECTS - 1 );
/* Set up the reference to the kernel data block */
krnlData = krnlDataPtr;
/* Allocate and initialise the object table */
krnlData->objectTable = \
clAlloc( "initObjectTable",
OBJECT_TABLE_ALLOCSIZE * sizeof( OBJECT_INFO ) );
if( krnlData->objectTable == NULL )
return( CRYPT_ERROR_MEMORY );
for( i = 0; i < OBJECT_TABLE_ALLOCSIZE; i++ )
krnlData->objectTable[ i ] = OBJECT_INFO_TEMPLATE;
krnlData->objectTableSize = OBJECT_TABLE_ALLOCSIZE;
krnlData->objectStateInfo = OBJECT_STATE_INFO_TEMPLATE;
/* Initialise object-related information. This isn't strictly part of
the object table but is used to assign unique ID values to objects
within the table, since table entries (object handles) may be reused
as objects are destroyed and new ones created in their place */
krnlData->objectUniqueID = 0;
/* Initialize any data structures required to make the object table
thread-safe */
MUTEX_CREATE( objectTable );
/* Postconditions */
POST( krnlData->objectTable != NULL );
POST( krnlData->objectTableSize == OBJECT_TABLE_ALLOCSIZE );
FORALL( i, 0, OBJECT_TABLE_ALLOCSIZE,
!memcmp( &krnlData->objectTable[ i ], &OBJECT_INFO_TEMPLATE, \
sizeof( OBJECT_INFO ) ) );
POST( krnlData->objectStateInfo.lfsrMask == OBJECT_TABLE_ALLOCSIZE && \
krnlData->objectStateInfo.lfsrPoly == INITIAL_LFSRPOLY && \
krnlData->objectStateInfo.objectHandle == SYSTEM_OBJECT_HANDLE - 1 );
POST( krnlData->objectUniqueID == 0 );
return( CRYPT_OK );
}
void endObjects( void )
{
/* Hinc igitur effuge */
MUTEX_LOCK( objectTable );
zeroise( krnlData->objectTable,
krnlData->objectTableSize * sizeof( OBJECT_INFO ) );
clFree( "endObjectTable", krnlData->objectTable );
krnlData->objectTable = NULL;
krnlData->objectTableSize = 0;
krnlData->objectUniqueID = 0;
MUTEX_UNLOCK( objectTable );
MUTEX_DESTROY( objectTable );
krnlData = NULL;
}
/****************************************************************************
* *
* Object Table Management *
* *
****************************************************************************/
/* Destroy an object's instance data and object table entry */
void destroyObjectData( const int objectHandle )
{
OBJECT_INFO *objectInfoPtr = &krnlData->objectTable[ objectHandle ];
assert( isWritePtr( objectInfoPtr->objectPtr,
objectInfoPtr->objectSize ) );
/* Destroy the object's data and clear the object table entry */
if( objectInfoPtr->flags & OBJECT_FLAG_SECUREMALLOC )
krnlMemfree( &objectInfoPtr->objectPtr );
else
{
zeroise( objectInfoPtr->objectPtr, objectInfoPtr->objectSize );
clFree( "destroyObjectData", objectInfoPtr->objectPtr );
}
krnlData->objectTable[ objectHandle ] = OBJECT_INFO_TEMPLATE;
}
/* Destroy an object. This is only called when cryptlib is shutting down,
normally objects are destroyed directly in response to messages */
static void destroyObject( const int objectHandle )
{
const MESSAGE_FUNCTION messageFunction = \
krnlData->objectTable[ objectHandle ].messageFunction;
/* If there's no object present at this position, just clear the
entry (it should be cleared anyway) */
if( messageFunction == NULL )
{
krnlData->objectTable[ objectHandle ] = OBJECT_INFO_TEMPLATE;
return;
}
/* Destroy the object and its object table entry */
messageFunction( krnlData->objectTable[ objectHandle ].objectPtr,
MESSAGE_DESTROY, NULL, 0 );
destroyObjectData( objectHandle );
}
/* Destroy all objects at a given nesting level */
static int destroySelectedObjects( const int currentDepth )
{
const OBJECT_INFO *objectTable = krnlData->objectTable;
int objectHandle, status = CRYPT_OK;
for( objectHandle = NO_SYSTEM_OBJECTS; \
objectHandle < krnlData->objectTableSize; \
objectHandle++ )
{
const int dependentObject = \
objectTable[ objectHandle ].dependentObject;
int depth = 1;
/* If there's nothing there, continue */
if( objectTable[ objectHandle ].objectPtr == NULL )
continue;
/* There's an object still present, determine its nesting depth.
Dependent devices are terminal so we only follow the path down for
dependent objects */
if( isValidObject( dependentObject ) )
{
if( isValidObject( objectTable[ dependentObject ].dependentObject ) )
depth = 3;
else
if( isValidObject( objectTable[ dependentObject ].dependentDevice ) )
depth = 2;
}
else
if( isValidObject( objectTable[ objectHandle ].dependentDevice ) )
depth = 2;
/* If the nesting level of the object matches the current level,
destroy it. We unlock the object table around the access to
prevent remaining active objects from blocking the shutdown (the
closingDown flag takes care of any other messages that may arrive
during this process).
"For death is come up into our windows, and it is entered into
our palaces, to cut off the children from the without"
-- Jeremiah 9:21 */
if( depth >= currentDepth )
{
MUTEX_UNLOCK( objectTable );
krnlSendNotifier( objectHandle, IMESSAGE_DESTROY );
status = CRYPT_ERROR_INCOMPLETE;
MUTEX_LOCK( objectTable );
}
}
return( status );
}
/* Destroy all objects */
int destroyObjects( void )
{
OBJECT_INFO *objectTable = krnlData->objectTable;
int depth, objectHandle, status = CRYPT_OK;
PRE( krnlData->shutdownLevel == SHUTDOWN_LEVEL_THREADS );
/* Indicate that we're shutting down the object handling. From now on
all messages other than object-destruction ones will be rejected by
the kernel. This is needed in order to have any remaining active
objects exit quickly, since we don't want them to block the shutdown.
Note that we do this before we lock the object table to encourage
anything that might have the table locked to exit quickly once we try
and lock the table */
krnlData->shutdownLevel = SHUTDOWN_LEVEL_MESSAGES;
/* Lock the object table to ensure that other threads don't try to
access it */
MUTEX_LOCK( objectTable );
/* Destroy all system objects except the root system object ("The death
of God left the angels in a strange position" - Donald Barthelme, "On
Angels"). We have to do this before we destroy any unclaimed
leftover objects because some of them may depend on system objects,
if the system objects aren't destroyed they'll be erroneously flagged
as leftover objects. The destruction is done explicitly by invoking
the object's message function directly because the message dispatcher
checks to make sure that they're never destroyed through a standard
message, which would indicate a programming error */
for( objectHandle = SYSTEM_OBJECT_HANDLE + 1;
objectHandle < NO_SYSTEM_OBJECTS; objectHandle++ )
destroyObject( objectHandle );
/* Postcondition: All system objects except the root system object have
been destroyed */
FORALL( i, SYSTEM_OBJECT_HANDLE + 1, NO_SYSTEM_OBJECTS,
!memcmp( &objectTable[ i ], &OBJECT_INFO_TEMPLATE, \
sizeof( OBJECT_INFO ) ) );
/* Delete any unclaimed leftover objects. This is rather more complex
than just rumbling through deleting each object we find since some
objects have dependent objects underneath them, and deleting the
lower-level object causes problems when we later delete their parents
(the code handles it cleanly, but we get a kernel trap warning us that
we're trying to delete a non-present object). Because of this we have
to delete the objects in order of depth, first all three-level objects
(e.g. cert -> context -> device), then all two-level objects, and
finally all one-level objects. This means that we can never delete
another object out from under a dependent object */
for( depth = 3; depth > 0; depth-- )
{
int localStatus = destroySelectedObjects( depth );
if( cryptStatusError( localStatus ) )
status = localStatus;
}
/* Postcondition: All objects except the root system object have been
destroyed */
FORALL( i, SYSTEM_OBJECT_HANDLE + 1, krnlData->objectTableSize,
!memcmp( &objectTable[ i ], &OBJECT_INFO_TEMPLATE, \
sizeof( OBJECT_INFO ) ) );
/* Finally, destroy the system root object */
destroyObject( SYSTEM_OBJECT_HANDLE );
/* Unlock the object table to allow access by other threads */
MUTEX_UNLOCK( objectTable );
return( status );
}
/****************************************************************************
* *
* Object Creation/Destruction *
* *
****************************************************************************/
/* Create a new object. This function has to be very careful about locking
to ensure that another thread can't manipulate the newly-created object
while it's in an indeterminate state. To accomplish this it locks the
object table and tries to create the new object. If this succeeds it sets
the OBJECT_FLAG_NOTINITED flag pending completion of the object's
initialisation by the caller, unlocks the object table, and returns
control to the caller. While the object is in this state, the kernel
will allow it to process only two message types, either a notification
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -