3604df
From 998ccd5de71df70a611595166fb914c7e7fbe130 Mon Sep 17 00:00:00 2001
3604df
From: N Balachandran <nbalacha@redhat.com>
3604df
Date: Fri, 9 Dec 2016 11:04:13 +0530
3604df
Subject: [PATCH 234/235] cluster/dht: Fix memory corruption while accessing
3604df
 regex stored in private
3604df
3604df
If reconfigure is executed parallely (or concurrently with dht_init),
3604df
there are races that can corrupt memory. One such race is modification
3604df
of regexes stored in conf (conf->rsync_regex_valid and
3604df
conf->extra_regex_valid) through dht_init_regex. With change [1],
3604df
reconfigure codepath can get executed parallely (with itself or with
3604df
dht_init) and this fix is needed.
3604df
3604df
Also, a reconfigure can race with any thread doing dht_layout_search,
3604df
resulting in dht_layout_search accessing regex freed up by reconfigure
3604df
(like in bz 1399134).
3604df
3604df
[1] http://review.gluster.org/15046
3604df
3604df
Upstream patches:
3604df
master: http://review.gluster.org/#/c/15945/
3604df
release-3.8 : http://review.gluster.org/#/c/15793/
3604df
release-3.9 : http://review.gluster.org/#/c/15949/
3604df
3604df
Change-Id: I62daadc5886338b61107e20920a2727d510c4c84
3604df
BUG: 1399100
3604df
Original-author: Raghavendra G <rgowdapp@redhat.com>
3604df
Signed-off-by: N Balachandran <nbalacha@redhat.com>
3604df
Reviewed-on: https://code.engineering.redhat.com/gerrit/92555
3604df
Reviewed-by: Atin Mukherjee <amukherj@redhat.com>
3604df
Tested-by: Atin Mukherjee <amukherj@redhat.com>
3604df
---
3604df
 xlators/cluster/dht/src/dht-common.h |  1 +
3604df
 xlators/cluster/dht/src/dht-hashfn.c | 54 ++++++++++++++++++++++--------------
3604df
 xlators/cluster/dht/src/dht-shared.c | 54 ++++++++++++++++++++----------------
3604df
 3 files changed, 64 insertions(+), 45 deletions(-)
3604df
3604df
diff --git a/xlators/cluster/dht/src/dht-common.h b/xlators/cluster/dht/src/dht-common.h
3604df
index 227dc08..e87bd90 100644
3604df
--- a/xlators/cluster/dht/src/dht-common.h
3604df
+++ b/xlators/cluster/dht/src/dht-common.h
3604df
@@ -551,6 +551,7 @@ struct dht_conf {
3604df
         /* lock migration */
3604df
 
3604df
         gf_boolean_t    lock_migration_enabled;
3604df
+        gf_lock_t       lock;
3604df
 };
3604df
 typedef struct dht_conf dht_conf_t;
3604df
 
3604df
diff --git a/xlators/cluster/dht/src/dht-hashfn.c b/xlators/cluster/dht/src/dht-hashfn.c
3604df
index 66e3ede..f8e614a 100644
3604df
--- a/xlators/cluster/dht/src/dht-hashfn.c
3604df
+++ b/xlators/cluster/dht/src/dht-hashfn.c
3604df
@@ -41,12 +41,16 @@ dht_hash_compute_internal (int type, const char *name, uint32_t *hash_p)
3604df
 
3604df
 static
3604df
 gf_boolean_t
3604df
-dht_munge_name (const char *original, char *modified, size_t len, regex_t *re)
3604df
+dht_munge_name (const char *original, char *modified,
3604df
+                size_t len, regex_t *re)
3604df
 {
3604df
-        regmatch_t      matches[2];
3604df
-        size_t          new_len;
3604df
+        regmatch_t  matches[2] = {{0}, };
3604df
+        size_t      new_len    = 0;
3604df
+        int         ret        = 0;
3604df
 
3604df
-        if (regexec(re,original,2,matches,0) != REG_NOMATCH) {
3604df
+        ret = regexec(re, original, 2, matches, 0);
3604df
+
3604df
+        if (ret != REG_NOMATCH) {
3604df
                 if (matches[1].rm_so != -1) {
3604df
                         new_len = matches[1].rm_eo - matches[1].rm_so;
3604df
                         /* Equal would fail due to the NUL at the end. */
3604df
@@ -60,7 +64,7 @@ dht_munge_name (const char *original, char *modified, size_t len, regex_t *re)
3604df
         }
3604df
 
3604df
         /* This is guaranteed safe because of how the dest was allocated. */
3604df
-        strcpy(modified,original);
3604df
+        strcpy(modified, original);
3604df
         return _gf_false;
3604df
 }
3604df
 
3604df
@@ -68,28 +72,36 @@ int
3604df
 dht_hash_compute (xlator_t *this, int type, const char *name, uint32_t *hash_p)
3604df
 {
3604df
         char            *rsync_friendly_name    = NULL;
3604df
-        dht_conf_t      *priv                   = this->private;
3604df
+        dht_conf_t      *priv                   = NULL;
3604df
         size_t           len                    = 0;
3604df
         gf_boolean_t     munged                 = _gf_false;
3604df
 
3604df
-        if (priv->extra_regex_valid) {
3604df
-                len = strlen(name) + 1;
3604df
-                rsync_friendly_name = alloca(len);
3604df
-                munged = dht_munge_name (name, rsync_friendly_name, len,
3604df
-                                         &priv->extra_regex);
3604df
-        }
3604df
+        priv = this->private;
3604df
 
3604df
-        if (!munged && priv->rsync_regex_valid) {
3604df
-                len = strlen(name) + 1;
3604df
-                rsync_friendly_name = alloca(len);
3604df
-                gf_msg_trace (this->name, 0, "trying regex for %s", name);
3604df
-                munged = dht_munge_name (name, rsync_friendly_name, len,
3604df
-                                         &priv->rsync_regex);
3604df
-                if (munged) {
3604df
-                        gf_msg_debug (this->name, 0,
3604df
-                                      "munged down to %s", rsync_friendly_name);
3604df
+        LOCK (&priv->lock);
3604df
+        {
3604df
+                if (priv->extra_regex_valid) {
3604df
+                        len = strlen(name) + 1;
3604df
+                        rsync_friendly_name = alloca(len);
3604df
+                        munged = dht_munge_name (name, rsync_friendly_name, len,
3604df
+                                                 &priv->extra_regex);
3604df
+                }
3604df
+
3604df
+                if (!munged && priv->rsync_regex_valid) {
3604df
+                        len = strlen(name) + 1;
3604df
+                        rsync_friendly_name = alloca(len);
3604df
+                        gf_msg_trace (this->name, 0, "trying regex for %s",
3604df
+                                      name);
3604df
+                        munged = dht_munge_name (name, rsync_friendly_name, len,
3604df
+                                                 &priv->rsync_regex);
3604df
+                        if (munged) {
3604df
+                                gf_msg_debug (this->name, 0,
3604df
+                                              "munged down to %s",
3604df
+                                              rsync_friendly_name);
3604df
+                        }
3604df
                 }
3604df
         }
3604df
+        UNLOCK (&priv->lock);
3604df
 
3604df
         if (!munged) {
3604df
                 rsync_friendly_name = (char *)name;
3604df
diff --git a/xlators/cluster/dht/src/dht-shared.c b/xlators/cluster/dht/src/dht-shared.c
3604df
index 48ec9ff..40f8832 100644
3604df
--- a/xlators/cluster/dht/src/dht-shared.c
3604df
+++ b/xlators/cluster/dht/src/dht-shared.c
3604df
@@ -336,9 +336,9 @@ out:
3604df
 }
3604df
 void
3604df
 dht_init_regex (xlator_t *this, dict_t *odict, char *name,
3604df
-                regex_t *re, gf_boolean_t *re_valid)
3604df
+                regex_t *re, gf_boolean_t *re_valid, dht_conf_t *conf)
3604df
 {
3604df
-        char    *temp_str;
3604df
+        char       *temp_str = NULL;
3604df
 
3604df
         if (dict_get_str (odict, name, &temp_str) != 0) {
3604df
                 if (strcmp(name,"rsync-hash-regex")) {
3604df
@@ -347,25 +347,29 @@ dht_init_regex (xlator_t *this, dict_t *odict, char *name,
3604df
                 temp_str = "^\\.(.+)\\.[^.]+$";
3604df
         }
3604df
 
3604df
-        if (*re_valid) {
3604df
-                regfree(re);
3604df
-                *re_valid = _gf_false;
3604df
-        }
3604df
+        LOCK (&conf->lock);
3604df
+        {
3604df
+                if (*re_valid) {
3604df
+                        regfree(re);
3604df
+                        *re_valid = _gf_false;
3604df
+                }
3604df
 
3604df
-        if (!strcmp(temp_str,"none")) {
3604df
-                return;
3604df
-        }
3604df
+                if (!strcmp(temp_str, "none")) {
3604df
+                        goto unlock;
3604df
+                }
3604df
 
3604df
-        if (regcomp(re,temp_str,REG_EXTENDED) == 0) {
3604df
-                gf_msg_debug (this->name, 0,
3604df
-                              "using regex %s = %s", name, temp_str);
3604df
-                *re_valid = _gf_true;
3604df
-        }
3604df
-        else {
3604df
-                gf_msg (this->name, GF_LOG_WARNING, 0,
3604df
-                        DHT_MSG_REGEX_INFO,
3604df
-                        "compiling regex %s failed", temp_str);
3604df
+                if (regcomp(re, temp_str, REG_EXTENDED) == 0) {
3604df
+                        gf_msg_debug (this->name, 0,
3604df
+                                      "using regex %s = %s", name, temp_str);
3604df
+                        *re_valid = _gf_true;
3604df
+                } else {
3604df
+                        gf_msg (this->name, GF_LOG_WARNING, 0,
3604df
+                                DHT_MSG_REGEX_INFO,
3604df
+                                "compiling regex %s failed", temp_str);
3604df
+                }
3604df
         }
3604df
+unlock:
3604df
+        UNLOCK (&conf->lock);
3604df
 }
3604df
 
3604df
 int
3604df
@@ -486,9 +490,9 @@ dht_reconfigure (xlator_t *this, dict_t *options)
3604df
         }
3604df
 
3604df
         dht_init_regex (this, options, "rsync-hash-regex",
3604df
-                        &conf->rsync_regex, &conf->rsync_regex_valid);
3604df
+                        &conf->rsync_regex, &conf->rsync_regex_valid, conf);
3604df
         dht_init_regex (this, options, "extra-hash-regex",
3604df
-                        &conf->extra_regex, &conf->extra_regex_valid);
3604df
+                        &conf->extra_regex, &conf->extra_regex_valid, conf);
3604df
 
3604df
         GF_OPTION_RECONF ("weighted-rebalance", conf->do_weighting, options,
3604df
                           bool, out);
3604df
@@ -627,6 +631,10 @@ dht_init (xlator_t *this)
3604df
                 goto err;
3604df
         }
3604df
 
3604df
+        LOCK_INIT (&conf->subvolume_lock);
3604df
+        LOCK_INIT (&conf->layout_lock);
3604df
+        LOCK_INIT (&conf->lock);
3604df
+
3604df
         /* We get the commit-hash to set only for rebalance process */
3604df
         if (dict_get_uint32 (this->options,
3604df
                              "commit-hash", &commit_hash) == 0) {
3604df
@@ -776,17 +784,15 @@ dht_init (xlator_t *this)
3604df
         }
3604df
 
3604df
         dht_init_regex (this, this->options, "rsync-hash-regex",
3604df
-                        &conf->rsync_regex, &conf->rsync_regex_valid);
3604df
+                        &conf->rsync_regex, &conf->rsync_regex_valid, conf);
3604df
         dht_init_regex (this, this->options, "extra-hash-regex",
3604df
-                        &conf->extra_regex, &conf->extra_regex_valid);
3604df
+                        &conf->extra_regex, &conf->extra_regex_valid, conf);
3604df
 
3604df
         ret = dht_layouts_init (this, conf);
3604df
         if (ret == -1) {
3604df
                 goto err;
3604df
         }
3604df
 
3604df
-        LOCK_INIT (&conf->subvolume_lock);
3604df
-        LOCK_INIT (&conf->layout_lock);
3604df
 
3604df
         conf->gen = 1;
3604df
 
3604df
-- 
3604df
2.9.3
3604df