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 92ba7fd5cb2fc3e0049b1ec60e7cc878a16e40f6)
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 7930d18..8c84970 100644
--- a/ServiceManager.cpp
+++ b/ServiceManager.cpp
@@ -179,6 +179,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) {
@@ -189,7 +190,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;
             }
         }