Search code examples
android-ndkandroid-binder

C++ Binder without addService()


Is it possible to use C++ Binder API to communicate between two non-privileged processes?

All examples I found (e.g. https://github.com/mcr/Android-HelloWorldService) rely on registering service via ServiceManager->addService() which throws following error when executing on a non-rooted phone:

E/ServiceManager﹕ add_service('my.test.service',0x48) uid=2000 - PERMISSION DENIED

Solution

  • Inside the AOSP (Android Open Source Project) in the file frameworks/native/cmds/servicemanager/service_manager.c you can find the following method:

    int svc_can_register(uid_t uid, const uint16_t *name)
    {
        size_t n;
    
        if ((uid == 0) || (uid == AID_SYSTEM))
            return 1;
    
        for (n = 0; n < sizeof(allowed) / sizeof(allowed[0]); n++)
            if ((uid == allowed[n].uid) && str16eq(name, allowed[n].name))
                return 1;
    
        return 0;
    }
    

    and a bit above:

    /* TODO:
     * These should come from a config file or perhaps be
     * based on some namespace rules of some sort (media
     * uid can register media.*, etc)
     */
    static struct {
        uid_t uid;
        const char *name;
    } allowed[] = {
        { AID_MEDIA, "media.audio_flinger" },
        { AID_MEDIA, "media.log" },
        { AID_MEDIA, "media.player" },
        { AID_MEDIA, "media.camera" },
        { AID_MEDIA, "media.audio_policy" },
        { AID_DRM,   "drm.drmManager" },
        { AID_NFC,   "nfc" },
        { AID_BLUETOOTH, "bluetooth" },
        { AID_RADIO, "radio.phone" },
        { AID_RADIO, "radio.sms" },
        { AID_RADIO, "radio.phonesubinfo" },
        { AID_RADIO, "radio.simphonebook" },
    /* TODO: remove after phone services are updated: */
        { AID_RADIO, "phone" },
        { AID_RADIO, "sip" },
        { AID_RADIO, "isms" },
        { AID_RADIO, "iphonesubinfo" },
        { AID_RADIO, "simphonebook" },
        { AID_MEDIA, "common_time.clock" },
        { AID_MEDIA, "common_time.config" },
        { AID_KEYSTORE, "android.security.keystore" },
    };
    

    and further down:

    if (!svc_can_register(uid, s)) {
        ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n",
             str8(s), handle, uid);
        return -1;
    }
    

    Conclusion: the system binary in /system/bin/servicemanager doesn't allow it. (for security reasons) Possible solutions:

    • kill and reuse PID and name of service listed
    • recompile your own servicemanager binary and use this one
    • inject your code in this binary, to allow everyone
    • change the PID servicemanager reads (change the ioctl response servicemanager gets in binder.h (same directory))
    • or just start your server in a binary having root permissions. Clients can connect without root, but the server needs it.