Cumulative security CVE-2014-3686 patch

0cf0fcc Add os_exec() helper to run external programs
12b6e6a wpa_cli: Use os_exec() for action script execution
515fa39 hostapd_cli: Use more robust mechanism for action script execution

Bug: 17880188

Change-Id: I0c6162f5339b1f3d8d2cc59203b919455abd592b
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index 1c4a84c..95f28d3 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -238,28 +238,19 @@
 static int hostapd_cli_exec(const char *program, const char *arg1,
 			    const char *arg2)
 {
-	char *cmd;
+	char *arg;
 	size_t len;
 	int res;
-	int ret = 0;
 
-	len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3;
-	cmd = os_malloc(len);
-	if (cmd == NULL)
+	len = os_strlen(arg1) + os_strlen(arg2) + 2;
+	arg = os_malloc(len);
+	if (arg == NULL)
 		return -1;
-	res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2);
-	if (res < 0 || (size_t) res >= len) {
-		os_free(cmd);
-		return -1;
-	}
-	cmd[len - 1] = '\0';
-#ifndef _WIN32_WCE
-	if (system(cmd) < 0)
-		ret = -1;
-#endif /* _WIN32_WCE */
-	os_free(cmd);
+	os_snprintf(arg, len, "%s %s", arg1, arg2);
+	res = os_exec(program, arg, 1);
+	os_free(arg);
 
-	return ret;
+	return res;
 }
 
 
diff --git a/src/utils/os.h b/src/utils/os.h
index f196209..b9247d8 100644
--- a/src/utils/os.h
+++ b/src/utils/os.h
@@ -601,6 +601,15 @@
  */
 int os_memcmp_const(const void *a, const void *b, size_t len);
 
+/**
+ * os_exec - Execute an external program
+ * @program: Path to the program
+ * @arg: Command line argument string
+ * @wait_completion: Whether to wait until the program execution completes
+ * Returns: 0 on success, -1 on error
+ */
+int os_exec(const char *program, const char *arg, int wait_completion);
+
 
 #ifdef OS_REJECT_C_LIB_FUNCTIONS
 #define malloc OS_DO_NOT_USE_malloc
diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c
index 7498967..523a4d0 100644
--- a/src/utils/os_unix.c
+++ b/src/utils/os_unix.c
@@ -9,6 +9,7 @@
 #include "includes.h"
 
 #include <time.h>
+#include <sys/wait.h>
 
 #ifdef ANDROID
 #include <sys/capability.h>
@@ -554,3 +555,57 @@
 }
 
 #endif /* WPA_TRACE */
+
+
+int os_exec(const char *program, const char *arg, int wait_completion)
+{
+	pid_t pid;
+	int pid_status;
+
+	pid = fork();
+	if (pid < 0) {
+		perror("fork");
+		return -1;
+	}
+
+	if (pid == 0) {
+		/* run the external command in the child process */
+		const int MAX_ARG = 30;
+		char *_program, *_arg, *pos;
+		char *argv[MAX_ARG + 1];
+		int i;
+
+		_program = os_strdup(program);
+		_arg = os_strdup(arg);
+
+		argv[0] = _program;
+
+		i = 1;
+		pos = _arg;
+		while (i < MAX_ARG && pos && *pos) {
+			while (*pos == ' ')
+				pos++;
+			if (*pos == '\0')
+				break;
+			argv[i++] = pos;
+			pos = os_strchr(pos, ' ');
+			if (pos)
+				*pos++ = '\0';
+		}
+		argv[i] = NULL;
+
+		execv(program, argv);
+		perror("execv");
+		os_free(_program);
+		os_free(_arg);
+		exit(0);
+		return -1;
+	}
+
+	if (wait_completion) {
+		/* wait for the child process to complete in the parent */
+		waitpid(pid, &pid_status, 0);
+	}
+
+	return 0;
+}
diff --git a/src/utils/os_win32.c b/src/utils/os_win32.c
index 55937de..57ee132 100644
--- a/src/utils/os_win32.c
+++ b/src/utils/os_win32.c
@@ -258,3 +258,9 @@
 
 	return res;
 }
+
+
+int os_exec(const char *program, const char *arg, int wait_completion)
+{
+	return -1;
+}
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 8811d6f..0ad6187 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -3149,28 +3149,19 @@
 static int wpa_cli_exec(const char *program, const char *arg1,
 			const char *arg2)
 {
-	char *cmd;
+	char *arg;
 	size_t len;
 	int res;
-	int ret = 0;
 
-	len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3;
-	cmd = os_malloc(len);
-	if (cmd == NULL)
+	len = os_strlen(arg1) + os_strlen(arg2) + 2;
+	arg = os_malloc(len);
+	if (arg == NULL)
 		return -1;
-	res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2);
-	if (res < 0 || (size_t) res >= len) {
-		os_free(cmd);
-		return -1;
-	}
-	cmd[len - 1] = '\0';
-#ifndef _WIN32_WCE
-	if (system(cmd) < 0)
-		ret = -1;
-#endif /* _WIN32_WCE */
-	os_free(cmd);
+	os_snprintf(arg, len, "%s %s", arg1, arg2);
+	res = os_exec(program, arg, 1);
+	os_free(arg);
 
-	return ret;
+	return res;
 }