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
Change-Id: Ie69d92f9006d10e7e3e4871f5760823291ed8e1f
diff --git a/AccessControl.cpp b/AccessControl.cpp
index abcb569..985feb7 100644
--- a/AccessControl.cpp
+++ b/AccessControl.cpp
@@ -18,6 +18,7 @@
 };
 
 using android::FQName;
+using Context = AccessControl::Context;
 
 AccessControl::AccessControl() {
     mSeHandle = selinux_android_hw_service_context_handle();
@@ -36,7 +37,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()) {
@@ -44,7 +45,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) {
@@ -55,36 +56,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 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;
 
@@ -94,7 +101,7 @@
         return false;
     }
 
-    allowed = checkPermission(sourcePid, targetContext, perm, interface);
+    allowed = checkPermission(context, sourceAuditPid, targetContext, perm, interface);
 
     freecon(targetContext);