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,10 +21,12 @@
 
 /*
  * 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,14 +374,11 @@
 
 /*
  * 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;
+shift_bits(uint_t *arr, int arrlen, int nbits)
 {
         int     i, j;
         uint_t  lo, hi;
 
         /*

@@ -405,14 +404,11 @@
 
 /*
  * 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;
+check_seq(svc_rpc_gss_data *cl, uint_t seq_num, bool_t *kill_context)
 {
         int                     i, j;
         uint_t                  bit;
 
         /*

@@ -463,12 +459,11 @@
 
 /*
  * Set server callback.
  */
 bool_t
-rpc_gss_set_callback(cb)
-        rpc_gss_callback_t      *cb;
+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,13 +501,11 @@
  * 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;
+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,15 +540,12 @@
 
 /*
  * 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;
+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,34 +567,41 @@
                         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) {
+                                    &gidlen, crgetuid(CRED())))
+                                    != GSS_S_COMPLETE) {
                                 RPCGSS_LOG(1, "rpc_gss_getcred: "
-                                    "kgsscred_expname_to_unix_cred failed %x\n",
-                                    gssstat);
+                                            "kgsscred_expname_to_unix_cred "
+                                            "failed %x\n", gssstat);
                                 *ucred = NULL;
                         } else {
-                                client_data->u_cred.gidlen = (short)gidlen;
+                                        client_data->u_cred.gidlen =
+                                            (short)gidlen;
                                 client_data->u_cred_set =
-                                    gethrestime_sec() + svc_rpcgss_gid_timeout;
+                                            gethrestime_sec() +
+                                            svc_rpcgss_gid_timeout;
                         }
-                    } else if (client_data->u_cred_set < gethrestime_sec()) {
+                        } 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) {
+                                    &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.gidlen =
+                                            (short)gidlen;
                                 client_data->u_cred_set =
-                                    gethrestime_sec() + svc_rpcgss_gid_timeout;
+                                            gethrestime_sec() +
+                                            svc_rpcgss_gid_timeout;
                         }
                     }
                 }
         }
 

@@ -907,10 +904,11 @@
                 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,10 +970,15 @@
         /* 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,10 +994,11 @@
             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,15 +1475,12 @@
 /*
  * 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;
+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,12 +1487,12 @@
         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)
+        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,12 +1563,11 @@
 
 /*
  * Insert client context into hash list and LRU list.
  */
 static void
-insert_client(client_data)
-        svc_rpc_gss_data        *client_data;
+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,12 +1591,11 @@
 /*
  * 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;
+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,12 +1633,11 @@
 /*
  * 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;
+find_client(uint_t key)
 {
         int                     index = HASH(key);
         svc_rpc_gss_data        *cl = NULL;
 
         ASSERT(mutex_owned(&ctx_mutex));

@@ -1653,12 +1651,11 @@
 
 /*
  * Destroy a client context.
  */
 static void
-destroy_client(client_data)
-        svc_rpc_gss_data        *client_data;
+destroy_client(svc_rpc_gss_data *client_data)
 {
         OM_uint32               minor;
         int                     index = HASH(client_data->key);
 
         ASSERT(mutex_owned(&ctx_mutex));

@@ -1771,26 +1768,22 @@
 /*
  * 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_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)
+        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,25 +1794,21 @@
 
 /*
  * 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_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)
+        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,