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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
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"
38 static pthread_mutex_t delete_sessions_mutex
= PTHREAD_MUTEX_INITIALIZER
;
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.
50 kernel_delete_all_sessions(CK_SLOT_ID slotID
, boolean_t wrapper_only
)
52 kernel_session_t
*session_p
;
55 (void) pthread_mutex_lock(&delete_sessions_mutex
);
57 pslot
= slot_table
[slotID
];
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.
65 (void) pthread_mutex_lock(&pslot
->sl_mutex
);
66 if (pslot
->sl_sess_list
== NULL
)
69 session_p
= pslot
->sl_sess_list
;
71 * Set SESSION_IS_CLOSING flag so any access to this
72 * session will be rejected.
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
);
79 session_p
->ses_close_sync
|= SESSION_IS_CLOSING
;
80 (void) pthread_mutex_unlock(&session_p
->session_mutex
);
82 (void) pthread_mutex_unlock(&pslot
->sl_mutex
);
83 kernel_delete_session(slotID
, session_p
, B_FALSE
, wrapper_only
);
85 (void) pthread_mutex_unlock(&pslot
->sl_mutex
);
86 (void) pthread_mutex_unlock(&delete_sessions_mutex
);
90 * Create a new session struct, and add it to the slot's session list.
92 * This function is called by C_OpenSession(), which hold the slot lock.
95 kernel_add_session(CK_SLOT_ID slotID
, CK_FLAGS flags
, CK_VOID_PTR pApplication
,
96 CK_NOTIFY notify
, CK_ULONG
*sessionhandle_p
)
99 kernel_session_t
*new_sp
= NULL
;
100 crypto_open_session_t open_session
;
101 kernel_slot_t
*pslot
;
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
);
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;
120 /* Initialize the lock for the newly created session */
121 if (pthread_mutex_init(&new_sp
->session_mutex
, NULL
) != 0) {
123 return (CKR_CANT_LOCK
);
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) {
134 rv
= CKR_FUNCTION_FAILED
;
136 rv
= crypto2pkcs11_error_number(open_session
.os_return_value
);
140 (void) pthread_mutex_destroy(&new_sp
->session_mutex
);
145 new_sp
->k_session
= open_session
.os_session
;
147 (void) pthread_mutex_init(&new_sp
->ses_free_mutex
, NULL
);
148 (void) pthread_cond_init(&new_sp
->ses_free_cond
, NULL
);
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
;
156 pslot
->sl_sess_list
->prev
= new_sp
;
157 new_sp
->next
= pslot
->sl_sess_list
;
159 pslot
->sl_sess_list
= new_sp
;
162 /* Type casting the address of a session struct to a session handle */
163 *sessionhandle_p
= (CK_ULONG
)new_sp
;
170 * - Remove the session from the slot's session list.
171 * - Release all the objects created by the session.
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.
180 kernel_delete_session(CK_SLOT_ID slotID
, kernel_session_t
*session_p
,
181 boolean_t slot_lock_held
, boolean_t wrapper_only
)
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
;
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
194 pslot
= slot_table
[slotID
];
195 if (!slot_lock_held
) {
196 /* Acquire the slot lock */
197 (void) pthread_mutex_lock(&pslot
->sl_mutex
);
201 * Remove the session from the slot's session list first.
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
;
209 /* Session is the only one in the list */
210 pslot
->sl_sess_list
= NULL
;
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
;
219 /* Session is the last one in the list */
220 session_p
->prev
->next
= NULL
;
224 if (!slot_lock_held
) {
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
234 (void) pthread_mutex_unlock(&pslot
->sl_mutex
);
237 /* Acquire the individual session lock */
238 (void) pthread_mutex_lock(&session_p
->session_mutex
);
241 * Make sure another thread hasn't freed the session.
243 if (session_p
->magic_marker
!= KERNELTOKEN_SESSION_MAGIC
) {
244 (void) pthread_mutex_unlock(&session_p
->session_mutex
);
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.
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().
258 (void) pthread_mutex_lock(&session_p
->ses_free_mutex
);
261 session_p
->ses_refcnt
= 0;
264 while (session_p
->ses_refcnt
!= 0) {
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
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
);
279 session_p
->ses_close_sync
&= ~SESSION_REFCNT_WAITING
;
281 /* Mark session as no longer valid. */
282 session_p
->magic_marker
= 0;
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
);
289 * Remove all the objects created in this session, waiting
290 * until each object's refcnt is 0.
292 kernel_delete_all_objects_in_session(session_p
, wrapper_only
);
294 /* In case application did not call Final */
295 if (session_p
->digest
.context
!= NULL
) {
296 digest_buf_t
*bufp
= session_p
->digest
.context
;
298 if (bufp
->buf
!= NULL
) {
299 free_soft_ctx(get_sp(&session_p
->digest
), OP_DIGEST
);
300 bzero(bufp
->buf
, bufp
->indata_len
);
306 free(session_p
->encrypt
.context
);
308 free(session_p
->decrypt
.context
);
310 if (session_p
->sign
.context
!= NULL
) {
311 digest_buf_t
*bufp
= session_p
->sign
.context
;
313 if (bufp
->buf
!= NULL
) {
314 free_soft_ctx(get_sp(&session_p
->sign
), OP_SIGN
);
315 bzero(bufp
->buf
, bufp
->indata_len
);
321 if (session_p
->verify
.context
!= NULL
) {
322 digest_buf_t
*bufp
= session_p
->verify
.context
;
324 if (bufp
->buf
!= NULL
) {
325 free_soft_ctx(get_sp(&session_p
->verify
), OP_VERIFY
);
326 bzero(bufp
->buf
, bufp
->indata_len
);
332 k_session
= session_p
->k_session
;
334 /* Reset SESSION_IS_CLOSING flag. */
335 session_p
->ses_close_sync
&= ~SESSION_IS_CLOSING
;
337 (void) pthread_mutex_unlock(&session_p
->session_mutex
);
338 /* Destroy the individual session lock */
339 (void) pthread_mutex_destroy(&session_p
->session_mutex
);
342 close_session
.cs_session
= k_session
;
343 while (ioctl(kernel_fd
, CRYPTO_CLOSE_SESSION
,
344 &close_session
) < 0) {
349 * Ignore ioctl return codes. If the library tells the kernel
350 * to close a session and the kernel says "I don't know what
351 * session you're talking about", there's not much that can be
352 * done. All sessions in the kernel will be closed when the
353 * application exits and closes /dev/crypto.
356 kernel_session_delay_free(session_p
);
359 * If there is no more session remained in this slot, reset the slot's
360 * session state to CKU_PUBLIC. Also, clean up all the token object
361 * wrappers in the library for this slot.
363 /* Acquire the slot lock if lock is not held */
364 if (!slot_lock_held
) {
365 (void) pthread_mutex_lock(&pslot
->sl_mutex
);
368 if (pslot
->sl_sess_list
== NULL
) {
369 /* Reset the session auth state. */
370 pslot
->sl_state
= CKU_PUBLIC
;
372 /* Clean up token object wrappers. */
373 objp
= pslot
->sl_tobj_list
;
376 (void) pthread_mutex_destroy(&objp
->object_mutex
);
377 (void) kernel_object_delay_free(objp
);
380 pslot
->sl_tobj_list
= NULL
;
383 /* Release the slot lock if lock is not held */
384 if (!slot_lock_held
) {
385 (void) pthread_mutex_unlock(&pslot
->sl_mutex
);
390 * This function is used to type cast a session handle to a pointer to
391 * the session struct. Also, it does the following things:
392 * 1) Check to see if the session struct is tagged with a session
393 * magic number. This is to detect when an application passes
394 * a bogus session pointer.
395 * 2) Acquire the locks on the designated session.
396 * 3) Check to see if the session is in the closing state that another
397 * thread is performing.
398 * 4) Increment the session reference count by one. This is to prevent
399 * this session from being closed by other thread.
400 * 5) Release the locks on the designated session.
403 handle2session(CK_SESSION_HANDLE hSession
, kernel_session_t
**session_p
)
405 kernel_session_t
*sp
= (kernel_session_t
*)(hSession
);
409 (sp
->magic_marker
!= KERNELTOKEN_SESSION_MAGIC
)) {
410 return (CKR_SESSION_HANDLE_INVALID
);
412 (void) pthread_mutex_lock(&sp
->session_mutex
);
413 if (sp
->ses_close_sync
& SESSION_IS_CLOSING
) {
414 rv
= CKR_SESSION_CLOSED
;
416 /* Increment session ref count. */
420 (void) pthread_mutex_unlock(&sp
->session_mutex
);
430 * This function adds the to-be-freed session to a linked list.
431 * When the number of sessions queued in the linked list reaches the
432 * maximum threshold MAX_SES_TO_BE_FREED, it will free the first
433 * session (FIFO) in the list.
436 kernel_session_delay_free(kernel_session_t
*sp
)
438 kernel_session_t
*tmp
;
440 (void) pthread_mutex_lock(&ses_delay_freed
.ses_to_be_free_mutex
);
442 /* Add the newly deleted session at the end of the list */
444 if (ses_delay_freed
.first
== NULL
) {
445 ses_delay_freed
.last
= sp
;
446 ses_delay_freed
.first
= sp
;
448 ses_delay_freed
.last
->next
= sp
;
449 ses_delay_freed
.last
= sp
;
452 if (++ses_delay_freed
.count
>= MAX_SES_TO_BE_FREED
) {
454 * Free the first session in the list only if
455 * the total count reaches maximum threshold.
457 ses_delay_freed
.count
--;
458 tmp
= ses_delay_freed
.first
->next
;
459 free(ses_delay_freed
.first
);
460 ses_delay_freed
.first
= tmp
;
462 (void) pthread_mutex_unlock(&ses_delay_freed
.ses_to_be_free_mutex
);
466 * Acquire all slots' mutexes and all their sessions' mutexes.
468 * 1. delete_sessions_mutex
472 * 3. session_p->session_mutex
473 * 4. session_p->ses_free_mutex
476 kernel_acquire_all_slots_mutexes()
479 kernel_slot_t
*pslot
;
480 kernel_session_t
*session_p
;
482 (void) pthread_mutex_lock(&delete_sessions_mutex
);
484 for (slotID
= 0; slotID
< slot_count
; slotID
++) {
485 pslot
= slot_table
[slotID
];
486 (void) pthread_mutex_lock(&pslot
->sl_mutex
);
488 /* Iterate through sessions acquiring all mutexes */
489 session_p
= pslot
->sl_sess_list
;
493 (void) pthread_mutex_lock(&session_p
->session_mutex
);
494 (void) pthread_mutex_lock(&session_p
->ses_free_mutex
);
496 objp
= session_p
->object_list
;
498 (void) pthread_mutex_lock(&objp
->object_mutex
);
502 session_p
= session_p
->next
;
507 /* Release in opposite order to kernel_acquire_all_slots_mutexes(). */
509 kernel_release_all_slots_mutexes()
512 kernel_slot_t
*pslot
;
513 kernel_session_t
*session_p
;
515 for (slotID
= 0; slotID
< slot_count
; slotID
++) {
516 pslot
= slot_table
[slotID
];
518 /* Iterate through sessions releasing all mutexes */
519 session_p
= pslot
->sl_sess_list
;
523 objp
= session_p
->object_list
;
525 (void) pthread_mutex_unlock(
526 &objp
->object_mutex
);
530 (void) pthread_mutex_unlock(&session_p
->ses_free_mutex
);
531 (void) pthread_mutex_unlock(&session_p
->session_mutex
);
532 session_p
= session_p
->next
;
535 (void) pthread_mutex_unlock(&pslot
->sl_mutex
);
538 (void) pthread_mutex_unlock(&delete_sessions_mutex
);