Creare l'elaborazione
Per un file system, la maggior parte delle operazioni di sicurezza interessanti si verifica durante l'elaborazione IRP_MJ_CREATE . Si tratta di questo passaggio che deve analizzare la richiesta in ingresso, determinare se il chiamante dispone dei diritti appropriati per eseguire l'operazione e concedere o negare l'operazione in base alle esigenze. Fortunatamente, per gli sviluppatori di file system, la maggior parte del meccanismo decisionale viene implementata all'interno di Security Reference Monitor. Pertanto, nella maggior parte dei casi, il file system deve chiamare solo le routine di Monitoraggio riferimenti di sicurezza appropriate per determinare correttamente l'accesso. Il rischio per un file system si verifica quando non riesce a chiamare queste routine in base alle esigenze e concede in modo inappropriato l'accesso a un chiamante.
Per un file system standard, ad esempio il file system FAT, i controlli effettuati come parte di IRP_MJ_CREATE sono principalmente controlli semantici. Ad esempio, il file system FAT dispone di numerosi controlli per garantire che l'elaborazione IRP_MJ_CREATE sia consentita in base allo stato del file o della directory. Questi controlli eseguiti dal file system FAT includono controlli per i supporti di sola lettura (ad esempio, tentativi di eseguire operazioni distruttive di "creazione", ad esempio sovrascrittura o sostituzione, nei supporti di sola lettura non sono consentiti), controlli di accesso di condivisione e controlli di oplock. Una delle parti più difficili di questa analisi consiste nel rendersi conto che un'operazione a un livello (ad esempio a livello di file) può essere disallowed a causa dello stato di una risorsa a livello diverso (ad esempio, il livello del volume). Ad esempio, un file potrebbe non essere aperto se un altro processo ha bloccato esclusivamente il volume. I casi comuni da controllare includono:
Il livello di file è compatibile con lo stato del livello del volume? Il blocco a livello di volume deve essere rispettato. Pertanto, se un processo contiene un blocco a livello di volume esclusivo, solo i thread all'interno di tale processo possono aprire i file. I thread di altri processi non devono essere autorizzati ad aprire file.
Il livello di file è aperto compatibile con lo stato del supporto? Alcune operazioni di "creazione" modificano il file come parte dell'operazione "create". Ciò include la sovrascrittura, la sostituzione e anche l'aggiornamento dell'ora dell'ultimo accesso nel file. Queste operazioni di creazione non sono consentite nei supporti di sola lettura e l'ora dell'ultimo accesso non viene aggiornata.
Il livello del volume è compatibile con lo stato a livello di file? Un volume esclusivo aperto non è consentito se sono presenti file aperti nel volume. Si tratta di un problema comune per i nuovi sviluppatori perché tentano di aprire il volume e riscontrano un errore. In caso di errore, è possibile utilizzare FSCTL_DISMOUNT_VOLUME per invalidare gli handle aperti e forzare un smontaggio, consentendo l'accesso esclusivo al volume appena montato.
Inoltre, gli attributi di file devono essere compatibili. Impossibile aprire un file con l'attributo di sola lettura per l'accesso in scrittura. Si noti che l'accesso desiderato deve essere controllato dopo l'espansione dei diritti generici. Ad esempio, questo controllo all'interno del file system FASTFAT si trova nella funzione FatCheckFileAccess (vedere il file di origine Acchksup.c dagli esempi fastfat contenuti in WDK).
L'esempio di codice seguente è specifico della semantica FAT. Un file system che implementa anche daCLs, esegue un controllo di sicurezza aggiuntivo usando le routine Di monitoraggio dei riferimenti di sicurezza (ad esempio, SeAccessCheck).
//
// check for a read-only Dirent
//
if (FlagOn(DirentAttributes, FAT_DIRENT_ATTR_READ_ONLY)) {
//
// Check the desired access for a read-only Dirent
// Don't allow
// WRITE, FILE_APPEND_DATA, FILE_ADD_FILE,
// FILE_ADD_SUBDIRECTORY, and FILE_DELETE_CHILD
//
if (FlagOn(*DesiredAccess, ~(DELETE |
READ_CONTROL |
WRITE_OWNER |
WRITE_DAC |
SYNCHRONIZE |
ACCESS_SYSTEM_SECURITY |
FILE_READ_DATA |
FILE_READ_EA |
FILE_WRITE_EA |
FILE_READ_ATTRIBUTES |
FILE_WRITE_ATTRIBUTES |
FILE_EXECUTE |
FILE_LIST_DIRECTORY |
FILE_TRAVERSE))) {
DebugTrace(0, Dbg, "Cannot open readonly\n", 0);
try_return( Result = FALSE );
}
Un controllo più sottile implementato da FASTFAT consiste nel garantire che l'accesso richiesto dal chiamante sia un elemento sul quale il file system FAT è a conoscenza (nella funzione FatCheckFileAccess in Acchksup.c dall'esempio fastfat contenuto in WDK):
Nell'esempio di codice seguente viene illustrato un concetto importante per la sicurezza del file system. Verificare che ciò che viene passato al file system non rientra nei limiti previsti. L'approccio conservativo e appropriato dal punto di vista della sicurezza è che, se non si comprende una richiesta di accesso, è necessario rifiutare tale richiesta.
//
// Check the desired access for the object.
// Reject what we do not understand.
// The model of file systems using ACLs is that
// they do not type the ACL to the object that the
// ACL is on.
// Permissions are not checked for consistency vs.
// the object type - dir/file.
//
if (FlagOn(*DesiredAccess, ~(DELETE |
READ_CONTROL |
WRITE_OWNER |
WRITE_DAC |
SYNCHRONIZE |
ACCESS_SYSTEM_SECURITY |
FILE_WRITE_DATA |
FILE_READ_EA |
FILE_WRITE_EA |
FILE_READ_ATTRIBUTES |
FILE_WRITE_ATTRIBUTES |
FILE_LIST_DIRECTORY |
FILE_TRAVERSE |
FILE_DELETE_CHILD |
FILE_APPEND_DATA))) {
DebugTrace(0, Dbg, "Cannot open object\n", 0);
try_return( Result = FALSE );
}
Fortunatamente per i file system, dopo aver eseguito il controllo di sicurezza durante l'elaborazione iniziale della creazione, i controlli di sicurezza successivi vengono eseguiti dal gestore di I/O. Ad esempio, il gestore di I/O garantisce che le applicazioni in modalità utente non eseguano un'operazione di scrittura su un file aperto solo per l'accesso in lettura. Infatti, un file system non deve tentare di applicare la semantica di sola lettura all'oggetto file, anche se è stata aperta solo per l'accesso in lettura, durante la routine dispatch di IRP_MJ_WRITE. Ciò è dovuto al modo in cui gestione memoria associa un oggetto file specifico a un oggetto sezione specificato. La scrittura successiva tramite tale sezione verrà inviata come IRP_MJ_WRITE operazioni sull'oggetto file, anche se il file è stato aperto in sola lettura. In altre parole, l'imposizione dell'accesso viene eseguita quando un handle di file viene convertito nell'oggetto file corrispondente nei punti di ingresso del servizio di sistema Nt da ObReferenceObjectByHandle.
Esistono due posizioni aggiuntive all'interno di un file system in cui i controlli di sicurezza semantica devono essere eseguiti in modo simile all'elaborazione "create":
Durante l'elaborazione di ridenominazione o collegamento rigido.
Durante l'elaborazione delle operazioni di controllo del file system.
La ridenominazione dell'elaborazione e dell'elaborazione dei controlli del file system viene illustrata nelle sezioni successive.
Si noti che non si tratta di un elenco completo di problemi semantici correlati all'elaborazione di "creazione". L'intento di questa sezione è attirare l'attenzione su questi problemi per gli sviluppatori di file system. Tutti i problemi semantici devono essere identificati per un file system specifico, implementati per soddisfare la semantica specifica e testati per garantire che l'implementazione gestisca i vari casi.