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

📄 objects.c

📁 cryptlib是功能强大的安全工具集。允许开发人员快速在自己的软件中集成加密和认证服务。
💻 C
📖 第 1 页 / 共 2 页
字号:
   from the caller that the init stage is complete (which sets the object's
   state to OK), or a destroy object message, which sets the
   OBJECT_FLAG_SIGNALLED flag pending arrival of the init complete
   notification, whereupon the object is immediately destroyed.  The state
   diagram for this is:
									 State
						  Notinited			Signalled
			--------+-------------------+-----------------
			-> OK	| state -> OK,		| Msg -> Destroy
					| ret( OK )			|
	Msg.	Destroy	| state -> Sig'd,	| state -> Sig'd,
					| ret( OK )			| ret( OK )
			CtrlMsg	| process as usual	| process as usual
			NonCtrl	| ret( Notinited )	| ret( Sig'd )

   The initialisation process for an object is therefore:

	status = krnlCreateObject( ... );
	if( cryptStatusError( status ) )
		return( status );

	// Complete object-specific initialisation
	initStatus = ...;

	status = krnlSendMessage( ..., state -> CRYPT_OK );
	return( ( cryptStatusError( initStatus ) ? initStatus : status );

   If the object is destroyed during the object-specific initialisation
   (either by the init code when an error is encountered or due to an
   external signal), the destroy is deferred until the change state message
   at the end occurs.  If a destroy is pending, the change state is converted
   to a destroy and the newly-created object is destroyed.

   This mechanism ensures that the object table is only locked for a very
   short time (typically for only a few lines of executed code in the create
   object function) so that slow initialisation (for example of keyset
   objects associated with network links) can't block other objects.

   In addition to the locking, we need to be careful with how we create new
   objects because if we just allocate handles sequentially and reuse handles
   as soon as possible, an existing object could be signalled and a new one
   created in its place without the caller or owning object realizing that
   they're now working with a different object (although the kernel can tell
   them apart because it maintains an internal unique ID for each object).
   Unix systems handle this by always incrementing pids and assuming that 
   there won't be any problems when they wrap, we do the same thing but in
   addition allocate handles in a non-sequential manner using an LFSR to
   step through the object table.  There's no strong reason for this apart 
   from helping disabuse users of the notion that any cryptlib objects have 
   stdin/stdout-style fixed handles, but it only costs a few extra clocks so 
   we may as well do it */

static int findFreeResource( int value )
	{
	int oldValue = value, iterations;

	/* Preconditions: We're starting with a valid object handle, and it's not
	   a system object */
	PRE( isValidHandle( value ) );
	PRE( value >= NO_SYSTEM_OBJECTS );

	/* Step through the entire table looking for a free entry */
	for( iterations = 0; isValidHandle( value ) && \
						 iterations < krnlData->objectTableSize; \
		 iterations++ )
		{
		INV( iterations < krnlData->objectTableSize );

		/* Get the next value: Multiply by x and reduce by the polynomial */
		value <<= 1;
		if( value & krnlData->objectStateInfo.lfsrMask )
			value ^= krnlData->objectStateInfo.lfsrPoly;

		INV( isValidHandle( value ) );

		/* If we've found a free object or we've covered the entire table, 
		   exit.  We do this check after we update the value rather than as
		   part of the loop test to ensure that we always progress to a new
		   object handle whenever we call this function.  If we did the 
		   check as part of the loop test then deleting and creating an
		   object would result in the handle of the deleted object being
		   re-assigned to the new object */
		if( isFreeObject( value ) || value == oldValue )
			break;
		}
	if( value == oldValue || iterations >= krnlData->objectTableSize || \
		!isValidHandle( value ) )
		{
		/* Postcondition: We tried all locations and there are no free slots
		   available (or, vastly less likely, an internal error has 
		   occurred) */
		POST( iterations == krnlData->objectTableSize - 2 );
		FORALL( i, 0, krnlData->objectTableSize,
				krnlData->objectTable[ i ].objectPtr != NULL );

		return( CRYPT_ERROR );
		}

	/* Postconditions: We found a handle to a free slot */
	POST( isValidHandle( value ) );
	POST( isFreeObject( value ) );

	return( value );
	}

static int expandObjectTable( void )
	{
	static const int lfsrPolyTable[] = \
							{	  0x83,	   0x11D,	 0x211,	   0x409,
								 0x805,   0x1053,   0x201B,   0x402B,
								0x8003,  0x1002D,  0x20009,  0x40027,
							   0x80027, 0x100009, 0x200005, 0x400003 };
	OBJECT_INFO *newTable;
	int objectHandle, i;
	ORIGINAL_INT_VAR( oldLfsrPoly, krnlData->objectStateInfo.lfsrPoly );

	/* If we're already at the maximum number of allowed objects, don't
	   create any more.  This prevents both accidental runaway code that
	   creates huge numbers of objects and DoS attacks */
	if( krnlData->objectTableSize >= MAX_OBJECTS )
		return( CRYPT_ERROR_MEMORY );

	/* Precondition: We haven't exceeded the maximum number of objects */
	PRE( krnlData->objectTableSize < MAX_OBJECTS );

	/* Expand the table */
	newTable = clDynAlloc( "krnlCreateObject", \
						   ( krnlData->objectTableSize * 2 ) * \
								sizeof( OBJECT_INFO ) );
	if( newTable == NULL )
		return( CRYPT_ERROR_MEMORY );

	/* Copy the information across to the new table, set up the newly-
	   allocated entries, and clear the old table */
	memcpy( newTable, krnlData->objectTable,
			krnlData->objectTableSize * sizeof( OBJECT_INFO ) );
	for( i = krnlData->objectTableSize; \
		 i < krnlData->objectTableSize * 2; i++ )
		newTable[ i ] = OBJECT_INFO_TEMPLATE;
	zeroise( krnlData->objectTable, \
			 krnlData->objectTableSize * sizeof( OBJECT_INFO ) );
	clFree( "krnlCreateObject", krnlData->objectTable );
	krnlData->objectTable = newTable;
	krnlData->objectTableSize *= 2;

	/* Add the new object at the end of the existing table */
	krnlData->objectStateInfo.lfsrMask <<= 1;
	for( i = 0; i < 16; i++ )
		if( lfsrPolyTable[ i ] > krnlData->objectStateInfo.lfsrPoly )
			break;
	krnlData->objectStateInfo.lfsrPoly = lfsrPolyTable[ i ];
	objectHandle = findFreeResource( krnlData->objectStateInfo.objectHandle );

	/* Postcondition: We've moved on to the next LFSR polynomial value,
	   the LFSR output covers the entire table, and we now have roonm for 
	   the new object */
	POST( ( krnlData->objectStateInfo.lfsrPoly & ~0x7F ) == \
		  ( ORIGINAL_VALUE( oldLfsrPoly ) & ~0xFF ) << 1 );
	POST( krnlData->objectStateInfo.lfsrMask == \
		  ( krnlData->objectStateInfo.lfsrPoly & ~0x7F ) );
	POST( krnlData->objectTableSize == krnlData->objectStateInfo.lfsrMask );
	POST( isValidHandle( objectHandle ) );

	return( objectHandle );
	}

int krnlCreateObject( void **objectDataPtr, const int objectDataSize,
					  const OBJECT_TYPE type, const int subType,
					  const int createObjectFlags, const CRYPT_USER owner,
					  const int actionFlags,
					  MESSAGE_FUNCTION messageFunction )
	{
	OBJECT_INFO objectInfo;
	OBJECT_STATE_INFO *objectStateInfo = &krnlData->objectStateInfo;
	int objectHandle = objectStateInfo->objectHandle, bitCount;

	/* Preconditions (the subType check is just the standard hakmem bitcount
	   which ensures that we don't try and create multi-typed objects, the
	   sole exception to this rule is the default user object, which acts as
	   both a user and an SO object) */
	PRE( isWritePtr( krnlData, sizeof( KERNEL_DATA ) ) );
	PRE( isWritePtr( objectDataPtr, sizeof( void * ) ) );
	PRE( objectDataSize > 16 && objectDataSize < 16384 );
	PRE( isValidType( type ) );
	PRE( ( bitCount = ( subType & ~SUBTYPE_CLASS_MASK ) - \
						( ( ( subType & ~SUBTYPE_CLASS_MASK ) >> 1 ) & 033333333333 ) - \
						( ( ( subType & ~SUBTYPE_CLASS_MASK ) >> 2 ) & 011111111111 ) ) != 0 );
	PRE( ( ( bitCount + ( bitCount >> 3 ) ) & 030707070707 ) % 63 == 1 );
	PRE( !( createObjectFlags & \
			~( CREATEOBJECT_FLAG_SECUREMALLOC | CREATEOBJECT_FLAG_DUMMY ) ) );
	PRE( owner == CRYPT_UNUSED || isValidHandle( owner ) );
	PRE( actionFlags >= 0 && actionFlags < ACTION_PERM_LAST );
	PRE( messageFunction != NULL );

	/* Enforce the parameter check explicitly at runtime as well */
	bitCount = ( subType & ~SUBTYPE_CLASS_MASK ) - \
			   ( ( ( subType & ~SUBTYPE_CLASS_MASK ) >> 1 ) & 033333333333 ) - \
			   ( ( ( subType & ~SUBTYPE_CLASS_MASK ) >> 2 ) & 011111111111 );
	if( !isWritePtr( objectDataPtr, sizeof( void * ) ) || \
		objectDataSize <= 16 || objectDataSize >= 16384 || \
		!isValidType( type ) || \
		( ( bitCount + ( bitCount >> 3 ) ) & 030707070707 ) % 63 != 1 || \
		( createObjectFlags & \
			~( CREATEOBJECT_FLAG_SECUREMALLOC | CREATEOBJECT_FLAG_DUMMY ) ) || \
		( owner != CRYPT_UNUSED && !isValidHandle( owner ) ) || \
		actionFlags < 0 || actionFlags >= ACTION_PERM_LAST || \
		messageFunction == NULL )
		{
		assert( NOTREACHED );
		return( CRYPT_ERROR_PERMISSION );
		}

	*objectDataPtr = NULL;

	/* If we haven't been initialised yet or we're in the middle of a 
	   shutdown, we can't create any new objects */
	if( !isWritePtr( krnlData, sizeof( KERNEL_DATA ) ) || \
		!krnlData->isInitialised )
		return( CRYPT_ERROR_NOTINITED );
	if( krnlData->shutdownLevel >= SHUTDOWN_LEVEL_MESSAGES )
		{
		assert( NOTREACHED );
		return( CRYPT_ERROR_PERMISSION );
		}

	/* Allocate memory for the object and set up the object table entry.  The
	   object is always created as an internal object, it's up to the caller
	   to make it externally visible.  Since this step doesn't access the
	   object table, we do it outside the locked section */
	if( createObjectFlags & CREATEOBJECT_FLAG_SECUREMALLOC )
		{
		int status = krnlMemalloc( objectDataPtr, objectDataSize );
		if( cryptStatusError( status ) )
			return( status );
		}
	else
		if( ( *objectDataPtr = clAlloc( "krnlCreateObject", \
										objectDataSize ) ) == NULL )
			return( CRYPT_ERROR_MEMORY );
	memset( *objectDataPtr, 0, objectDataSize );
	objectInfo = OBJECT_INFO_TEMPLATE;
	objectInfo.objectPtr = *objectDataPtr;
	objectInfo.objectSize = objectDataSize;
	if( createObjectFlags & CREATEOBJECT_FLAG_SECUREMALLOC )
		objectInfo.flags |= OBJECT_FLAG_SECUREMALLOC;
	objectInfo.owner = owner;
	objectInfo.type = type;
	objectInfo.subType = subType;
	objectInfo.actionFlags = actionFlags;
	objectInfo.uniqueID = krnlData->objectUniqueID;
	objectInfo.messageFunction = messageFunction;

	/* Make sure that the kernel has been initialised and lock the object 
	   table for exclusive access */
	MUTEX_LOCK( initialisation );
	MUTEX_LOCK( objectTable );
	MUTEX_UNLOCK( initialisation );

	/* The first objects created are internal objects with predefined
	   handles (spes lucis aeternae).  As we create these objects we ratchet
	   up through the fixed handles until we reach the last fixed object,
	   whereupon we allocate handles normally */
	if( objectHandle < NO_SYSTEM_OBJECTS - 1 )
		{
		PRE( ( objectHandle == SYSTEM_OBJECT_HANDLE - 1 && \
			   owner == CRYPT_UNUSED && \
			   type == OBJECT_TYPE_DEVICE && \
			   subType == SUBTYPE_DEV_SYSTEM ) || \
			 ( objectHandle == DEFAULTUSER_OBJECT_HANDLE - 1 && \
			   owner == SYSTEM_OBJECT_HANDLE && \
			   type == OBJECT_TYPE_USER && \
			   subType == SUBTYPE_USER_SO ) );
		objectHandle++;
		POST( isValidHandle( objectHandle ) && \
			  objectHandle < NO_SYSTEM_OBJECTS && \
			  objectHandle == objectStateInfo->objectHandle + 1 );
		}
	else
		{
		PRE( isValidHandle( owner ) );

		/* Search the table for a free entry */
		objectHandle = findFreeResource( objectHandle );
		}

	/* If the table is full, expand it */
	if( !isValidHandle( objectHandle ) )
		{
		objectHandle = expandObjectTable();
		if( cryptStatusError( objectHandle ) )
			{
			MUTEX_UNLOCK( objectTable );

			/* Free the object instance data storage that we allocated 
			   earlier */
			if( objectInfo.flags & OBJECT_FLAG_SECUREMALLOC )
				krnlMemfree( &objectInfo.objectPtr );
			else
				{
				zeroise( objectInfo.objectPtr, objectInfo.objectSize );
				clFree( "destroyObjectData", objectInfo.objectPtr );
				}
			return( objectHandle );
			}
		}

	/* Inner precondition: This object table slot is free */
	PRE( isFreeObject( objectHandle ) );

	/* Set up the new object entry in the table and update the object table
	   state */
	krnlData->objectTable[ objectHandle ] = objectInfo;
	if( objectHandle == NO_SYSTEM_OBJECTS - 1 )
		{
		/* If this is the last system object, we've been allocating handles
		   sequentially up to this point.  From now on we start allocating
		   handles starting from a randomised location in the table */
		objectStateInfo->objectHandle = \
			( ( int ) getTime() ) & ( objectStateInfo->lfsrMask - 1 );
		if( objectStateInfo->objectHandle < NO_SYSTEM_OBJECTS )
			/* Can occur with probability 
			   NO_SYSTEM_OBJECTS / OBJECT_TABLE_ALLOCSIZE */
			objectStateInfo->objectHandle = NO_SYSTEM_OBJECTS + 42;
		}
	else
		objectStateInfo->objectHandle = objectHandle;

	/* Update the object unique ID value */
	if( krnlData->objectUniqueID < 0 || \
		krnlData->objectUniqueID >= INT_MAX - 1 )
		krnlData->objectUniqueID = NO_SYSTEM_OBJECTS;
	else
		krnlData->objectUniqueID++;
	POST( krnlData->objectUniqueID > 0 && \
		  krnlData->objectUniqueID < INT_MAX );

	/* Postconditions: It's a valid object that's been set up as required */
	POST( isValidObject( objectHandle ) );
	POST( objectInfo.objectPtr == *objectDataPtr );
	POST( objectInfo.owner == owner );
	POST( objectInfo.type == type );
	POST( objectInfo.subType == subType );
	POST( objectInfo.actionFlags == actionFlags );
	POST( objectInfo.messageFunction == messageFunction );

	MUTEX_UNLOCK( objectTable );
	return( objectHandle );
	}

⌨️ 快捷键说明

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