21ab4e
From 3cbb78a63b282d8c0d7c75f3b6c3816a7deb06c1 Mon Sep 17 00:00:00 2001
21ab4e
From: Niels de Vos <ndevos@redhat.com>
21ab4e
Date: Tue, 4 Jul 2017 20:11:11 +0200
21ab4e
Subject: [PATCH 550/557] nfs/nlm: keep track of the call-state and frame for
21ab4e
 notifications
21ab4e
21ab4e
When blocking locks are used, a new frame is allocated that is used to
21ab4e
send the notification to the client once once the lock becomes
21ab4e
available. In all other cases, the frame that contains the request from
21ab4e
the client will be used for the reply.
21ab4e
21ab4e
Because there was no way to track the different clients with their
21ab4e
requests (captured in the call-state), the call-state could be free'd
21ab4e
before the notification was sent to the client. This caused a
21ab4e
use-after-free of the call-state and could trigger segfaults of the
21ab4e
Gluster/NFS server or incorrect replies on (un)lock requests.
21ab4e
21ab4e
By introducing a nlm4_notify_args structure, the call-state and frame
21ab4e
can be tracked better. This prevents the possibility of segfaulting when
21ab4e
the call-state is used after being free'd.
21ab4e
21ab4e
Cherry picked from commit b81997264f079983fa02bd5fa2b3715224942b00:
21ab4e
> BUG: 1467313
21ab4e
> Change-Id: I285d2bc552f509e5145653b7a50afcff827cd612
21ab4e
> Signed-off-by: Niels de Vos <ndevos@redhat.com>
21ab4e
> Reviewed-on: https://review.gluster.org/17700
21ab4e
> Smoke: Gluster Build System <jenkins@build.gluster.org>
21ab4e
> CentOS-regression: Gluster Build System <jenkins@build.gluster.org>
21ab4e
> Reviewed-by: Kaleb KEITHLEY <kkeithle@redhat.com>
21ab4e
> Reviewed-by: jiffin tony Thottan <jthottan@redhat.com>
21ab4e
21ab4e
Change-Id: I285d2bc552f509e5145653b7a50afcff827cd612
21ab4e
BUG: 1411344
21ab4e
Signed-off-by: Niels de Vos <ndevos@redhat.com>
21ab4e
Reviewed-on: https://code.engineering.redhat.com/gerrit/111769
21ab4e
Reviewed-by: Atin Mukherjee <amukherj@redhat.com>
21ab4e
---
21ab4e
 xlators/nfs/server/src/nfs-mem-types.h |   1 +
21ab4e
 xlators/nfs/server/src/nlm4.c          | 107 +++++++++++++++++++++++++--------
21ab4e
 2 files changed, 84 insertions(+), 24 deletions(-)
21ab4e
21ab4e
diff --git a/xlators/nfs/server/src/nfs-mem-types.h b/xlators/nfs/server/src/nfs-mem-types.h
21ab4e
index 88c688f..5cac0eb 100644
21ab4e
--- a/xlators/nfs/server/src/nfs-mem-types.h
21ab4e
+++ b/xlators/nfs/server/src/nfs-mem-types.h
21ab4e
@@ -50,6 +50,7 @@ enum gf_nfs_mem_types_ {
21ab4e
         gf_nfs_mt_arr,
21ab4e
         gf_nfs_mt_auth_cache,
21ab4e
         gf_nfs_mt_auth_cache_entry,
21ab4e
+        gf_nfs_mt_nlm4_notify,
21ab4e
         gf_nfs_mt_end
21ab4e
 };
21ab4e
 #endif
21ab4e
diff --git a/xlators/nfs/server/src/nlm4.c b/xlators/nfs/server/src/nlm4.c
21ab4e
index d678edc..8b7c747 100644
21ab4e
--- a/xlators/nfs/server/src/nlm4.c
21ab4e
+++ b/xlators/nfs/server/src/nlm4.c
21ab4e
@@ -922,28 +922,64 @@ rpcerr:
21ab4e
         return ret;
21ab4e
 }
21ab4e
 
21ab4e
-int
21ab4e
+struct nlm4_notify_args {
21ab4e
+        GF_REF_DECL;            /* refcounting */
21ab4e
+
21ab4e
+        nfs3_call_state_t *cs;  /* call state, w/ lock request details */
21ab4e
+        call_frame_t *frame;    /* frame to us for the reply */
21ab4e
+};
21ab4e
+
21ab4e
+static int
21ab4e
 nlm4svc_send_granted_cbk (struct rpc_req *req, struct iovec *iov, int count,
21ab4e
                           void *myframe)
21ab4e
 {
21ab4e
-        STACK_DESTROY (((call_frame_t*)myframe)->root);
21ab4e
+        call_frame_t            *frame = myframe;
21ab4e
+        struct nlm4_notify_args *args  = frame->local;
21ab4e
+
21ab4e
+        GF_REF_PUT (args);
21ab4e
         return 0;
21ab4e
 }
21ab4e
 
21ab4e
+static void
21ab4e
+nlm4_notify_free (struct nlm4_notify_args *ncf)
21ab4e
+{
21ab4e
+        GF_REF_PUT (ncf->cs);
21ab4e
+        STACK_DESTROY (ncf->frame->root);
21ab4e
+        GF_FREE (ncf);
21ab4e
+}
21ab4e
+
21ab4e
+static struct nlm4_notify_args*
21ab4e
+nlm4_notify_init (nfs3_call_state_t *cs)
21ab4e
+{
21ab4e
+        struct nlm4_notify_args *ncf = NULL;
21ab4e
+
21ab4e
+        ncf = GF_CALLOC (1, sizeof (struct nlm4_notify_args),
21ab4e
+                         gf_nfs_mt_nlm4_notify);
21ab4e
+        if (!ncf)
21ab4e
+                /* GF_CALLOW will log the ENOMEM error */
21ab4e
+                goto out;
21ab4e
+
21ab4e
+        GF_REF_INIT (ncf, nlm4_notify_free);
21ab4e
+        ncf->cs = GF_REF_GET (cs);
21ab4e
+
21ab4e
+out:
21ab4e
+        return ncf;
21ab4e
+}
21ab4e
+
21ab4e
 static int
21ab4e
-nlm_handle_connect (struct rpc_clnt *rpc_clnt, nfs3_call_state_t *cs);
21ab4e
+nlm_handle_connect (struct rpc_clnt *rpc_clnt, struct nlm4_notify_args *ncf);
21ab4e
 
21ab4e
 int
21ab4e
 nlm_rpcclnt_notify (struct rpc_clnt *rpc_clnt, void *mydata,
21ab4e
                     rpc_clnt_event_t fn, void *data)
21ab4e
 {
21ab4e
-        nfs3_call_state_t *cs          = NULL;
21ab4e
+        struct nlm4_notify_args   *ncf     = mydata;
21ab4e
 
21ab4e
-        cs = mydata;
21ab4e
+        GF_VALIDATE_OR_GOTO ("NLM4-notify", ncf, out);
21ab4e
 
21ab4e
         switch (fn) {
21ab4e
         case RPC_CLNT_CONNECT:
21ab4e
-                nlm_handle_connect (rpc_clnt, cs);
21ab4e
+                nlm_handle_connect (rpc_clnt, ncf);
21ab4e
                 break;
21ab4e
 
21ab4e
         case RPC_CLNT_MSG:
21ab4e
@@ -952,18 +988,22 @@ nlm_rpcclnt_notify (struct rpc_clnt *rpc_clnt, void *mydata,
21ab4e
         case RPC_CLNT_DISCONNECT:
21ab4e
                 nlm_unset_rpc_clnt (rpc_clnt);
21ab4e
                 break;
21ab4e
+
21ab4e
+        case RPC_CLNT_DESTROY:
21ab4e
+                GF_REF_PUT (ncf);
21ab4e
+                break;
21ab4e
+
21ab4e
         default:
21ab4e
                 break;
21ab4e
         }
21ab4e
-
21ab4e
+out:
21ab4e
         return 0;
21ab4e
 }
21ab4e
 
21ab4e
 void *
21ab4e
-nlm4_establish_callback (void *csarg)
21ab4e
+nlm4_establish_callback (nfs3_call_state_t *cs, call_frame_t *cbk_frame)
21ab4e
 {
21ab4e
         int                           ret                        = -1;
21ab4e
-        nfs3_call_state_t            *cs                         = NULL;
21ab4e
         union gf_sock_union           sock_union;
21ab4e
         dict_t                       *options                    = NULL;
21ab4e
         char                          peerip[INET6_ADDRSTRLEN+1] = {0};
21ab4e
@@ -971,9 +1011,8 @@ nlm4_establish_callback (void *csarg)
21ab4e
         char                          myip[INET6_ADDRSTRLEN+1]   = {0};
21ab4e
         rpc_clnt_t                   *rpc_clnt                   = NULL;
21ab4e
         int                           port                       = -1;
21ab4e
+        struct nlm4_notify_args      *ncf                        = NULL;
21ab4e
 
21ab4e
-
21ab4e
-        cs = (nfs3_call_state_t *) csarg;
21ab4e
         glusterfs_this_set (cs->nfsx);
21ab4e
 
21ab4e
         rpc_transport_get_peeraddr (cs->trans, NULL, 0, &sock_union.storage,
21ab4e
@@ -1056,6 +1095,15 @@ nlm4_establish_callback (void *csarg)
21ab4e
                 goto err;
21ab4e
         }
21ab4e
 
21ab4e
+        ncf = nlm4_notify_init (cs);
21ab4e
+        if (!ncf) {
21ab4e
+                ret = -1;
21ab4e
+                goto err;
21ab4e
+        }
21ab4e
+
21ab4e
+        ncf->frame = cbk_frame;
21ab4e
+        ncf->frame->local = ncf;
21ab4e
+
21ab4e
         /* TODO: is 32 frames in transit enough ? */
21ab4e
         rpc_clnt = rpc_clnt_new (options, cs->nfsx, "NLM-client", 32);
21ab4e
         if (rpc_clnt == NULL) {
21ab4e
@@ -1064,7 +1112,7 @@ nlm4_establish_callback (void *csarg)
21ab4e
                 goto err;
21ab4e
         }
21ab4e
 
21ab4e
-        ret = rpc_clnt_register_notify (rpc_clnt, nlm_rpcclnt_notify, cs);
21ab4e
+        ret = rpc_clnt_register_notify (rpc_clnt, nlm_rpcclnt_notify, ncf);
21ab4e
         if (ret == -1) {
21ab4e
                 gf_msg (GF_NLM, GF_LOG_ERROR, errno, NFS_MSG_RPC_CLNT_ERROR,
21ab4e
                         "rpc_clnt_register_connect error");
21ab4e
@@ -1078,17 +1126,21 @@ nlm4_establish_callback (void *csarg)
21ab4e
                 ret = 0;
21ab4e
 
21ab4e
 err:
21ab4e
-        if (ret == -1 && rpc_clnt) {
21ab4e
-                rpc_clnt_unref (rpc_clnt);
21ab4e
+        if (ret == -1) {
21ab4e
+                if (rpc_clnt)
21ab4e
+                        rpc_clnt_unref (rpc_clnt);
21ab4e
+                if (ncf)
21ab4e
+                        GF_REF_PUT (ncf);
21ab4e
         }
21ab4e
 
21ab4e
         return rpc_clnt;
21ab4e
 }
21ab4e
 
21ab4e
-void
21ab4e
-nlm4svc_send_granted (nfs3_call_state_t *cs)
21ab4e
+static void
21ab4e
+nlm4svc_send_granted (struct nlm4_notify_args *ncf)
21ab4e
 {
21ab4e
         int ret = -1;
21ab4e
+        nfs3_call_state_t *cs = ncf->cs;
21ab4e
         rpc_clnt_t *rpc_clnt = NULL;
21ab4e
         struct iovec            outmsg = {0, };
21ab4e
         nlm4_testargs testargs;
21ab4e
@@ -1099,7 +1151,7 @@ nlm4svc_send_granted (nfs3_call_state_t *cs)
21ab4e
 
21ab4e
         rpc_clnt = nlm_get_rpc_clnt (cs->args.nlm4_lockargs.alock.caller_name);
21ab4e
         if (rpc_clnt == NULL) {
21ab4e
-                nlm4_establish_callback ((void*)cs);
21ab4e
+                nlm4_establish_callback (cs, ncf->frame);
21ab4e
                 return;
21ab4e
         }
21ab4e
 
21ab4e
@@ -1150,9 +1202,10 @@ nlm4svc_send_granted (nfs3_call_state_t *cs)
21ab4e
                 goto ret;
21ab4e
         }
21ab4e
 
21ab4e
+        GF_REF_GET (ncf);
21ab4e
         ret = rpc_clnt_submit (rpc_clnt, &nlm4clntprog, NLM4_GRANTED,
21ab4e
                                nlm4svc_send_granted_cbk, &outmsg, 1,
21ab4e
-                               NULL, 0, iobref, cs->frame, NULL, 0,
21ab4e
+                               NULL, 0, iobref, ncf->frame, NULL, 0,
21ab4e
                                NULL, 0, NULL);
21ab4e
 
21ab4e
         if (ret < 0) {
21ab4e
@@ -1167,7 +1220,6 @@ ret:
21ab4e
                 iobuf_unref (iobuf);
21ab4e
 
21ab4e
         rpc_clnt_unref (rpc_clnt);
21ab4e
-        nfs3_call_state_wipe (cs);
21ab4e
         return;
21ab4e
 }
21ab4e
 
21ab4e
@@ -1338,6 +1390,7 @@ nlm4svc_lock_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
21ab4e
         char                            *caller_name = NULL;
21ab4e
         nfs3_call_state_t               *cs          = NULL;
21ab4e
         pthread_t                        thr;
21ab4e
+        struct nlm4_notify_args         *ncf         = NULL;
21ab4e
 
21ab4e
         cs = frame->local;
21ab4e
         caller_name = cs->args.nlm4_lockargs.alock.caller_name;
21ab4e
@@ -1359,14 +1412,18 @@ nlm4svc_lock_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
21ab4e
 
21ab4e
 err:
21ab4e
         if (cs->args.nlm4_lockargs.block) {
21ab4e
-                cs->frame = copy_frame (frame);
21ab4e
-                frame->local = NULL;
21ab4e
-                nlm4svc_send_granted (cs);
21ab4e
+                ncf = nlm4_notify_init (cs);
21ab4e
+                if (ncf) {
21ab4e
+                        ncf->frame = copy_frame (frame);
21ab4e
+                        ncf->frame->local = ncf;
21ab4e
+                        nlm4svc_send_granted (ncf);
21ab4e
+                }
21ab4e
         } else {
21ab4e
                 nlm4_generic_reply (cs->req, cs->args.nlm4_lockargs.cookie,
21ab4e
                                     stat);
21ab4e
                 nfs3_call_state_wipe (cs);
21ab4e
         }
21ab4e
+
21ab4e
         return 0;
21ab4e
 }
21ab4e
 
21ab4e
@@ -2378,13 +2435,15 @@ nlm4svc_sm_notify (struct nlm_sm_status *status)
21ab4e
 /* RPC_CLNT_CONNECT gets called on (re)connects and should be able to handle
21ab4e
  * different NLM requests. */
21ab4e
 static int
21ab4e
-nlm_handle_connect (struct rpc_clnt *rpc_clnt, nfs3_call_state_t *cs)
21ab4e
+nlm_handle_connect (struct rpc_clnt *rpc_clnt, struct nlm4_notify_args *ncf)
21ab4e
 {
21ab4e
         int                 ret         = -1;
21ab4e
         int                 nlm_proc    = NLM4_NULL;
21ab4e
+        nfs3_call_state_t  *cs          = NULL;
21ab4e
         struct nlm4_lock   *alock       = NULL;
21ab4e
         char               *caller_name = NULL;
21ab4e
 
21ab4e
+        cs = GF_REF_GET (ncf->cs);
21ab4e
         if (!cs || !cs->req) {
21ab4e
                 gf_msg (GF_NLM, GF_LOG_ERROR, EINVAL, NFS_MSG_RPC_CLNT_ERROR,
21ab4e
                         "Spurious notify?!");
21ab4e
@@ -2426,7 +2485,7 @@ nlm_handle_connect (struct rpc_clnt *rpc_clnt, nfs3_call_state_t *cs)
21ab4e
                 /* extra ref taken with nlm_set_rpc_clnt() */
21ab4e
                 rpc_clnt_unref (rpc_clnt);
21ab4e
 
21ab4e
-                nlm4svc_send_granted (cs);
21ab4e
+                nlm4svc_send_granted (ncf);
21ab4e
                 break;
21ab4e
 
21ab4e
         case NLM4_CANCEL:
21ab4e
-- 
21ab4e
1.8.3.1
21ab4e