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 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * Copyright 2018, Joyent, Inc. 26 */ 27 28 #include <pthread.h> 29 #include <errno.h> 30 #include <sys/crypto/ioctl.h> 31 #include <security/cryptoki.h> 32 #include "kernelGlobal.h" 33 #include "kernelSession.h" 34 #include "kernelEmulate.h" 35 36 static CK_RV 37 common_digest_init(CK_SESSION_HANDLE hSession, 38 CK_MECHANISM_PTR pMechanism, boolean_t is_external_caller) 39 { 40 CK_RV rv; 41 kernel_session_t *session_p; 42 boolean_t ses_lock_held = B_FALSE; 43 crypto_digest_init_t digest_init; 44 crypto_mech_type_t k_mech_type; 45 int r; 46 47 if (!kernel_initialized) 48 return (CKR_CRYPTOKI_NOT_INITIALIZED); 49 50 if (pMechanism == NULL) 51 return (CKR_ARGUMENTS_BAD); 52 53 /* 54 * Get the kernel's internal mechanism number. 55 */ 56 rv = kernel_mech(pMechanism->mechanism, &k_mech_type); 57 if (rv != CKR_OK) 58 return (rv); 59 60 /* 61 * Obtain the session pointer. Also, increment the session 62 * reference count. 63 */ 64 rv = handle2session(hSession, &session_p); 65 if (rv != CKR_OK) 66 return (rv); 67 68 /* Acquire the session lock */ 69 (void) pthread_mutex_lock(&session_p->session_mutex); 70 ses_lock_held = B_TRUE; 71 72 /* 73 * This active flag will remain ON until application calls either 74 * C_Digest or C_DigestFinal to actually obtain the value of 75 * the message digest. 76 */ 77 session_p->digest.flags |= CRYPTO_OPERATION_ACTIVE; 78 79 if (SLOT_HAS_LIMITED_HASH(session_p) && is_external_caller) { 80 session_p->digest.mech.mechanism = pMechanism->mechanism; 81 session_p->digest.mech.pParameter = NULL; 82 session_p->digest.mech.ulParameterLen = 0; 83 session_p->digest.flags |= CRYPTO_EMULATE; 84 rv = emulate_buf_init(session_p, EDIGEST_LENGTH, OP_DIGEST); 85 REFRELE(session_p, ses_lock_held); 86 return (rv); 87 } 88 89 digest_init.di_session = session_p->k_session; 90 (void) pthread_mutex_unlock(&session_p->session_mutex); 91 ses_lock_held = B_FALSE; 92 digest_init.di_mech.cm_type = k_mech_type; 93 digest_init.di_mech.cm_param = pMechanism->pParameter; 94 95 /* 96 * If pParameter is NULL, set cm_param_len to be 0, so that ioctl call 97 * will have a clean input data. 98 */ 99 if (pMechanism->pParameter != NULL) 100 digest_init.di_mech.cm_param_len = pMechanism->ulParameterLen; 101 else 102 digest_init.di_mech.cm_param_len = 0; 103 104 while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_INIT, &digest_init)) < 0) { 105 if (errno != EINTR) 106 break; 107 } 108 if (r < 0) { 109 rv = CKR_FUNCTION_FAILED; 110 } else { 111 rv = crypto2pkcs11_error_number(digest_init.di_return_value); 112 } 113 114 if (rv != CKR_OK) { 115 (void) pthread_mutex_lock(&session_p->session_mutex); 116 ses_lock_held = B_TRUE; 117 session_p->digest.flags &= ~CRYPTO_OPERATION_ACTIVE; 118 /* 119 * Decrement the session reference count. 120 * We hold the session lock, and REFRELE() 121 * will release the session lock for us. 122 */ 123 REFRELE(session_p, ses_lock_held); 124 return (rv); 125 } 126 127 /* 128 * Decrement the session reference count. 129 * We do not hold the session lock. 130 */ 131 REFRELE(session_p, ses_lock_held); 132 return (rv); 133 } 134 135 CK_RV 136 C_DigestInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism) 137 { 138 return (common_digest_init(hSession, pMechanism, B_TRUE)); 139 } 140 141 CK_RV 142 C_Digest(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, 143 CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen) 144 { 145 CK_RV rv; 146 kernel_session_t *session_p; 147 boolean_t ses_lock_held = B_FALSE; 148 crypto_digest_t digest; 149 int r; 150 151 if (!kernel_initialized) 152 return (CKR_CRYPTOKI_NOT_INITIALIZED); 153 154 /* 155 * Obtain the session pointer. Also, increment the session 156 * reference count. 157 */ 158 rv = handle2session(hSession, &session_p); 159 if (rv != CKR_OK) 160 return (rv); 161 162 if ((pData == NULL && ulDataLen != 0) || pulDigestLen == NULL) { 163 rv = CKR_ARGUMENTS_BAD; 164 goto clean_exit; 165 } 166 167 /* Acquire the session lock */ 168 (void) pthread_mutex_lock(&session_p->session_mutex); 169 ses_lock_held = B_TRUE; 170 171 /* Application must call C_DigestInit before calling C_Digest */ 172 if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) { 173 /* 174 * Decrement the session reference count. 175 * We hold the session lock, and REFRELE() 176 * will release the session lock for us. 177 */ 178 REFRELE(session_p, ses_lock_held); 179 return (CKR_OPERATION_NOT_INITIALIZED); 180 } 181 182 /* 183 * C_Digest must be called without intervening C_DigestUpdate 184 * calls. 185 */ 186 if (session_p->digest.flags & CRYPTO_OPERATION_UPDATE) { 187 /* 188 * C_Digest can not be used to terminate a multi-part 189 * operation, so we'll leave the active digest operation 190 * flag on and let the application continue with the 191 * digest update operation. 192 * 193 * Decrement the session reference count. 194 * We hold the session lock, and REFRELE() 195 * will release the session lock for us. 196 */ 197 REFRELE(session_p, ses_lock_held); 198 return (CKR_FUNCTION_FAILED); 199 } 200 201 if (session_p->digest.flags & CRYPTO_EMULATE) { 202 crypto_active_op_t *opp; 203 CK_MECHANISM_PTR pMechanism; 204 205 opp = &(session_p->digest); 206 if (opp->context == NULL) { 207 REFRELE(session_p, ses_lock_held); 208 return (CKR_ARGUMENTS_BAD); 209 } 210 pMechanism = &(opp->mech); 211 212 if ((ulDataLen < SLOT_THRESHOLD(session_p)) || 213 (ulDataLen > SLOT_HASH_MAX_INDATA_LEN(session_p))) { 214 session_p->digest.flags |= CRYPTO_EMULATE_USING_SW; 215 (void) pthread_mutex_unlock(&session_p->session_mutex); 216 ses_lock_held = B_FALSE; 217 218 rv = do_soft_digest(get_spp(opp), pMechanism, 219 pData, ulDataLen, pDigest, pulDigestLen, 220 OP_INIT | OP_SINGLE); 221 goto done; 222 } else if (!(session_p->digest.flags & 223 CRYPTO_EMULATE_INIT_DONE)) { 224 session_p->digest.flags |= CRYPTO_EMULATE_INIT_DONE; 225 (void) pthread_mutex_unlock(&session_p->session_mutex); 226 ses_lock_held = B_FALSE; 227 228 rv = common_digest_init(hSession, pMechanism, B_FALSE); 229 if (rv != CKR_OK) 230 goto clean_exit; 231 (void) pthread_mutex_lock(&session_p->session_mutex); 232 ses_lock_held = B_TRUE; 233 } 234 } 235 236 digest.cd_session = session_p->k_session; 237 (void) pthread_mutex_unlock(&session_p->session_mutex); 238 ses_lock_held = B_FALSE; 239 digest.cd_datalen = ulDataLen; 240 digest.cd_databuf = (char *)pData; 241 digest.cd_digestbuf = (char *)pDigest; 242 digest.cd_digestlen = *pulDigestLen; 243 244 while ((r = ioctl(kernel_fd, CRYPTO_DIGEST, &digest)) < 0) { 245 if (errno != EINTR) 246 break; 247 } 248 if (r < 0) { 249 rv = CKR_FUNCTION_FAILED; 250 } else { 251 rv = crypto2pkcs11_error_number(digest.cd_return_value); 252 } 253 254 if ((rv == CKR_OK) || (rv == CKR_BUFFER_TOO_SMALL)) 255 *pulDigestLen = digest.cd_digestlen; 256 257 done: 258 if ((rv == CKR_BUFFER_TOO_SMALL) || 259 (rv == CKR_OK && pDigest == NULL)) { 260 /* 261 * We will not terminate the active digest operation flag, 262 * when the application-supplied buffer is too small, or 263 * the application asks for the length of buffer to hold 264 * the message digest. 265 * 266 * Decrement the session reference count. 267 * We do not hold the session lock. 268 */ 269 REFRELE(session_p, ses_lock_held); 270 return (rv); 271 } 272 273 clean_exit: 274 /* 275 * Terminates the active digest operation. 276 * Application needs to call C_DigestInit again for next 277 * digest operation. 278 */ 279 (void) pthread_mutex_lock(&session_p->session_mutex); 280 ses_lock_held = B_TRUE; 281 282 REINIT_OPBUF(&session_p->digest); 283 session_p->digest.flags = 0; 284 285 /* 286 * Decrement the session reference count. 287 * We hold the session lock, and REFRELE() 288 * will release the session lock for us. 289 */ 290 REFRELE(session_p, ses_lock_held); 291 292 return (rv); 293 } 294 295 CK_RV 296 C_DigestUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, 297 CK_ULONG ulPartLen) 298 { 299 300 CK_RV rv; 301 kernel_session_t *session_p; 302 boolean_t ses_lock_held = B_FALSE; 303 crypto_digest_update_t digest_update; 304 int r; 305 306 if (!kernel_initialized) 307 return (CKR_CRYPTOKI_NOT_INITIALIZED); 308 309 /* 310 * Obtain the session pointer. Also, increment the session 311 * reference count. 312 */ 313 rv = handle2session(hSession, &session_p); 314 if (rv != CKR_OK) 315 return (rv); 316 317 if (pPart == NULL) { 318 rv = CKR_ARGUMENTS_BAD; 319 goto clean_exit; 320 } 321 322 /* Acquire the session lock */ 323 (void) pthread_mutex_lock(&session_p->session_mutex); 324 ses_lock_held = B_TRUE; 325 326 /* 327 * Application must call C_DigestInit before calling 328 * C_DigestUpdate. 329 */ 330 if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) { 331 /* 332 * Decrement the session reference count. 333 * We hold the session lock, and REFRELE() 334 * will release the session lock for us. 335 */ 336 REFRELE(session_p, ses_lock_held); 337 return (CKR_OPERATION_NOT_INITIALIZED); 338 } 339 340 /* Set update flag to protect C_Digest */ 341 session_p->digest.flags |= CRYPTO_OPERATION_UPDATE; 342 343 if (session_p->digest.flags & CRYPTO_EMULATE) { 344 (void) pthread_mutex_unlock(&session_p->session_mutex); 345 ses_lock_held = B_FALSE; 346 rv = emulate_update(session_p, pPart, ulPartLen, OP_DIGEST); 347 goto done; 348 } 349 350 digest_update.du_session = session_p->k_session; 351 (void) pthread_mutex_unlock(&session_p->session_mutex); 352 ses_lock_held = B_FALSE; 353 digest_update.du_datalen = ulPartLen; 354 digest_update.du_databuf = (char *)pPart; 355 356 while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_UPDATE, 357 &digest_update)) < 0) { 358 if (errno != EINTR) 359 break; 360 } 361 if (r < 0) { 362 rv = CKR_FUNCTION_FAILED; 363 } else { 364 rv = crypto2pkcs11_error_number(digest_update.du_return_value); 365 } 366 367 done: 368 if (rv == CKR_OK) { 369 /* 370 * Decrement the session reference count. 371 * We do not hold the session lock. 372 */ 373 REFRELE(session_p, ses_lock_held); 374 return (CKR_OK); 375 } 376 377 clean_exit: 378 /* 379 * After an error occurred, terminate the current digest 380 * operation by resetting the active and update flags. 381 */ 382 (void) pthread_mutex_lock(&session_p->session_mutex); 383 ses_lock_held = B_TRUE; 384 REINIT_OPBUF(&session_p->digest); 385 session_p->digest.flags = 0; 386 387 /* 388 * Decrement the session reference count. 389 * We hold the session lock, and REFRELE() 390 * will release the session lock for us. 391 */ 392 REFRELE(session_p, ses_lock_held); 393 394 return (rv); 395 } 396 397 398 CK_RV 399 C_DigestKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey) 400 { 401 402 CK_RV rv; 403 kernel_session_t *session_p; 404 kernel_object_t *key_p; 405 boolean_t ses_lock_held = B_FALSE; 406 CK_BYTE_PTR pPart; 407 CK_ULONG ulPartLen; 408 crypto_digest_key_t digest_key; 409 crypto_digest_update_t digest_update; 410 int r; 411 412 if (!kernel_initialized) 413 return (CKR_CRYPTOKI_NOT_INITIALIZED); 414 415 /* 416 * Obtain the session pointer. Also, increment the session 417 * reference count. 418 */ 419 rv = handle2session(hSession, &session_p); 420 if (rv != CKR_OK) 421 return (rv); 422 423 /* Obtain the object pointer. */ 424 HANDLE2OBJECT(hKey, key_p, rv); 425 if (rv != CKR_OK) { 426 (void) pthread_mutex_lock(&session_p->session_mutex); 427 ses_lock_held = B_TRUE; 428 REINIT_OPBUF(&session_p->digest); 429 session_p->digest.flags = 0; 430 REFRELE(session_p, ses_lock_held); 431 return (rv); 432 } 433 434 /* Check the key type */ 435 if (key_p->is_lib_obj && (key_p->class != CKO_SECRET_KEY)) { 436 rv = CKR_KEY_INDIGESTIBLE; 437 goto clean_exit; 438 } 439 440 /* 441 * Application must call C_DigestInit before calling 442 * C_DigestKey. 443 */ 444 (void) pthread_mutex_lock(&session_p->session_mutex); 445 ses_lock_held = B_TRUE; 446 447 if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) { 448 /* 449 * Decrement the session reference count. 450 * We hold the session lock, and REFRELE() 451 * will release the session lock for us. 452 */ 453 OBJ_REFRELE(key_p); 454 REFRELE(session_p, ses_lock_held); 455 return (CKR_OPERATION_NOT_INITIALIZED); 456 } 457 session_p->digest.flags |= CRYPTO_OPERATION_UPDATE; 458 459 /* 460 * If the key object is from the HW provider, call CRYPTO_DIGEST_KEY 461 * ioctl. Otherwise, call CRYPTO_DIGEST_UPDATE ioctl and pass the key 462 * by value. 463 */ 464 if (key_p->is_lib_obj) { 465 digest_update.du_session = session_p->k_session; 466 } else { 467 digest_key.dk_session = session_p->k_session; 468 } 469 (void) pthread_mutex_unlock(&session_p->session_mutex); 470 ses_lock_held = B_FALSE; 471 472 if (!key_p->is_lib_obj) { 473 if (session_p->digest.flags & CRYPTO_EMULATE) { 474 rv = CKR_FUNCTION_NOT_SUPPORTED; 475 goto clean_exit; 476 } 477 digest_key.dk_key.ck_format = CRYPTO_KEY_REFERENCE; 478 digest_key.dk_key.ck_obj_id = key_p->k_handle; 479 while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_KEY, 480 &digest_key)) < 0) { 481 if (errno != EINTR) 482 break; 483 } 484 if (r < 0) { 485 rv = CKR_FUNCTION_FAILED; 486 } else { 487 rv = crypto2pkcs11_error_number( 488 digest_key.dk_return_value); 489 } 490 } else { 491 ulPartLen = OBJ_SEC_VALUE_LEN(key_p); 492 if (ulPartLen == 0) { 493 rv = CKR_KEY_SIZE_RANGE; 494 goto clean_exit; 495 } 496 497 pPart = (CK_BYTE_PTR) OBJ_SEC_VALUE(key_p); 498 if (pPart == NULL) { 499 rv = CKR_KEY_HANDLE_INVALID; 500 goto clean_exit; 501 } 502 503 (void) pthread_mutex_lock(&session_p->session_mutex); 504 ses_lock_held = B_TRUE; 505 if (session_p->digest.flags & CRYPTO_EMULATE) { 506 (void) pthread_mutex_unlock(&session_p->session_mutex); 507 ses_lock_held = B_FALSE; 508 rv = emulate_update(session_p, pPart, 509 ulPartLen, OP_DIGEST); 510 goto done; 511 } 512 (void) pthread_mutex_unlock(&session_p->session_mutex); 513 ses_lock_held = B_FALSE; 514 515 digest_update.du_datalen = ulPartLen; 516 digest_update.du_databuf = (char *)pPart; 517 518 while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_UPDATE, 519 &digest_update)) < 0) { 520 if (errno != EINTR) 521 break; 522 } 523 if (r < 0) { 524 rv = CKR_FUNCTION_FAILED; 525 } else { 526 rv = crypto2pkcs11_error_number( 527 digest_update.du_return_value); 528 } 529 } 530 531 done: 532 if (rv == CKR_OK) { 533 /* 534 * Decrement the session reference count. 535 * We do not hold the session lock. 536 */ 537 OBJ_REFRELE(key_p); 538 REFRELE(session_p, ses_lock_held); 539 return (CKR_OK); 540 } 541 542 clean_exit: 543 OBJ_REFRELE(key_p); 544 /* 545 * After an error occurred, terminate the current digest 546 * operation by resetting the active and update flags. 547 */ 548 (void) pthread_mutex_lock(&session_p->session_mutex); 549 ses_lock_held = B_TRUE; 550 REINIT_OPBUF(&session_p->digest); 551 session_p->digest.flags = 0; 552 553 /* 554 * Decrement the session reference count. 555 * We hold the session lock, and REFRELE() 556 * will release the session lock for us. 557 */ 558 REFRELE(session_p, ses_lock_held); 559 return (rv); 560 } 561 562 563 CK_RV 564 C_DigestFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest, 565 CK_ULONG_PTR pulDigestLen) 566 { 567 568 CK_RV rv; 569 kernel_session_t *session_p; 570 boolean_t ses_lock_held = B_FALSE; 571 crypto_digest_final_t digest_final; 572 int r; 573 574 if (!kernel_initialized) 575 return (CKR_CRYPTOKI_NOT_INITIALIZED); 576 577 /* 578 * Obtain the session pointer. Also, increment the session 579 * reference count. 580 */ 581 rv = handle2session(hSession, &session_p); 582 if (rv != CKR_OK) 583 return (rv); 584 585 if (pulDigestLen == NULL) { 586 rv = CKR_ARGUMENTS_BAD; 587 goto clean_exit; 588 } 589 590 /* Acquire the session lock */ 591 (void) pthread_mutex_lock(&session_p->session_mutex); 592 ses_lock_held = B_TRUE; 593 594 /* 595 * Application must call C_DigestInit before calling 596 * C_DigestFinal. 597 */ 598 if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) { 599 /* 600 * Decrement the session reference count. 601 * We hold the session lock, and REFRELE() 602 * will release the session lock for us. 603 */ 604 REFRELE(session_p, ses_lock_held); 605 return (CKR_OPERATION_NOT_INITIALIZED); 606 } 607 608 /* The order of checks is important here */ 609 if (session_p->digest.flags & CRYPTO_EMULATE_USING_SW) { 610 if (session_p->digest.flags & CRYPTO_EMULATE_UPDATE_DONE) { 611 (void) pthread_mutex_unlock(&session_p->session_mutex); 612 ses_lock_held = B_FALSE; 613 rv = do_soft_digest(get_spp(&session_p->digest), 614 NULL, NULL, 0, pDigest, pulDigestLen, OP_FINAL); 615 } else { 616 /* 617 * We end up here if an earlier C_DigestFinal() call 618 * took the C_Digest() path and it had returned 619 * CKR_BUFFER_TOO_SMALL. 620 */ 621 digest_buf_t *bufp = session_p->digest.context; 622 (void) pthread_mutex_unlock(&session_p->session_mutex); 623 ses_lock_held = B_FALSE; 624 if (bufp == NULL || bufp->buf == NULL) { 625 rv = CKR_ARGUMENTS_BAD; 626 goto clean_exit; 627 } 628 rv = do_soft_digest(get_spp(&session_p->digest), 629 NULL, bufp->buf, bufp->indata_len, 630 pDigest, pulDigestLen, OP_SINGLE); 631 } 632 goto done; 633 } else if (session_p->digest.flags & CRYPTO_EMULATE) { 634 digest_buf_t *bufp = session_p->digest.context; 635 636 /* 637 * We are emulating a single-part operation now. 638 * So, clear the flag. 639 */ 640 session_p->digest.flags &= ~CRYPTO_OPERATION_UPDATE; 641 if (bufp == NULL || bufp->buf == NULL) { 642 rv = CKR_ARGUMENTS_BAD; 643 goto clean_exit; 644 } 645 REFRELE(session_p, ses_lock_held); 646 rv = C_Digest(hSession, bufp->buf, bufp->indata_len, 647 pDigest, pulDigestLen); 648 return (rv); 649 } 650 651 digest_final.df_session = session_p->k_session; 652 (void) pthread_mutex_unlock(&session_p->session_mutex); 653 ses_lock_held = B_FALSE; 654 digest_final.df_digestlen = *pulDigestLen; 655 digest_final.df_digestbuf = (char *)pDigest; 656 657 while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_FINAL, &digest_final)) < 0) { 658 if (errno != EINTR) 659 break; 660 } 661 if (r < 0) { 662 rv = CKR_FUNCTION_FAILED; 663 } else { 664 rv = crypto2pkcs11_error_number(digest_final.df_return_value); 665 } 666 667 if ((rv == CKR_OK) || (rv == CKR_BUFFER_TOO_SMALL)) 668 *pulDigestLen = digest_final.df_digestlen; 669 670 done: 671 if ((rv == CKR_BUFFER_TOO_SMALL) || 672 (rv == CKR_OK && pDigest == NULL)) { 673 /* 674 * We will not terminate the active digest operation flag, 675 * when the application-supplied buffer is too small, or 676 * the application asks for the length of buffer to hold 677 * the message digest. 678 * 679 * Decrement the session reference count. 680 * We do not hold the session lock. 681 */ 682 REFRELE(session_p, ses_lock_held); 683 return (rv); 684 } 685 686 clean_exit: 687 /* Terminates the active digest operation */ 688 (void) pthread_mutex_lock(&session_p->session_mutex); 689 ses_lock_held = B_TRUE; 690 REINIT_OPBUF(&session_p->digest); 691 session_p->digest.flags = 0; 692 693 /* 694 * Decrement the session reference count. 695 * We hold the session lock, and REFRELE() 696 * will release the session lock for us. 697 */ 698 REFRELE(session_p, ses_lock_held); 699 700 return (rv); 701 } 702