Elaborazione del controllo file system
La gestione dell'operazione di IRP_MJ_FILE_SYSTEM_CONTROL è diversa dalla gestione del buffer dei dati richiesta da altre operazioni all'interno del file system. Ciò avviene perché ogni operazione stabilisce il meccanismo di trasferimento dei dati specifico per la gestione I/O come parte del codice di controllo tramite la macro CTL_CODE. Inoltre, il codice di controllo specifica l'accesso al file richiesto dal chiamante. Un file system deve essere particolarmente consapevole di questo problema quando si definisce il codice di controllo, perché questo accesso viene applicato dalla gestione I/O. Alcuni codici di controllo I/O (FSCTL_MOVE_FILE , ad esempio) specificano FILE_SPECIAL_ACCESS, che è un meccanismo per consentire al file system di indicare che la sicurezza dell'operazione verrà controllata direttamente dal file system. FILE_SPECIAL_ACCESS è numericamente equivalente a FILE_ANY_ACCESS, quindi la gestione I/O non fornisce controlli di sicurezza specifici, rinviando invece al file system. FILE_SPECIAL_ACCESS fornisce principalmente la documentazione che verranno effettuati controlli aggiuntivi dal file system.
Diverse operazioni di file system specificano FILE_SPECIAL_ACCESS. L'operazione di FSCTL_MOVE_FILE viene usata come parte dell'interfaccia di deframmentazione per i file system e specifica FILE_SPECIAL_ACCESS. Poiché si vuole essere in grado di deframmentare i file aperti che sono attivamente in lettura e scrittura, l'handle da usare ha solo FILE_READ_ATTRIBUTES concesso l'accesso per evitare conflitti di accesso di condivisione. Tuttavia, questa operazione deve essere un'operazione con privilegi perché il disco viene modificato a basso livello. La soluzione consiste nel verificare che l'handle usato per emettere il FSCTL_MOVE_FILE sia un volume utente di archiviazione con accesso diretto (DASD), ovvero un handle con privilegi. Il codice del file system FASTFAT che garantisce che l'operazione venga eseguita rispetto a un volume utente aperto si trova nella funzione FatMoveFile (vedere il file sorgente fsctrl.c dall'esempio fastfat che il WDK contiene):
//
// 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 struttura utilizzata dall'operazione di FSCTL_MOVE_FILE specifica il file spostato:
typedef struct {
HANDLE FileHandle;
LARGE_INTEGER StartingVcn;
LARGE_INTEGER StartingLcn;
ULONG ClusterCount;
} MOVE_FILE_DATA, *PMOVE_FILE_DATA;
Come indicato in precedenza, l'handle usato per emettere il FSCTL_MOVE_FILE è un'operazione "aperta" dell'intero volume, mentre l'operazione si applica effettivamente all'handle di file specificato nel buffer di input MOVE_FILE_DATA. Ciò rende i controlli di sicurezza per questa operazione leggermente complessi. Ad esempio, questa interfaccia deve convertire l'handle di file in un oggetto file che rappresenta il file spostato. Ciò richiede un'attenta considerazione sulla parte di qualsiasi driver. FASTFAT esegue questa operazione usando ObReferenceObject in modo sorvegliato nella funzione FatMoveFile nel file di origine fsctrl.c nell'esempio fastfat che il WDK contiene:
//
// 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.
// //
Si noti l'uso di Irp-RequestorMode> per assicurarsi che se il chiamante sia un'applicazione in modalità utente, l'handle non può essere un handle kernel. L'accesso richiesto è 0 in modo che un file possa essere spostato mentre è in corso l'accesso attivo. Si noti infine che questa chiamata deve essere effettuata nel contesto del processo corretto se la chiamata è stata generata in modalità utente. Il codice sorgente del file system FASTFAT applica questo codice anche nella funzione FatMoveFile 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 );
Questi controlli di sicurezza semantica eseguiti dal file system FAT sono tipici di quelli richiesti da un file system per qualsiasi operazione che passa un handle. Inoltre, il file system FAT deve eseguire controlli di integrità specifici dell'operazione. Questi controlli di integrità sono per assicurarsi che i parametri diversi siano compatibili (il file spostato è nel volume aperto, ad esempio) per impedire al chiamante di eseguire un'operazione con privilegi quando non deve essere consentito.
Per qualsiasi file system, la sicurezza corretta è una parte essenziale delle operazioni di controllo del file system, che includono:
Convalida degli handle utente in modo appropriato.
Protezione dell'accesso al buffer utente.
Convalida della semantica dell'operazione specifica.
In molti casi, il codice necessario per eseguire la convalida e la sicurezza appropriate possono costituire una parte sostanziale del codice all'interno della funzione specificata.