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 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 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 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 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 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 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 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