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,