BandwidthController: validate interface / chain names

Only allow alphanumeric, dashes, underscores, or colons in
interface and chain names. First character must be alphanumeric.

Bug: 14320836
Bug: 14323009
Change-Id: Ieac729719d0f9038f60c7afcb327f17d292d6ca6
diff --git a/BandwidthController.cpp b/BandwidthController.cpp
index 65be1d1..a7c2c2c 100644
--- a/BandwidthController.cpp
+++ b/BandwidthController.cpp
@@ -27,6 +27,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <ctype.h>
 
 #define __STDC_FORMAT_MACROS 1
 #include <inttypes.h>
@@ -707,6 +708,11 @@
     std::list<QuotaInfo>::iterator it;
     std::string quotaCmd;
 
+    if (!isNameLegal(iface)) {
+        ALOGE("setInterfaceQuota: Invalid iface \"%s\"", iface);
+        return -1;
+    }
+
     if (!maxBytes) {
         /* Don't talk about -1, deprecate it. */
         ALOGE("Invalid bytes value. 1..max_int64.");
@@ -771,11 +777,37 @@
     return getInterfaceQuota("shared", bytes);
 }
 
+bool BandwidthController::isNameLegal(const char* name) {
+    size_t i;
+    size_t name_len = strlen(name);
+    if (name_len == 0) {
+        return false;
+    }
+
+    /* First character must be alphanumeric */
+    if (!isalnum(name[0])) {
+        return false;
+    }
+
+    for (i = 1; i < name_len; i++) {
+        if (!isalnum(name[i]) && (name[i] != '_') && (name[i] != '-') && (name[i] != ':')) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
 int BandwidthController::getInterfaceQuota(const char *costName, int64_t *bytes) {
     FILE *fp;
     char *fname;
     int scanRes;
 
+    if (!isNameLegal(costName)) {
+        ALOGE("getInterfaceQuota: Invalid costName \"%s\"", costName);
+        return -1;
+    }
+
     asprintf(&fname, "/proc/net/xt_quota/%s", costName);
     fp = fopen(fname, "r");
     free(fname);
@@ -797,6 +829,11 @@
     const char *costName;
     std::list<QuotaInfo>::iterator it;
 
+    if (!isNameLegal(iface)) {
+        ALOGE("removeInterfaceQuota: Invalid iface \"%s\"", iface);
+        return -1;
+    }
+
     if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
         ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
         return -1;
@@ -826,6 +863,11 @@
     FILE *fp;
     char *fname;
 
+    if (!isNameLegal(quotaName)) {
+        ALOGE("updateQuota: Invalid quotaName \"%s\"", quotaName);
+        return -1;
+    }
+
     asprintf(&fname, "/proc/net/xt_quota/%s", quotaName);
     fp = fopen(fname, "w");
     free(fname);
@@ -1000,6 +1042,11 @@
 int BandwidthController::setInterfaceAlert(const char *iface, int64_t bytes) {
     std::list<QuotaInfo>::iterator it;
 
+    if (!isNameLegal(iface)) {
+        ALOGE("setInterfaceAlert: Invalid iface \"%s\"", iface);
+        return -1;
+    }
+
     if (!bytes) {
         ALOGE("Invalid bytes value. 1..max_int64.");
         return -1;
@@ -1020,6 +1067,11 @@
 int BandwidthController::removeInterfaceAlert(const char *iface) {
     std::list<QuotaInfo>::iterator it;
 
+    if (!isNameLegal(iface)) {
+        ALOGE("removeInterfaceAlert: Invalid iface \"%s\"", iface);
+        return -1;
+    }
+
     for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
         if (it->ifaceName == iface)
             break;
@@ -1039,6 +1091,11 @@
     int res = 0;
     char *alertName;
 
+    if (!isNameLegal(costName)) {
+        ALOGE("setCostlyAlert: Invalid costName \"%s\"", costName);
+        return -1;
+    }
+
     if (!bytes) {
         ALOGE("Invalid bytes value. 1..max_int64.");
         return -1;
@@ -1064,6 +1121,11 @@
     char *alertName;
     int res = 0;
 
+    if (!isNameLegal(costName)) {
+        ALOGE("removeCostlyAlert: Invalid costName \"%s\"", costName);
+        return -1;
+    }
+
     asprintf(&alertName, "%sAlert", costName);
     if (!*alertBytes) {
         ALOGE("No prior alert set for %s alert", costName);