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();