BUG/MEDIUM: vars: make functions vars_get_by_{name,desc} thread-safe

This patch adds a lock to functions vars_get_by_name() and
vars_get_by_desc() to protect accesses to the list of variables.

After the variable is fetched, a sample data is duplicated by using
smp_dup() because the variable may be modified by another thread.

This should be backported to all versions supporting vars along with
"BUG/MINOR: sample: secure convs that accept base64 string and var name
as args" which this patch depends on.

(cherry picked from commit 14518f2305027dfd537c1be0f88350337b5fba23)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
(cherry picked from commit bdea395d630bdb92e5d882e235439a1560e12296)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
(cherry picked from commit 6524481ea5ab6ca5888450d535d011046d7d2f80)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
(cherry picked from commit dd8b4da9e1bd908111a2829d5aadec338d345865)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
diff --git a/src/vars.c b/src/vars.c
index 49ff672..d959b5b 100644
--- a/src/vars.c
+++ b/src/vars.c
@@ -571,9 +571,13 @@
 	sample_clear_stream(name, scope, smp);
 }
 
-/* this function fills a sample with the
- * variable content. Returns 1 if the sample
- * is filled, otherwise it returns 0.
+/* This function fills a sample with the variable content.
+ *
+ * Keep in mind that a sample content is duplicated by using smp_dup()
+ * and it therefore uses a pre-allocated trash chunk as returned by
+ * get_trash_chunk().
+ *
+ * Returns 1 if the sample is filled, otherwise it returns 0.
  */
 int vars_get_by_name(const char *name, size_t len, struct sample *smp)
 {
@@ -592,19 +596,29 @@
 		return 0;
 
 	/* Get the variable entry. */
+	HA_RWLOCK_RDLOCK(VARS_LOCK, &vars->rwlock);
 	var = var_get(vars, name);
-	if (!var)
+	if (!var) {
+		HA_RWLOCK_RDUNLOCK(VARS_LOCK, &vars->rwlock);
 		return 0;
+	}
 
 	/* Copy sample. */
 	smp->data = var->data;
-	smp->flags = SMP_F_CONST;
+	smp_dup(smp);
+
+	HA_RWLOCK_RDUNLOCK(VARS_LOCK, &vars->rwlock);
 	return 1;
 }
 
-/* this function fills a sample with the
- * content of the variable described by <var_desc>. Returns 1
- * if the sample is filled, otherwise it returns 0.
+/* This function fills a sample with the content of the variable described
+ * by <var_desc>.
+ *
+ * Keep in mind that a sample content is duplicated by using smp_dup()
+ * and it therefore uses a pre-allocated trash chunk as returned by
+ * get_trash_chunk().
+ *
+ * Returns 1 if the sample is filled, otherwise it returns 0.
  */
 int vars_get_by_desc(const struct var_desc *var_desc, struct sample *smp)
 {
@@ -619,13 +633,18 @@
 		return 0;
 
 	/* Get the variable entry. */
+	HA_RWLOCK_RDLOCK(VARS_LOCK, &vars->rwlock);
 	var = var_get(vars, var_desc->name);
-	if (!var)
+	if (!var) {
+		HA_RWLOCK_RDUNLOCK(VARS_LOCK, &vars->rwlock);
 		return 0;
+	}
 
 	/* Copy sample. */
 	smp->data = var->data;
-	smp->flags = SMP_F_CONST;
+	smp_dup(smp);
+
+	HA_RWLOCK_RDUNLOCK(VARS_LOCK, &vars->rwlock);
 	return 1;
 }