Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bc744ae5 authored by Devin Moore's avatar Devin Moore
Browse files

IServiceManager add checkServiceAccess to delegate sepolicy check

Android Virtualization Framework is in charge of VSOCK communications on
Android devices. Specifically, virtmgr manages these connection for AVF
clients that own VMs. It is forked from the owner and can get the
selinux SID of that owning process.
We want to check that the owning process has access to services that it
is requesting.
So we provide a new checkServiceAccess method that takes the SID of the
owner and checks if it has access to "find" a given service before
virtmgr provides access to it.

Flag: EXEMPT Clients of this new functionality will be flagged
Test: atest vm_accessor_test
Bug: 358427181
Change-Id: Ie389af62f1af541a554294d79f72b4c3b65c3e45
parent e226cba6
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -68,6 +68,7 @@ class ServiceManagerMock : public IServiceManager {
                                             const sp<LocalRegistrationCallback>&));
    MOCK_METHOD0(getServiceDebugInfo, std::vector<ServiceDebugInfo>());
    MOCK_METHOD1(enableAddServiceCache, void(bool));
    MOCK_METHOD5(checkServiceAccess, bool(const String16&, pid_t, uid_t, const String16&, const String16&));

  protected:
    MOCK_METHOD0(onAsBinder, IBinder*());
+59 −0
Original line number Diff line number Diff line
@@ -1179,6 +1179,65 @@ Status ServiceManager::getServiceDebugInfo(std::vector<ServiceDebugInfo>* outRet
    return Status::ok();
}

Status ServiceManager::checkServiceAccessImpl(const Access::CallingContext& ctx,
                                              const std::string& name,
                                              const std::string& permission, bool* outReturn) {
    *outReturn = false;
    if (permission == "find") {
        std::optional<std::string> _accessor;
        if (auto status = canFindService(ctx, name, &_accessor); !status.isOk()) {
            return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denied.");
        }
    } else if (permission == "add") {
        std::optional<std::string> _accessor;
        if (auto status = canAddService(ctx, name, &_accessor); !status.isOk()) {
            return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denied.");
        }
    } else if (permission == "list") {
        if (!mAccess->canList(ctx)) {
            return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denied.");
        }
    } else {
        ALOGE("Unknown service_manager permission: %s", permission.c_str());
        return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "Invalid permission");
    }

    *outReturn = true;
    return Status::ok();
}

Status ServiceManager::checkServiceAccess(const IServiceManager::CallerContext& callerCtx,
                                          const std::string& name, const std::string& permission,
                                          bool* outReturn) {
    if (callerCtx.sidName.empty() || name.empty() || permission.empty()) {
        return Status::
                fromExceptionCode(Status::EX_SECURITY,
                                  String8::format("Call to checkServiceAccess has incomplete "
                                                  "arguments. "
                                                  "the caller security context (sid): \"%s\", "
                                                  "name: \"%s\", permission: \"%s\".",
                                                  callerCtx.sidName.c_str(), name.c_str(),
                                                  permission.c_str()));
    }
    // The caller must have check_access permission
    Access::CallingContext directCallerCtx = mAccess->getCallingContext();
    // TODO add check_access permission in system/sepolicy/private/access_vectors
    // For now, the only user of this, virtmgr, already has access to these
    // services because it needs to proxy them.
    auto status = checkServiceAccessImpl(directCallerCtx, name, permission, outReturn);
    if (!status.isOk() || !*outReturn) {
        return Status::fromExceptionCode(Status::EX_SECURITY,
                                         "Caller is not allowed to delegate this check to "
                                         "servicemanager.");
    }

    Access::CallingContext callingCtx;
    callingCtx.debugPid = callerCtx.debugPid;
    callingCtx.uid = callerCtx.uid;
    callingCtx.sid = callerCtx.sidName;
    return checkServiceAccessImpl(callingCtx, name, permission, outReturn);
}

void ServiceManager::clear() {
    mNameToService.clear();
    mNameToRegistrationCallback.clear();
+6 −1
Original line number Diff line number Diff line
@@ -68,6 +68,9 @@ public:
                                          const sp<IClientCallback>& cb) override;
    binder::Status tryUnregisterService(const std::string& name, const sp<IBinder>& binder) override;
    binder::Status getServiceDebugInfo(std::vector<ServiceDebugInfo>* outReturn) override;
    binder::Status checkServiceAccess(const os::IServiceManager::CallerContext& callerCtx,
                                      const std::string& name, const std::string& permission,
                                      bool* outReturn) override;
    void binderDied(const wp<IBinder>& who) override;
    void handleClientCallbacks();

@@ -120,7 +123,9 @@ private:
                                 std::optional<std::string>* accessor);
    binder::Status canFindService(const Access::CallingContext& ctx, const std::string& name,
                                  std::optional<std::string>* accessor);

    binder::Status checkServiceAccessImpl(const Access::CallingContext& ctx,
                                          const std::string& name, const std::string& permission,
                                          bool* outReturn);
    ServiceMap mNameToService;
    ServiceCallbackMap mNameToRegistrationCallback;
    ClientCallbackMap mNameToClientCallback;
+11 −0
Original line number Diff line number Diff line
@@ -473,6 +473,17 @@ Status BackendUnifiedServiceManager::getServiceDebugInfo(
                                     kUnsupportedOpNoServiceManager);
}

Status BackendUnifiedServiceManager::checkServiceAccess(
        const AidlServiceManager::CallerContext& callerCtx, const std::string& name,
        const std::string& permission, bool* _aidl_return) {
    if (mTheRealServiceManager) {
        return mTheRealServiceManager->checkServiceAccess(callerCtx, name, permission,
                                                          _aidl_return);
    }
    return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION,
                                     kUnsupportedOpNoServiceManager);
}

[[clang::no_destroy]] static std::once_flag gUSmOnce;
[[clang::no_destroy]] static sp<BackendUnifiedServiceManager> gUnifiedServiceManager;

+4 −0
Original line number Diff line number Diff line
@@ -147,6 +147,10 @@ public:
                                        const sp<IBinder>& service) override;
    binder::Status getServiceDebugInfo(::std::vector<os::ServiceDebugInfo>* _aidl_return) override;

    binder::Status checkServiceAccess(const os::IServiceManager::CallerContext& callerCtx,
                                      const ::std::string& name, const ::std::string& permission,
                                      bool* _aidl_return) override;

    void enableAddServiceCache(bool value) { mEnableAddServiceCache = value; }
    // for legacy ABI
    const String16& getInterfaceDescriptor() const override {
Loading