1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
5 * Authors: Doug Rabson <dfr@rabson.org>
6 * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 /* Modified from the kernel GSSAPI code for RPC-over-TLS. */
31
32 #include <sys/cdefs.h>
33 #include "opt_kern_tls.h"
34
35 #include <sys/param.h>
36 #include <sys/capsicum.h>
37 #include <sys/file.h>
38 #include <sys/filedesc.h>
39 #include <sys/jail.h>
40 #include <sys/kernel.h>
41 #include <sys/lock.h>
42 #include <sys/malloc.h>
43 #include <sys/mbuf.h>
44 #include <sys/mutex.h>
45 #include <sys/priv.h>
46 #include <sys/proc.h>
47 #include <sys/socketvar.h>
48 #include <sys/syscall.h>
49 #include <sys/syscallsubr.h>
50 #include <sys/sysent.h>
51 #include <sys/sysproto.h>
52 #include <sys/tree.h>
53
54 #include <net/vnet.h>
55
56 #include <rpc/rpc.h>
57 #include <rpc/rpc_com.h>
58 #include <rpc/krpc.h>
59 #include <rpc/rpcsec_tls.h>
60
61 #include <vm/vm.h>
62 #include <vm/pmap.h>
63 #include <vm/vm_param.h>
64
65 #include "rpctlscd.h"
66 #include "rpctlssd.h"
67
68 /*
69 * Syscall hooks
70 */
71 static struct syscall_helper_data rpctls_syscalls[] = {
72 SYSCALL_INIT_HELPER(rpctls_syscall),
73 SYSCALL_INIT_LAST
74 };
75
76 static struct opaque_auth rpctls_null_verf;
77
78 KRPC_VNET_DECLARE(uint64_t, svc_vc_tls_handshake_success);
79 KRPC_VNET_DECLARE(uint64_t, svc_vc_tls_handshake_failed);
80
81 static CLIENT *rpctls_connect_handle;
82 static CLIENT *rpctls_server_handle;
83
84 struct upsock {
85 RB_ENTRY(upsock) tree;
86 struct socket *so;
87 union {
88 CLIENT *cl;
89 SVCXPRT *xp;
90 };
91 bool server;
92 };
93
94 static RB_HEAD(upsock_t, upsock) upcall_sockets;
95 static intptr_t
upsock_compare(const struct upsock * a,const struct upsock * b)96 upsock_compare(const struct upsock *a, const struct upsock *b)
97 {
98 return ((intptr_t)((uintptr_t)a->so/2 - (uintptr_t)b->so/2));
99 }
100 RB_GENERATE_STATIC(upsock_t, upsock, tree, upsock_compare);
101 static struct mtx rpctls_lock;
102
103 static enum clnt_stat rpctls_server(SVCXPRT *xprt, uint32_t *flags,
104 uid_t *uid, int *ngrps, gid_t **gids);
105
106 static CLIENT *
rpctls_client_nl_create(const char * group,const rpcprog_t program,const rpcvers_t version)107 rpctls_client_nl_create(const char *group, const rpcprog_t program,
108 const rpcvers_t version)
109 {
110 CLIENT *cl;
111
112 cl = client_nl_create(group, program, version);
113 KASSERT(cl, ("%s: netlink client already exist", __func__));
114 /*
115 * Set the try_count to 1 so that no retries of the RPC occur. Since
116 * it is an upcall to a local daemon, requests should not be lost and
117 * doing one of these RPCs multiple times is not correct. If the
118 * server is not working correctly, the daemon can get stuck in
119 * SSL_connect() trying to read data from the socket during the upcall.
120 * Set a timeout (currently 15sec) and assume the daemon is hung when
121 * the timeout occurs.
122 */
123 clnt_control(cl, CLSET_RETRIES, &(int){1});
124 clnt_control(cl, CLSET_TIMEOUT, &(struct timeval){.tv_sec = 15});
125 clnt_control(cl, CLSET_WAITCHAN, __DECONST(char *, group));
126
127 return (cl);
128 }
129
130 int
rpctls_init(void)131 rpctls_init(void)
132 {
133 int error;
134
135 error = syscall_helper_register(rpctls_syscalls, SY_THR_STATIC_KLD);
136 if (error != 0) {
137 printf("rpctls_init: cannot register syscall\n");
138 return (error);
139 }
140 mtx_init(&rpctls_lock, "rpctls lock", NULL, MTX_DEF);
141 rpctls_null_verf.oa_flavor = AUTH_NULL;
142 rpctls_null_verf.oa_base = RPCTLS_START_STRING;
143 rpctls_null_verf.oa_length = strlen(RPCTLS_START_STRING);
144 rpctls_connect_handle = rpctls_client_nl_create("tlsclnt",
145 RPCTLSCD, RPCTLSCDVERS);
146 rpctls_server_handle = rpctls_client_nl_create("tlsserv",
147 RPCTLSSD, RPCTLSSDVERS);
148 return (0);
149 }
150
151 int
sys_rpctls_syscall(struct thread * td,struct rpctls_syscall_args * uap)152 sys_rpctls_syscall(struct thread *td, struct rpctls_syscall_args *uap)
153 {
154 struct file *fp;
155 struct upsock *upsp, ups;
156 int fd = -1, error;
157
158 error = priv_check(td, PRIV_NFS_DAEMON);
159 if (error != 0)
160 return (error);
161
162 KRPC_CURVNET_SET(KRPC_TD_TO_VNET(td));
163 mtx_lock(&rpctls_lock);
164 upsp = RB_FIND(upsock_t, &upcall_sockets,
165 &(struct upsock){
166 .so = (struct socket *)(uintptr_t)uap->socookie });
167 if (__predict_true(upsp != NULL)) {
168 RB_REMOVE(upsock_t, &upcall_sockets, upsp);
169 /*
170 * The upsp points to stack of NFS mounting thread. Even
171 * though we removed it from the tree, we still don't own it.
172 * Make a copy before releasing the lock. The mounting thread
173 * may timeout the RPC and unroll its stack.
174 */
175 ups = *upsp;
176 }
177 mtx_unlock(&rpctls_lock);
178 if (upsp == NULL) {
179 KRPC_CURVNET_RESTORE();
180 printf("%s: socket lookup failed\n", __func__);
181 return (EPERM);
182 }
183 if ((error = falloc(td, &fp, &fd, 0)) != 0) {
184 /*
185 * The socket will not be acquired by the daemon,
186 * but has been removed from the upcall socket RB.
187 * As such, it needs to be closed here.
188 */
189 soclose(ups.so);
190 KRPC_CURVNET_RESTORE();
191 return (error);
192 }
193 soref(ups.so);
194 if (ups.server) {
195 /*
196 * Once this file descriptor is associated
197 * with the socket, it cannot be closed by
198 * the server side krpc code (svc_vc.c).
199 */
200 sx_xlock(&ups.xp->xp_lock);
201 ups.xp->xp_tls = RPCTLS_FLAGS_HANDSHFAIL;
202 sx_xunlock(&ups.xp->xp_lock);
203 } else {
204 /*
205 * Initialize TLS state so that clnt_vc_destroy() will
206 * not close the socket and will leave that for the
207 * daemon to do.
208 */
209 CLNT_CONTROL(ups.cl, CLSET_TLS, &(int){RPCTLS_INHANDSHAKE});
210 }
211 finit(fp, FREAD | FWRITE, DTYPE_SOCKET, ups.so, &socketops);
212 fdrop(fp, td); /* Drop fp reference. */
213 td->td_retval[0] = fd;
214 KRPC_CURVNET_RESTORE();
215
216 return (error);
217 }
218
219 /* Error handling for both client and server failed RPC upcalls. */
220 static void
rpctls_rpc_failed(struct upsock * ups,struct socket * so)221 rpctls_rpc_failed(struct upsock *ups, struct socket *so)
222 {
223
224 mtx_lock(&rpctls_lock);
225 if (RB_FIND(upsock_t, &upcall_sockets, ups)) {
226 struct upsock *removed __diagused;
227
228 removed = RB_REMOVE(upsock_t, &upcall_sockets, ups);
229 mtx_unlock(&rpctls_lock);
230 MPASS(removed == ups);
231 /*
232 * Since the socket was still in the RB tree when
233 * this function was called, the daemon will not
234 * close it. As such, it needs to be closed here.
235 */
236 soclose(so);
237 } else {
238 /*
239 * The daemon has taken the socket from the tree, but
240 * failed to do the handshake.
241 */
242 mtx_unlock(&rpctls_lock);
243 /*
244 * Do a shutdown on the socket, since the daemon is
245 * probably stuck in SSL_accept() or SSL_connect() trying to
246 * read the socket. Do not soclose() the socket, since the
247 * daemon will close() the socket after SSL_accept()
248 * returns an error.
249 */
250 soshutdown(so, SHUT_RD);
251 }
252 }
253
254 /* Do an upcall for a new socket connect using TLS. */
255 enum clnt_stat
rpctls_connect(CLIENT * newclient,char * certname,struct socket * so,uint32_t * reterr)256 rpctls_connect(CLIENT *newclient, char *certname, struct socket *so,
257 uint32_t *reterr)
258 {
259 struct rpctlscd_connect_arg arg;
260 struct rpctlscd_connect_res res;
261 struct rpc_callextra ext;
262 enum clnt_stat stat;
263 struct upsock ups = {
264 .so = so,
265 .cl = newclient,
266 .server = false,
267 };
268
269 /* First, do the AUTH_TLS NULL RPC. */
270 memset(&ext, 0, sizeof(ext));
271 ext.rc_auth = authtls_create();
272 stat = clnt_call_private(newclient, &ext, NULLPROC, (xdrproc_t)xdr_void,
273 NULL, (xdrproc_t)xdr_void, NULL, (struct timeval){ .tv_sec = 30 });
274 AUTH_DESTROY(ext.rc_auth);
275 if (stat == RPC_AUTHERROR)
276 return (stat);
277 if (stat != RPC_SUCCESS)
278 return (RPC_SYSTEMERROR);
279
280 mtx_lock(&rpctls_lock);
281 RB_INSERT(upsock_t, &upcall_sockets, &ups);
282 mtx_unlock(&rpctls_lock);
283
284 /* Temporarily block reception during the handshake upcall. */
285 CLNT_CONTROL(newclient, CLSET_BLOCKRCV, &(int){1});
286
287 /* Do the connect handshake upcall. */
288 if (certname != NULL) {
289 arg.certname.certname_len = strlen(certname);
290 arg.certname.certname_val = certname;
291 } else
292 arg.certname.certname_len = 0;
293 arg.socookie = (uint64_t)so;
294 stat = rpctlscd_connect_2(&arg, &res, rpctls_connect_handle);
295 if (stat == RPC_SUCCESS)
296 *reterr = res.reterr;
297 else
298 rpctls_rpc_failed(&ups, so);
299
300 /* Unblock reception. */
301 CLNT_CONTROL(newclient, CLSET_BLOCKRCV, &(int){0});
302
303 #ifdef INVARIANTS
304 mtx_lock(&rpctls_lock);
305 MPASS((RB_FIND(upsock_t, &upcall_sockets, &ups) == NULL));
306 mtx_unlock(&rpctls_lock);
307 #endif
308
309 return (stat);
310 }
311
312 /* Do an upcall to handle an non-application data record using TLS. */
313 enum clnt_stat
rpctls_cl_handlerecord(void * socookie,uint32_t * reterr)314 rpctls_cl_handlerecord(void *socookie, uint32_t *reterr)
315 {
316 struct rpctlscd_handlerecord_arg arg;
317 struct rpctlscd_handlerecord_res res;
318 enum clnt_stat stat;
319
320 /* Do the handlerecord upcall. */
321 arg.socookie = (uint64_t)socookie;
322 stat = rpctlscd_handlerecord_2(&arg, &res, rpctls_connect_handle);
323 if (stat == RPC_SUCCESS)
324 *reterr = res.reterr;
325 return (stat);
326 }
327
328 enum clnt_stat
rpctls_srv_handlerecord(void * socookie,uint32_t * reterr)329 rpctls_srv_handlerecord(void *socookie, uint32_t *reterr)
330 {
331 struct rpctlssd_handlerecord_arg arg;
332 struct rpctlssd_handlerecord_res res;
333 enum clnt_stat stat;
334
335 /* Do the handlerecord upcall. */
336 arg.socookie = (uint64_t)socookie;
337 stat = rpctlssd_handlerecord_2(&arg, &res, rpctls_server_handle);
338 if (stat == RPC_SUCCESS)
339 *reterr = res.reterr;
340 return (stat);
341 }
342
343 /* Do an upcall to shut down a socket using TLS. */
344 enum clnt_stat
rpctls_cl_disconnect(void * socookie,uint32_t * reterr)345 rpctls_cl_disconnect(void *socookie, uint32_t *reterr)
346 {
347 struct rpctlscd_disconnect_arg arg;
348 struct rpctlscd_disconnect_res res;
349 enum clnt_stat stat;
350
351 /* Do the disconnect upcall. */
352 arg.socookie = (uint64_t)socookie;
353 stat = rpctlscd_disconnect_2(&arg, &res, rpctls_connect_handle);
354 if (stat == RPC_SUCCESS)
355 *reterr = res.reterr;
356 return (stat);
357 }
358
359 enum clnt_stat
rpctls_srv_disconnect(void * socookie,uint32_t * reterr)360 rpctls_srv_disconnect(void *socookie, uint32_t *reterr)
361 {
362 struct rpctlssd_disconnect_arg arg;
363 struct rpctlssd_disconnect_res res;
364 enum clnt_stat stat;
365
366 /* Do the disconnect upcall. */
367 arg.socookie = (uint64_t)socookie;
368 stat = rpctlssd_disconnect_2(&arg, &res, rpctls_server_handle);
369 if (stat == RPC_SUCCESS)
370 *reterr = res.reterr;
371 return (stat);
372 }
373
374 /* Do an upcall for a new server socket using TLS. */
375 static enum clnt_stat
rpctls_server(SVCXPRT * xprt,uint32_t * flags,uid_t * uid,int * ngrps,gid_t ** gids)376 rpctls_server(SVCXPRT *xprt, uint32_t *flags, uid_t *uid, int *ngrps,
377 gid_t **gids)
378 {
379 enum clnt_stat stat;
380 struct upsock ups = {
381 .so = xprt->xp_socket,
382 .xp = xprt,
383 .server = true,
384 };
385 struct rpctlssd_connect_arg arg;
386 struct rpctlssd_connect_res res;
387 gid_t *gidp;
388 uint32_t *gidv;
389 int i;
390
391 mtx_lock(&rpctls_lock);
392 RB_INSERT(upsock_t, &upcall_sockets, &ups);
393 mtx_unlock(&rpctls_lock);
394
395 /* Do the server upcall. */
396 res.gid.gid_val = NULL;
397 arg.socookie = (uint64_t)xprt->xp_socket;
398 stat = rpctlssd_connect_2(&arg, &res, rpctls_server_handle);
399 if (stat == RPC_SUCCESS) {
400 *flags = res.flags;
401 if ((*flags & (RPCTLS_FLAGS_CERTUSER |
402 RPCTLS_FLAGS_DISABLED)) == RPCTLS_FLAGS_CERTUSER) {
403 *ngrps = res.gid.gid_len;
404 *uid = res.uid;
405 *gids = gidp = mem_alloc(*ngrps * sizeof(gid_t));
406 gidv = res.gid.gid_val;
407 for (i = 0; i < *ngrps; i++)
408 *gidp++ = *gidv++;
409 }
410 } else
411 rpctls_rpc_failed(&ups, xprt->xp_socket);
412
413 mem_free(res.gid.gid_val, 0);
414
415 #ifdef INVARIANTS
416 mtx_lock(&rpctls_lock);
417 MPASS((RB_FIND(upsock_t, &upcall_sockets, &ups) == NULL));
418 mtx_unlock(&rpctls_lock);
419 #endif
420
421 return (stat);
422 }
423
424 /*
425 * Handle the NULL RPC with authentication flavor of AUTH_TLS.
426 * This is a STARTTLS command, so do the upcall to the rpctlssd daemon,
427 * which will do the TLS handshake.
428 */
429 enum auth_stat
_svcauth_rpcsec_tls(struct svc_req * rqst,struct rpc_msg * msg)430 _svcauth_rpcsec_tls(struct svc_req *rqst, struct rpc_msg *msg)
431
432 {
433 bool_t call_stat;
434 enum clnt_stat stat;
435 SVCXPRT *xprt;
436 uint32_t flags;
437 int ngrps;
438 uid_t uid;
439 gid_t *gidp;
440 #ifdef KERN_TLS
441 u_int maxlen;
442 #endif
443
444 KRPC_CURVNET_SET_QUIET(KRPC_TD_TO_VNET(curthread));
445 KRPC_VNET(svc_vc_tls_handshake_failed)++;
446 /* Initialize reply. */
447 rqst->rq_verf = rpctls_null_verf;
448
449 /* Check client credentials. */
450 if (rqst->rq_cred.oa_length != 0 ||
451 msg->rm_call.cb_verf.oa_length != 0 ||
452 msg->rm_call.cb_verf.oa_flavor != AUTH_NULL) {
453 KRPC_CURVNET_RESTORE();
454 return (AUTH_BADCRED);
455 }
456
457 if (rqst->rq_proc != NULLPROC) {
458 KRPC_CURVNET_RESTORE();
459 return (AUTH_REJECTEDCRED);
460 }
461
462 call_stat = FALSE;
463 #ifdef KERN_TLS
464 if (rpctls_getinfo(&maxlen, false, true))
465 call_stat = TRUE;
466 #endif
467 if (!call_stat) {
468 KRPC_CURVNET_RESTORE();
469 return (AUTH_REJECTEDCRED);
470 }
471
472 /*
473 * Disable reception for the krpc so that the TLS handshake can
474 * be done on the socket in the rpctlssd daemon.
475 */
476 xprt = rqst->rq_xprt;
477 sx_xlock(&xprt->xp_lock);
478 xprt->xp_dontrcv = TRUE;
479 sx_xunlock(&xprt->xp_lock);
480
481 /*
482 * Send the reply to the NULL RPC with AUTH_TLS, which is the
483 * STARTTLS command for Sun RPC.
484 */
485 call_stat = svc_sendreply(rqst, (xdrproc_t)xdr_void, NULL);
486 if (!call_stat) {
487 sx_xlock(&xprt->xp_lock);
488 xprt->xp_dontrcv = FALSE;
489 sx_xunlock(&xprt->xp_lock);
490 xprt_active(xprt); /* Harmless if already active. */
491 KRPC_CURVNET_RESTORE();
492 return (AUTH_REJECTEDCRED);
493 }
494
495 /* Do an upcall to do the TLS handshake. */
496 stat = rpctls_server(xprt, &flags, &uid, &ngrps, &gidp);
497
498 /* Re-enable reception on the socket within the krpc. */
499 sx_xlock(&xprt->xp_lock);
500 xprt->xp_dontrcv = FALSE;
501 if (stat == RPC_SUCCESS) {
502 xprt->xp_tls = flags;
503 if ((flags & (RPCTLS_FLAGS_CERTUSER |
504 RPCTLS_FLAGS_DISABLED)) == RPCTLS_FLAGS_CERTUSER) {
505 xprt->xp_ngrps = ngrps;
506 xprt->xp_uid = uid;
507 xprt->xp_gidp = gidp;
508 }
509 KRPC_VNET(svc_vc_tls_handshake_failed)--;
510 KRPC_VNET(svc_vc_tls_handshake_success)++;
511 }
512 sx_xunlock(&xprt->xp_lock);
513 xprt_active(xprt); /* Harmless if already active. */
514 KRPC_CURVNET_RESTORE();
515
516 return (RPCSEC_GSS_NODISPATCH);
517 }
518
519 /*
520 * Get kern.ipc.tls.enable and kern.ipc.tls.maxlen.
521 */
522 bool
rpctls_getinfo(u_int * maxlenp,bool rpctlscd_run,bool rpctlssd_run)523 rpctls_getinfo(u_int *maxlenp, bool rpctlscd_run, bool rpctlssd_run)
524 {
525 u_int maxlen;
526 bool enable;
527 int error;
528 size_t siz;
529
530 if (!mb_use_ext_pgs)
531 return (false);
532 siz = sizeof(enable);
533 error = kernel_sysctlbyname(curthread, "kern.ipc.tls.enable",
534 &enable, &siz, NULL, 0, NULL, 0);
535 if (error != 0)
536 return (false);
537 siz = sizeof(maxlen);
538 error = kernel_sysctlbyname(curthread, "kern.ipc.tls.maxlen",
539 &maxlen, &siz, NULL, 0, NULL, 0);
540 if (error != 0)
541 return (false);
542 *maxlenp = maxlen;
543 return (enable);
544 }
545