Kommunikationsprinzip von Android Binder (8): IPC-Berechtigungskontrolle

Quellcode basierend auf: Android R

0. Vorwort

In mehreren früheren Blog-Beiträgen haben wir eine eingehende Analyse der Kommunikationsprinzipien von Android Binder durchgeführt. Zu diesen Blog-Beiträgen gehören: Binder-Einführung , Servicemanager-Start , Service-Registrierung , Service-Erwerb , Service-Registrierung und -Erwerb , CS unten nativ , Java CS unter .

In diesem Artikel wird die Berechtigungskontrolle unter IPC weiter analysiert.

Weg: 

Frameworks/base/core/java/android/os/Binder.java

Frameworks/base/core/jin/android_util_Binder.cpp

Frameworks/native/libs/binder/IPCThreadState.cpp

1. Java-Code

frameworks/base/core/java/android/os/Binder.java

public static final native long clearCallingIdentity();

public static final native void restoreCallingIdentity(long token);

2. JNI-Code

frameworks/base/core/jin/android_util_Binder.cpp

static jlong android_os_Binder_clearCallingIdentity()
{
    return IPCThreadState::self()->clearCallingIdentity();
}

static void android_os_Binder_restoreCallingIdentity(JNIEnv* env, jobject clazz, jlong token)
{
    // XXX temporary sanity check to debug crashes.
    int uid = (int)(token>>32);
    if (uid > 0 && uid < 999) {
        // In Android currently there are no uids in this range.
        char buf[128];
        sprintf(buf, "Restoring bad calling ident: 0x%" PRIx64, token);
        jniThrowException(env, "java/lang/IllegalStateException", buf);
        return;
    }
    IPCThreadState::self()->restoreCallingIdentity(token);
}

Das Wiederherstellungsparameter-Token ist der Rückgabewert der Clear-Schnittstelle.

3. Code in IPCThreadState

frameworks/native/libs/binder/IPCThreadState.cpp

int64_t IPCThreadState::clearCallingIdentity()
{
    // ignore mCallingSid for legacy reasons
    int64_t token = ((int64_t)mCallingUid<<32) | mCallingPid;
    clearCaller();
    return token;
}

void IPCThreadState::restoreCallingIdentity(int64_t token)
{
    mCallingUid = (int)(token>>32);
    mCallingSid = nullptr;  // not enough data to restore
    mCallingPid = (int)token;
}

clearCallingIdentity macht hauptsächlich zwei Dinge:

  • Die hohen 32 Bits sind mCallingUid und die niedrigen 32 Bits sind mCallingPid . Sie werden im Token gespeichert und später durch restartCallingIdentity() wiederhergestellt .
  • Rufen Sie clearCaller() auf, um vorübergehend die genaue PID und UID des Prozesses zu erhalten, in dem sich IPCThreadState befindet.
void IPCThreadState::clearCaller()
{
    mCallingPid = getpid();
    mCallingSid = nullptr;  // expensive to lookup
    mCallingUid = getuid();
}

4. Nutzungsszenarien

  •  Thread A ruft Thread B über den Binder auf. Es ist auch möglich, dass sich Thread A und Thread B in unterschiedlichen Prozessen befinden.
  • Thread B hat diese Logik:
    •  Sobald die Komponente einen Aufruf von Thread A empfängt, können mCallingPid und mCallingUid im IPCThreadState, in dem sich Thread B befindet, zu diesem Zeitpunkt geändert werden, siehe 4.2;
    • Wenn Komponente eins die Funktion von Komponente zwei aufruft, möchte sie die PID und UID von Komponente eins selbst anzeigen, siehe 4.1;
    • Wenn Komponente zwei abgeschlossen ist und zu Komponente eins zurückkehren muss, müssen mCallingPid und mCallingUid in IPCThreadState wiederhergestellt werden; 

 4.1 Rufen Sie die PID und UID des aktuellen Bidner-Threads ab

JAVA:
public static final native int getCallingPid();
public static final native int getCallingUid();

JNI:
static jint android_os_Binder_getCallingPid()
{
    return IPCThreadState::self()->getCallingPid();
}
static jint android_os_Binder_getCallingUid()
{
    return IPCThreadState::self()->getCallingUid();
}

Die aufrufende PID und die aufrufende UID können im Thread über die Binder-Schnittstelle abgerufen werden. Natürlich kann die native auch über IPCThreadState abgerufen werden:

pid_t IPCThreadState::getCallingPid() const
{
    return mCallingPid;
}
uid_t IPCThreadState::getCallingUid() const
{
    return mCallingUid;
}

Woher kamen also die ursprüngliche mCallingPid und mCallingUid?

IPCThreadState::IPCThreadState()
    : mProcess(ProcessState::self()),
      ...
{
    ...
    clearCaller();
    ...
}

clearCaller() wurde in Abschnitt 3 analysiert. Hier werden beim Erstellen jedes Binder-Threads die PID und die UID des aktuellen Threads abgerufen.

4.2 IPCThreadState ändert als Empfänger die aufrufende PID und UID

status_t IPCThreadState::executeCommand(int32_t cmd)
{
    ...
    case BR_TRANSACTION:
        const pid_t origPid = mCallingPid;   //备份mCallingPid 和mCallingUid
        const char* origSid = mCallingSid;
        const uid_t origUid = mCallingUid;
        ...
        mCallingPid = tr.sender_pid;    //这里会修改成sender 的pid 和uid
        mCallingSid = reinterpret_cast<const char*>(tr_secctx.secctx);
        mCallingUid = tr.sender_euid;
        ...
        if (tr.target.ptr) {
            // We only have a weak reference on the target object, so we must first try to
            // safely acquire a strong reference before doing anything else with it.
            if (reinterpret_cast<RefBase::weakref_type*>(
                    tr.target.ptr)->attemptIncStrong(this)) {
                error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer, //进入接收端,此时的pid和uid都为sender的
                        &reply, tr.flags);
                reinterpret_cast<BBinder*>(tr.cookie)->decStrong(this);
            } else {
                error = UNKNOWN_TRANSACTION;
            }
        } else {
            error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
        }
        ...
        mCallingPid = origPid; //从接收端返回后,pid和uid 需要改为原始的
        mCallingSid = origSid;
        mCallingUid = origUid;
        ...
}

Siehe die Kommentare im Code. In transact() befinden sich beide auf der Empfangsseite. Die PID und die UID befinden sich zu diesem Zeitpunkt beide auf der Absenderseite. Wenn Sie während dieses Vorgangs die ursprüngliche mCallingPid und mCallingUid von Binder erhalten müssen, können Sie dies tun Ich muss „clear“ und „restore“ aufrufen.

Zum Beispiel in AMS:

    public ComponentName startService(IApplicationThread caller, Intent service,
            ...
            String callingFeatureId, int userId)
            throws TransactionTooLargeException {
        ...
        synchronized(this) {
            final int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            ComponentName res;
            try {
                res = mServices.startServiceLocked(caller, service,
                        resolvedType, callingPid, callingUid,
                        requireForeground, callingPackage, callingFeatureId, userId);
            } finally {
                Binder.restoreCallingIdentity(origId);
            }
            return res;
        }
    }

Wenn Sie ActiveServices.startServiceLocked () aufrufen, müssen Sie die PID und UID des aktuellen Threads kennen. Sie müssen sie vor dem Aufruf löschen und nach der Rückkehr des Aufrufs wiederherstellen.

Zu diesem Zeitpunkt ist die IPC-Berechtigungskontrollanalyse abgeschlossen.

Supongo que te gusta

Origin blog.csdn.net/jingerppp/article/details/131529505
Recomendado
Clasificación