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