Description: FIX CVE-2018-7033
 Fix security issue that can cause SQL Injection attacks against SlurmDBD
 This patch was adapted from the changes of the 17.02 upstream branch 
Author: Gennaro Oliva <oliva.g@na.icar.cnr.it>
Bug-Debian: https://bugs.debian.org/893044
Origin: https://github.com/SchedMD/slurm/commit/db468895240ad6817628d07054fe54e71273b2fe
Origin: https://github.com/SchedMD/slurm/commit/2f5e924bf6e018dbcef24bcda9683d6b3662f6d4
Last-Update: 2018-06-22

--- a/src/common/pack.c
+++ b/src/common/pack.c
@@ -56,6 +56,7 @@
 #include "src/common/macros.h"
 #include "src/common/pack.h"
 #include "src/common/xmalloc.h"
+#include "src/slurmdbd/read_config.h"
 
 /*
  * Define slurm-specific aliases for use by plugins, see slurm_xlator.h
@@ -89,6 +90,8 @@ strong_alias(unpackmem,		slurm_unpackmem
 strong_alias(unpackmem_ptr,	slurm_unpackmem_ptr);
 strong_alias(unpackmem_xmalloc,	slurm_unpackmem_xmalloc);
 strong_alias(unpackmem_malloc,	slurm_unpackmem_malloc);
+strong_alias(unpackstr_xmalloc_escaped, slurm_unpackstr_xmalloc_escaped);
+strong_alias(unpackstr_xmalloc_chooser, slurm_unpackstr_xmalloc_chooser);
 strong_alias(packstr_array,	slurm_packstr_array);
 strong_alias(unpackstr_array,	slurm_unpackstr_array);
 strong_alias(packmem_array,	slurm_packmem_array);
@@ -773,6 +776,78 @@ int unpackmem_malloc(char **valp, uint32
 }
 
 /*
+ * Given a buffer containing a network byte order 16-bit integer,
+ * and an arbitrary char string, copy the data string into the location
+ * specified by valp and escape ' and \ to be database safe.
+ * Also return the sizes of 'valp' in bytes.
+ * Adjust buffer counters.
+ * NOTE: valp is set to point into a newly created buffer,
+ *	the caller is responsible for calling xfree() on *valp
+ *	if non-NULL (set to NULL on zero size buffer value)
+ * NOTE: size_valp may not match how much data was processed from buffer, but
+ *       will match the length of the returned 'valp'.
+ * WARNING: These escapes are sufficient to protect MariaDB/MySQL, but
+ *          may not be sufficient if databases are added in the future.
+ */
+int unpackstr_xmalloc_escaped(char **valp, uint32_t *size_valp, Buf buffer)
+{
+	uint32_t ns;
+
+	if (remaining_buf(buffer) < sizeof(ns))
+		return SLURM_ERROR;
+
+	memcpy(&ns, &buffer->head[buffer->processed], sizeof(ns));
+	*size_valp = ntohl(ns);
+	buffer->processed += sizeof(ns);
+
+	if (*size_valp > MAX_PACK_MEM_LEN) {
+		error("%s: Buffer to be unpacked is too large (%u > %u)",
+		      __func__, *size_valp, MAX_PACK_MEM_LEN);
+		return SLURM_ERROR;
+	} else if (*size_valp > 0) {
+		uint32_t cnt = *size_valp;
+
+		if (remaining_buf(buffer) < cnt)
+			return SLURM_ERROR;
+
+		/* make a buffer 2 times the size just to be safe */
+		*valp = xmalloc_nz((cnt * 2) + 1);
+		if (*valp) {
+			char *copy = NULL, *str, tmp;
+			uint32_t i;
+			copy = *valp;
+			str = &buffer->head[buffer->processed];
+
+			for (i = 0; i < cnt && *str; i++) {
+				tmp = *str++;
+				if ((tmp == '\\') || (tmp == '\'')) {
+					*copy++ = '\\';
+					(*size_valp)++;
+				}
+
+				*copy++ = tmp;
+			}
+
+			/* Since we used xmalloc_nz, terminate the string. */
+			*copy++ = '\0';
+		}
+
+		/* add the original value since that is what we processed */
+		buffer->processed += cnt;
+	} else
+		*valp = NULL;
+	return SLURM_SUCCESS;
+}
+
+int unpackstr_xmalloc_chooser(char **valp, uint32_t *size_valp, Buf buf)
+{
+	if (slurmdbd_conf)
+		return unpackstr_xmalloc_escaped(valp, size_valp, buf);
+	else
+		return unpackmem_xmalloc(valp, size_valp, buf);
+}
+
+/*
  * Given a pointer to array of char * (char ** or char *[] ) and a size
  * (size_val), convert size_val to network byte order and store in the
  * buffer followed by the data at valp. Adjust buffer counters.
--- a/src/common/pack.h
+++ b/src/common/pack.h
@@ -133,6 +133,9 @@ int	unpackmem_ptr(char **valp, uint32_t
 int	unpackmem_xmalloc(char **valp, uint32_t *size_valp, Buf buffer);
 int	unpackmem_malloc(char **valp, uint32_t *size_valp, Buf buffer);
 
+int	unpackstr_xmalloc_escaped(char **valp, uint32_t *size_valp, Buf buffer);
+int	unpackstr_xmalloc_chooser(char **valp, uint32_t *size_valp, Buf buffer);
+
 void	packstr_array(char **valp, uint32_t size_val, Buf buffer);
 int	unpackstr_array(char ***valp, uint32_t* size_val, Buf buffer);
 
@@ -436,8 +439,12 @@ int	unpackmem_array(char *valp, uint32_t
 #define safe_unpackstr_malloc	                        \
         safe_unpackmem_malloc
 
-#define safe_unpackstr_xmalloc	                        \
-        safe_unpackmem_xmalloc
+#define safe_unpackstr_xmalloc(valp, size_valp, buf) do {	\
+	assert(sizeof(*size_valp) == sizeof(uint32_t));        	\
+	assert(buf->magic == BUF_MAGIC);		        \
+	if (unpackstr_xmalloc_chooser(valp, size_valp, buf))    \
+		goto unpack_error;		       		\
+} while (0)
 
 #define safe_packstr_array(array,size_val,buf) do {	\
 	assert(size_val == 0 || array != NULL);		\
--- a/src/common/slurm_xlator.h
+++ b/src/common/slurm_xlator.h
@@ -257,6 +257,8 @@
 #define	unpackmem_ptr		slurm_unpackmem_ptr
 #define	unpackmem_xmalloc	slurm_unpackmem_xmalloc
 #define	unpackmem_malloc	slurm_unpackmem_malloc
+#define	unpackstr_xmalloc_escaped slurm_unpackstr_xmalloc_escaped
+#define	unpackstr_xmalloc_chooser slurm_unpackstr_xmalloc_chooser
 #define	packstr_array		slurm_packstr_array
 #define	unpackstr_array		slurm_unpackstr_array
 #define	packmem_array		slurm_packmem_array
--- a/src/plugins/accounting_storage/mysql/as_mysql_cluster.c
+++ b/src/plugins/accounting_storage/mysql/as_mysql_cluster.c
@@ -1092,9 +1092,9 @@ extern int as_mysql_node_down(mysql_conn
 		return SLURM_ERROR;
 
 	if (reason)
-		my_reason = slurm_add_slash_to_quotes(reason);
+		my_reason = reason;
 	else
-		my_reason = slurm_add_slash_to_quotes(node_ptr->reason);
+		my_reason = node_ptr->reason;
 
 	row = mysql_fetch_row(result);
 	if (row && (node_ptr->node_state == slurm_atoul(row[0])) &&
@@ -1103,7 +1103,6 @@ extern int as_mysql_node_down(mysql_conn
 		debug("as_mysql_node_down: no change needed %u == %s "
 		      "and %s == %s",
 		     node_ptr->node_state, row[0], my_reason, row[1]);
-		xfree(my_reason);
 		mysql_free_result(result);
 		return SLURM_SUCCESS;
 	}
@@ -1138,7 +1137,7 @@ extern int as_mysql_node_down(mysql_conn
 	       mysql_conn->conn, THIS_FILE, __LINE__, query);
 	rc = mysql_db_query(mysql_conn, query);
 	xfree(query);
-	xfree(my_reason);
+
 	return rc;
 }
 
--- a/src/plugins/accounting_storage/mysql/as_mysql_job.c
+++ b/src/plugins/accounting_storage/mysql/as_mysql_job.c
@@ -243,8 +243,7 @@ extern int as_mysql_job_start(mysql_conn
 	int rc=SLURM_SUCCESS;
 	char *nodes = NULL, *jname = NULL, *node_inx = NULL;
 	int track_steps = 0;
-	char *block_id = NULL, *partition = NULL,
-		*gres_req = NULL, *gres_alloc = NULL;
+	char *block_id = NULL, *partition = NULL;
 	char *query = NULL;
 	int reinit = 0;
 	time_t begin_time, check_time, start_time, submit_time;
@@ -402,9 +401,9 @@ extern int as_mysql_job_start(mysql_conn
 no_rollup_change:
 
 	if (job_ptr->name && job_ptr->name[0])
-		jname = slurm_add_slash_to_quotes(job_ptr->name);
+		jname = job_ptr->name;
 	else {
-		jname = xstrdup("allocation");
+		jname = "allocation";
 		track_steps = 1;
 	}
 
@@ -447,15 +446,9 @@ no_rollup_change:
 				       job_ptr->assoc_id);
 
 	if (!IS_JOB_PENDING(job_ptr) && job_ptr->part_ptr)
-		partition = slurm_add_slash_to_quotes(job_ptr->part_ptr->name);
+		partition = job_ptr->part_ptr->name;
 	else if (job_ptr->partition)
-		partition = slurm_add_slash_to_quotes(job_ptr->partition);
-
-	if (job_ptr->gres_req)
-		gres_req = slurm_add_slash_to_quotes(job_ptr->gres_req);
-
-	if (job_ptr->gres_alloc)
-		gres_alloc = slurm_add_slash_to_quotes(job_ptr->gres_alloc);
+		partition = job_ptr->partition;
 
 	if (!job_ptr->db_index) {
 		query = xstrdup_printf(
@@ -480,9 +473,9 @@ no_rollup_change:
 			xstrcat(query, ", wckey");
 		if (node_inx)
 			xstrcat(query, ", node_inx");
-		if (gres_req)
+		if (job_ptr->gres_req)
 			xstrcat(query, ", gres_req");
-		if (gres_alloc)
+		if (job_ptr->gres_alloc)
 			xstrcat(query, ", gres_alloc");
 		if (array_recs && array_recs->task_id_str)
 			xstrcat(query, ", array_task_str, array_max_tasks, "
@@ -523,10 +516,10 @@ no_rollup_change:
 			xstrfmtcat(query, ", '%s'", job_ptr->wckey);
 		if (node_inx)
 			xstrfmtcat(query, ", '%s'", node_inx);
-		if (gres_req)
-			xstrfmtcat(query, ", '%s'", gres_req);
-		if (gres_alloc)
-			xstrfmtcat(query, ", '%s'", gres_alloc);
+		if (job_ptr->gres_req)
+			xstrfmtcat(query, ", '%s'", job_ptr->gres_req);
+		if (job_ptr->gres_alloc)
+			xstrfmtcat(query, ", '%s'", job_ptr->gres_alloc);
 		if (array_recs && array_recs->task_id_str)
 			xstrfmtcat(query, ", '%s', %u, %u",
 				   array_recs->task_id_str,
@@ -573,10 +566,11 @@ no_rollup_change:
 			xstrfmtcat(query, ", wckey='%s'", job_ptr->wckey);
 		if (node_inx)
 			xstrfmtcat(query, ", node_inx='%s'", node_inx);
-		if (gres_req)
-			xstrfmtcat(query, ", gres_req='%s'", gres_req);
-		if (gres_alloc)
-			xstrfmtcat(query, ", gres_alloc='%s'", gres_alloc);
+		if (job_ptr->gres_req)
+			xstrfmtcat(query, ", gres_req='%s'", job_ptr->gres_req);
+		if (job_ptr->gres_alloc)
+			xstrfmtcat(query, ", gres_alloc='%s'",
+				   job_ptr->gres_alloc);
 		if (array_recs && array_recs->task_id_str)
 			xstrfmtcat(query, ", array_task_str='%s', "
 				   "array_max_tasks=%u, array_task_pending=%u",
@@ -626,10 +620,11 @@ no_rollup_change:
 			xstrfmtcat(query, "wckey='%s', ", job_ptr->wckey);
 		if (node_inx)
 			xstrfmtcat(query, "node_inx='%s', ", node_inx);
-		if (gres_req)
-			xstrfmtcat(query, "gres_req='%s', ", gres_req);
-		if (gres_alloc)
-			xstrfmtcat(query, "gres_alloc='%s', ", gres_alloc);
+		if (job_ptr->gres_req)
+			xstrfmtcat(query, "gres_req='%s', ", job_ptr->gres_req);
+		if (job_ptr->gres_alloc)
+			xstrfmtcat(query, "gres_alloc='%s', ",
+				   job_ptr->gres_alloc);
 		if (array_recs && array_recs->task_id_str)
 			xstrfmtcat(query, "array_task_str='%s', "
 				   "array_max_tasks=%u, "
@@ -670,10 +665,6 @@ no_rollup_change:
 	}
 
 	xfree(block_id);
-	xfree(partition);
-	xfree(gres_req);
-	xfree(gres_alloc);
-	xfree(jname);
 	xfree(query);
 
 	/* now we will reset all the steps */
@@ -716,11 +707,9 @@ extern List as_mysql_modify_job(mysql_co
 	if (job->derived_ec != NO_VAL)
 		xstrfmtcat(vals, ", derived_ec=%u", job->derived_ec);
 
-	if (job->derived_es) {
-		char *derived_es = slurm_add_slash_to_quotes(job->derived_es);
-		xstrfmtcat(vals, ", derived_es='%s'", derived_es);
-		xfree(derived_es);
-	}
+	if (job->derived_es)
+		xstrfmtcat(vals, ", derived_es='%s'", job->derived_es);
+
 	if (!vals) {
 		errno = SLURM_NO_CHANGE_IN_DATA;
 		error("No change specified for job modification");
@@ -904,11 +893,8 @@ extern int as_mysql_job_complete(mysql_c
 	if (job_ptr->derived_ec != NO_VAL)
 		xstrfmtcat(query, ", derived_ec=%u", job_ptr->derived_ec);
 
-	if (job_ptr->comment) {
-		char *comment = slurm_add_slash_to_quotes(job_ptr->comment);
-		xstrfmtcat(query, ", derived_es='%s'", comment);
-		xfree(comment);
-	}
+	if (job_ptr->comment)
+		xstrfmtcat(query, ", derived_es='%s'", job_ptr->comment);
 
 	exit_code = job_ptr->exit_code;
 	if (exit_code == 1) {
@@ -937,7 +923,7 @@ extern int as_mysql_step_start(mysql_con
 	int tasks = 0, nodes = 0, task_dist = 0;
 	int rc=SLURM_SUCCESS;
 	char node_list[BUFFER_SIZE];
-	char *node_inx = NULL, *step_name = NULL;
+	char *node_inx = NULL;
 	time_t start_time, submit_time;
 	char *query = NULL;
 
@@ -1070,8 +1056,6 @@ extern int as_mysql_step_start(mysql_con
 		}
 	}
 
-	step_name = slurm_add_slash_to_quotes(step_ptr->name);
-
 	/* we want to print a -1 for the requid so leave it a
 	   %d */
 	/* The stepid could be -2 so use %d not %u */
@@ -1090,7 +1074,7 @@ extern int as_mysql_step_start(mysql_con
 		mysql_conn->cluster_name, step_table,
 		step_ptr->job_ptr->db_index,
 		step_ptr->step_id,
-		(int)start_time, step_name,
+		(int)start_time, step_ptr->name,
 		JOB_RUNNING, step_ptr->tres_alloc_str,
 		nodes, tasks, node_list, node_inx, task_dist,
 		step_ptr->cpu_freq_max, step_ptr->cpu_freq_min,
@@ -1102,7 +1086,6 @@ extern int as_mysql_step_start(mysql_con
 		DB_DEBUG(mysql_conn->conn, "query\n%s", query);
 	rc = mysql_db_query(mysql_conn, query);
 	xfree(query);
-	xfree(step_name);
 
 	return rc;
 }
--- a/src/plugins/accounting_storage/mysql/as_mysql_resv.c
+++ b/src/plugins/accounting_storage/mysql/as_mysql_resv.c
@@ -98,11 +98,9 @@ static int _setup_resv_limits(slurmdb_re
 	}
 
 	if (resv->name) {
-		char *tmp_char = slurm_add_slash_to_quotes(resv->name);
 		xstrcat(*cols, ", resv_name");
-		xstrfmtcat(*vals, ", '%s'", tmp_char);
-		xstrfmtcat(*extra, ", resv_name='%s'", tmp_char);
-		xfree(tmp_char);
+		xstrfmtcat(*vals, ", '%s'", resv->name);
+		xstrfmtcat(*extra, ", resv_name='%s'", resv->name);
 	}
 
 	if (resv->nodes) {
