Share via


Dateisystemsteuerungsverarbeitung

Die Behandlung des IRP_MJ_FILE_SYSTEM_CONTROL Vorgangs unterscheidet sich von der Datenpufferbehandlung, die für andere Vorgänge im Dateisystem erforderlich ist. Dies liegt daran, dass jeder Vorgang seinen spezifischen Datenübertragungsmechanismus für den E/A-Manager als Teil seines Steuerungscodes mithilfe des CTL_CODE Makros festlegt. Darüber hinaus gibt der Steuerungscode den Dateizugriff an, der vom Aufrufer benötigt wird. Ein Dateisystem sollte dieses Problem beim Definieren des Steuerungscodes besonders beachten, da dieser Zugriff vom E/A-Manager erzwungen wird. Einige E/A-Steuerungscodes (z. B. FSCTL_MOVE_FILE) geben FILE_SPECIAL_ACCESS an. Dies ist ein Mechanismus, mit dem das Dateisystem angeben kann, dass die Sicherheit des Vorgangs direkt vom Dateisystem überprüft wird. FILE_SPECIAL_ACCESS ist numerisch gleichwertig mit FILE_ANY_ACCESS, sodass der E/A-Manager keine spezifischen Sicherheitsüberprüfungen bereitstellt, sondern stattdessen auf das Dateisystem zurückgestellt wird. FILE_SPECIAL_ACCESS stellt hauptsächlich Dokumentation bereit, dass zusätzliche Überprüfungen vom Dateisystem vorgenommen werden.

Mehrere Dateisystemvorgänge geben FILE_SPECIAL_ACCESS an. Der FSCTL_MOVE_FILE-Vorgang wird als Teil der Defragmentierungsschnittstelle für Dateisysteme verwendet und gibt FILE_SPECIAL_ACCESS an. Da Sie in der Lage sein möchten, geöffnete Dateien zu defragmentieren, die aktiv gelesen und geschrieben werden, hat das zu verwendende Handle nur FILE_READ_ATTRIBUTES Zugriff gewährt, um Freigabezugriffskonflikte zu vermeiden. Dieser Vorgang muss jedoch ein privilegierter Vorgang sein, da der Datenträger auf niedriger Ebene geändert wird. Die Lösung besteht darin, zu überprüfen, ob das Zum Ausgeben der FSCTL_MOVE_FILE verwendete Handle ein geöffnetes DASD-Benutzervolume (Direct Access Storage Device) ist, bei dem es sich um ein privilegiertes Handle handelt. Der FASTFAT-Dateisystemcode, der sicherstellt, dass dieser Vorgang für ein geöffnetes Benutzervolume ausgeführt wird, befindet sich in der FatMoveFile-Funktion (siehe die Quelldatei fsctrl.c aus dem fastfat-Beispiel, das das WDK enthält):

    //
    //  extract and decode the file object and check for type of open
    //

    if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &FcbOrDcb, &Ccb ) != UserVolumeOpen) {

        FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );

        DebugTrace(-1, Dbg, "FatMoveFile -> %08lx\n", STATUS_INVALID_PARAMETER);
        return STATUS_INVALID_PARAMETER;
    }

Die vom FSCTL_MOVE_FILE-Vorgang verwendete Struktur gibt die zu verschiebende Datei an:

typedef struct {
    HANDLE FileHandle;
    LARGE_INTEGER StartingVcn;
    LARGE_INTEGER StartingLcn;
    ULONG ClusterCount;
} MOVE_FILE_DATA, *PMOVE_FILE_DATA;

Wie bereits erwähnt, ist das Zum Ausgeben der FSCTL_MOVE_FILE verwendete Handle ein "open"-Vorgang des gesamten Volumes, während der Vorgang tatsächlich auf das Dateihandle angewendet wird, das im MOVE_FILE_DATA Eingabepuffer angegeben ist. Dies macht die Sicherheitsüberprüfungen für diesen Vorgang etwas komplex. Diese Schnittstelle muss beispielsweise das Dateihandle in ein Dateiobjekt konvertieren, das die zu verschiebende Datei darstellt. Dies erfordert eine sorgfältige Abwägung durch jeden Fahrer. FASTFAT führt dies mithilfe von ObReferenceObject in einer geschützten Weise in der FatMoveFile-Funktion in der Quelldatei fsctrl.c im fastfat-Beispiel aus, das das WDK enthält:

    //
    //  Try to get a pointer to the file object from the handle passed in.
    //

    Status = ObReferenceObjectByHandle( InputBuffer->FileHandle,
                                        0,
                                        *IoFileObjectType,
                                        Irp->RequestorMode,
                                        &FileObject,
                                        NULL );

    if (!NT_SUCCESS(Status)) {

        FatCompleteRequest( IrpContext, Irp, Status );

        DebugTrace(-1, Dbg, "FatMoveFile -> %08lx\n", Status);
        return Status;
    }
    //  Complete the following steps to ensure that this is not an invalid attempt
    //
    //    - check that the file object is opened on the same volume as the
    //      DASD handle used to call this routine.
    //
    //    - extract and decode the file object and check for type of open.
    //
    //    - if this is a directory, verify that it's not the root and that
    //      you are not trying to move the first cluster.  You cannot move the
    //      first cluster because sub-directories have this cluster number
    //      in them and there is no safe way to simultaneously update them
    //      all.
    //
    //  Allow movefile on the root directory if it's FAT32, since the root dir
    //  is a real chained file.
    //    //

Beachten Sie die Verwendung von Irp-RequestorMode>, um sicherzustellen, dass das Handle kein Kernelhandle sein kann, wenn es sich bei dem Aufrufer um eine Anwendung im Benutzermodus handelt. Der erforderliche Zugriff ist 0, sodass eine Datei verschoben werden kann, während aktiv darauf zugegriffen wird. Beachten Sie schließlich, dass dieser Aufruf im richtigen Prozesskontext erfolgen muss, wenn der Aufruf aus dem Benutzermodus stammt. Der Quellcode aus dem FASTFAT-Dateisystem erzwingt dies auch in der FatMoveFile-Funktion in fsctrl.c:

    //
    //  Force WAIT to true. There is a handle in the input buffer that can only
    //  be referenced within the originating process.
    //

    SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );

Diese semantischen Sicherheitsüberprüfungen, die vom FAT-Dateisystem durchgeführt werden, sind typisch für die, die von einem Dateisystem für jeden Vorgang benötigt werden, der ein Handle übergibt. Darüber hinaus muss das FAT-Dateisystem auch integritätsspezifische Überprüfungen durchführen, die für den Vorgang spezifisch sind. Diese Integritätsüberprüfungen sollen sicherstellen, dass die unterschiedlichen Parameter kompatibel sind (die zu verschiebende Datei befindet sich z. B. auf dem geöffneten Volume), um zu verhindern, dass der Aufrufer einen privilegierten Vorgang ausführt, wenn er nicht zulässig sein sollte.

Für jedes Dateisystem ist die richtige Sicherheit ein wesentlicher Bestandteil von Dateisystemsteuerungsvorgängen, darunter:

  • Überprüfen von Benutzerhandles entsprechend.

  • Schützen des Benutzerpufferzugriffs.

  • Überprüfen der Semantik des spezifischen Vorgangs.

In vielen Fällen kann der Code, der für eine ordnungsgemäße Validierung und Sicherheit erforderlich ist, einen wesentlichen Teil des Codes innerhalb der angegebenen Funktion ausmachen.