get selinux context on add call arrival.
interfaceChain may take too long and allow for the PID
to become invalidated.
Bug: 68217907
Test: hidl's run_all_device_tests, boot + camera/YT sanity
Merged-In: Ie69d92f9006d10e7e3e4871f5760823291ed8e1f
Change-Id: Ie69d92f9006d10e7e3e4871f5760823291ed8e1f
(cherry picked from commit 8165cd3e0044896bed17be2c580d60bc93b4ed2b)
diff --git a/AccessControl.cpp b/AccessControl.cpp
index 82761e1..fac4dc1 100644
--- a/AccessControl.cpp
+++ b/AccessControl.cpp
@@ -16,6 +16,7 @@
};
using android::FQName;
+using Context = AccessControl::Context;
AccessControl::AccessControl() {
mSeHandle = selinux_android_hw_service_context_handle();
@@ -34,7 +35,7 @@
selinux_set_callback(SELINUX_CB_LOG, mSeCallbacks);
}
-bool AccessControl::canAdd(const std::string& fqName, pid_t pid) {
+bool AccessControl::canAdd(const std::string& fqName, const Context &context, pid_t pid) {
FQName fqIface(fqName);
if (!fqIface.isValid()) {
@@ -42,7 +43,7 @@
}
const std::string checkName = fqIface.package() + "::" + fqIface.name();
- return checkPermission(pid, kPermissionAdd, checkName.c_str());
+ return checkPermission(context, pid, kPermissionAdd, checkName.c_str());
}
bool AccessControl::canGet(const std::string& fqName, pid_t pid) {
@@ -53,36 +54,42 @@
}
const std::string checkName = fqIface.package() + "::" + fqIface.name();
- return checkPermission(pid, kPermissionGet, checkName.c_str());
+ return checkPermission(getContext(pid), pid, kPermissionGet, checkName.c_str());
}
bool AccessControl::canList(pid_t pid) {
- return checkPermission(pid, mSeContext, kPermissionList, nullptr);
+ return checkPermission(getContext(pid), pid, mSeContext, kPermissionList, nullptr);
}
-bool AccessControl::checkPermission(pid_t sourcePid, const char *targetContext,
- const char *perm, const char *interface) {
+Context AccessControl::getContext(pid_t sourcePid) {
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);
+ ALOGE("SELinux: failed to retrieve process context for pid %d", sourcePid);
+ return Context(nullptr, freecon);
+ }
+
+ return Context(sourceContext, freecon);
+}
+
+bool AccessControl::checkPermission(const Context &context, pid_t sourceAuditPid, const char *targetContext, const char *perm, const char *interface) {
+ if (context == nullptr) {
return false;
}
- ad.pid = sourcePid;
+ bool allowed = false;
+ struct audit_data ad;
+
+ ad.pid = sourceAuditPid;
ad.interfaceName = interface;
- allowed = (selinux_check_access(sourceContext, targetContext, "hwservice_manager",
+ allowed = (selinux_check_access(context.get(), targetContext, "hwservice_manager",
perm, (void *) &ad) == 0);
- freecon(sourceContext);
-
return allowed;
}
-bool AccessControl::checkPermission(pid_t sourcePid, const char *perm, const char *interface) {
+bool AccessControl::checkPermission(const Context &context, pid_t sourceAuditPid, const char *perm, const char *interface) {
char *targetContext = NULL;
bool allowed = false;
@@ -92,7 +99,7 @@
return false;
}
- allowed = checkPermission(sourcePid, targetContext, perm, interface);
+ allowed = checkPermission(context, sourceAuditPid, targetContext, perm, interface);
freecon(targetContext);
diff --git a/AccessControl.h b/AccessControl.h
index e91de27..63a2098 100644
--- a/AccessControl.h
+++ b/AccessControl.h
@@ -8,12 +8,18 @@
class AccessControl {
public:
AccessControl();
- bool canAdd(const std::string& fqName, pid_t pid);
+
+ using Context = std::unique_ptr<char, decltype(&freecon)>;
+ Context getContext(pid_t sourcePid);
+
+ bool canAdd(const std::string& fqName, const Context &context, 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);
+
+ bool checkPermission(const Context &context, pid_t sourceAuditPid, const char *targetContext, const char *perm, const char *interface);
+ bool checkPermission(const Context &context, pid_t sourcePid, const char *perm, const char *interface);
static int auditCallback(void *data, security_class_t cls, char *buf, size_t len);
diff --git a/ServiceManager.cpp b/ServiceManager.cpp
index 41b8e45..0705c71 100644
--- a/ServiceManager.cpp
+++ b/ServiceManager.cpp
@@ -194,6 +194,7 @@
// TODO(b/34235311): use HIDL way to determine this
// also, this assumes that the PID that is registering is the pid that is the service
pid_t pid = IPCThreadState::self()->getCallingPid();
+ auto context = mAcl.getContext(pid);
auto ret = service->interfaceChain([&](const auto &interfaceChain) {
if (interfaceChain.size() == 0) {
@@ -204,7 +205,7 @@
for(size_t i = 0; i < interfaceChain.size(); i++) {
std::string fqName = interfaceChain[i];
- if (!mAcl.canAdd(fqName, pid)) {
+ if (!mAcl.canAdd(fqName, context, pid)) {
return;
}
}