1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <pthread.h>
27 #include <syslog.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <sys/crypto/ioctl.h>
32 #include <security/cryptoki.h>
33 #include "kernelGlobal.h"
34 #include "kernelSession.h"
35 #include "kernelSlot.h"
36 #include "kernelEmulate.h"
37
38 static pthread_mutex_t delete_sessions_mutex = PTHREAD_MUTEX_INITIALIZER;
39
40 /*
41 * Delete all the sessions. First, obtain the slot lock.
42 * Then start to delete one session at a time. The boolean wrapper_only
43 * argument indicates that whether the caller only wants to clean up the
44 * session wrappers and the object wrappers in the library.
45 * - When this function is called by C_CloseAllSessions or indirectly by
46 * C_Finalize, wrapper_only is FALSE.
47 * - When this function is called by cleanup_child, wrapper_only is TRUE.
48 */
49 void
kernel_delete_all_sessions(CK_SLOT_ID slotID,boolean_t wrapper_only)50 kernel_delete_all_sessions(CK_SLOT_ID slotID, boolean_t wrapper_only)
51 {
52 kernel_session_t *session_p;
53 kernel_slot_t *pslot;
54
55 (void) pthread_mutex_lock(&delete_sessions_mutex);
56
57 pslot = slot_table[slotID];
58
59 /*
60 * Delete all the sessions in the slot's session list.
61 * The routine kernel_delete_session() updates the linked list.
62 * So, we do not need to maintain the list here.
63 */
64 for (;;) {
65 (void) pthread_mutex_lock(&pslot->sl_mutex);
66 if (pslot->sl_sess_list == NULL)
67 break;
68
69 session_p = pslot->sl_sess_list;
70 /*
71 * Set SESSION_IS_CLOSING flag so any access to this
72 * session will be rejected.
73 */
74 (void) pthread_mutex_lock(&session_p->session_mutex);
75 if (session_p->ses_close_sync & SESSION_IS_CLOSING) {
76 (void) pthread_mutex_unlock(&session_p->session_mutex);
77 continue;
78 }
79 session_p->ses_close_sync |= SESSION_IS_CLOSING;
80 (void) pthread_mutex_unlock(&session_p->session_mutex);
81
82 (void) pthread_mutex_unlock(&pslot->sl_mutex);
83 kernel_delete_session(slotID, session_p, B_FALSE, wrapper_only);
84 }
85 (void) pthread_mutex_unlock(&pslot->sl_mutex);
86 (void) pthread_mutex_unlock(&delete_sessions_mutex);
87 }
88
89 /*
90 * Create a new session struct, and add it to the slot's session list.
91 *
92 * This function is called by C_OpenSession(), which hold the slot lock.
93 */
94 CK_RV
kernel_add_session(CK_SLOT_ID slotID,CK_FLAGS flags,CK_VOID_PTR pApplication,CK_NOTIFY notify,CK_ULONG * sessionhandle_p)95 kernel_add_session(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication,
96 CK_NOTIFY notify, CK_ULONG *sessionhandle_p)
97 {
98 CK_RV rv = CKR_OK;
99 kernel_session_t *new_sp = NULL;
100 crypto_open_session_t open_session;
101 kernel_slot_t *pslot;
102 int r;
103
104 /* Allocate a new session struct */
105 new_sp = calloc(1, sizeof (kernel_session_t));
106 if (new_sp == NULL) {
107 return (CKR_HOST_MEMORY);
108 }
109
110 new_sp->magic_marker = KERNELTOKEN_SESSION_MAGIC;
111 new_sp->pApplication = pApplication;
112 new_sp->Notify = notify;
113 new_sp->flags = flags;
114 new_sp->ses_RO = (flags & CKF_RW_SESSION) ? B_FALSE : B_TRUE;
115 new_sp->ses_slotid = slotID;
116 new_sp->object_list = NULL;
117 new_sp->ses_refcnt = 0;
118 new_sp->ses_close_sync = 0;
119
120 /* Initialize the lock for the newly created session */
121 if (pthread_mutex_init(&new_sp->session_mutex, NULL) != 0) {
122 free(new_sp);
123 return (CKR_CANT_LOCK);
124 }
125
126 pslot = slot_table[slotID];
127 open_session.os_provider_id = pslot->sl_provider_id;
128 open_session.os_flags = flags;
129 while ((r = ioctl(kernel_fd, CRYPTO_OPEN_SESSION, &open_session)) < 0) {
130 if (errno != EINTR)
131 break;
132 }
133 if (r < 0) {
134 rv = CKR_FUNCTION_FAILED;
135 } else {
136 rv = crypto2pkcs11_error_number(open_session.os_return_value);
137 }
138
139 if (rv != CKR_OK) {
140 (void) pthread_mutex_destroy(&new_sp->session_mutex);
141 free(new_sp);
142 return (rv);
143 }
144
145 new_sp->k_session = open_session.os_session;
146
147 (void) pthread_mutex_init(&new_sp->ses_free_mutex, NULL);
148 (void) pthread_cond_init(&new_sp->ses_free_cond, NULL);
149
150 /* Insert the new session in front of the slot's session list */
151 if (pslot->sl_sess_list == NULL) {
152 pslot->sl_sess_list = new_sp;
153 new_sp->prev = NULL;
154 new_sp->next = NULL;
155 } else {
156 pslot->sl_sess_list->prev = new_sp;
157 new_sp->next = pslot->sl_sess_list;
158 new_sp->prev = NULL;
159 pslot->sl_sess_list = new_sp;
160 }
161
162 /* Type casting the address of a session struct to a session handle */
163 *sessionhandle_p = (CK_ULONG)new_sp;
164
165 return (CKR_OK);
166 }
167
168 /*
169 * Delete a session:
170 * - Remove the session from the slot's session list.
171 * - Release all the objects created by the session.
172 *
173 * The boolean argument slot_lock_held is used to indicate that whether
174 * the caller of this function holds the slot lock or not.
175 * - When called by kernel_delete_all_sessions(), which is called by
176 * C_Finalize() or C_CloseAllSessions() -- slot_lock_held = TRUE.
177 * - When called by C_CloseSession() -- slot_lock_held = FALSE.
178 */
179 void
kernel_delete_session(CK_SLOT_ID slotID,kernel_session_t * session_p,boolean_t slot_lock_held,boolean_t wrapper_only)180 kernel_delete_session(CK_SLOT_ID slotID, kernel_session_t *session_p,
181 boolean_t slot_lock_held, boolean_t wrapper_only)
182 {
183 crypto_session_id_t k_session;
184 crypto_close_session_t close_session;
185 kernel_slot_t *pslot;
186 kernel_object_t *objp;
187 kernel_object_t *objp1;
188
189 /*
190 * Check to see if the caller holds the lock on the global
191 * session list. If not, we need to acquire that lock in
192 * order to proceed.
193 */
194 pslot = slot_table[slotID];
195 if (!slot_lock_held) {
196 /* Acquire the slot lock */
197 (void) pthread_mutex_lock(&pslot->sl_mutex);
198 }
199
200 /*
201 * Remove the session from the slot's session list first.
202 */
203 if (pslot->sl_sess_list == session_p) {
204 /* Session is the first one in the list */
205 if (session_p->next) {
206 pslot->sl_sess_list = session_p->next;
207 session_p->next->prev = NULL;
208 } else {
209 /* Session is the only one in the list */
210 pslot->sl_sess_list = NULL;
211 }
212 } else {
213 /* Session is not the first one in the list */
214 if (session_p->next) {
215 /* Session is in the middle of the list */
216 session_p->prev->next = session_p->next;
217 session_p->next->prev = session_p->prev;
218 } else {
219 /* Session is the last one in the list */
220 session_p->prev->next = NULL;
221 }
222 }
223
224 if (!slot_lock_held) {
225 /*
226 * If the slot lock is obtained by
227 * this function, then release that lock after
228 * removing the session from session linked list.
229 * We want the releasing of the objects of the
230 * session, and freeing of the session itself to
231 * be done without holding the slot's session list
232 * lock.
233 */
234 (void) pthread_mutex_unlock(&pslot->sl_mutex);
235 }
236
237 /* Acquire the individual session lock */
238 (void) pthread_mutex_lock(&session_p->session_mutex);
239
240 /*
241 * Make sure another thread hasn't freed the session.
242 */
243 if (session_p->magic_marker != KERNELTOKEN_SESSION_MAGIC) {
244 (void) pthread_mutex_unlock(&session_p->session_mutex);
245 return;
246 }
247
248 /*
249 * The deletion of a session must be blocked when the session reference
250 * count is not zero. This means that if the thread that is attempting
251 * to close the session must wait until the prior operations on this
252 * session are finished.
253 *
254 * Unless we are being forced to shut everything down, this only
255 * happens if the library's _fini() is running not if someone
256 * explicitly called C_Finalize().
257 */
258 (void) pthread_mutex_lock(&session_p->ses_free_mutex);
259
260 if (wrapper_only) {
261 session_p->ses_refcnt = 0;
262 }
263
264 while (session_p->ses_refcnt != 0) {
265 /*
266 * We set the SESSION_REFCNT_WAITING flag before we put
267 * this closing thread in a wait state, so other non-closing
268 * operation thread will wake it up only when
269 * the session reference count becomes zero and this flag
270 * is set.
271 */
272 session_p->ses_close_sync |= SESSION_REFCNT_WAITING;
273 (void) pthread_mutex_unlock(&session_p->session_mutex);
274 (void) pthread_cond_wait(&session_p->ses_free_cond,
275 &session_p->ses_free_mutex);
276 (void) pthread_mutex_lock(&session_p->session_mutex);
277 }
278
279 session_p->ses_close_sync &= ~SESSION_REFCNT_WAITING;
280
281 /* Mark session as no longer valid. */
282 session_p->magic_marker = 0;
283
284 (void) pthread_mutex_unlock(&session_p->ses_free_mutex);
285 (void) pthread_mutex_destroy(&session_p->ses_free_mutex);
286 (void) pthread_cond_destroy(&session_p->ses_free_cond);
287
288 /*
289 * Remove all the objects created in this session, waiting
290 * until each object's refcnt is 0.
291 */
292 kernel_delete_all_objects_in_session(session_p, wrapper_only);
293
294 /* In case application did not call Final */
295 if (session_p->digest.context != NULL) {
296 digest_buf_t *bufp = session_p->digest.context;
297
298 if (bufp->buf != NULL) {
299 free_soft_ctx(get_sp(&session_p->digest), OP_DIGEST);
300 bzero(bufp->buf, bufp->indata_len);
301 free(bufp->buf);
302 }
303 free(bufp);
304 }
305
306 if (session_p->encrypt.context != NULL)
307 free(session_p->encrypt.context);
308
309 if (session_p->decrypt.context != NULL)
310 free(session_p->decrypt.context);
311
312 if (session_p->sign.context != NULL) {
313 digest_buf_t *bufp = session_p->sign.context;
314
315 if (bufp->buf != NULL) {
316 free_soft_ctx(get_sp(&session_p->sign), OP_SIGN);
317 bzero(bufp->buf, bufp->indata_len);
318 free(bufp->buf);
319 }
320 free(bufp);
321 }
322
323 if (session_p->verify.context != NULL) {
324 digest_buf_t *bufp = session_p->verify.context;
325
326 if (bufp->buf != NULL) {
327 free_soft_ctx(get_sp(&session_p->verify), OP_VERIFY);
328 bzero(bufp->buf, bufp->indata_len);
329 free(bufp->buf);
330 }
331 free(bufp);
332 }
333
334 k_session = session_p->k_session;
335
336 /* Reset SESSION_IS_CLOSING flag. */
337 session_p->ses_close_sync &= ~SESSION_IS_CLOSING;
338
339 (void) pthread_mutex_unlock(&session_p->session_mutex);
340 /* Destroy the individual session lock */
341 (void) pthread_mutex_destroy(&session_p->session_mutex);
342
343 if (!wrapper_only) {
344 close_session.cs_session = k_session;
345 while (ioctl(kernel_fd, CRYPTO_CLOSE_SESSION,
346 &close_session) < 0) {
347 if (errno != EINTR)
348 break;
349 }
350 /*
351 * Ignore ioctl return codes. If the library tells the kernel
352 * to close a session and the kernel says "I don't know what
353 * session you're talking about", there's not much that can be
354 * done. All sessions in the kernel will be closed when the
355 * application exits and closes /dev/crypto.
356 */
357 }
358 kernel_session_delay_free(session_p);
359
360 /*
361 * If there is no more session remained in this slot, reset the slot's
362 * session state to CKU_PUBLIC. Also, clean up all the token object
363 * wrappers in the library for this slot.
364 */
365 /* Acquire the slot lock if lock is not held */
366 if (!slot_lock_held) {
367 (void) pthread_mutex_lock(&pslot->sl_mutex);
368 }
369
370 if (pslot->sl_sess_list == NULL) {
371 /* Reset the session auth state. */
372 pslot->sl_state = CKU_PUBLIC;
373
374 /* Clean up token object wrappers. */
375 objp = pslot->sl_tobj_list;
376 while (objp) {
377 objp1 = objp->next;
378 (void) pthread_mutex_destroy(&objp->object_mutex);
379 (void) kernel_object_delay_free(objp);
380 objp = objp1;
381 }
382 pslot->sl_tobj_list = NULL;
383 }
384
385 /* Release the slot lock if lock is not held */
386 if (!slot_lock_held) {
387 (void) pthread_mutex_unlock(&pslot->sl_mutex);
388 }
389 }
390
391 /*
392 * This function is used to type cast a session handle to a pointer to
393 * the session struct. Also, it does the following things:
394 * 1) Check to see if the session struct is tagged with a session
395 * magic number. This is to detect when an application passes
396 * a bogus session pointer.
397 * 2) Acquire the locks on the designated session.
398 * 3) Check to see if the session is in the closing state that another
399 * thread is performing.
400 * 4) Increment the session reference count by one. This is to prevent
401 * this session from being closed by other thread.
402 * 5) Release the locks on the designated session.
403 */
404 CK_RV
handle2session(CK_SESSION_HANDLE hSession,kernel_session_t ** session_p)405 handle2session(CK_SESSION_HANDLE hSession, kernel_session_t **session_p)
406 {
407 kernel_session_t *sp = (kernel_session_t *)(hSession);
408 CK_RV rv;
409
410 if ((sp == NULL) ||
411 (sp->magic_marker != KERNELTOKEN_SESSION_MAGIC)) {
412 return (CKR_SESSION_HANDLE_INVALID);
413 } else {
414 (void) pthread_mutex_lock(&sp->session_mutex);
415 if (sp->ses_close_sync & SESSION_IS_CLOSING) {
416 rv = CKR_SESSION_CLOSED;
417 } else {
418 /* Increment session ref count. */
419 sp->ses_refcnt++;
420 rv = CKR_OK;
421 }
422 (void) pthread_mutex_unlock(&sp->session_mutex);
423 }
424
425 if (rv == CKR_OK)
426 *session_p = sp;
427
428 return (rv);
429 }
430
431 /*
432 * This function adds the to-be-freed session to a linked list.
433 * When the number of sessions queued in the linked list reaches the
434 * maximum threshold MAX_SES_TO_BE_FREED, it will free the first
435 * session (FIFO) in the list.
436 */
437 void
kernel_session_delay_free(kernel_session_t * sp)438 kernel_session_delay_free(kernel_session_t *sp)
439 {
440 kernel_session_t *tmp;
441
442 (void) pthread_mutex_lock(&ses_delay_freed.ses_to_be_free_mutex);
443
444 /* Add the newly deleted session at the end of the list */
445 sp->next = NULL;
446 if (ses_delay_freed.first == NULL) {
447 ses_delay_freed.last = sp;
448 ses_delay_freed.first = sp;
449 } else {
450 ses_delay_freed.last->next = sp;
451 ses_delay_freed.last = sp;
452 }
453
454 if (++ses_delay_freed.count >= MAX_SES_TO_BE_FREED) {
455 /*
456 * Free the first session in the list only if
457 * the total count reaches maximum threshold.
458 */
459 ses_delay_freed.count--;
460 tmp = ses_delay_freed.first->next;
461 free(ses_delay_freed.first);
462 ses_delay_freed.first = tmp;
463 }
464 (void) pthread_mutex_unlock(&ses_delay_freed.ses_to_be_free_mutex);
465 }
466
467 /*
468 * Acquire all slots' mutexes and all their sessions' mutexes.
469 * Order:
470 * 1. delete_sessions_mutex
471 * for each slot:
472 * 2. pslot->sl_mutex
473 * for each session:
474 * 3. session_p->session_mutex
475 * 4. session_p->ses_free_mutex
476 */
477 void
kernel_acquire_all_slots_mutexes()478 kernel_acquire_all_slots_mutexes()
479 {
480 int slotID;
481 kernel_slot_t *pslot;
482 kernel_session_t *session_p;
483
484 (void) pthread_mutex_lock(&delete_sessions_mutex);
485
486 for (slotID = 0; slotID < slot_count; slotID++) {
487 pslot = slot_table[slotID];
488 (void) pthread_mutex_lock(&pslot->sl_mutex);
489
490 /* Iterate through sessions acquiring all mutexes */
491 session_p = pslot->sl_sess_list;
492 while (session_p) {
493 struct object *objp;
494
495 (void) pthread_mutex_lock(&session_p->session_mutex);
496 (void) pthread_mutex_lock(&session_p->ses_free_mutex);
497
498 objp = session_p->object_list;
499 while (objp) {
500 (void) pthread_mutex_lock(&objp->object_mutex);
501 objp = objp->next;
502 }
503
504 session_p = session_p->next;
505 }
506 }
507 }
508
509 /* Release in opposite order to kernel_acquire_all_slots_mutexes(). */
510 void
kernel_release_all_slots_mutexes()511 kernel_release_all_slots_mutexes()
512 {
513 int slotID;
514 kernel_slot_t *pslot;
515 kernel_session_t *session_p;
516
517 for (slotID = 0; slotID < slot_count; slotID++) {
518 pslot = slot_table[slotID];
519
520 /* Iterate through sessions releasing all mutexes */
521 session_p = pslot->sl_sess_list;
522 while (session_p) {
523 struct object *objp;
524
525 objp = session_p->object_list;
526 while (objp) {
527 (void) pthread_mutex_unlock(
528 &objp->object_mutex);
529 objp = objp->next;
530 }
531
532 (void) pthread_mutex_unlock(&session_p->ses_free_mutex);
533 (void) pthread_mutex_unlock(&session_p->session_mutex);
534 session_p = session_p->next;
535 }
536
537 (void) pthread_mutex_unlock(&pslot->sl_mutex);
538 }
539
540 (void) pthread_mutex_unlock(&delete_sessions_mutex);
541 }
542