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 }