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