Creazione di driver reliable Kernel-Mode
I driver costituiscono una percentuale significativa del codice totale eseguito in modalità kernel. Un driver in modalità kernel è, in effetti, un componente del sistema operativo. Pertanto, i driver affidabili e sicuri contribuiscono in modo significativo alla attendibilità complessiva del sistema operativo. Per creare un driver in modalità kernel affidabile, seguire queste linee guida:
Proteggere correttamente gli oggetti dispositivo.
L'accesso utente ai driver e ai dispositivi di un sistema è controllato dai descrittori di sicurezza assegnati dal sistema agli oggetti dispositivo. Nella maggior parte dei casi, il sistema imposta i parametri di sicurezza del dispositivo quando viene installato un dispositivo. Per altre informazioni, vedere Creazione di installazioni di dispositivi protetti. A volte è opportuno che un driver giochi un ruolo nel controllare l'accesso al dispositivo. Per altre informazioni, vedere Protezione degli oggetti dispositivo.
Convalidare correttamente gli oggetti dispositivo.
Se un driver crea più tipi di oggetti dispositivo, deve verificare quale tipo riceve in ogni IRP. Per altre informazioni, vedere Errore di convalida degli oggetti dispositivo.
Usare le funzioni "safe string".
Quando si modificano stringhe, un driver deve usare funzioni stringa sicure anziché le funzioni stringa fornite con librerie di runtime del linguaggio C/C++. Per altre informazioni, vedere Uso di funzioni stringa sicure.
Convalidare gli handle di oggetto.
I driver che ricevono handle di oggetto come input devono verificare che gli handle siano validi, siano accessibili e siano del tipo previsto. Per altre informazioni sull'uso degli handle di oggetti, vedere gli argomenti seguenti:
Supportare correttamente i multiprocessori.
Non presupporre mai che il driver venga eseguito solo nei sistemi a processore singolo. Per informazioni sulle tecniche di programmazione che è possibile usare per assicurarsi che il driver funzioni correttamente nei sistemi multiprocessore, vedere gli argomenti seguenti:
Gestire correttamente lo stato del driver.
È importante verificare sempre che il driver sia nello stato in cui si presuppone che si trovi. Ad esempio, se il driver riceve un IRP, è già in corso la manutenzione di un IRP dello stesso tipo? Se il conducente non verifica questa situazione, il primo IRP potrebbe andare perso. Per altre informazioni, vedere Errore di controllo dello stato di un driver.
Convalidare i valori di input IRP.
È essenziale, sia dal punto di vista dell'affidabilità che della sicurezza, convalidare tutti i valori associati a un IRP, ad esempio indirizzi e lunghezze del buffer. Negli argomenti seguenti vengono fornite informazioni sulla convalida dei valori di input IRP:
DispatchReadWrite con I/O memorizzato nel buffer
Errori nell'I/O memorizzato nel buffer
DispatchReadWrite con I/O diretto
Gestire correttamente lo stack di I/O.
Quando si passano i runtime di integrazione nello stack di driver, è importante che i driver chiamino IoSkipCurrentIrpStackLocation o IoCopyCurrentIrpStackLocationToNext per configurare la posizione dello stack di I/O del driver successivo. Non scrivere codice che copia direttamente una posizione dello stack di I/O alla successiva.
Gestire correttamente le operazioni di completamento di IRP.
Un driver non deve mai completare un IRP con un valore di stato di STATUS_SUCCESS a meno che non supporti e non elabori effettivamente l'IRP. Per informazioni sui modi corretti per gestire le operazioni di completamento di IRP, vedere Completamento dei runtime di integrazione.
Gestire correttamente le operazioni di annullamento di IRP.
Le operazioni di annullamento possono essere difficili da scrivere correttamente perché in genere vengono eseguite in modo asincrono. I problemi nel codice che gestisce le operazioni di annullamento possono passare inosservati per molto tempo, perché questo codice in genere non viene eseguito frequentemente in un sistema in esecuzione.
Assicurarsi di leggere e comprendere tutte le informazioni fornite in Annullamento dei runtime di integrazione. Prestare particolare attenzione alla sincronizzazione dell'annullamento di IRP e dei punti da considerare durante l'annullamento dei runtime di integrazione.
Un modo per evitare i problemi di sincronizzazione associati alle operazioni di annullamento consiste nell'implementare una coda IRP sicura per l'annullamento. Una coda IRP annullata è una coda gestita da driver introdotta per Windows XP e versioni successive del sistema operativo, ma è anche compatibile con le versioni precedenti.
Gestire correttamente le operazioni di pulizia e chiusura di IRP.
Assicurarsi di comprendere la differenza tra IRP_MJ_CLEANUP e IRP_MJ_CLOSE richieste. Le richieste di pulizia arrivano dopo che un'applicazione chiude tutti gli handle in un oggetto file, ma a volte prima che tutte le richieste di I/O siano state completate. Le richieste di chiusura arrivano dopo il completamento o l'annullamento di tutte le richieste di I/O per l'oggetto file. Per altre informazioni, vedere gli argomenti seguenti:
Routine DispatchCreate, DispatchClose e DispatchCreateClose
Errori nella gestione delle operazioni di pulizia e chiusura
Per altre informazioni sulla gestione corretta dei runtime di integrazione, vedere Errori aggiuntivi nella gestione dei runtime di integrazione.
Uso di Driver Verifier
Driver Verifier è lo strumento più importante che è possibile usare per garantire l'affidabilità del driver. Driver Verifier può verificare la presenza di una serie di problemi comuni relativi ai driver, tra cui alcuni di quelli descritti in questa sezione. Tuttavia, l'uso di Driver Verifier non sostituisce la progettazione attenta e ponderata del software.