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

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

Add NDK APIs for new checkServiceAccess method in libbinder

This is used to delegate service checks for another process instead of
the process making the call to servicemanager.

Flag: EXEMPT Clients of this new functionality will be flagged
Test: atest vm_accessor_test
Bug: 358427181
Change-Id: Icf2140b61972caced0ef36e60b6c2e920361d41f
parent bc744ae5
Loading
Loading
Loading
Loading
+34 −0
Original line number Diff line number Diff line
@@ -14,6 +14,15 @@
 * limitations under the License.
 */

/*
 * This file defines the AServiceManager LLNDK APIs that vendor and system
 * processes use to interact with the Binder servicemanager process in /system.
 * It provides a stable API for most of the functionality of the libbinder
 * IServiceManager APIs in
 * `frameworks/native/libs/binder/include/binder/IServiceManager.h`.
 *
 * All strings are expected be UTF-8.
 */
#pragma once

#include <android/binder_ibinder.h>
@@ -315,4 +324,29 @@ bool AServiceManager_tryUnregister() __INTRODUCED_IN(31);
 */
void AServiceManager_reRegister() __INTRODUCED_IN(31);

/**
 * Check if this 'callerSid' has access for the 'permission' for a given service 'name'.
 *
 * This is useful when a process will be making calls to servicemanager on behalf of another
 * process (callerCtx).
 *
 * \param caller_sid - UTF-8 encoded string. SELinux context of the process that is being checked.
 * \param caller_debug_pid - PID of the process that is being checked. This can
 *                           only be used in logging for debugging because PIDs are
 *                           reused. Servicemanager uses it for logging denials.
 * \param caller_uid - UID of the process that is being checked. Servicemanager
 *                     only uses this for logging denials for better debugging.
 * \param instance - UTF-8 encoded string. Instance name of the service that the caller
 *                   wants to interact with.
 * \param permission - UTF-8 encoded string. The servicemanager SELinux permission that the process
 *                     is interested in for the service. This is either "find", "list", or "add".
 *
 * \return True if the process with `caller_sid` has the SELinux `permission`
 *         for the given service `instance`. False if it does not have
 *         permission or some error occurred.
 */
bool AServiceManager_checkServiceAccess(const char* caller_sid, pid_t caller_debug_pid,
                                        uid_t caller_uid, const char* instance,
                                        const char* permission) __INTRODUCED_IN(37);

__END_DECLS
+5 −0
Original line number Diff line number Diff line
@@ -222,6 +222,11 @@ LIBBINDER_NDK36 { # introduced=36
    ABinderRpc_ConnectionInfo_delete; # systemapi
};

LIBBINDER_NDK37 { # introduced=37
  global:
    AServiceManager_checkServiceAccess; # systemapi llndk
};

LIBBINDER_NDK_PLATFORM {
  global:
    AParcel_getAllowFds;
+12 −0
Original line number Diff line number Diff line
@@ -250,3 +250,15 @@ void AServiceManager_reRegister() {
    auto serviceRegistrar = android::binder::LazyServiceRegistrar::getInstance();
    serviceRegistrar.reRegister();
}

bool AServiceManager_checkServiceAccess(const char* caller_sid, pid_t caller_debug_pid,
                                        uid_t caller_uid, const char* instance,
                                        const char* permission) {
    LOG_ALWAYS_FATAL_IF(caller_sid == nullptr, "caller_sid == nullptr");
    LOG_ALWAYS_FATAL_IF(instance == nullptr, "instance == nullptr");
    LOG_ALWAYS_FATAL_IF(permission == nullptr, "permission == nullptr");

    sp<IServiceManager> sm = defaultServiceManager();
    return sm->checkServiceAccess(String16(caller_sid), caller_debug_pid, caller_uid,
                                  String16(instance), String16(permission));
}
+19 −0
Original line number Diff line number Diff line
@@ -1085,6 +1085,25 @@ TEST(NdkBinder, GetClassInterfaceDescriptor) {
    ASSERT_STREQ(IFoo::kIFooDescriptor, AIBinder_Class_getDescriptor(IFoo::kClass));
}

TEST(NdkBinder, CheckServiceAccessOk) {
    // This test case runs as su which has access to all services
    EXPECT_TRUE(AServiceManager_checkServiceAccess("u:r:su:s0", 0, 0, "adb", "find"));
}

TEST(NdkBinder, CheckServiceAccessNotOk) {
    EXPECT_FALSE(
            AServiceManager_checkServiceAccess("u:r:some_unknown_sid:s0", 0, 0, "adb", "find"));
}

TEST(NdkBinder, InvalidCheckServiceAccessArgs) {
    EXPECT_DEATH(AServiceManager_checkServiceAccess(nullptr, 0, 0, nullptr, nullptr), "nullptr");
    EXPECT_DEATH(AServiceManager_checkServiceAccess("u:r:su:s0", 0, 0, nullptr, nullptr),
                 "nullptr");
    EXPECT_DEATH(AServiceManager_checkServiceAccess("u:r:su:s0", 0, 0, "adb", nullptr), "nullptr");
    EXPECT_DEATH(AServiceManager_checkServiceAccess("u:r:su:s0", 0, 0, nullptr, "find"), "nullptr");
    EXPECT_FALSE(AServiceManager_checkServiceAccess("u:r:su:s0", 0, 0, "adb", "unknown"));
}

static void addOne(int* to) {
    if (!to) return;
    ++(*to);