remove "// static" comments am: e606433c10 am: d7e3d23dea
am: d283b46a3a

Change-Id: Id70deacc6098f062ebb94f00bebf5f455d60837d
diff --git a/AccessControl.cpp b/AccessControl.cpp
new file mode 100644
index 0000000..82761e1
--- /dev/null
+++ b/AccessControl.cpp
@@ -0,0 +1,114 @@
+#include <android-base/logging.h>
+#include <hidl-util/FQName.h>
+#include <log/log.h>
+
+#include "AccessControl.h"
+
+namespace android {
+
+static const char *kPermissionAdd = "add";
+static const char *kPermissionGet = "find";
+static const char *kPermissionList = "list";
+
+struct audit_data {
+    const char* interfaceName;
+    pid_t       pid;
+};
+
+using android::FQName;
+
+AccessControl::AccessControl() {
+    mSeHandle = selinux_android_hw_service_context_handle();
+    LOG_ALWAYS_FATAL_IF(mSeHandle == NULL, "Failed to acquire SELinux handle.");
+
+    if (getcon(&mSeContext) != 0) {
+        LOG_ALWAYS_FATAL("Failed to acquire hwservicemanager context.");
+    }
+
+    selinux_status_open(true);
+
+    mSeCallbacks.func_audit = AccessControl::auditCallback;
+    selinux_set_callback(SELINUX_CB_AUDIT, mSeCallbacks);
+
+    mSeCallbacks.func_log = selinux_log_callback; /* defined in libselinux */
+    selinux_set_callback(SELINUX_CB_LOG, mSeCallbacks);
+}
+
+bool AccessControl::canAdd(const std::string& fqName, pid_t pid) {
+    FQName fqIface(fqName);
+
+    if (!fqIface.isValid()) {
+        return false;
+    }
+    const std::string checkName = fqIface.package() + "::" + fqIface.name();
+
+    return checkPermission(pid, kPermissionAdd, checkName.c_str());
+}
+
+bool AccessControl::canGet(const std::string& fqName, pid_t pid) {
+    FQName fqIface(fqName);
+
+    if (!fqIface.isValid()) {
+        return false;
+    }
+    const std::string checkName = fqIface.package() + "::" + fqIface.name();
+
+    return checkPermission(pid, kPermissionGet, checkName.c_str());
+}
+
+bool AccessControl::canList(pid_t pid) {
+    return checkPermission(pid, mSeContext, kPermissionList, nullptr);
+}
+
+bool AccessControl::checkPermission(pid_t sourcePid, const char *targetContext,
+                                    const char *perm, const char *interface) {
+    char *sourceContext = NULL;
+    bool allowed = false;
+    struct audit_data ad;
+
+    if (getpidcon(sourcePid, &sourceContext) < 0) {
+        ALOGE("SELinux: failed to retrieved process context for pid %d", sourcePid);
+        return false;
+    }
+
+    ad.pid = sourcePid;
+    ad.interfaceName = interface;
+
+    allowed = (selinux_check_access(sourceContext, targetContext, "hwservice_manager",
+                                    perm, (void *) &ad) == 0);
+
+    freecon(sourceContext);
+
+    return allowed;
+}
+
+bool AccessControl::checkPermission(pid_t sourcePid, const char *perm, const char *interface) {
+    char *targetContext = NULL;
+    bool allowed = false;
+
+    // Lookup service in hwservice_contexts
+    if (selabel_lookup(mSeHandle, &targetContext, interface, 0) != 0) {
+        ALOGE("No match for interface %s in hwservice_contexts", interface);
+        return false;
+    }
+
+    allowed = checkPermission(sourcePid, targetContext, perm, interface);
+
+    freecon(targetContext);
+
+    return allowed;
+}
+
+int AccessControl::auditCallback(void *data, security_class_t /*cls*/, char *buf, size_t len) {
+    struct audit_data *ad = (struct audit_data *)data;
+
+    if (!ad || !ad->interfaceName) {
+        ALOGE("No valid hwservicemanager audit data");
+        return 0;
+    }
+
+    snprintf(buf, len, "interface=%s pid=%d", ad->interfaceName, ad->pid);
+    return 0;
+}
+
+} // namespace android
diff --git a/AccessControl.h b/AccessControl.h
new file mode 100644
index 0000000..e91de27
--- /dev/null
+++ b/AccessControl.h
@@ -0,0 +1,25 @@
+#include <string>
+
+#include <selinux/android.h>
+#include <selinux/avc.h>
+
+namespace android {
+
+class AccessControl {
+public:
+    AccessControl();
+    bool canAdd(const std::string& fqName, pid_t pid);
+    bool canGet(const std::string& fqName, pid_t pid);
+    bool canList(pid_t pid);
+private:
+    bool checkPermission(pid_t sourcePid, const char *perm, const char *interface);
+    bool checkPermission(pid_t sourcePid, const char *targetContext, const char *perm, const char *interface);
+
+    static int auditCallback(void *data, security_class_t cls, char *buf, size_t len);
+
+    char*                  mSeContext;
+    struct selabel_handle* mSeHandle;
+    union selinux_callback mSeCallbacks;
+};
+
+} // namespace android
diff --git a/Android.bp b/Android.bp
index 2f5153e..5079b43 100644
--- a/Android.bp
+++ b/Android.bp
@@ -18,6 +18,7 @@
         "hwservicemanager.rc",
     ],
     srcs: [
+        "AccessControl.cpp",
         "HidlService.cpp",
         "ServiceManager.cpp",
         "service.cpp",
diff --git a/ServiceManager.cpp b/ServiceManager.cpp
index 973da58..7930d18 100644
--- a/ServiceManager.cpp
+++ b/ServiceManager.cpp
@@ -149,6 +149,11 @@
 // Methods from ::android::hidl::manager::V1_0::IServiceManager follow.
 Return<sp<IBase>> ServiceManager::get(const hidl_string& fqName,
                                       const hidl_string& name) {
+    pid_t pid = IPCThreadState::self()->getCallingPid();
+    if (!mAcl.canGet(fqName, pid)) {
+        return nullptr;
+    }
+
     auto ifaceIt = mServiceMap.find(fqName);
     if (ifaceIt == mServiceMap.end()) {
         return nullptr;
@@ -180,6 +185,15 @@
             return;
         }
 
+        // First, verify you're allowed to add() the whole interface hierarchy
+        for(size_t i = 0; i < interfaceChain.size(); i++) {
+            std::string fqName = interfaceChain[i];
+
+            if (!mAcl.canAdd(fqName, pid)) {
+                return;
+            }
+        }
+
         for(size_t i = 0; i < interfaceChain.size(); i++) {
             std::string fqName = interfaceChain[i];
 
@@ -218,6 +232,11 @@
                                                                const hidl_string& name) {
     using ::android::hardware::getTransport;
 
+    pid_t pid = IPCThreadState::self()->getCallingPid();
+    if (!mAcl.canGet(fqName, pid)) {
+        return Transport::EMPTY;
+    }
+
     switch (getTransport(fqName, name)) {
         case vintf::Transport::HWBINDER:
              return Transport::HWBINDER;
@@ -230,8 +249,14 @@
 }
 
 Return<void> ServiceManager::list(list_cb _hidl_cb) {
+    pid_t pid = IPCThreadState::self()->getCallingPid();
+    if (!mAcl.canList(pid)) {
+        _hidl_cb({});
+        return Void();
+    }
 
     hidl_vec<hidl_string> list;
+
     list.resize(countExistingService());
 
     size_t idx = 0;
@@ -245,6 +270,12 @@
 
 Return<void> ServiceManager::listByInterface(const hidl_string& fqName,
                                              listByInterface_cb _hidl_cb) {
+    pid_t pid = IPCThreadState::self()->getCallingPid();
+    if (!mAcl.canGet(fqName, pid)) {
+        _hidl_cb({});
+        return Void();
+    }
+
     auto ifaceIt = mServiceMap.find(fqName);
     if (ifaceIt == mServiceMap.end()) {
         _hidl_cb(hidl_vec<hidl_string>());
@@ -283,6 +314,11 @@
         return false;
     }
 
+    pid_t pid = IPCThreadState::self()->getCallingPid();
+    if (!mAcl.canGet(fqName, pid)) {
+        return false;
+    }
+
     PackageInterfaceMap &ifaceMap = mServiceMap[fqName];
 
     if (name.empty()) {
@@ -315,6 +351,12 @@
 }
 
 Return<void> ServiceManager::debugDump(debugDump_cb _cb) {
+    pid_t pid = IPCThreadState::self()->getCallingPid();
+    if (!mAcl.canList(pid)) {
+        _cb({});
+        return Void();
+    }
+
     std::vector<IServiceManager::InstanceDebugInfo> list;
     forEachServiceEntry([&] (const HidlService *service) {
         hidl_vec<int32_t> clientPids;
@@ -342,6 +384,13 @@
 Return<void> ServiceManager::registerPassthroughClient(const hidl_string &fqName,
         const hidl_string &name) {
     pid_t pid = IPCThreadState::self()->getCallingPid();
+    if (!mAcl.canGet(fqName, pid)) {
+        /* We guard this function with "get", because it's typically used in
+         * the getService() path, albeit for a passthrough service in this
+         * case
+         */
+        return Void();
+    }
 
     PackageInterfaceMap &ifaceMap = mServiceMap[fqName];
 
diff --git a/ServiceManager.h b/ServiceManager.h
index 9fafadf..c616d80 100644
--- a/ServiceManager.h
+++ b/ServiceManager.h
@@ -6,6 +6,7 @@
 #include <hidl/MQDescriptor.h>
 #include <map>
 
+#include "AccessControl.h"
 #include "HidlService.h"
 
 namespace android {
@@ -91,6 +92,8 @@
         std::vector<sp<IServiceNotification>> mPackageListeners{};
     };
 
+    AccessControl mAcl;
+
     /**
      * Access to this map doesn't need to be locked, since hwservicemanager
      * is single-threaded.
diff --git a/service.cpp b/service.cpp
index 9c501be..f33d7d2 100644
--- a/service.cpp
+++ b/service.cpp
@@ -96,8 +96,16 @@
     IPCThreadState::self()->setTheContextObject(service);
     // Then tell binder kernel
     ioctl(binder_fd, BINDER_SET_CONTEXT_MGR, 0);
+    // Only enable FIFO inheritance for hwbinder
+    // FIXME: remove define when in the kernel
+#define BINDER_SET_INHERIT_FIFO_PRIO    _IO('b', 10)
 
-    int rc = property_set("hwservicemanager.ready", "true");
+    int rc = ioctl(binder_fd, BINDER_SET_INHERIT_FIFO_PRIO);
+    if (rc) {
+        ALOGE("BINDER_SET_INHERIT_FIFO_PRIO failed with error %d\n", rc);
+    }
+
+    rc = property_set("hwservicemanager.ready", "true");
     if (rc) {
         ALOGE("Failed to set \"hwservicemanager.ready\" (error %d). "\
               "HAL services will not start!\n", rc);