1 /****************************************************************************
2 *																			*
3 *							Semaphores and Mutexes							*
4 *						Copyright Peter Gutmann 1997-2005					*
5 *																			*
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9   #include "crypt.h"
10   #include "acl.h"
11   #include "kernel.h"
12 #else
13   #include "crypt.h"
14   #include "kernel/acl.h"
15   #include "kernel/kernel.h"
16 #endif /* Compiler-specific includes */
17 
18 /* A pointer to the kernel data block */
19 
20 static KERNEL_DATA *krnlData = NULL;
21 
22 /****************************************************************************
23 *																			*
24 *							Init/Shutdown Functions							*
25 *																			*
26 ****************************************************************************/
27 
28 /* A template to initialise the semaphore table */
29 
30 static const SEMAPHORE_INFO SEMAPHORE_INFO_TEMPLATE = \
31 				{ SEMAPHORE_STATE_UNINITED, 0, 0 };
32 
33 /* Create and destroy the semaphores and mutexes.  Since mutexes usually
34    aren't scalar values and are declared and accessed via macros that
35    manipulate various fields, we have to handle a pile of them individually
36    rather than using an array of mutexes */
37 
38 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
initSemaphores(INOUT KERNEL_DATA * krnlDataPtr)39 int initSemaphores( INOUT KERNEL_DATA *krnlDataPtr )
40 	{
41 	int i, status;
42 
43 	assert( isWritePtr( krnlDataPtr, sizeof( KERNEL_DATA ) ) );
44 
45 	static_assert( MUTEX_LAST == 4, "Mutex value" );
46 
47 	/* Set up the reference to the kernel data block */
48 	krnlData = krnlDataPtr;
49 
50 	/* Clear the semaphore table */
51 	for( i = 0; i < SEMAPHORE_LAST; i++ )
52 		krnlData->semaphoreInfo[ i ] = SEMAPHORE_INFO_TEMPLATE;
53 
54 	/* Initialize any data structures required to make the semaphore table
55 	   thread-safe */
56 	MUTEX_CREATE( semaphore, status );
57 	ENSURES( cryptStatusOK( status ) );
58 
59 	/* Initialize the mutexes */
60 	MUTEX_CREATE( mutex1, status );
61 	ENSURES( cryptStatusOK( status ) );
62 	MUTEX_CREATE( mutex2, status );
63 	ENSURES( cryptStatusOK( status ) );
64 	MUTEX_CREATE( mutex3, status );
65 	ENSURES( cryptStatusOK( status ) );
66 
67 	return( CRYPT_OK );
68 	}
69 
endSemaphores(void)70 void endSemaphores( void )
71 	{
72 	REQUIRES_V( ( krnlData->initLevel == INIT_LEVEL_KRNLDATA && \
73 				  krnlData->shutdownLevel == SHUTDOWN_LEVEL_NONE ) || \
74 				( krnlData->initLevel == INIT_LEVEL_KRNLDATA && \
75 				  krnlData->shutdownLevel == SHUTDOWN_LEVEL_MESSAGES ) || \
76 				( krnlData->initLevel == INIT_LEVEL_FULL && \
77 				  krnlData->shutdownLevel >= SHUTDOWN_LEVEL_MESSAGES ) );
78 
79 	/* Signal that kernel mechanisms are no longer available */
80 	krnlData->shutdownLevel = SHUTDOWN_LEVEL_MUTEXES;
81 
82 	/* Shut down the mutexes */
83 	MUTEX_DESTROY( mutex3 );
84 	MUTEX_DESTROY( mutex2 );
85 	MUTEX_DESTROY( mutex1 );
86 
87 	/* Destroy any data structures required to make the semaphore table
88 	   thread-safe */
89 	MUTEX_DESTROY( semaphore );
90 	}
91 
92 /****************************************************************************
93 *																			*
94 *							Semaphore Functions								*
95 *																			*
96 ****************************************************************************/
97 
98 /* Under multithreaded OSes, we often need to wait for certain events before
99    we can continue (for example when asynchronously accessing system
100    objects anything that depends on the object being available needs to
101    wait for the access to complete) or handle mutual exclusion when accessing
102    a shared resource.  The following functions abstract this handling,
103    providing a lightweight semaphore mechanism via mutexes, which is used
104    before checking a system synchronisation object (mutexes usually don't
105    require a kernel entry, while semaphores usually do).  The semaphore
106    function works a bit like the Win32 Enter/LeaveCriticalSection()
107    routines, which perform a quick check on a user-level lock and only call
108    the kernel-level handler if necessary (in most cases this isn't
109    necessary).  A useful side-effect is that since they work with
110    lightweight local locks instead of systemwide locking objects, they
111    aren't vulnerable to security problems where (for example) another
112    process can mess with a globally visible object handle.  This is
113    particularly problematic under Windows, where (for example) CreateMutex()
114    can return a handle to an already-existing object of the same name rather
115    than a newly-created object (there's no O_EXCL functionality).
116 
117    Semaphores are one-shots, so that once set and cleared they can't be
118    reset.  This is handled by enforcing the following state transitions:
119 
120 	Uninited -> Set | Clear
121 	Set -> Set | Clear
122 	Clear -> Clear
123 
124    The handling is complicated somewhat by the fact that on some systems the
125    semaphore has to be explicitly deleted, but only the last thread to use it
126    can safely delete it.  In order to handle this, we reference-count the
127    semaphore and let the last thread out delete it.  This is handled by
128    introducing an additional state preClear, which indicates that while the
129    semaphore object is still present, the last thread out should delete it,
130    bringing it to the true clear state */
131 
setSemaphore(IN_ENUM (SEMAPHORE)const SEMAPHORE_TYPE semaphore,const MUTEX_HANDLE object)132 void setSemaphore( IN_ENUM( SEMAPHORE ) const SEMAPHORE_TYPE semaphore,
133 				   const MUTEX_HANDLE object )
134 	{
135 	SEMAPHORE_INFO *semaphoreInfo;
136 
137 	REQUIRES_V( semaphore > SEMAPHORE_NONE && semaphore < SEMAPHORE_LAST );
138 
139 	/* It's safe to get a pointer to this outside the lock, we just can't
140 	   access it yet */
141 	semaphoreInfo = &krnlData->semaphoreInfo[ semaphore ];
142 
143 	/* Lock the semaphore table, set the semaphore, and unlock it again */
144 	MUTEX_LOCK( semaphore );
145 	if( semaphoreInfo->state == SEMAPHORE_STATE_UNINITED )
146 		{
147 		/* The semaphore can only be set if it's currently in the uninited
148 		   state.  Since the semaphore handle may be a non-scalar type we
149 		   have to use a cast to make it non-const (semaphoreInfo->object
150 		   can be const if it's a pointer but has to be non-const if it's
151 		   a scalar) */
152 		*semaphoreInfo = SEMAPHORE_INFO_TEMPLATE;
153 		semaphoreInfo->state = SEMAPHORE_STATE_SET;
154 		semaphoreInfo->object = ( MUTEX_HANDLE ) object;
155 		}
156 	MUTEX_UNLOCK( semaphore );
157 	}
158 
clearSemaphore(IN_ENUM (SEMAPHORE)const SEMAPHORE_TYPE semaphore)159 void clearSemaphore( IN_ENUM( SEMAPHORE ) const SEMAPHORE_TYPE semaphore )
160 	{
161 	SEMAPHORE_INFO *semaphoreInfo;
162 
163 	REQUIRES_V( semaphore > SEMAPHORE_NONE && semaphore < SEMAPHORE_LAST );
164 
165 	/* It's safe to get a pointer to this outside the lock, we just can't
166 	   access it yet */
167 	semaphoreInfo = &krnlData->semaphoreInfo[ semaphore ];
168 
169 	/* Lock the semaphore table, clear the semaphore, and unlock it again */
170 	MUTEX_LOCK( semaphore );
171 	if( semaphoreInfo->state == SEMAPHORE_STATE_SET )
172 		{
173 		/* Precondition: The reference count is valid.  Note that we have to
174 		   make this an assert() rather than a REQUIRES() because the latter
175 		   would exit with the semaphore still held */
176 #if !( defined( __WINCE__ ) && _WIN32_WCE < 400 )
177 		assert( semaphoreInfo[ semaphore ].refCount >= 0 );
178 #endif /* Fix for bug in PocketPC 2002 emulator with eVC++ 3.0 */
179 
180 		/* If there are threads waiting on this semaphore, tell the last
181 		   thread out to turn out the lights */
182 		if( semaphoreInfo->refCount > 0 )
183 			semaphoreInfo->state = SEMAPHORE_STATE_PRECLEAR;
184 		else
185 			{
186 			/* No threads waiting on the semaphore, we can delete it */
187 			THREAD_CLOSE( semaphoreInfo->object );
188 			*semaphoreInfo = SEMAPHORE_INFO_TEMPLATE;
189 			}
190 		}
191 	MUTEX_UNLOCK( semaphore );
192 	}
193 
194 /* Wait on a semaphore.  This occurs in two phases, first we extract the
195    information that we need from the semaphore table, then we unlock it and
196    wait on the semaphore if necessary.  This is necessary because the wait
197    can take an indeterminate amount of time and we don't want to tie up the
198    other semaphores while this occurs.  Note that this type of waiting on
199    local (rather than system) semaphores where possible greatly improves
200    performance, in some cases the wait on a signalled system semaphore can
201    take several seconds whereas waiting on the local semaphore only takes a
202    few ms.  Once the wait has completed, we update the semaphore state as
203    per the longer description above */
204 
205 CHECK_RETVAL_BOOL \
krnlWaitSemaphore(IN_ENUM (SEMAPHORE)const SEMAPHORE_TYPE semaphore)206 BOOLEAN krnlWaitSemaphore( IN_ENUM( SEMAPHORE ) const SEMAPHORE_TYPE semaphore )
207 	{
208 	SEMAPHORE_INFO *semaphoreInfo;
209 	MUTEX_HANDLE object DUMMY_INIT_MUTEX;
210 	BOOLEAN semaphoreSet = FALSE;
211 	int status = CRYPT_OK;
212 
213 	REQUIRES_B( semaphore > SEMAPHORE_NONE && semaphore < SEMAPHORE_LAST );
214 
215 	/* If we're in a shutdown and the semaphores have been destroyed, don't
216 	   try and acquire the semaphore mutex.  In this case anything that
217 	   they're protecting should be set to a shutdown state in which any
218 	   access fails, so this isn't a problem */
219 	if( krnlData->shutdownLevel >= SHUTDOWN_LEVEL_MUTEXES )
220 		return( FALSE );
221 
222 	/* Lock the semaphore table, extract the information that we need, and
223 	   unlock it again */
224 	semaphoreInfo = &krnlData->semaphoreInfo[ semaphore ];
225 	MUTEX_LOCK( semaphore );
226 	if( semaphoreInfo->state == SEMAPHORE_STATE_SET )
227 		{
228 		/* Precondition: The reference count is valid.  Note that we have to
229 		   make this an assert() rather than a REQUIRES() because the latter
230 		   would exit with the semaphore still held */
231 		assert( semaphoreInfo->refCount >= 0 );
232 
233 		/* The semaphore is set and not in use, extract the information we
234 		   require and mark is as being in use */
235 		object = semaphoreInfo->object;
236 		semaphoreInfo->refCount++;
237 		semaphoreSet = TRUE;
238 		}
239 	MUTEX_UNLOCK( semaphore );
240 
241 	/* If the semaphore wasn't set or is in use, exit now */
242 	if( !semaphoreSet )
243 		return( TRUE );
244 
245 	/* Wait on the object */
246 	assert( memcmp( &object, &SEMAPHORE_INFO_TEMPLATE.object,
247 					sizeof( MUTEX_HANDLE ) ) );
248 	THREAD_WAIT( object, status );
249 	if( cryptStatusError( status ) )
250 		{
251 		DEBUG_DIAG(( "Wait on object failed" ));
252 		assert( DEBUG_WARN );
253 		return( FALSE );
254 		}
255 
256 	/* Lock the semaphore table, update the information, and unlock it
257 	   again */
258 	MUTEX_LOCK( semaphore );
259 	if( semaphoreInfo->state == SEMAPHORE_STATE_SET || \
260 		semaphoreInfo->state == SEMAPHORE_STATE_PRECLEAR )
261 		{
262 		/* The semaphore is still set, update the reference count */
263 		semaphoreInfo->refCount--;
264 
265 		/* Inner precondition: The reference count is valid.  Note that we
266 		   have to make this an assert() rather than a REQUIRES() because
267 		   the latter would exit with the semaphore still held */
268 		assert( semaphoreInfo->refCount >= 0 );
269 
270 		/* If the object owner has signalled that it's done with the object
271 		   and the reference count has reached zero, we can delete it */
272 		if( semaphoreInfo->state == SEMAPHORE_STATE_PRECLEAR || \
273 			semaphoreInfo->refCount <= 0 )
274 			{
275 			/* No threads waiting on the semaphore, we can delete it */
276 			THREAD_CLOSE( object );
277 			*semaphoreInfo = SEMAPHORE_INFO_TEMPLATE;
278 			}
279 		}
280 	MUTEX_UNLOCK( semaphore );
281 
282 	return( TRUE );
283 	}
284 
285 /****************************************************************************
286 *																			*
287 *								Mutex Functions								*
288 *																			*
289 ****************************************************************************/
290 
291 /* Enter and exit a mutex */
292 
293 CHECK_RETVAL \
krnlEnterMutex(IN_ENUM (MUTEX)const MUTEX_TYPE mutex)294 int krnlEnterMutex( IN_ENUM( MUTEX ) const MUTEX_TYPE mutex )
295 	{
296 	REQUIRES( mutex > MUTEX_NONE && mutex < MUTEX_LAST );
297 
298 	/* If we're in a shutdown and the mutexes have been destroyed, don't
299 	   try and acquire them.  In this case anything that they're protecting
300 	   should be set to a shutdown state in which any access fails, so this
301 	   isn't a problem */
302 	if( krnlData->shutdownLevel >= SHUTDOWN_LEVEL_MUTEXES )
303 		return( CRYPT_ERROR_PERMISSION );
304 
305 	switch( mutex )
306 		{
307 		case MUTEX_SCOREBOARD:
308 			MUTEX_LOCK( mutex1 );
309 			break;
310 
311 		case MUTEX_SOCKETPOOL:
312 			MUTEX_LOCK( mutex2 );
313 			break;
314 
315 		case MUTEX_RANDOM:
316 			MUTEX_LOCK( mutex3 );
317 			break;
318 
319 		default:
320 			retIntError();
321 		}
322 
323 	return( CRYPT_OK );
324 	}
325 
krnlExitMutex(IN_ENUM (MUTEX)const MUTEX_TYPE mutex)326 void krnlExitMutex( IN_ENUM( MUTEX ) const MUTEX_TYPE mutex )
327 	{
328 	REQUIRES_V( mutex > MUTEX_NONE && mutex < MUTEX_LAST );
329 
330 	/* If we're in a shutdown and the mutexes have been destroyed, don't
331 	   try and acquire them.  In this case anything that they're protecting
332 	   should be set to a shutdown state in which any access fails, so this
333 	   isn't a problem */
334 	if( krnlData->shutdownLevel >= SHUTDOWN_LEVEL_MUTEXES )
335 		return;
336 
337 	switch( mutex )
338 		{
339 		case MUTEX_SCOREBOARD:
340 			MUTEX_UNLOCK( mutex1 );
341 			break;
342 
343 		case MUTEX_SOCKETPOOL:
344 			MUTEX_UNLOCK( mutex2 );
345 			break;
346 
347 		case MUTEX_RANDOM:
348 			MUTEX_UNLOCK( mutex3 );
349 			break;
350 
351 		default:
352 			retIntError_Void();
353 		}
354 	}
355