netd: reduce privileges

netd doesn't need full root capabilities. Rather, it only needs
CAP_NET_ADMIN and CAP_NET_RAW. Reduce the capabilities to that
set.

netd continues to run with UID=0, which allows applications spawned
by netd to continue to have CAP_NET_ADMIN and CAP_NET_RAW. It also
allows netd to access /proc and /sys files as UID=0.

Change-Id: I439d22150109697213c0cc83276ddb668007b978
diff --git a/main.cpp b/main.cpp
index b466e42..e86a58b 100644
--- a/main.cpp
+++ b/main.cpp
@@ -22,6 +22,8 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+#include <sys/capability.h>
+#include <linux/prctl.h>
 
 #include <fcntl.h>
 #include <dirent.h>
@@ -39,6 +41,42 @@
 static void sigchld_handler(int sig);
 static void blockSigpipe();
 
+static void dropPrivileges() {
+    struct __user_cap_header_struct header;
+    struct __user_cap_data_struct cap[2];
+    int i;
+    int result;
+
+    // First drop unneeded capabilities from our bounding set,
+    // which affects children we exec.
+    for (i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) {
+        if (i == CAP_NET_ADMIN || i == CAP_NET_RAW) {
+            continue;
+        }
+        result = prctl(PR_CAPBSET_DROP, i, 0, 0, 0);
+        if (result != 0) {
+            perror("PR_CAPBSET_DROP failed: unable to drop privileges");
+            exit(1);
+        }
+    }
+
+    // Then drop capabilities from the current process.
+    memset(&header, 0, sizeof(header));
+    memset(cap, 0, sizeof(cap));
+
+    header.version = _LINUX_CAPABILITY_VERSION_3;
+    header.pid = 0;
+    cap[CAP_TO_INDEX(CAP_NET_ADMIN)].effective |= CAP_TO_MASK(CAP_NET_ADMIN);
+    cap[CAP_TO_INDEX(CAP_NET_ADMIN)].permitted |= CAP_TO_MASK(CAP_NET_ADMIN);
+    cap[CAP_TO_INDEX(CAP_NET_RAW)].effective   |= CAP_TO_MASK(CAP_NET_RAW);
+    cap[CAP_TO_INDEX(CAP_NET_RAW)].permitted   |= CAP_TO_MASK(CAP_NET_RAW);
+    result = capset(&header, cap);
+    if (result != 0) {
+        perror("capset failed: unable to drop privileges");
+        exit(1);
+    }
+}
+
 int main() {
 
     CommandListener *cl;
@@ -47,6 +85,7 @@
     MDnsSdListener *mdnsl;
 
     ALOGI("Netd 1.0 starting");
+    dropPrivileges();
 
 //    signal(SIGCHLD, sigchld_handler);
     blockSigpipe();