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 (c) 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 #include <sys/systm.h> 26 #include <sys/cmn_err.h> 27 #include <sys/stropts.h> 28 #include <sys/strsun.h> 29 #include <sys/socketvar.h> 30 #include <sys/sockfilter.h> 31 #include <inet/kssl/ksslapi.h> 32 #include <sys/note.h> 33 #include <sys/taskq.h> 34 35 /* 36 * Name of the KSSL filter 37 */ 38 #define KSSL_FILNAME "ksslf" 39 40 static struct modlmisc ksslf_modlmisc = { 41 &mod_miscops, 42 "Kernel SSL socket filter" 43 }; 44 45 static struct modlinkage ksslf_modlinkage = { 46 MODREV_1, 47 &ksslf_modlmisc, 48 NULL 49 }; 50 51 /* 52 * kssl filter cookie 53 */ 54 typedef struct ksslf { 55 boolean_t ksslf_pending; /* waiting for 1st SSL rec. */ 56 boolean_t ksslf_inhandshake; /* during SSL handshake */ 57 kssl_ent_t ksslf_ent; /* SSL table entry */ 58 kssl_ctx_t ksslf_ctx; /* SSL session */ 59 kssl_endpt_type_t ksslf_type; /* is proxy/is proxied/none */ 60 struct sockaddr_in6 ksslf_laddr; /* local address */ 61 socklen_t ksslf_laddrlen; 62 struct ksslf *ksslf_listener; 63 } ksslf_t; 64 65 static void kssl_input_callback(void *, mblk_t *, kssl_cmd_t); 66 67 /* 68 * Allocate kssl state 69 */ 70 sof_rval_t 71 kssl_attach_passive_cb(sof_handle_t handle, sof_handle_t ph, 72 void *parg, struct sockaddr *laddr, socklen_t laddrlen, 73 struct sockaddr *faddr, socklen_t faddrlen, void **cookiep) 74 { 75 ksslf_t *listener = (ksslf_t *)parg; 76 ksslf_t *new; 77 78 _NOTE(ARGUNUSED(handle, ph, faddrlen, laddr, laddrlen)); 79 80 if (listener == NULL || listener->ksslf_ent == NULL) 81 return (SOF_RVAL_DETACH); 82 /* 83 * Only way for a fallback listener to receive connections is when 84 * a handshake fails and socket is moved from the proxy to the fallback. 85 * Connections that come in directly on the fallback are denied. 86 */ 87 if (listener->ksslf_type == KSSL_HAS_PROXY) 88 return (SOF_RVAL_EACCES); 89 90 /* Allocate the SSL context for the new connection */ 91 new = kmem_zalloc(sizeof (ksslf_t), KM_NOSLEEP); 92 if (new == NULL) 93 return (SOF_RVAL_ENOMEM); 94 95 /* 96 * The mss is initialized to SSL3_MAX_RECORD_LEN, but might be 97 * updated by the mblk_prop callback. 98 */ 99 if (kssl_init_context(listener->ksslf_ent, faddr, SSL3_MAX_RECORD_LEN, 100 &new->ksslf_ctx) != KSSL_STS_OK) 101 return (SOF_RVAL_ENOMEM); 102 103 new->ksslf_pending = B_TRUE; 104 new->ksslf_inhandshake = B_TRUE; 105 ASSERT(laddrlen <= sizeof (new->ksslf_laddr)); 106 new->ksslf_laddrlen = laddrlen; 107 bcopy(laddr, &new->ksslf_laddr, laddrlen); 108 new->ksslf_laddr.sin6_port = listener->ksslf_laddr.sin6_port; 109 new->ksslf_listener = listener; 110 111 *cookiep = new; 112 /* 113 * We are in handshake, defer the notification of this connection 114 * until it is completed. 115 */ 116 return (SOF_RVAL_DEFER); 117 } 118 119 void 120 kssl_detach_cb(sof_handle_t handle, void *cookie, cred_t *cr) 121 { 122 ksslf_t *kssl = (ksslf_t *)cookie; 123 124 _NOTE(ARGUNUSED(handle, cr)); 125 126 if (kssl == NULL) 127 return; 128 129 if (kssl->ksslf_ent != NULL) { 130 kssl_release_ent(kssl->ksslf_ent, handle, kssl->ksslf_type); 131 kssl->ksslf_ent = NULL; 132 } 133 if (kssl->ksslf_ctx != NULL) { 134 kssl_release_ctx(kssl->ksslf_ctx); 135 kssl->ksslf_ctx = NULL; 136 } 137 138 kmem_free(kssl, sizeof (ksslf_t)); 139 } 140 141 sof_rval_t 142 kssl_bind_cb(sof_handle_t handle, void *cookie, struct sockaddr *name, 143 socklen_t *namelen, cred_t *cr) 144 { 145 kssl_ent_t ent; 146 kssl_endpt_type_t type; 147 ksslf_t *kssl; 148 in_port_t origport; 149 150 _NOTE(ARGUNUSED(cr)); 151 152 if (cookie != NULL) 153 return (SOF_RVAL_EINVAL); 154 155 if (*namelen < sizeof (struct sockaddr_in)) { 156 sof_bypass(handle); 157 return (SOF_RVAL_CONTINUE); 158 } 159 160 origport = ((struct sockaddr_in *)name)->sin_port; 161 /* Check if KSSL has been configured for this address */ 162 type = kssl_check_proxy(name, *namelen, handle, &ent); 163 164 switch (type) { 165 case KSSL_NO_PROXY: 166 sof_bypass(handle); 167 break; 168 case KSSL_HAS_PROXY: 169 case KSSL_IS_PROXY: 170 kssl = kmem_zalloc(sizeof (ksslf_t), KM_SLEEP); 171 kssl->ksslf_type = type; 172 kssl->ksslf_ent = ent; 173 174 /* 175 * In the unlikely event that there are multiple simultaneous 176 * bind requests, and the cookie was already swapped out, then 177 * just drop this cookie and let the bind continue unmodified. 178 */ 179 if (sof_cas_cookie(handle, cookie, kssl) != cookie) { 180 kssl_release_ent(ent, handle, type); 181 kmem_free(kssl, sizeof (ksslf_t)); 182 ((struct sockaddr_in *)name)->sin_port = origport; 183 break; 184 } 185 186 kssl->ksslf_laddrlen = *namelen; 187 bcopy(name, &kssl->ksslf_laddr, kssl->ksslf_laddrlen); 188 kssl->ksslf_laddr.sin6_port = origport; 189 /* 190 * kssl_check_proxy updated the sockaddr, so just 191 * pass it along to the protocol. 192 */ 193 return ((type == KSSL_HAS_PROXY) ? SOF_RVAL_RETURN : 194 SOF_RVAL_CONTINUE); 195 } 196 return (SOF_RVAL_CONTINUE); 197 } 198 199 sof_rval_t 200 kssl_listen_cb(sof_handle_t handle, void *cookie, int *backlog, cred_t *cr) 201 { 202 ksslf_t *kssl = (ksslf_t *)cookie; 203 204 _NOTE(ARGUNUSED(backlog, cr)); 205 206 /* 207 * The cookie can be NULL in the unlikely event of an application doing 208 * listen() without binding to an address. Those listeners are of no 209 * interest. 210 */ 211 if (kssl == NULL) { 212 sof_bypass(handle); 213 return (SOF_RVAL_CONTINUE); 214 } 215 216 return (SOF_RVAL_CONTINUE); 217 218 } 219 220 /* 221 * Outgoing connections are not of interest, so just bypass the filter. 222 */ 223 sof_rval_t 224 kssl_connect_cb(sof_handle_t handle, void *cookie, struct sockaddr *name, 225 socklen_t *namelen, cred_t *cr) 226 { 227 _NOTE(ARGUNUSED(cookie, name, namelen, cr)); 228 229 sof_bypass(handle); 230 return (SOF_RVAL_CONTINUE); 231 } 232 233 static void 234 kssl_mblk_prop_cb(sof_handle_t handle, void *cookie, ssize_t *maxblk, 235 ushort_t *wroff, ushort_t *tail) 236 { 237 ksslf_t *kssl = (ksslf_t *)cookie; 238 239 _NOTE(ARGUNUSED(handle)); 240 241 /* only care about passively opened sockets */ 242 if (kssl == NULL || !kssl->ksslf_pending) 243 return; 244 /* 245 * If this is endpoint is handling SSL, then reserve extra 246 * offset and space at the end. Also have sockfs allocate 247 * SSL3_MAX_RECORD_LEN packets, overriding the previous setting. 248 * The extra cost of signing and encrypting multiple MSS-size 249 * records (12 of them with Ethernet), instead of a single 250 * contiguous one by the stream head largely outweighs the 251 * statistical reduction of ACKs, when applicable. The peer 252 * will also save on decryption and verification costs. 253 */ 254 if (*maxblk == INFPSZ || *maxblk > SSL3_MAX_RECORD_LEN) 255 *maxblk = SSL3_MAX_RECORD_LEN; 256 else 257 kssl_set_mss(kssl->ksslf_ctx, *maxblk); 258 *wroff += SSL3_WROFFSET; 259 *tail += SSL3_MAX_TAIL_LEN; 260 } 261 262 sof_rval_t 263 kssl_getsockname_cb(sof_handle_t handle, void *cookie, struct sockaddr *addr, 264 socklen_t *addrlen, cred_t *cr) 265 { 266 ksslf_t *kssl = (ksslf_t *)cookie; 267 268 _NOTE(ARGUNUSED(handle, cr)); 269 270 if (kssl == NULL) 271 return (SOF_RVAL_CONTINUE); 272 273 if (*addrlen < kssl->ksslf_laddrlen) 274 return (SOF_RVAL_EINVAL); 275 276 *addrlen = kssl->ksslf_laddrlen; 277 bcopy(&kssl->ksslf_laddr, addr, kssl->ksslf_laddrlen); 278 279 return (SOF_RVAL_RETURN); 280 } 281 282 /* 283 * Called for every packet sent to the protocol. 284 * If the message is successfully processed, then it is returned. 285 */ 286 mblk_t * 287 kssl_data_out_cb(sof_handle_t handle, void *cookie, mblk_t *mp, 288 struct nmsghdr *msg, cred_t *cr, sof_rval_t *rv) 289 { 290 ksslf_t *kssl = (ksslf_t *)cookie; 291 mblk_t *recmp; 292 293 _NOTE(ARGUNUSED(handle, msg, cr)); 294 295 *rv = SOF_RVAL_CONTINUE; 296 if (kssl == NULL || kssl->ksslf_ctx == NULL) 297 return (mp); 298 299 if ((recmp = kssl_build_record(kssl->ksslf_ctx, mp)) == NULL) { 300 freemsg(mp); 301 *rv = SOF_RVAL_EINVAL; 302 return (NULL); 303 } 304 return (recmp); 305 } 306 307 /* 308 * Called from shutdown() processing. This will produce close_notify message 309 * to indicate the end of data to the client. 310 */ 311 sof_rval_t 312 kssl_shutdown_cb(sof_handle_t handle, void *cookie, int *howp, cred_t *cr) 313 { 314 ksslf_t *kssl = (ksslf_t *)cookie; 315 mblk_t *outmp; 316 boolean_t flowctrld; 317 struct nmsghdr msg; 318 319 _NOTE(ARGUNUSED(cr)); 320 321 if (kssl == NULL || kssl->ksslf_ctx == NULL) 322 return (SOF_RVAL_CONTINUE); 323 324 /* 325 * We only want to send close_notify when doing SHUT_WR/SHUT_RDWR 326 * because it signals that server is done writing data. 327 */ 328 if (*howp == SHUT_RD) 329 return (SOF_RVAL_CONTINUE); 330 331 /* Go on if we fail to build the record. */ 332 if ((outmp = kssl_build_record(kssl->ksslf_ctx, NULL)) == NULL) 333 return (SOF_RVAL_CONTINUE); 334 335 bzero(&msg, sizeof (msg)); 336 (void) sof_inject_data_out(handle, outmp, &msg, 337 &flowctrld); 338 339 return (SOF_RVAL_CONTINUE); 340 } 341 342 /* 343 * Called for each incoming segment. 344 * 345 * A packet may carry multiple SSL records, so the function calls 346 * kssl_input() in a loop, until all records are handled. 347 */ 348 mblk_t * 349 kssl_data_in_cb(sof_handle_t handle, void *cookie, mblk_t *mp, int flags, 350 size_t *lenp) 351 { 352 ksslf_t *kssl = cookie; 353 kssl_cmd_t kssl_cmd; 354 mblk_t *outmp, *retmp = NULL, **tail = &retmp; 355 boolean_t more = B_FALSE; 356 boolean_t flowctrld; 357 358 _NOTE(ARGUNUSED(flags)); 359 360 if (kssl == NULL || kssl->ksslf_ctx == NULL) { 361 sof_bypass(handle); 362 return (mp); 363 } 364 365 *lenp = 0; 366 do { 367 kssl_cmd = kssl_input(kssl->ksslf_ctx, mp, &outmp, 368 &more, kssl_input_callback, (void *)handle); 369 370 switch (kssl_cmd) { 371 case KSSL_CMD_SEND: { 372 struct nmsghdr msg; 373 374 DTRACE_PROBE(kssl_cmd_send); 375 bzero(&msg, sizeof (msg)); 376 (void) sof_inject_data_out(handle, outmp, &msg, 377 &flowctrld); 378 } 379 /* FALLTHROUGH */ 380 case KSSL_CMD_NONE: 381 DTRACE_PROBE(kssl_cmd_none); 382 if (kssl->ksslf_pending) { 383 kssl->ksslf_pending = B_FALSE; 384 sof_newconn_ready(handle); 385 } 386 break; 387 388 case KSSL_CMD_QUEUED: 389 DTRACE_PROBE(kssl_cmd_queued); 390 break; 391 392 case KSSL_CMD_DELIVER_PROXY: 393 case KSSL_CMD_DELIVER_SSL: 394 DTRACE_PROBE(kssl_cmd_proxy__ssl); 395 /* 396 * We're at a phase where records are sent upstreams, 397 * past the handshake 398 */ 399 kssl->ksslf_inhandshake = B_FALSE; 400 401 *tail = outmp; 402 *lenp += MBLKL(outmp); 403 while (outmp->b_cont != NULL) { 404 outmp = outmp->b_cont; 405 *lenp += MBLKL(outmp); 406 } 407 tail = &outmp->b_cont; 408 break; 409 410 case KSSL_CMD_NOT_SUPPORTED: { 411 ksslf_t *listener = kssl->ksslf_listener; 412 sof_handle_t fallback; 413 414 DTRACE_PROBE(kssl_cmd_not_supported); 415 /* 416 * Stop the SSL processing by the proxy, and 417 * switch to the userland SSL 418 */ 419 if (kssl->ksslf_pending) { 420 kssl->ksslf_pending = B_FALSE; 421 422 DTRACE_PROBE1(kssl_no_can_do, sof_handle_t, 423 handle); 424 425 sof_bypass(handle); 426 427 ASSERT(listener->ksslf_ent != NULL); 428 fallback = 429 kssl_find_fallback(listener->ksslf_ent); 430 /* 431 * No fallback: the remote will timeout and 432 * disconnect. 433 */ 434 if (fallback != NULL && 435 sof_newconn_move(handle, fallback)) 436 sof_newconn_ready(handle); 437 } 438 if (mp != NULL) { 439 *tail = mp; 440 *lenp += MBLKL(mp); 441 while (mp->b_cont != NULL) { 442 mp = mp->b_cont; 443 *lenp += MBLKL(mp); 444 } 445 tail = &mp->b_cont; 446 } 447 break; 448 } 449 } 450 mp = NULL; 451 } while (more); 452 453 return (retmp); 454 } 455 456 /* 457 * Process queued data before it's copied by the user. 458 * 459 * If the message is successfully processed, then it is returned. 460 * A failed message will be freed. 461 */ 462 mblk_t * 463 kssl_data_in_proc_cb(sof_handle_t handle, void *cookie, mblk_t *mp, 464 cred_t *cr, size_t *lenp) 465 { 466 ksslf_t *kssl = (ksslf_t *)cookie; 467 kssl_cmd_t kssl_cmd; 468 mblk_t *out; 469 470 _NOTE(ARGUNUSED(cr)); 471 472 if (kssl == NULL || kssl->ksslf_ctx) 473 return (mp); 474 475 *lenp = 0; 476 477 kssl_cmd = kssl_handle_mblk(kssl->ksslf_ctx, &mp, &out); 478 479 switch (kssl_cmd) { 480 case KSSL_CMD_NONE: 481 return (NULL); 482 case KSSL_CMD_DELIVER_PROXY: 483 *lenp = msgdsize(mp); 484 return (mp); 485 case KSSL_CMD_SEND: { 486 struct nmsghdr msg; 487 boolean_t flowctrld; 488 489 ASSERT(out != NULL); 490 bzero(&msg, sizeof (msg)); 491 492 (void) sof_inject_data_out(handle, out, &msg, 493 &flowctrld); 494 return (NULL); 495 } 496 default: 497 /* transient error. */ 498 return (NULL); 499 } 500 } 501 502 /* 503 * Continue processing the incoming flow after an asynchronous callback. 504 */ 505 static void 506 kssl_input_asynch(void *arg) 507 { 508 sof_handle_t handle = (sof_handle_t)arg; 509 ksslf_t *kssl = (ksslf_t *)sof_get_cookie(handle); 510 size_t len = 0; 511 boolean_t flowctrld; 512 mblk_t *mp; 513 514 if ((mp = kssl_data_in_cb(handle, kssl, NULL, 0, &len)) != NULL) { 515 ASSERT(len != 0); 516 (void) sof_inject_data_in(handle, mp, len, 0, &flowctrld); 517 } 518 kssl_async_done(kssl->ksslf_ctx); 519 } 520 521 /* 522 * Callback function for the cases kssl_input() had to submit an asynchronous 523 * job and need to come back when done to carry on the input processing. 524 * This routine follows the conentions of timeout and interrupt handlers. 525 * (no blocking, ...) 526 */ 527 static void 528 kssl_input_callback(void *arg, mblk_t *mp, kssl_cmd_t kssl_cmd) 529 { 530 sof_handle_t handle = (sof_handle_t)arg; 531 ksslf_t *kssl = (ksslf_t *)sof_get_cookie(handle); 532 boolean_t flowctrld; 533 534 ASSERT(kssl != NULL); 535 536 switch (kssl_cmd) { 537 case KSSL_CMD_SEND: { 538 struct nmsghdr msg; 539 540 if (mp == NULL) 541 break; 542 bzero(&msg, sizeof (msg)); 543 544 (void) sof_inject_data_out(handle, mp, &msg, &flowctrld); 545 } 546 /* FALLTHROUGH */ 547 case KSSL_CMD_NONE: 548 break; 549 550 case KSSL_CMD_DELIVER_PROXY: 551 case KSSL_CMD_DELIVER_SSL: 552 (void) sof_inject_data_in(handle, mp, msgdsize(mp), 0, 553 &flowctrld); 554 break; 555 556 case KSSL_CMD_NOT_SUPPORTED: 557 /* Stop the SSL processing */ 558 sof_bypass(handle); 559 } 560 /* 561 * Process any input that may have accumulated while we're waiting for 562 * the call-back. This must be done by a taskq because kssl_input might 563 * block when handling client_finish messages. 564 */ 565 if (taskq_dispatch(system_taskq, kssl_input_asynch, handle, 566 TQ_NOSLEEP) == NULL) { 567 DTRACE_PROBE(kssl_err__taskq_dispatch_failed); 568 kssl_async_done(kssl->ksslf_ctx); 569 } 570 } 571 572 sof_ops_t ksslf_ops = { 573 .sofop_attach_passive = kssl_attach_passive_cb, 574 .sofop_detach = kssl_detach_cb, 575 .sofop_bind = kssl_bind_cb, 576 .sofop_connect = kssl_connect_cb, 577 .sofop_listen = kssl_listen_cb, 578 .sofop_data_in = kssl_data_in_cb, 579 .sofop_data_in_proc = kssl_data_in_proc_cb, 580 .sofop_data_out = kssl_data_out_cb, 581 .sofop_mblk_prop = kssl_mblk_prop_cb, 582 .sofop_getsockname = kssl_getsockname_cb, 583 .sofop_shutdown = kssl_shutdown_cb, 584 }; 585 586 int 587 _init(void) 588 { 589 int error; 590 591 if ((error = sof_register(SOF_VERSION, KSSL_FILNAME, 592 &ksslf_ops, 0)) != 0) 593 return (error); 594 if ((error = mod_install(&ksslf_modlinkage)) != 0) 595 (void) sof_unregister(KSSL_FILNAME); 596 597 return (error); 598 } 599 600 int 601 _fini(void) 602 { 603 int error; 604 605 if ((error = sof_unregister(KSSL_FILNAME)) != 0) 606 return (error); 607 608 return (mod_remove(&ksslf_modlinkage)); 609 } 610 611 int 612 _info(struct modinfo *modinfop) 613 { 614 return (mod_info(&ksslf_modlinkage, modinfop)); 615 }