Browse Source

gluon-status-page-api: support batadv-in-VLAN on ibss interface

introduce function to recurse down to the lowest layer-2 interface
corresponding to a given interface.
also re-introduce some of the previously removed input validation plus
some more to protect against glob and path based exploits.
Daniel Golle 8 years ago
parent
commit
4ce85afc22
1 changed files with 63 additions and 2 deletions
  1. 63 2
      package/gluon-status-page-api/src/stations.c

+ 63 - 2
package/gluon-status-page-api/src/stations.c

@@ -4,7 +4,12 @@
 #include <json-c/json.h>
 #include <iwinfo.h>
 #include <net/if.h>
+#include <glob.h>
+#include <alloca.h>
 
+#define NETIF_PREFIX "/sys/class/net/"
+#define VIRTIF_PREFIX "/sys/devices/virtual/net/"
+#define LOWERGLOB_SUFFIX "/lower_*"
 
 static struct json_object *get_stations(const struct iwinfo_ops *iw, const char *ifname) {
   int len;
@@ -40,12 +45,68 @@ static void badrequest() {
   exit(1);
 }
 
+// recurse down to the lowest layer-2 interface
+static int interface_get_lowest(const char *ifname, char *hwifname);
+static int interface_get_lowest(const char *ifname, char *hwifname) {
+  glob_t globbuf;
+  char *fnamebuf = alloca(1 + strlen(VIRTIF_PREFIX) + IF_NAMESIZE +
+                          strlen(LOWERGLOB_SUFFIX));
+  char *lowentry = NULL;
+
+
+  sprintf(fnamebuf, "%s%s%s", VIRTIF_PREFIX, ifname, LOWERGLOB_SUFFIX);
+  glob(fnamebuf, GLOB_NOSORT | GLOB_NOESCAPE, NULL, &globbuf);
+
+  if (globbuf.gl_pathc == 1) {
+    lowentry = alloca(1 + strlen(globbuf.gl_pathv[0]));
+    strncpy(lowentry, globbuf.gl_pathv[0], 1 + strlen(globbuf.gl_pathv[0]));
+  }
+
+  globfree(&globbuf);
+
+  if (!lowentry) {
+    char *path = alloca(1 + strlen(NETIF_PREFIX) + strlen(ifname));
+    sprintf(path, "%s%s", NETIF_PREFIX, ifname);
+
+    if(access(path, F_OK) != 0)
+      return false;
+
+    strncpy(hwifname, ifname, IF_NAMESIZE - 1);
+    return true;
+  } else {
+    char buf[PATH_MAX];
+    ssize_t len;
+
+    if ((len = readlink(lowentry, buf, sizeof(buf)-1)) != -1)
+      buf[len] = '\0';
+    else
+      return false;
+
+    if (strncmp(buf, "../", 3) == 0) {
+      return interface_get_lowest(strrchr(buf, '/') + 1, hwifname);
+    } else {
+      return false;
+    }
+  }
+}
+
 int main(int argc, char *argv[]) {
   if (argc != 2)
     badrequest();
 
   const char *ifname = argv[1];
-  const struct iwinfo_ops *iw = iwinfo_backend(ifname);
+  char hwifname[IF_NAMESIZE] = "";
+
+  if (strlen(ifname) >= IF_NAMESIZE)
+    badrequest();
+
+  if (strcspn(ifname, "/\\[]{}*?") != strlen(ifname))
+    badrequest();
+
+  if (!interface_get_lowest(ifname, hwifname))
+    badrequest();
+
+  const struct iwinfo_ops *iw = iwinfo_backend(hwifname);
 
   if (iw == NULL)
     badrequest();
@@ -54,7 +115,7 @@ int main(int argc, char *argv[]) {
 
   while (true) {
     struct json_object *obj;
-    obj = get_stations(iw, ifname);
+    obj = get_stations(iw, hwifname);
     printf("data: %s\n\n", json_object_to_json_string_ext(obj, JSON_C_TO_STRING_PLAIN));
     fflush(stdout);
     json_object_put(obj);