Freigeben über


Überprüfen auf Durchquerungsberechtigungen für IRP_MJ_CREATE

Eines der Hauptanliegen IRP_MJ_CREATE Überprüfungen ist, ob der Aufrufer über die Berechtigung zum Durchlaufen verfügt. Dies ist das Recht, auf den Pfad zu einem Objekt zuzugreifen. Das heißt, ein Aufrufer kann Zugriff auf ein Dateiobjekt wie dirA/dirB/file haben, aber nicht über die Berechtigung zum Zugreifen auf den Inhalt der Verzeichnisse entlang des Pfads des Dateiobjekts (dirA und dirA/dirB).

Standardmäßig gewährt Windows allen Benutzern Traverse-Berechtigungen. Die Konstante "Benutzerrecht" ist SeChangeNotifyPrivilege, die FILE_TRAVERSE in einem ACCESS_MASK zugeordnet ist. Als Sicherheitsfeature können Systemadministratoren einem Benutzer die Traverse-Berechtigung entfernen.

Da die meisten Aufrufer über Traverse-Berechtigungen verfügen, besteht eine der ersten Überprüfungen, die das Dateisystem normalerweise durchführt, darin, diese Berechtigung im Feld AccessState-Flags> des Sicherheitskontexts des IRP zu überprüfen:

    BOOLEAN traverseCheck = 
        !(IrpContext->IrpSp->Parameters.Create.SecurityContext->AccessState->Flags
            & TOKEN_HAS_TRAVERSE_PRIVILEGE);

Das Dateisystem verwendet Flags , um nachzuverfolgen, welche Zugriffsrechte im Verlauf eines Vorgangs gewährt wurden. Das Dateisystem kann dann einfach zuerst schnell die Zugriffsstatusbits überprüfen und die Kosten für einen Zugriffsüberprüfungsaufruf vermeiden, wenn der Zugriff bereits gewährt wurde (traverseCheck = 0).

Wenn zuvor noch keine Traverse-Berechtigung gewährt wurde, muss das Dateisystem eine Durchlaufüberprüfung für jedes Verzeichnis entlang des Pfads zur geöffneten Datei durchführen. Im folgenden Teilcodeausschnitt wird die Durchlaufüberprüfung mithilfe einer generischen Routine durchgeführt, die normalerweise für die meisten Sicherheitsüberprüfungen verwendet wird:


{
// accessParams is passed to the file system and is normally based
// on the fields of the same name from the IRP.

// Only one thread can be looking at this data structure in memory
// at a time (and potentially changing it), so acquire a lock on it.

    SeLockSubjectContext(
        &accessParams.AccessState->SubjectSecurityContext);

// Check whether the desired access can be granted.
// For this example, assume desiredAccess = FILE_TRAVERSE

    granted = SeAccessCheck( Fcb->SecurityDescriptor,
        &AccessParams.AccessState->SubjectSecurityContext,
        TRUE,
        AccessParams.desiredAccess,
        0,
        &Privileges,
        IoGetFileObjectGenericMapping(),
        AccessParams.AccessMode,
        &AccessParams.GrantedAccess,
        &AccessParams.status );

    // The file system uses AccessState to cache access privileges
    // that have been granted thus far along the operation's code
    // path. Update AccessState with the newly acquired Privileges.
    
    if (Privileges != NULL) {

        (void) SeAppendPrivileges(AccessParams.AccessState, Privileges );
        SeFreePrivileges( Privileges );
        Privileges = NULL;
    }

    if (granted) {
        //
        // The desired access was granted, so clear the
        // granted bits from desiredAccess. 
        //
        AccessParams.desiredAccess &= 
            ~(AccessParams.GrantedAccess | MAXIMUM_ALLOWED);
 
        if (!checkOnly) {
        //
        // The caller wants to modify the access state for this 
        // request
        //
            AccessParams.AccessState->PreviouslyGrantedAccess |= 
                AccessParams.GrantedAccess;
        }

        if (maxDesired) {

            maxDelete = 
                (BOOLEAN)(AccessParams.AccessState->PreviouslyGrantedAccess & 
                    DELETE);
            maxReadAttr = 
                (BOOLEAN)(AccessParams.AccessState->PreviouslyGrantedAccess & 
                    FILE_READ_ATTRIBUTES);
        }
        AccessParams.AccessState->RemainingDesiredAccess &= 
            ~(AccessParams.GrantedAccess | MAXIMUM_ALLOWED);
    }

    // Release the lock on the security context
    SeUnlockSubjectContext(&accessParams.AccessState->SubjectSecurityContext);  
}

Diese Funktion führt eine generische Sicherheitsüberprüfung durch. Diese Funktion muss dabei die folgenden Probleme behandeln:

  • Es muss den richtigen Sicherheitsdeskriptor angeben, der für die Überprüfung verwendet werden soll.

  • Es muss den Sicherheitskontext übergeben (dies sind die Anmeldeinformationen der Entität, die den Vorgang ausführt).

  • Sie muss den Zugriffsstatus basierend auf den Ergebnissen der Sicherheitsüberprüfung aktualisieren.

  • Die Option MAXIMUM_ALLOWED muss berücksichtigt werden (siehe ntifs.h). Die Option MAXIMUM_ALLOWED gibt an, dass das Dateisystem den Zugriff auf den maximal möglichen Zugriff des Dateisystems festlegen soll (z. B. Lese-/Schreibzugriff/Löschen). Nur sehr wenige Anwendungen verwenden die Option MAXIMUM_ALLOWED, da diese Option im FASTFAT-Dateisystem nicht unterstützt wird. Da das MAXIMUM_ALLOWED Optionsbits keine der Zugriffsbits ist, die das FASTFAT-Dateisystem erkennt, lehnt es Zugriffsanforderungen für die angegebene Datei ab. Eine Anwendung, die versucht, eine Datei auf einem FASTFAT-Volume mit der option MAXIMUM_ALLOWED zu öffnen, stellt fest, dass die Anforderung fehlschlägt. Ausführliche Informationen finden Sie unter der FatCheckFileAccess-Funktion in der Acchksup.c-Quelldatei des FASTFAT-Beispielcodes, den das WDK enthält.

Beachten Sie, dass für eine einfache Durchlaufüberprüfung der angeforderte Zugriff FILE_TRAVERSE und der Sicherheitsdeskriptor der des Verzeichnisses ist, durch das der Aufrufer zu durchlaufen versucht, und nicht der angeforderte Zugriff aus dem ursprünglichen IRP_MJ_CREATE IRP.