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 }