Partager via


Traitement du contrôle du système de fichiers

La gestion de l’opération IRP_MJ_FILE_SYSTEM_CONTROL est différente de la gestion de la mémoire tampon de données requise par d’autres opérations au sein du système de fichiers. En effet, chaque opération établit son mécanisme de transfert de données spécifique pour le gestionnaire d’E/S dans le cadre de son code de contrôle au moyen de la macro CTL_CODE. En outre, le code de contrôle spécifie l’accès au fichier requis par l’appelant. Un système de fichiers doit être particulièrement conscient de ce problème lors de la définition du code de contrôle, car cet accès est appliqué par le gestionnaire d’E/S. Certains codes de contrôle d’E/S (FSCTL_MOVE_FILE , par exemple) spécifient FILE_SPECIAL_ACCESS, qui est un mécanisme permettant au système de fichiers d’indiquer que la sécurité de l’opération sera vérifiée directement par le système de fichiers. FILE_SPECIAL_ACCESS étant numériquement équivalent à FILE_ANY_ACCESS, le gestionnaire d’E/S ne fournit pas de vérifications de sécurité spécifiques, s’en reportant au système de fichiers. FILE_SPECIAL_ACCESS fournit principalement la documentation indiquant que des vérifications supplémentaires seront effectuées par le système de fichiers.

Plusieurs opérations de système de fichiers spécifient FILE_SPECIAL_ACCESS. L’opération FSCTL_MOVE_FILE est utilisée dans le cadre de l’interface de défragmentation pour les systèmes de fichiers et spécifie FILE_SPECIAL_ACCESS. Étant donné que vous souhaitez pouvoir défragmenter les fichiers ouverts qui sont activement en cours de lecture et d’écriture, le handle à utiliser n’a qu’FILE_READ_ATTRIBUTES accordé l’accès pour éviter les conflits d’accès de partage. Toutefois, cette opération doit être une opération privilégiée, car le disque est en cours de modification à un niveau faible. La solution consiste à vérifier que le handle utilisé pour émettre le FSCTL_MOVE_FILE est un volume utilisateur d’appareil de stockage direct (DASD) ouvert, qui est un handle privilégié. Le code système de fichiers FASTFAT qui garantit que cette opération est effectuée sur un volume utilisateur ouvert se trouve dans la fonction FatMoveFile (consultez le fichier source fsctrl.c de l’exemple fastfat que contient le WDK) :

    //
    //  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;
    }

La structure utilisée par l’opération FSCTL_MOVE_FILE spécifie le fichier en cours de déplacement :

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

Comme indiqué précédemment, le handle utilisé pour émettre le FSCTL_MOVE_FILE est une opération « ouverte » de l’ensemble du volume, tandis que l’opération s’applique en fait au handle de fichier spécifié dans la mémoire tampon d’entrée MOVE_FILE_DATA. Cela rend les vérifications de sécurité pour cette opération un peu complexes. Par exemple, cette interface doit convertir le handle de fichier en un objet de fichier qui représente le fichier en cours de déplacement. Cela nécessite une attention particulière de la part de n’importe quel pilote. FASTFAT effectue cette opération en utilisant ObReferenceObject de manière protégée dans la fonction FatMoveFile du fichier source fsctrl.c de l’exemple fastfat que contient le WDK :

    //
    //  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.
    //    //

Notez l’utilisation d’Irp-RequestorMode> pour vous assurer que si l’appelant est une application en mode utilisateur, le handle ne peut pas être un handle de noyau. L’accès requis est 0 afin qu’un fichier puisse être déplacé pendant qu’il est activement accessible. Enfin, notez que cet appel doit être effectué dans le contexte de processus correct si l’appel provient du mode utilisateur. Le code source du système de fichiers FASTFAT l’applique également dans la fonction FatMoveFile dans 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 );

Ces vérifications sémantiques de sécurité effectuées par le système de fichiers FAT sont typiques de celles requises par un système de fichiers pour toute opération qui passe un handle. En outre, le système de fichiers FAT doit également effectuer des vérifications d’intégrité spécifiques à l’opération. Ces vérifications d’intégrité permettent de s’assurer que les paramètres disparates sont compatibles (le fichier en cours de déplacement se trouve sur le volume ouvert, par exemple) afin d’empêcher l’appelant d’effectuer une opération privilégiée alors qu’elle ne doit pas être autorisée.

Pour tout système de fichiers, une sécurité correcte est une partie essentielle des opérations de contrôle du système de fichiers, qui incluent :

  • Validation appropriée des handles utilisateur.

  • Protection de l’accès à la mémoire tampon utilisateur.

  • Validation de la sémantique de l’opération spécifique.

Dans de nombreux cas, le code nécessaire pour effectuer une validation et une sécurité appropriées peut constituer une partie substantielle du code au sein de la fonction donnée.