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