📄 sendmsg.c
字号:
{
if( messageQueueInfo != NULL )
*messageQueueInfo = messageQueue[ i ];
dequeueMessage( i );
return( TRUE );
}
}
/* Postcondition: There are no more messages for this object present in
the queue */
FORALL( i, 0, krnlData->queueEnd,
messageQueue[ i ].objectHandle != objectHandle );
return( FALSE );
}
/* Dequeue all messages for an object in the queue */
static void dequeueAllMessages( const int objectHandle )
{
/* Dequeue all messages for a given object */
while( getNextMessage( objectHandle, NULL ) );
/* Postcondition: There are no more messages for this object present in
the queue */
FORALL( i, 0, krnlData->queueEnd,
krnlData->messageQueue[ i ].objectHandle != objectHandle );
}
/****************************************************************************
* *
* Message Dispatcher *
* *
****************************************************************************/
/* Dispatch a message to an object */
static int dispatchMessage( const int localObjectHandle,
const MESSAGE_QUEUE_DATA *messageQueueData,
OBJECT_INFO *objectInfoPtr,
const void *aclPtr )
{
const MESSAGE_HANDLING_INFO *handlingInfoPtr = \
messageQueueData->handlingInfoPtr;
const MESSAGE_FUNCTION messageFunction = objectInfoPtr->messageFunction;
const MESSAGE_TYPE localMessage = messageQueueData->message & MESSAGE_MASK;
void *objectPtr = objectInfoPtr->objectPtr;
const int lockCount = objectInfoPtr->lockCount + 1;
int status;
PRE( isValidHandle( localObjectHandle ) );
PRE( isReadPtr( messageQueueData, sizeof( MESSAGE_QUEUE_DATA ) ) );
PRE( isWritePtr( objectInfoPtr, sizeof( OBJECT_INFO ) ) );
/* If there's a pre-dispatch handler present, apply it */
if( handlingInfoPtr->preDispatchFunction != NULL )
{
status = handlingInfoPtr->preDispatchFunction( localObjectHandle,
messageQueueData->message,
messageQueueData->messageDataPtr,
messageQueueData->messageValue,
aclPtr );
if( cryptStatusError( status ) )
return( status );
}
/* Mark the object as busy so that we have it available for our
exclusive use and further messages to it will be enqueued, dispatch
the message with the object table unlocked, and mark the object as
non-busy again */
objectInfoPtr->lockCount++;
#ifdef USE_THREADS
objectInfoPtr->lockOwner = THREAD_SELF();
#endif /* USE_THREADS */
MUTEX_UNLOCK( objectTable );
status = messageFunction( objectPtr, localMessage,
( void * ) messageQueueData->messageDataPtr,
messageQueueData->messageValue );
MUTEX_LOCK( objectTable );
objectInfoPtr = &krnlData->objectTable[ localObjectHandle ];
assert( localObjectHandle == SYSTEM_OBJECT_HANDLE || \
( objectInfoPtr->type == OBJECT_TYPE_USER && \
localMessage == MESSAGE_SETATTRIBUTE && \
messageQueueData->messageValue == \
localObjectHandle == SYSTEM_OBJECT_HANDLE ) || \
objectInfoPtr->lockCount == lockCount );
/* The system object and to a lesser extent the user object may unlock
themselves while processing a message when they forward the message
elsewhere or perform non-object-specific processing, so we only
decrement the lock count if it's unchanged and we still own the
object. We have to perform the ownership check to avoid the
situation where we unlock the object and another thread locks it,
leading to an (apparently) unchanged lock count */
if( objectInfoPtr->lockCount == lockCount && \
isObjectOwner( localObjectHandle ) )
objectInfoPtr->lockCount--;
/* Postcondition: The lock count is non-negative and, if it's not the
system object or a user object, has been reset to its previous
value */
POST( objectInfoPtr->lockCount >= 0 && \
( localObjectHandle == SYSTEM_OBJECT_HANDLE ||
( objectInfoPtr->type == OBJECT_TYPE_USER && \
localMessage == MESSAGE_SETATTRIBUTE && \
messageQueueData->messageValue == \
localObjectHandle == SYSTEM_OBJECT_HANDLE ) || \
objectInfoPtr->lockCount == lockCount - 1 ) );
/* If there's a post-dispatch handler present, apply it. Since a
destroy object message always succeeds but can return an error code
(typically CRYPT_ERROR_INCOMPLETE), we don't treat an error return as
a real error status for the purposes of further processing */
if( ( cryptStatusOK( status ) || localMessage == MESSAGE_DESTROY ) && \
handlingInfoPtr->postDispatchFunction != NULL )
status = handlingInfoPtr->postDispatchFunction( localObjectHandle,
messageQueueData->message,
messageQueueData->messageDataPtr,
messageQueueData->messageValue,
aclPtr );
return( status );
}
/* Send a message to an object */
int krnlSendMessage( const int objectHandle, const MESSAGE_TYPE message,
void *messageDataPtr, const int messageValue )
{
const ATTRIBUTE_ACL *attributeACL = NULL;
const MESSAGE_HANDLING_INFO *handlingInfoPtr;
OBJECT_INFO *objectTable = krnlData->objectTable;
OBJECT_INFO *objectInfoPtr;
MESSAGE_QUEUE_DATA enqueuedMessageData;
const BOOLEAN isInternalMessage = \
( message & MESSAGE_FLAG_INTERNAL ) ? TRUE : FALSE;
const void *aclPtr = NULL;
MESSAGE_TYPE localMessage = message & MESSAGE_MASK;
int localObjectHandle = objectHandle, status = CRYPT_OK;
/* Preconditions. For external messages we don't provide any assertions
at this point since they're coming straight from the user and could
contain any values, and for internal messages we only trap on
programming errors (thus for example isValidHandle() vs.
isValidObject(), since this would trap if a message is sent to a
destroyed object) */
PRE( isWritePtr( krnlData, sizeof( KERNEL_DATA ) ) );
PRE( isValidMessage( localMessage ) );
PRE( !isInternalMessage || isValidHandle( objectHandle ) );
/* Enforce the precondition at runtime as well */
if( !isValidMessage( localMessage ) )
{
assert( NOTREACHED );
return( CRYPT_ERROR_NOTAVAIL );
}
/* Get the information that we need to handle this message */
handlingInfoPtr = &messageHandlingInfo[ localMessage ];
/* Inner preconditions now that we have the handling information: Message
parameters must be within the allowed range (again, this traps on
programming errors only). This is done as a large number of
individual assertions rather than a single huge check so that a failed
assertion can provide more detailed information than just "it broke" */
PRE( handlingInfoPtr->paramCheck == PARAMTYPE_NONE_NONE ||
handlingInfoPtr->paramCheck == PARAMTYPE_NONE_ANY || \
handlingInfoPtr->paramCheck == PARAMTYPE_NONE_BOOLEAN || \
handlingInfoPtr->paramCheck == PARAMTYPE_NONE_CHECKTYPE || \
handlingInfoPtr->paramCheck == PARAMTYPE_DATA_NONE || \
handlingInfoPtr->paramCheck == PARAMTYPE_DATA_ANY || \
handlingInfoPtr->paramCheck == PARAMTYPE_DATA_BOOLEAN || \
handlingInfoPtr->paramCheck == PARAMTYPE_DATA_LENGTH || \
handlingInfoPtr->paramCheck == PARAMTYPE_DATA_OBJTYPE || \
handlingInfoPtr->paramCheck == PARAMTYPE_DATA_MECHTYPE || \
handlingInfoPtr->paramCheck == PARAMTYPE_DATA_ITEMTYPE || \
handlingInfoPtr->paramCheck == PARAMTYPE_DATA_FORMATTYPE || \
handlingInfoPtr->paramCheck == PARAMTYPE_DATA_COMPARETYPE );
PRE( handlingInfoPtr->paramCheck != PARAMTYPE_NONE_NONE || \
( handlingInfoPtr->paramCheck == PARAMTYPE_NONE_NONE && \
messageDataPtr == NULL && messageValue == 0 ) );
PRE( handlingInfoPtr->paramCheck != PARAMTYPE_NONE_ANY || \
( handlingInfoPtr->paramCheck == PARAMTYPE_NONE_ANY && \
messageDataPtr == NULL ) );
PRE( handlingInfoPtr->paramCheck != PARAMTYPE_NONE_BOOLEAN || \
( handlingInfoPtr->paramCheck == PARAMTYPE_NONE_BOOLEAN && \
messageDataPtr == NULL && \
( messageValue == FALSE || messageValue == TRUE ) ) );
PRE( handlingInfoPtr->paramCheck != PARAMTYPE_NONE_CHECKTYPE || \
( handlingInfoPtr->paramCheck == PARAMTYPE_NONE_CHECKTYPE && \
messageDataPtr == NULL && \
( messageValue > MESSAGE_CHECK_NONE && \
messageValue < MESSAGE_CHECK_LAST ) ) );
PRE( handlingInfoPtr->paramCheck != PARAMTYPE_DATA_NONE || \
( handlingInfoPtr->paramCheck == PARAMTYPE_DATA_NONE && \
messageDataPtr != NULL && messageValue == 0 ) );
PRE( handlingInfoPtr->paramCheck != PARAMTYPE_DATA_ANY || \
( handlingInfoPtr->paramCheck == PARAMTYPE_DATA_ANY && \
messageDataPtr != NULL ) );
PRE( handlingInfoPtr->paramCheck != PARAMTYPE_DATA_BOOLEAN || \
( handlingInfoPtr->paramCheck == PARAMTYPE_DATA_BOOLEAN && \
messageDataPtr != NULL && \
( messageValue == FALSE || messageValue == TRUE ) ) );
PRE( handlingInfoPtr->paramCheck != PARAMTYPE_DATA_LENGTH || \
( handlingInfoPtr->paramCheck == PARAMTYPE_DATA_LENGTH && \
messageDataPtr != NULL && messageValue >= 0 ) );
PRE( handlingInfoPtr->paramCheck != PARAMTYPE_DATA_OBJTYPE || \
( handlingInfoPtr->paramCheck == PARAMTYPE_DATA_OBJTYPE && \
messageDataPtr != NULL && \
( messageValue > OBJECT_TYPE_NONE && messageValue < OBJECT_TYPE_LAST ) ) );
PRE( handlingInfoPtr->paramCheck != PARAMTYPE_DATA_MECHTYPE || \
( handlingInfoPtr->paramCheck == PARAMTYPE_DATA_MECHTYPE && \
messageDataPtr != NULL && \
( messageValue > MECHANISM_NONE && messageValue < MECHANISM_LAST ) ) );
PRE( handlingInfoPtr->paramCheck != PARAMTYPE_DATA_ITEMTYPE || \
( handlingInfoPtr->paramCheck == PARAMTYPE_DATA_ITEMTYPE && \
messageDataPtr != NULL && \
( messageValue > KEYMGMT_ITEM_NONE && messageValue < KEYMGMT_ITEM_LAST ) ) );
PRE( handlingInfoPtr->paramCheck != PARAMTYPE_DATA_FORMATTYPE || \
( handlingInfoPtr->paramCheck == PARAMTYPE_DATA_FORMATTYPE && \
messageDataPtr != NULL && \
( messageValue > CRYPT_CERTFORMAT_NONE && messageValue < CRYPT_CERTFORMAT_LAST ) ) );
PRE( handlingInfoPtr->paramCheck != PARAMTYPE_DATA_COMPARETYPE || \
( handlingInfoPtr->paramCheck == PARAMTYPE_DATA_COMPARETYPE && \
messageDataPtr != NULL && \
( messageValue > MESSAGE_COMPARE_NONE && \
messageValue < MESSAGE_COMPARE_LAST ) ) );
/* If it's an object-manipulation message get the attribute's mandatory
ACL; if it's an object-parameter message get the parameter's mandatory
ACL. Since these doesn't require access to any object information, we
can do it before we lock the object table */
if( isAttributeMessage( localMessage ) )
{
attributeACL = findAttributeACL( messageValue, isInternalMessage );
if( attributeACL == NULL )
return( CRYPT_ARGERROR_VALUE );
aclPtr = attributeACL;
}
if( isParamMessage( localMessage ) )
aclPtr = findParamACL( localMessage );
/* Inner precondition: If it's an attribute-manipulation message, we have
a valid ACL for the attribute present */
PRE( !isAttributeMessage( localMessage ) || attributeACL != NULL );
/* If we're in the middle of a shutdown, don't allow any further
messages except ones related to object destruction (the status read
is needed for objects capable of performing async ops, since the
shutdown code needs to determine whether they're currently busy).
The check outside the object-table lock is done in order to have any
remaining active objects exit quickly without tying up the object
table, since we don't want them to block the shutdown. In addition
if the thread is a leftover/long-running thread that's still active
after the shutdown has occurred, we can't access the object table
lock since it'll have been deleted */
if( krnlData->shutdownLevel >= SHUTDOWN_LEVEL_MESSAGES && \
!( localMessage == MESSAGE_DESTROY || \
localMessage == MESSAGE_DECREFCOUNT || \
( localMessage == MESSAGE_GETATTRIBUTE && \
messageValue == CRYPT_IATTRIBUTE_STATUS ) ) )
return( CRYPT_ERROR_PERMISSION );
/* Lock the object table to ensure that other threads don't try to
access it */
MUTEX_LOCK( objectTable );
/* The first line of defence: Make sure that the message is being sent
to a valid object and that the object is externally visible and
accessible to the caller if required by the message. The checks
performed are:
if( handle does not correspond to an object )
error;
if( message is external )
{
if( object is internal )
error;
if( object isn't owned by calling thread )
error;
}
This is equivalent to the shorter form fullObjectCheck() that used
elsewhere. The error condition reported in all of these cases is
that the object handle isn't valid */
if( !isValidObject( objectHandle ) )
status = CRYPT_ARGERROR_OBJECT;
else
if( !isInternalMessage && \
( isInternalObject( objectHandle ) || \
!checkObjectOwnership( objectTable[ objectHandle ] ) ) )
status = CRYPT_ARGERROR_OBJECT;
if( cryptStatusError( status ) )
{
MUTEX_UNLOCK( objectTable );
return( status );
}
/* Inner precondition now that the outer check has been passed: It's a
valid, accessible object and not a system object that can never be
explicitly destroyed or have its refCount altered */
PRE( isValidObject( objectHandle ) );
PRE( isInternalMessage || ( !isInternalObject( objectHandle ) && \
checkObjectOwnership( objectTable[ objectHandle ] ) ) );
PRE( fullObjectCheck( objectHandle, message ) );
PRE( objectHandle >= NO_SYSTEM_OBJECTS || \
( localMessage != MESSAGE_DESTROY && \
localMessage != MESSAGE_DECREFCOUNT && \
localMessage != MESSAGE_INCREFCOUNT ) );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -