3604df
From eebc1b2076206600e9ed9ac6b3cd061708f96401 Mon Sep 17 00:00:00 2001
3604df
From: Poornima G <pgurusid@redhat.com>
3604df
Date: Tue, 14 Feb 2017 12:45:36 +0530
3604df
Subject: [PATCH 291/294] rpcsvc: Add rpchdr and proghdr to iobref before
3604df
 submitting to transport
3604df
3604df
Backport of https://review.gluster.org/16613
3604df
3604df
Issue:
3604df
When fio is run on multiple clients (each client writes to its own files),
3604df
and meanwhile the clients does a readdirp, thus the client which did
3604df
a readdirp will now recieve the upcalls. In this scenario the client
3604df
disconnects with rpc decode failed error.
3604df
3604df
RCA:
3604df
Upcall calls rpcsvc_request_submit to submit the request to socket:
3604df
rpcsvc_request_submit currently:
3604df
rpcsvc_request_submit () {
3604df
   iobuf = iobuf_new
3604df
   iov = iobuf->ptr
3604df
   fill iobuf to contain xdrised upcall content - proghdr
3604df
   rpcsvc_callback_submit (..iov..)
3604df
   ...
3604df
   if (iobuf)
3604df
       iobuf_unref (iobuf)
3604df
}
3604df
3604df
rpcsvc_callback_submit (... iov...) {
3604df
   ...
3604df
   iobuf = iobuf_new
3604df
   iov1 = iobuf->ptr
3604df
   fill iobuf to contain xdrised rpc header - rpchdr
3604df
   msg.rpchdr = iov1
3604df
   msg.proghdr = iov
3604df
   ...
3604df
   rpc_transport_submit_request (msg)
3604df
   ...
3604df
   if (iobuf)
3604df
       iobuf_unref (iobuf)
3604df
}
3604df
3604df
rpcsvc_callback_submit assumes that once rpc_transport_submit_request()
3604df
returns the msg is written on to socket and thus the buffers(rpchdr, proghdr)
3604df
can be freed, which is not the case. In especially high workload,
3604df
rpc_transport_submit_request() may not be able to write to socket immediately
3604df
and hence adds it to its own queue and returns as successful. Thus, we have
3604df
use after free, for rpchdr and proghdr. Hence the clients gets garbage rpchdr
3604df
and proghdr and thus fails to decode the rpc, resulting in disconnect.
3604df
3604df
To prevent this, we need to add the rpchdr and proghdr to a iobref and send
3604df
it in msg:
3604df
   iobref_add (iobref, iobufs)
3604df
   msg.iobref = iobref;
3604df
The socket layer takes a ref on msg.iobref, if it cannot write to socket and
3604df
is adding to the queue. Thus we do not have use after free.
3604df
3604df
Thank You for discussing, debugging and fixing along:
3604df
Prashanth Pai <ppai@redhat.com>
3604df
Raghavendra G <rgowdapp@redhat.com>
3604df
Rajesh Joseph <rjoseph@redhat.com>
3604df
Kotresh HR <khiremat@redhat.com>
3604df
Mohammed Rafi KC <rkavunga@redhat.com>
3604df
Soumya Koduri <skoduri@redhat.com>
3604df
3604df
> Reviewed-on: https://review.gluster.org/16613
3604df
> Reviewed-by: Prashanth Pai <ppai@redhat.com>
3604df
> Smoke: Gluster Build System <jenkins@build.gluster.org>
3604df
> Reviewed-by: soumya k <skoduri@redhat.com>
3604df
> NetBSD-regression: NetBSD Build System <jenkins@build.gluster.org>
3604df
> CentOS-regression: Gluster Build System <jenkins@build.gluster.org>
3604df
> Reviewed-by: Raghavendra G <rgowdapp@redhat.com>
3604df
3604df
Change-Id: Ifa6bf6f4879141f42b46830a37c1574b21b37275
3604df
BUG: 1409135
3604df
Signed-off-by: Poornima G <pgurusid@redhat.com>
3604df
Reviewed-on: https://code.engineering.redhat.com/gerrit/97927
3604df
Reviewed-by: Atin Mukherjee <amukherj@redhat.com>
3604df
---
3604df
 rpc/rpc-lib/src/rpcsvc.c             | 33 +++++++++++++++++++++++++++++++--
3604df
 rpc/rpc-lib/src/rpcsvc.h             |  3 ++-
3604df
 xlators/mgmt/glusterd/src/glusterd.c |  6 ++++--
3604df
 xlators/protocol/server/src/server.c | 20 +++++++++++++-------
3604df
 4 files changed, 50 insertions(+), 12 deletions(-)
3604df
3604df
diff --git a/rpc/rpc-lib/src/rpcsvc.c b/rpc/rpc-lib/src/rpcsvc.c
3604df
index 2d2a7ff..641b63c 100644
3604df
--- a/rpc/rpc-lib/src/rpcsvc.c
3604df
+++ b/rpc/rpc-lib/src/rpcsvc.c
3604df
@@ -1000,6 +1000,7 @@ int rpcsvc_request_submit (rpcsvc_t *rpc, rpc_transport_t *trans,
3604df
         struct iovec            iov         = {0, };
3604df
         struct iobuf            *iobuf      = NULL;
3604df
         ssize_t                 xdr_size    = 0;
3604df
+        struct iobref           *iobref     = NULL;
3604df
 
3604df
         if (!req)
3604df
                 goto out;
3604df
@@ -1022,26 +1023,40 @@ int rpcsvc_request_submit (rpcsvc_t *rpc, rpc_transport_t *trans,
3604df
         iov.iov_len = ret;
3604df
         count = 1;
3604df
 
3604df
+        iobref = iobref_new ();
3604df
+        if (!iobref) {
3604df
+                ret = -1;
3604df
+                gf_log ("rpcsvc", GF_LOG_WARNING, "Failed to create iobref");
3604df
+                goto out;
3604df
+        }
3604df
+
3604df
+        iobref_add (iobref, iobuf);
3604df
+
3604df
         ret = rpcsvc_callback_submit (rpc, trans, prog, procnum,
3604df
-                                      &iov, count);
3604df
+                                      &iov, count, iobref);
3604df
 
3604df
 out:
3604df
         if (iobuf)
3604df
                 iobuf_unref (iobuf);
3604df
 
3604df
+        if (iobref)
3604df
+                iobref_unref (iobref);
3604df
+
3604df
         return ret;
3604df
 }
3604df
 
3604df
 int
3604df
 rpcsvc_callback_submit (rpcsvc_t *rpc, rpc_transport_t *trans,
3604df
                         rpcsvc_cbk_program_t *prog, int procnum,
3604df
-                        struct iovec *proghdr, int proghdrcount)
3604df
+                        struct iovec *proghdr, int proghdrcount,
3604df
+                        struct iobref *iobref)
3604df
 {
3604df
         struct iobuf          *request_iob = NULL;
3604df
         struct iovec           rpchdr      = {0,};
3604df
         rpc_transport_req_t    req;
3604df
         int                    ret         = -1;
3604df
         int                    proglen     = 0;
3604df
+        gf_boolean_t           new_iobref  = _gf_false;
3604df
 
3604df
         if (!rpc) {
3604df
                 goto out;
3604df
@@ -1063,11 +1078,22 @@ rpcsvc_callback_submit (rpcsvc_t *rpc, rpc_transport_t *trans,
3604df
                         "cannot build rpc-record");
3604df
                 goto out;
3604df
         }
3604df
+        if (!iobref) {
3604df
+                iobref = iobref_new ();
3604df
+                if (!iobref) {
3604df
+                        gf_log ("rpcsvc", GF_LOG_WARNING, "Failed to create iobref");
3604df
+                        goto out;
3604df
+                }
3604df
+                new_iobref = 1;
3604df
+        }
3604df
+
3604df
+        iobref_add (iobref, request_iob);
3604df
 
3604df
         req.msg.rpchdr = &rpchdr;
3604df
         req.msg.rpchdrcount = 1;
3604df
         req.msg.proghdr = proghdr;
3604df
         req.msg.proghdrcount = proghdrcount;
3604df
+        req.msg.iobref = iobref;
3604df
 
3604df
         ret = rpc_transport_submit_request (trans, &req;;
3604df
         if (ret == -1) {
3604df
@@ -1081,6 +1107,9 @@ rpcsvc_callback_submit (rpcsvc_t *rpc, rpc_transport_t *trans,
3604df
 out:
3604df
         iobuf_unref (request_iob);
3604df
 
3604df
+        if (new_iobref)
3604df
+               iobref_unref (iobref);
3604df
+
3604df
         return ret;
3604df
 }
3604df
 
3604df
diff --git a/rpc/rpc-lib/src/rpcsvc.h b/rpc/rpc-lib/src/rpcsvc.h
3604df
index 63a6dad..cf3e590 100644
3604df
--- a/rpc/rpc-lib/src/rpcsvc.h
3604df
+++ b/rpc/rpc-lib/src/rpcsvc.h
3604df
@@ -581,7 +581,8 @@ int rpcsvc_request_submit (rpcsvc_t *rpc, rpc_transport_t *trans,
3604df
 
3604df
 int rpcsvc_callback_submit (rpcsvc_t *rpc, rpc_transport_t *trans,
3604df
                             rpcsvc_cbk_program_t *prog, int procnum,
3604df
-                            struct iovec *proghdr, int proghdrcount);
3604df
+                            struct iovec *proghdr, int proghdrcount,
3604df
+                            struct iobref *iobref);
3604df
 
3604df
 rpcsvc_actor_t *
3604df
 rpcsvc_program_actor (rpcsvc_request_t *req);
3604df
diff --git a/xlators/mgmt/glusterd/src/glusterd.c b/xlators/mgmt/glusterd/src/glusterd.c
3604df
index 498672b..3bcf2d5 100644
3604df
--- a/xlators/mgmt/glusterd/src/glusterd.c
3604df
+++ b/xlators/mgmt/glusterd/src/glusterd.c
3604df
@@ -245,7 +245,8 @@ glusterd_fetchspec_notify (xlator_t *this)
3604df
                 list_for_each_entry (trans, &priv->xprt_list, list) {
3604df
                         rpcsvc_callback_submit (priv->rpc, trans,
3604df
                                                 &glusterd_cbk_prog,
3604df
-                                                GF_CBK_FETCHSPEC, NULL, 0);
3604df
+                                                GF_CBK_FETCHSPEC, NULL, 0,
3604df
+                                                NULL);
3604df
                 }
3604df
         }
3604df
         pthread_mutex_unlock (&priv->xprt_lock);
3604df
@@ -281,7 +282,8 @@ glusterd_fetchsnap_notify (xlator_t *this)
3604df
                 list_for_each_entry (trans, &priv->xprt_list, list) {
3604df
                         rpcsvc_callback_submit (priv->rpc, trans,
3604df
                                                 &glusterd_cbk_prog,
3604df
-                                                GF_CBK_GET_SNAPS, NULL, 0);
3604df
+                                                GF_CBK_GET_SNAPS, NULL, 0,
3604df
+                                                NULL);
3604df
                 }
3604df
         }
3604df
         pthread_mutex_unlock (&priv->xprt_lock);
3604df
diff --git a/xlators/protocol/server/src/server.c b/xlators/protocol/server/src/server.c
3604df
index 3c3664d..0bbfd09 100644
3604df
--- a/xlators/protocol/server/src/server.c
3604df
+++ b/xlators/protocol/server/src/server.c
3604df
@@ -1289,12 +1289,18 @@ server_process_event_upcall (xlator_t *this, void *data)
3604df
                         if (!client || strcmp(client->client_uid, client_uid))
3604df
                                 continue;
3604df
 
3604df
-                        rpcsvc_request_submit(conf->rpc, xprt,
3604df
-                                              &server_cbk_prog,
3604df
-                                              cbk_procnum,
3604df
-                                              up_req,
3604df
-                                              this->ctx,
3604df
-                                              xdrproc);
3604df
+                        ret = rpcsvc_request_submit (conf->rpc, xprt,
3604df
+                                                     &server_cbk_prog,
3604df
+                                                     cbk_procnum,
3604df
+                                                     up_req,
3604df
+                                                     this->ctx,
3604df
+                                                     xdrproc);
3604df
+                        if (ret < 0) {
3604df
+                                gf_msg_debug (this->name, 0, "Failed to send "
3604df
+                                              "upcall to client:%s upcall "
3604df
+                                              "event:%d", client_uid,
3604df
+                                              upcall_data->event_type);
3604df
+                        }
3604df
                         break;
3604df
                 }
3604df
         }
3604df
@@ -1329,7 +1335,7 @@ server_process_child_event (xlator_t *this, int32_t event, void *data,
3604df
                         rpcsvc_callback_submit (conf->rpc, xprt,
3604df
                                                 &server_cbk_prog,
3604df
                                                 cbk_procnum,
3604df
-                                                NULL, 0);
3604df
+                                                NULL, 0, NULL);
3604df
                 }
3604df
         }
3604df
         pthread_mutex_unlock (&conf->mutex);
3604df
-- 
3604df
2.9.3
3604df