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