Print this page
3354 kernel crash in rpcsec_gss after using gsscred
Reviewed by: Toomas Soome <tsoome@me.com>
Reviewed by: Carlos Neira <cneirabustos@gmail.com>
Approved by: Robert Mustacchi <rm@joyent.com>
NEX-4123 xdrmblk_getpos() is unreliable
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>

*** 21,30 **** --- 21,32 ---- /* * Copyright 2015 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2012 Milan Jurik. All rights reserved. + * Copyright 2012 Marcel Telka <marcel@telka.sk> + * Copyright 2018 OmniOS Community Edition (OmniOSce) Association. */ /* * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. *
*** 372,385 **** /* * Shift the array arr of length arrlen right by nbits bits. */ static void ! shift_bits(arr, arrlen, nbits) ! uint_t *arr; ! int arrlen; ! int nbits; { int i, j; uint_t lo, hi; /* --- 374,384 ---- /* * Shift the array arr of length arrlen right by nbits bits. */ static void ! shift_bits(uint_t *arr, int arrlen, int nbits) { int i, j; uint_t lo, hi; /*
*** 405,418 **** /* * Check that the received sequence number seq_num is valid. */ static bool_t ! check_seq(cl, seq_num, kill_context) ! svc_rpc_gss_data *cl; ! uint_t seq_num; ! bool_t *kill_context; { int i, j; uint_t bit; /* --- 404,414 ---- /* * Check that the received sequence number seq_num is valid. */ static bool_t ! check_seq(svc_rpc_gss_data *cl, uint_t seq_num, bool_t *kill_context) { int i, j; uint_t bit; /*
*** 463,474 **** /* * Set server callback. */ bool_t ! rpc_gss_set_callback(cb) ! rpc_gss_callback_t *cb; { rpc_gss_cblist_t *cbl, *tmp; if (cb->callback == NULL) { RPCGSS_LOG0(1, "rpc_gss_set_callback: no callback to set\n"); --- 459,469 ---- /* * Set server callback. */ bool_t ! rpc_gss_set_callback(rpc_gss_callback_t *cb) { rpc_gss_cblist_t *cbl, *tmp; if (cb->callback == NULL) { RPCGSS_LOG0(1, "rpc_gss_set_callback: no callback to set\n");
*** 506,518 **** * delegated credentials unless passed to server and the server * accepts the context. If a callback is not specified, accept * the incoming context. */ static bool_t ! do_callback(req, client_data) ! struct svc_req *req; ! svc_rpc_gss_data *client_data; { rpc_gss_cblist_t *cbl; bool_t ret = TRUE, found = FALSE; rpc_gss_lock_t lock; OM_uint32 minor; --- 501,511 ---- * delegated credentials unless passed to server and the server * accepts the context. If a callback is not specified, accept * the incoming context. */ static bool_t ! do_callback(struct svc_req *req, svc_rpc_gss_data *client_data) { rpc_gss_cblist_t *cbl; bool_t ret = TRUE, found = FALSE; rpc_gss_lock_t lock; OM_uint32 minor;
*** 547,561 **** /* * Get caller credentials. */ bool_t ! rpc_gss_getcred(req, rcred, ucred, cookie) ! struct svc_req *req; ! rpc_gss_rawcred_t **rcred; ! rpc_gss_ucred_t **ucred; ! void **cookie; { SVCAUTH *svcauth; svc_rpc_gss_data *client_data; int gssstat, gidlen; --- 540,551 ---- /* * Get caller credentials. */ bool_t ! rpc_gss_getcred(struct svc_req *req, rpc_gss_rawcred_t **rcred, ! rpc_gss_ucred_t **ucred, void **cookie) { SVCAUTH *svcauth; svc_rpc_gss_data *client_data; int gssstat, gidlen;
*** 577,610 **** if ((gssstat = kgsscred_expname_to_unix_cred( &client_data->client_name, &client_data->u_cred.uid, &client_data->u_cred.gid, &client_data->u_cred.gidlist, ! &gidlen, crgetuid(CRED()))) != GSS_S_COMPLETE) { RPCGSS_LOG(1, "rpc_gss_getcred: " ! "kgsscred_expname_to_unix_cred failed %x\n", ! gssstat); *ucred = NULL; } else { ! client_data->u_cred.gidlen = (short)gidlen; client_data->u_cred_set = ! gethrestime_sec() + svc_rpcgss_gid_timeout; } ! } else if (client_data->u_cred_set < gethrestime_sec()) { if ((gssstat = kgss_get_group_info( client_data->u_cred.uid, &client_data->u_cred.gid, &client_data->u_cred.gidlist, ! &gidlen, crgetuid(CRED()))) != GSS_S_COMPLETE) { RPCGSS_LOG(1, "rpc_gss_getcred: " "kgss_get_group_info failed %x\n", gssstat); *ucred = NULL; } else { ! client_data->u_cred.gidlen = (short)gidlen; client_data->u_cred_set = ! gethrestime_sec() + svc_rpcgss_gid_timeout; } } } } --- 567,607 ---- if ((gssstat = kgsscred_expname_to_unix_cred( &client_data->client_name, &client_data->u_cred.uid, &client_data->u_cred.gid, &client_data->u_cred.gidlist, ! &gidlen, crgetuid(CRED()))) ! != GSS_S_COMPLETE) { RPCGSS_LOG(1, "rpc_gss_getcred: " ! "kgsscred_expname_to_unix_cred " ! "failed %x\n", gssstat); *ucred = NULL; } else { ! client_data->u_cred.gidlen = ! (short)gidlen; client_data->u_cred_set = ! gethrestime_sec() + ! svc_rpcgss_gid_timeout; } ! } else if (client_data->u_cred_set ! < gethrestime_sec()) { if ((gssstat = kgss_get_group_info( client_data->u_cred.uid, &client_data->u_cred.gid, &client_data->u_cred.gidlist, ! &gidlen, crgetuid(CRED()))) ! != GSS_S_COMPLETE) { RPCGSS_LOG(1, "rpc_gss_getcred: " "kgss_get_group_info failed %x\n", gssstat); *ucred = NULL; } else { ! client_data->u_cred.gidlen = ! (short)gidlen; client_data->u_cred_set = ! gethrestime_sec() + ! svc_rpcgss_gid_timeout; } } } }
*** 907,916 **** --- 904,914 ---- cmn_err(CE_NOTE, "svcrpcsec_gss_taskq_func: do_gss_accept fail 0x%x", retval); } rpc_msg_free(&arg->msg, MAX_AUTH_BYTES); + SVC_RELE(arg->rq_xprt, NULL, FALSE); svc_clone_unlink(arg->rq_xprt); svc_clone_free(arg->rq_xprt); xdr_free(__xdr_rpc_gss_init_arg, (caddr_t)arg->rpc_call_arg); kmem_free(arg->rpc_call_arg, sizeof (*arg->rpc_call_arg));
*** 972,981 **** --- 970,984 ---- /* get a xprt clone for taskq thread, taskq func must free it */ arg->rq_xprt = svc_clone_init(); svc_clone_link(rqst->rq_xprt->xp_master, arg->rq_xprt, rqst->rq_xprt); arg->rq_xprt->xp_xid = rqst->rq_xprt->xp_xid; + /* + * Increment the reference count on the rpcmod slot so that is not + * freed before the task has finished. + */ + SVC_HOLD(arg->rq_xprt); /* set the appropriate wrap/unwrap routine for RPCSEC_GSS */ arg->rq_xprt->xp_auth.svc_ah_ops = svc_rpc_gss_ops; arg->rq_xprt->xp_auth.svc_ah_private = (caddr_t)client_data;
*** 991,1000 **** --- 994,1004 ---- svcrpcsec_gss_taskq_func, arg, DDI_SLEEP); if (ret == DDI_FAILURE) { cmn_err(CE_NOTE, "rpcsec_gss_init: taskq dispatch fail"); ret = RPCSEC_GSS_FAILED; rpc_msg_free(&arg->msg, MAX_AUTH_BYTES); + SVC_RELE(arg->rq_xprt, NULL, FALSE); svc_clone_unlink(arg->rq_xprt); svc_clone_free(arg->rq_xprt); kmem_free(arg, sizeof (*arg)); goto error2; }
*** 1471,1485 **** /* * Set response verifier. This is the checksum of the given number. * (e.g. sequence number or sequence window) */ static bool_t ! set_response_verf(rqst, msg, cl, num) ! struct svc_req *rqst; ! struct rpc_msg *msg; ! svc_rpc_gss_data *cl; ! uint_t num; { OM_uint32 minor; gss_buffer_desc in_buf, out_buf; uint_t num_net; --- 1475,1486 ---- /* * Set response verifier. This is the checksum of the given number. * (e.g. sequence number or sequence window) */ static bool_t ! set_response_verf(struct svc_req *rqst, struct rpc_msg *msg, ! svc_rpc_gss_data *cl, uint_t num) { OM_uint32 minor; gss_buffer_desc in_buf, out_buf; uint_t num_net;
*** 1486,1497 **** num_net = (uint_t)htonl(num); in_buf.length = sizeof (num); in_buf.value = (char *)&num_net; /* XXX uid ? */ ! if ((kgss_sign(&minor, cl->context, cl->qop, &in_buf, ! &out_buf)) != GSS_S_COMPLETE) return (FALSE); rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS; rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base; rqst->rq_xprt->xp_verf.oa_length = out_buf.length; --- 1487,1498 ---- num_net = (uint_t)htonl(num); in_buf.length = sizeof (num); in_buf.value = (char *)&num_net; /* XXX uid ? */ ! if ((kgss_sign(&minor, cl->context, cl->qop, &in_buf, &out_buf)) ! != GSS_S_COMPLETE) return (FALSE); rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS; rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base; rqst->rq_xprt->xp_verf.oa_length = out_buf.length;
*** 1562,1573 **** /* * Insert client context into hash list and LRU list. */ static void ! insert_client(client_data) ! svc_rpc_gss_data *client_data; { svc_rpc_gss_data *cl; int index = HASH(client_data->key); ASSERT(mutex_owned(&ctx_mutex)); --- 1563,1573 ---- /* * Insert client context into hash list and LRU list. */ static void ! insert_client(svc_rpc_gss_data *client_data) { svc_rpc_gss_data *cl; int index = HASH(client_data->key); ASSERT(mutex_owned(&ctx_mutex));
*** 1591,1602 **** /* * Fetch a client, given the client context handle. Move it to the * top of the LRU list since this is the most recently used context. */ static svc_rpc_gss_data * ! get_client(ctx_handle) ! gss_buffer_t ctx_handle; { uint_t key = *(uint_t *)ctx_handle->value; svc_rpc_gss_data *cl; mutex_enter(&ctx_mutex); --- 1591,1601 ---- /* * Fetch a client, given the client context handle. Move it to the * top of the LRU list since this is the most recently used context. */ static svc_rpc_gss_data * ! get_client(gss_buffer_t ctx_handle) { uint_t key = *(uint_t *)ctx_handle->value; svc_rpc_gss_data *cl; mutex_enter(&ctx_mutex);
*** 1634,1645 **** /* * Given the client context handle, find the context corresponding to it. * Don't change its LRU state since it may not be used. */ static svc_rpc_gss_data * ! find_client(key) ! uint_t key; { int index = HASH(key); svc_rpc_gss_data *cl = NULL; ASSERT(mutex_owned(&ctx_mutex)); --- 1633,1643 ---- /* * Given the client context handle, find the context corresponding to it. * Don't change its LRU state since it may not be used. */ static svc_rpc_gss_data * ! find_client(uint_t key) { int index = HASH(key); svc_rpc_gss_data *cl = NULL; ASSERT(mutex_owned(&ctx_mutex));
*** 1653,1664 **** /* * Destroy a client context. */ static void ! destroy_client(client_data) ! svc_rpc_gss_data *client_data; { OM_uint32 minor; int index = HASH(client_data->key); ASSERT(mutex_owned(&ctx_mutex)); --- 1651,1661 ---- /* * Destroy a client context. */ static void ! destroy_client(svc_rpc_gss_data *client_data) { OM_uint32 minor; int index = HASH(client_data->key); ASSERT(mutex_owned(&ctx_mutex));
*** 1771,1796 **** /* * Encrypt the serialized arguments from xdr_func applied to xdr_ptr * and write the result to xdrs. */ static bool_t ! svc_rpc_gss_wrap(auth, out_xdrs, xdr_func, xdr_ptr) ! SVCAUTH *auth; ! XDR *out_xdrs; ! bool_t (*xdr_func)(); ! caddr_t xdr_ptr; { svc_rpc_gss_parms_t *gss_parms = SVCAUTH_GSSPARMS(auth); bool_t ret; /* * If context is not established, or if neither integrity nor * privacy service is used, don't wrap - just XDR encode. * Otherwise, wrap data using service and QOP parameters. */ ! if (!gss_parms->established || ! gss_parms->service == rpc_gss_svc_none) return ((*xdr_func)(out_xdrs, xdr_ptr)); ret = __rpc_gss_wrap_data(gss_parms->service, (OM_uint32)gss_parms->qop_rcvd, (gss_ctx_id_t)gss_parms->context, --- 1768,1789 ---- /* * Encrypt the serialized arguments from xdr_func applied to xdr_ptr * and write the result to xdrs. */ static bool_t ! svc_rpc_gss_wrap(SVCAUTH *auth, XDR *out_xdrs, bool_t (*xdr_func)(), ! caddr_t xdr_ptr) { svc_rpc_gss_parms_t *gss_parms = SVCAUTH_GSSPARMS(auth); bool_t ret; /* * If context is not established, or if neither integrity nor * privacy service is used, don't wrap - just XDR encode. * Otherwise, wrap data using service and QOP parameters. */ ! if (!gss_parms->established || gss_parms->service == rpc_gss_svc_none) return ((*xdr_func)(out_xdrs, xdr_ptr)); ret = __rpc_gss_wrap_data(gss_parms->service, (OM_uint32)gss_parms->qop_rcvd, (gss_ctx_id_t)gss_parms->context,
*** 1801,1825 **** /* * Decrypt the serialized arguments and XDR decode them. */ static bool_t ! svc_rpc_gss_unwrap(auth, in_xdrs, xdr_func, xdr_ptr) ! SVCAUTH *auth; ! XDR *in_xdrs; ! bool_t (*xdr_func)(); ! caddr_t xdr_ptr; { svc_rpc_gss_parms_t *gss_parms = SVCAUTH_GSSPARMS(auth); /* * If context is not established, or if neither integrity nor * privacy service is used, don't unwrap - just XDR decode. * Otherwise, unwrap data. */ ! if (!gss_parms->established || ! gss_parms->service == rpc_gss_svc_none) return ((*xdr_func)(in_xdrs, xdr_ptr)); return (__rpc_gss_unwrap_data(gss_parms->service, (gss_ctx_id_t)gss_parms->context, gss_parms->seq_num, --- 1794,1814 ---- /* * Decrypt the serialized arguments and XDR decode them. */ static bool_t ! svc_rpc_gss_unwrap(SVCAUTH *auth, XDR *in_xdrs, bool_t (*xdr_func)(), ! caddr_t xdr_ptr) { svc_rpc_gss_parms_t *gss_parms = SVCAUTH_GSSPARMS(auth); /* * If context is not established, or if neither integrity nor * privacy service is used, don't unwrap - just XDR decode. * Otherwise, unwrap data. */ ! if (!gss_parms->established || gss_parms->service == rpc_gss_svc_none) return ((*xdr_func)(in_xdrs, xdr_ptr)); return (__rpc_gss_unwrap_data(gss_parms->service, (gss_ctx_id_t)gss_parms->context, gss_parms->seq_num,