netd: fix argument interpretation bug
While working around the logwrap() issue, it was replaced with system()
which could lead to various commands getting misinterpreted.
We now use a system() equivalent that doesn't use "sh -c".
Bug:5758556
Change-Id: I2599b526ac34bcfca18d05261286d902d547efda
diff --git a/BandwidthController.cpp b/BandwidthController.cpp
index f0a856e..be3cb28 100644
--- a/BandwidthController.cpp
+++ b/BandwidthController.cpp
@@ -42,6 +42,7 @@
#include <cutils/properties.h>
extern "C" int logwrap(int argc, const char **argv, int background);
+extern "C" int system_nosh(const char *command);
#include "BandwidthController.h"
@@ -185,7 +186,7 @@
fullCmd.insert(0, iptVer == IptIpV4 ? IPTABLES_PATH : IP6TABLES_PATH);
if (!useLogwrapCall) {
- res = system(fullCmd.c_str());
+ res = system_nosh(fullCmd.c_str());
} else {
if (StrncpyAndCheck(buffer, fullCmd.c_str(), sizeof(buffer))) {
LOGE("iptables command too long");
diff --git a/NatController.cpp b/NatController.cpp
index 5f6a46a..ed1b095 100644
--- a/NatController.cpp
+++ b/NatController.cpp
@@ -30,7 +30,7 @@
#include "NatController.h"
#include "SecondaryTableController.h"
-extern "C" int logwrap(int argc, const char **argv, int background);
+extern "C" int system_nosh(const char *command);
static char IPTABLES_PATH[] = "/system/bin/iptables";
static char IP_PATH[] = "/system/bin/ip";
@@ -55,7 +55,7 @@
}
asprintf(&buffer, "%s %s", path, cmd);
- res = system(buffer);
+ res = system_nosh(buffer);
free(buffer);
return res;
}
diff --git a/SecondaryTableController.cpp b/SecondaryTableController.cpp
index 1be1c79..287bba5 100644
--- a/SecondaryTableController.cpp
+++ b/SecondaryTableController.cpp
@@ -31,6 +31,8 @@
#include <cutils/log.h>
#include <cutils/properties.h>
+extern "C" int system_nosh(const char *command);
+
#include "ResponseCode.h"
#include "SecondaryTableController.h"
@@ -132,7 +134,7 @@
free(cmd);
return -1;
}
- ret = system(cmd);
+ ret = system_nosh(cmd);
free(cmd);
return ret;
}
diff --git a/ThrottleController.cpp b/ThrottleController.cpp
index c7dfad8..1ae31b8 100644
--- a/ThrottleController.cpp
+++ b/ThrottleController.cpp
@@ -36,7 +36,7 @@
static char TC_PATH[] = "/system/bin/tc";
-extern "C" int logwrap(int argc, const char **argv, int background);
+extern "C" int system_nosh(const char *command);
extern "C" int ifc_init(void);
extern "C" int ifc_up(const char *name);
extern "C" int ifc_down(const char *name);
@@ -53,7 +53,7 @@
}
asprintf(&buffer, "%s %s", TC_PATH, cmd);
- res = system(buffer);
+ res = system_nosh(buffer);
free(buffer);
return res;
}
diff --git a/logwrapper.c b/logwrapper.c
index 739f141..d9913f2 100644
--- a/logwrapper.c
+++ b/logwrapper.c
@@ -175,3 +175,66 @@
return 0;
}
+
+/*
+ * The following is based off of bionic/libc/unistd/system.c with
+ * modifications to avoid calling /system/bin/sh -c
+ */
+extern char **environ;
+int system_nosh(const char *command)
+{
+ pid_t pid;
+ sig_t intsave, quitsave;
+ sigset_t mask, omask;
+ int pstat;
+ char buffer[255];
+ char *argp[32];
+ char *next = buffer;
+ char *tmp;
+ int i = 0;
+
+ if (!command) /* just checking... */
+ return(1);
+
+ /*
+ * The command to argp splitting is from code that was
+ * reverted in Change: 11b4e9b2
+ */
+ if (strnlen(buffer, sizeof(buffer) - 1) == sizeof(buffer) - 1) {
+ LOGE("command line too long while processing: %s", command);
+ errno = E2BIG;
+ return -1;
+ }
+ strcpy(buffer, command); // Command len is already checked.
+ while ((tmp = strsep(&next, " "))) {
+ argp[i++] = tmp;
+ if (i == 32) {
+ LOGE("argument overflow while processing: %s", command);
+ errno = E2BIG;
+ return -1;
+ }
+ }
+ argp[i] = NULL;
+
+
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &mask, &omask);
+ switch (pid = vfork()) {
+ case -1: /* error */
+ sigprocmask(SIG_SETMASK, &omask, NULL);
+ return(-1);
+ case 0: /* child */
+ sigprocmask(SIG_SETMASK, &omask, NULL);
+ execve(argp[0], argp, environ);
+ _exit(127);
+ }
+
+ intsave = (sig_t) bsd_signal(SIGINT, SIG_IGN);
+ quitsave = (sig_t) bsd_signal(SIGQUIT, SIG_IGN);
+ pid = waitpid(pid, (int *)&pstat, 0);
+ sigprocmask(SIG_SETMASK, &omask, NULL);
+ (void)bsd_signal(SIGINT, intsave);
+ (void)bsd_signal(SIGQUIT, quitsave);
+ return (pid == -1 ? -1 : pstat);
+}