📄 cryptkrn.c
字号:
if( dependentObject != CRYPT_ERROR )
depth = \
( objectTable[ dependentObject ].dependentObject != CRYPT_ERROR || \
objectTable[ dependentObject ].dependentDevice != CRYPT_ERROR ) ? \
3 : 2;
else
if( objectTable[ objectHandle ].dependentDevice != CRYPT_ERROR )
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 )
{
unlockResource( objectTable );
krnlSendNotifier( objectHandle, IMESSAGE_DESTROY );
status = CRYPT_ERROR_INCOMPLETE;
lockResource( objectTable );
}
}
return( status );
}
int destroyObjects( void )
{
int depth, objectHandle, status = CRYPT_OK;
/* Indicate that we're in the middle of a shutdown. 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 */
isClosingDown = TRUE;
/* Lock the object table to ensure that other threads don't try to
access it */
lockResource( 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 dispatcher checks to
make sure that they're never destroyed through a standard message,
which indicates a programming error */
for( objectHandle = SYSTEM_OBJECT_HANDLE + 1;
objectHandle < NO_SYSTEM_OBJECTS; objectHandle++ )
{
if( objectTable[ objectHandle ].messageFunction != NULL )
objectTable[ objectHandle ].messageFunction( \
objectTable[ objectHandle ].objectPtr,
MESSAGE_DESTROY, NULL, 0 );
objectTable[ objectHandle ] = OBJECT_INFO_TEMPLATE;
}
/* 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 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, objectTableSize,
!memcmp( &objectTable[ i ], &OBJECT_INFO_TEMPLATE, \
sizeof( OBJECT_INFO ) ) );
/* Finally, destroy the root system object */
objectTable[ SYSTEM_OBJECT_HANDLE ].messageFunction( \
objectTable[ SYSTEM_OBJECT_HANDLE ].objectPtr,
MESSAGE_DESTROY, NULL, 0 );
objectTable[ SYSTEM_OBJECT_HANDLE ] = OBJECT_INFO_TEMPLATE;
/* Unlock the object table to allow access by other threads */
unlockResource( objectTable );
return( status );
}
static void endObjectTable( void )
{
/* Hinc igitur effuge */
lockResource( objectTable );
zeroise( objectTable, objectTableSize * sizeof( OBJECT_INFO ) );
clFree( "endObjectTable", objectTable );
objectTable = NULL;
isClosingDown = FALSE;
unlockResource( objectTable );
deleteResourceLock( objectTable );
}
/****************************************************************************
* *
* Alternative Object Acquisition *
* *
****************************************************************************/
/* Sending a message to an object only makes the one object which is the
target of the message available for use. When we need simultaneous
access to two objects (for example when copying a collection of cert
extensions from one cert to another), we have to use the krnlGetObject()/
krnlReleaseObject() functions to obtain access to the second object's
internals. These two functions can only provide access to certificates
(used when copying internal state such as cert extensions or CRL info
from one cert object to another), crypt hardware devices other than the
system object (used when a context tied to a device needs to perform an
operation using the device), and user objects (when committing config
data to persistent storage, we don't actually use the object data but
merely unlock it to allow others access while performing the potentially
lengthy update).
There is a second situation in which we need access to an object's
internals, and that occurs when we need to export/import a key from/to
a context. This is handled via the key extract functions at the end
of this module, see the comments there for further information */
/* Wait for an object to become available so that we can use it, with a
timeout for blocked objects. This is an internal function which is used
when mapping an object handle to object data, and is never called
directly. As an aid in identifying objects acting as bottlenecks, we
provide a function to warn about excessive waiting, along with information
on the object that was waited on, in debug mode */
#define MAX_WAITCOUNT 10000
#define WAITCOUNT_WARN_THRESHOLD 10
#ifndef NDEBUG
#include <stdio.h>
static void waitWarn( const int objectHandle, const int waitCount )
{
static const char *objectTypeNames[] = {
"None", "Context", "Keyset", "Envelope", "Certificate", "Device",
"Session", "User", "None", "None"
};
const OBJECT_INFO *objectInfoPtr = &objectTable[ objectHandle ];
char buffer[ 128 ];
if( objectHandle == SYSTEM_OBJECT_HANDLE )
strcpy( buffer, "system object" );
else
sPrintf( buffer, "%d (type %s, subtype %lX)",
objectHandle, objectInfoPtr->type, objectInfoPtr->subType );
fprintf( stderr, "\nWarning: Thread %X waited %d iteration%s for %s.\n",
THREAD_SELF(), waitCount, ( waitCount == 1 ) ? "" : "s",
buffer );
}
#endif /* Debug mode only */
static int waitForObject( const int objectHandle,
OBJECT_INFO **objectInfoPtrPtr )
{
const unsigned int uniqueID = objectTable[ objectHandle ].uniqueID;
int waitCount = 0;
/* Preconditions: The object is in use by another thread */
PRE( isValidObject( objectHandle ) );
PRE( isInUse( objectHandle ) && !isObjectOwner( objectHandle ) );
/* While the object is busy, put the thread to sleep. This is the
optimal portable way to wait on the resource, since it gives up this
thread's timeslice to allow other threads (including the one using
the object) to run (other methods such as mutexes with timers are
difficult to manage portably across different platforms) */
while( objectTable[ objectHandle ].uniqueID == uniqueID && \
isInUse( objectHandle ) && waitCount < MAX_WAITCOUNT && \
!isClosingDown )
{
unlockResource( objectTable );
waitCount++;
THREAD_YIELD();
lockResource( objectTable );
}
#ifndef NDEBUG
if( waitCount > WAITCOUNT_WARN_THRESHOLD )
/* If we waited more than WAITCOUNT_WARN_THRESHOLD iterations for
something this could be a sign of a resource usage bottleneck,
warn the user that there's a potential problem */
waitWarn( objectHandle, waitCount );
#endif /* NDEBUG */
/* If cryptlib is shutting down, exit */
if( isClosingDown )
return( CRYPT_ERROR_PERMISSION );
/* If we timed out waiting for the object, return a timeout error */
if( waitCount >= MAX_WAITCOUNT )
{
assert( NOTREACHED );
return( CRYPT_ERROR_TIMEOUT );
}
/* Make sure that nothing happened to the object while we were waiting
on it */
if( objectTable[ objectHandle ].uniqueID != uniqueID )
return( CRYPT_ERROR_SIGNALLED );
/* Update the object info pointer in case the object table was updated
while we had yielded control */
*objectInfoPtrPtr = &objectTable[ objectHandle ];
/* Postconditions: The object is available for use */
POST( isValidObject( objectHandle ) );
POST( !isInUse( objectHandle ) );
return( CRYPT_OK );
}
/* Release an object that we previously acquired directly. Note that we can
release the system object here (done when we don't need it any more but
need to carry out further operations with other objects), but we can't
ever acquire it */
static int releaseObject( const int objectHandle,
const BOOLEAN isNonKernelCall )
{
OBJECT_INFO *objectInfoPtr;
DECLARE_ORIGINAL_INT( lockCount );
lockResource( objectTable );
/* Preconditions: The object is in use by the caller */
PRE( isValidObject( objectHandle ) );
PRE( isInUse( objectHandle ) && isObjectOwner( objectHandle ) );
/* Perform similar access checks to the ones performed in
krnlSendMessage(): It's a valid object owned by the calling
thread */
if( !isValidObject( objectHandle ) || \
!checkObjectOwnership( objectTable[ objectHandle ] ) )
{
unlockResource( objectTable );
return( CRYPT_ARGERROR_OBJECT );
}
/* It's a valid object, get its info */
objectInfoPtr = &objectTable[ objectHandle ];
STORE_ORIGINAL_INT( lockCount, objectInfoPtr->lockCount );
/* Inner precondition: The object is in use and is of the correct type */
PRE( isInUse( objectHandle ) && isObjectOwner( objectHandle ) );
PRE( ( isNonKernelCall && \
( objectInfoPtr->type == OBJECT_TYPE_CERTIFICATE || \
objectInfoPtr->type == OBJECT_TYPE_DEVICE || \
objectInfoPtr->type == OBJECT_TYPE_USER ) ) || \
( !isNonKernelCall && objectInfoPtr->type == OBJECT_TYPE_CONTEXT ) );
/* Safety check: We should never be releasing an object that we don't
hold or which is of the incorrect type */
if( !isInUse( objectHandle ) || !isObjectOwner( objectHandle ) )
{
unlockResource( objectTable );
assert( NOTREACHED );
return( CRYPT_ERROR_PERMISSION );
}
if( ( isNonKernelCall && \
objectInfoPtr->type != OBJECT_TYPE_CERTIFICATE && \
objectInfoPtr->type != OBJECT_TYPE_DEVICE && \
objectInfoPtr->type != OBJECT_TYPE_USER ) || \
( !isNonKernelCall && objectInfoPtr->type != OBJECT_TYPE_CONTEXT ) )
{
unlockResource( objectTable );
assert( NOTREACHED );
return( CRYPT_ERROR_PERMISSION );
}
objectInfoPtr->lockCount--;
/* Postcondition: The object's lock count has been decremented and is
non-negative */
POST( objectInfoPtr->lockCount == \
ORIGINAL_VALUE( lockCount ) - 1 );
POST( objectInfoPtr->lockCount >= 0 );
unlockResource( objectTable );
return( CRYPT_OK );
}
/* Acquire/release an object */
int krnlGetObject( const int objectHandle, const OBJECT_TYPE type,
void **objectPtr, const int errorCode )
{
OBJECT_INFO *objectInfoPtr;
int status = CRYPT_OK;
/* Preconditions: It's a valid object */
PRE( isValidHandle( objectHandle ) && \
objectHandle != SYSTEM_OBJECT_HANDLE );
PRE( isValidType( type ) && \
( type == OBJECT_TYPE_CERTIFICATE || \
type == OBJECT_TYPE_DEVICE || type == OBJECT_TYPE_USER ) );
PRE( isWritePtr( objectPtr, sizeof( void * ) ) );
/* Clear the return value */
*objectPtr = NULL;
lockResource( objectTable );
/* Perform similar access checks to the ones performed in
krnlSendMessage(): It's a valid object of the correct type, and owned
by the calling thread */
if( !isValidObject( objectHandle ) || \
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -