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 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 * 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 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 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 = __DECONST(struct socket *, 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 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 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 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 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 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 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 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 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 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