Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Controlar la operación de IRP_MJ_FILE_SYSTEM_CONTROL es diferente del control del búfer de datos requerido por otras operaciones del sistema de archivos. Esto se debe a que cada operación establece su mecanismo de transferencia de datos específico para el administrador de E/S como parte de su código de control mediante la macro CTL_CODE. Además, el código de control especifica el acceso al archivo requerido por el autor de la llamada. Un sistema de archivos debe ser especialmente consciente de este problema al definir el código de control, ya que el administrador de E/S aplica este acceso. Algunos códigos de control de E/S (FSCTL_MOVE_FILE , por ejemplo) especifican FILE_SPECIAL_ACCESS, que es un mecanismo para permitir que el sistema de archivos indique que el sistema de archivos comprobará directamente la seguridad de la operación. FILE_SPECIAL_ACCESS es numéricamente equivalente a FILE_ANY_ACCESS, por lo que el administrador de E/S no proporciona ninguna comprobación de seguridad específica, aplazando en su lugar al sistema de archivos. FILE_SPECIAL_ACCESS proporciona principalmente documentación que el sistema de archivos realizará comprobaciones adicionales.
Varias operaciones del sistema de archivos especifican FILE_SPECIAL_ACCESS. La operación de FSCTL_MOVE_FILE se usa como parte de la interfaz de desfragmentación para los sistemas de archivos y especifica FILE_SPECIAL_ACCESS. Puesto que desea poder desfragmentar archivos abiertos que se están leyendo y escribiendo activamente, el identificador que se va a usar solo tiene FILE_READ_ATTRIBUTES acceso concedido para evitar conflictos de acceso compartido. Sin embargo, esta operación debe ser una operación con privilegios, ya que el disco se está modificando en un nivel bajo. La solución consiste en comprobar que el identificador usado para emitir el FSCTL_MOVE_FILE es un volumen de usuario del dispositivo de almacenamiento de acceso directo (DASD), que es un identificador con privilegios. El código del sistema de archivos FASTFAT que garantiza que esta operación se realiza en un volumen de usuario abierto está en la función FatMoveFile (consulte el archivo de código fuente fsctrl.c del ejemplo fastfat que contiene el 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 estructura utilizada por la operación de FSCTL_MOVE_FILE especifica el archivo que se va a mover:
typedef struct {
HANDLE FileHandle;
LARGE_INTEGER StartingVcn;
LARGE_INTEGER StartingLcn;
ULONG ClusterCount;
} MOVE_FILE_DATA, *PMOVE_FILE_DATA;
Como se indicó anteriormente, el identificador usado para emitir el FSCTL_MOVE_FILE es una operación "abierta" de todo el volumen, mientras que la operación se aplica realmente al identificador de archivo especificado en el búfer de entrada de MOVE_FILE_DATA. Esto hace que las comprobaciones de seguridad de esta operación sea algo compleja. Por ejemplo, esta interfaz debe convertir el identificador de archivo en un objeto de archivo que representa el archivo que se va a mover. Esto requiere una consideración cuidadosa sobre la parte de cualquier controlador. FASTFAT hace esto con ObReferenceObject de forma protegida en la función FatMoveFile en el archivo de origen fsctrl.c en la muestra fastfat que contiene el 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.
// //
Tenga en cuenta el uso de Irp-RequestorMode> para asegurarse de que si el autor de la llamada es una aplicación en modo de usuario, el identificador no puede ser un identificador de kernel. El acceso necesario es 0 para que se pueda mover un archivo mientras se accede activamente. Y, por último, tenga en cuenta que esta llamada debe realizarse en el contexto de proceso correcto si la llamada se originó en modo de usuario. El código fuente del sistema de archivos FASTFAT también aplica esto en la función FatMoveFile en 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 );
Estas comprobaciones de seguridad semánticas realizadas por el sistema de archivos FAT son típicas de las requeridas por un sistema de archivos para cualquier operación que pase un identificador. Además, el sistema de archivos FAT también debe realizar comprobaciones de integridad específicas de la operación. Estas comprobaciones de integridad son para asegurarse de que los parámetros dispares son compatibles (el archivo que se mueve está en el volumen que se abrió, por ejemplo) para evitar que el autor de la llamada realice una operación con privilegios cuando no se debe permitir.
Para cualquier sistema de archivos, la seguridad correcta es una parte esencial de las operaciones de control del sistema de archivos, que incluyen:
Validar los identificadores de usuario correctamente.
Protección del acceso al búfer de usuario.
Validación de la semántica de la operación específica.
En muchos casos, el código necesario para realizar una validación y seguridad adecuadas puede constituir una parte sustancial del código dentro de la función especificada.