Elenco di controllo per la sicurezza dei driver
Questo articolo fornisce un elenco di controllo per la sicurezza dei driver che consente agli sviluppatori di driver di ridurre il rischio di compromissione dei driver.
Panoramica della sicurezza dei driver
Un difetto di sicurezza è qualsiasi difetto che consente a un utente malintenzionato di causare un malfunzionamento di un driver in modo tale che causa l'arresto anomalo del sistema o diventa inutilizzabile. Inoltre, le vulnerabilità nel codice del driver possono consentire a un utente malintenzionato di accedere al kernel, creando una possibilità di compromettere l'intero sistema operativo. Quando la maggior parte degli sviluppatori sta lavorando sul driver, il loro obiettivo è quello di far funzionare correttamente il driver e non sul fatto che un utente malintenzionato tenti di sfruttare le vulnerabilità all'interno del codice.
Dopo il rilascio di un driver, tuttavia, gli utenti malintenzionati possono tentare di eseguire il probe e identificare i difetti di sicurezza. Gli sviluppatori devono considerare questi problemi durante la fase di progettazione e implementazione per ridurre al minimo la probabilità di tali vulnerabilità. L'obiettivo è eliminare tutti i difetti di sicurezza noti prima del rilascio del driver.
La creazione di driver più sicuri richiede la collaborazione dell'architetto di sistema (pensando coscientemente alle potenziali minacce al driver), lo sviluppatore implementa il codice (codificando in modo difensivo le operazioni comuni che possono essere l'origine degli exploit) e il team di test (cercando in modo proattivo di individuare debolezze e vulnerabilità). Coordinando correttamente tutte queste attività, la sicurezza del conducente è notevolmente migliorata.
Oltre a evitare i problemi associati a un driver attaccato, molti dei passaggi descritti, ad esempio l'uso più preciso della memoria kernel, aumenteranno l'affidabilità del driver. Ciò ridurrà i costi di supporto e aumenterà la soddisfazione dei clienti con il prodotto. Il completamento delle attività nell'elenco di controllo seguente consentirà di raggiungere tutti questi obiettivi.
Elenco di controllo per la sicurezza: completare l'attività di sicurezza descritta in ognuno di questi argomenti.
Verificare che sia necessario un driver kernel
Controllare l'accesso solo ai driver software
Non firmare il codice del driver di test di produzione
Eseguire l'analisi delle minacce
Seguire le linee guida per la codifica sicura dei driver
Implementare codice compatibile con HVCI
Seguire le procedure consigliate per il codice specifico della tecnologia
Eseguire la revisione del codice peer
Gestire il controllo di accesso dei driver
Migliorare la sicurezza dell'installazione dei dispositivi
Eseguire la firma corretta del driver di versione
Usare CodeQL per controllare il codice del driver
Aggiungere annotazioni SAL al codice driver
Usare Driver Verifier per verificare la presenza di vulnerabilità
Controllare il codice con BinSkim Binary Analyzer
Controllare il codice con i test del programma di compatibilità hardware
Esaminare le tecniche e le estensioni del debugger
Esaminare le risorse di codifica sicura
Esaminare il riepilogo delle considerazioni chiave
Verificare che sia necessario un driver kernel
Elemento dell'elenco di controllo per la sicurezza n. 1: verificare che sia necessario un driver del kernel e che un approccio a rischio inferiore, ad esempio il servizio o l'app di Windows, non sia un'opzione migliore.
I driver si trovano nel kernel windows e si verificano problemi durante l'esecuzione nel kernel espongono l'intero sistema operativo. Se è disponibile un'altra opzione, è probabile che il costo sia inferiore e abbia meno rischi associati rispetto alla creazione di un nuovo driver del kernel. Per altre informazioni sull'uso dei driver windows predefiniti, vedere Scrivere un driver?
Per informazioni sull'uso delle attività in background, vedi Supportare l'app con le attività in background.
Per informazioni sull'uso dei servizi Windows, vedere Servizi.
Usare i framework driver
Elemento dell'elenco di controllo per la sicurezza n. 2: usare i framework driver per ridurre le dimensioni del codice e aumentarne l'affidabilità e la sicurezza.
Usare Windows Driver Framework per ridurre le dimensioni del codice e aumentarne l'affidabilità e la sicurezza. Per iniziare, vedere Uso di WDF per sviluppare un driver. Per informazioni sull'uso del driver framework in modalità utente a basso rischio (UMDF), vedere Scelta di un modello di driver.
La scrittura di un driver Windows Driver Model (WDM) di vecchia moda richiede più tempo, costoso e quasi sempre comporta la ricreazione del codice disponibile nei framework driver.
Il codice sorgente di Windows Driver Framework è open source e disponibile in GitHub. Si tratta dello stesso codice sorgente da cui viene compilata la libreria di runtime WDF fornita in Windows 10. È possibile eseguire il debug del driver in modo più efficace quando è possibile seguire le interazioni tra il driver e WDF. Scaricarlo da https://github.com/Microsoft/Windows-Driver-Frameworks.
Controllare l'accesso solo ai driver software
Elemento dell'elenco di controllo di sicurezza n. 3: se verrà creato un driver solo software, è necessario implementare un controllo di accesso aggiuntivo.
I driver del kernel solo software non usano plug-and-play (PnP) per diventare associati a ID hardware specifici e possono essere eseguiti in qualsiasi PC. Tale driver può essere usato per scopi diversi da quello originariamente previsto, creando un vettore di attacco.
Poiché i driver del kernel solo software contengono rischi aggiuntivi, devono essere limitati all'esecuzione su hardware specifico (ad esempio, usando un ID PnP univoco per abilitare la creazione di un driver PnP o controllando la tabella SMBIOS per la presenza di hardware specifico).
Si supponga, ad esempio, che OEM Fabrikam voglia distribuire un driver che consenta un'utilità di overclocking per i propri sistemi. Se questo driver solo software dovesse essere eseguito in un sistema da un OEM diverso, l'instabilità o il danno del sistema potrebbero causare danni. I sistemi di Fabrikam devono includere un ID PnP univoco per abilitare la creazione di un driver PnP aggiornabile anche tramite Windows Update. Se non è possibile e Fabrikam crea un driver legacy, tale driver deve trovare un altro metodo per verificare che sia in esecuzione in un sistema Fabrikam, ad esempio esaminando la tabella SMBIOS prima di abilitare eventuali funzionalità.
Non firmare il codice di test di produzione
Elemento dell'elenco di controllo per la sicurezza n. 4: non firmare il codice di produzione, lo sviluppo, il test e il codice del driver del kernel di produzione.
Il codice del driver kernel usato per lo sviluppo, il test o la produzione può includere funzionalità pericolose che rappresentano un rischio per la sicurezza. Questo codice pericoloso non deve mai essere firmato con un certificato considerato attendibile da Windows. Il meccanismo corretto per l'esecuzione di codice driver pericoloso consiste nel disabilitare l'avvio protetto UEFI, abilitare il BCD "TESTSIGNING" e firmare il codice di sviluppo, test e produzione usando un certificato non attendibile (ad esempio, uno generato da makecert.exe).
Il codice firmato da un certificato SPC (Software Publishers Certificate) attendibile o da una firma WHQL (Hardware Quality Labs) windows non deve facilitare il bypass delle tecnologie di sicurezza e integrità del codice Windows. Prima che il codice sia firmato da una firma SPC o WHQL attendibile, verificare prima di tutto che sia conforme alle indicazioni fornite da Creazione di driver in modalità kernel affidabili. Inoltre, il codice non deve contenere comportamenti pericolosi, descritti di seguito. Per altre informazioni sulla firma del driver, vedere Firma del driver di versione più avanti in questo articolo.
Di seguito sono riportati alcuni esempi di comportamento pericoloso:
- Possibilità di eseguire il mapping di kernel arbitrario, memoria fisica o dispositivo alla modalità utente.
- Possibilità di leggere o scrivere kernel arbitrario, memoria fisica o del dispositivo, tra cui input/output della porta (I/O).
- Fornire l'accesso all'archiviazione che ignora il controllo di accesso di Windows.
- Possibilità di modificare hardware o firmware che il driver non è stato progettato per la gestione.
Eseguire l'analisi delle minacce
Elemento dell'elenco di controllo per la sicurezza n. 5: modificare un modello di minaccia driver esistente o creare un modello di minaccia personalizzato per il driver.
Nel considerare la sicurezza, una metodologia comune consiste nel creare modelli di minaccia specifici che tentano di descrivere i tipi di attacchi possibili. Questa tecnica è utile quando si progetta un driver perché impone allo sviluppatore di considerare in anticipo i potenziali vettori di attacco contro un driver. Dopo aver identificato potenziali minacce, uno sviluppatore di driver può quindi prendere in considerazione mezzi per difendersi da queste minacce per rafforzare la sicurezza complessiva del componente driver.
Questo articolo fornisce indicazioni specifiche per il driver per la creazione di un modello di minaccia leggero: modellazione delle minacce per i driver. L'articolo fornisce un diagramma del modello di minaccia del driver di esempio che può essere usato come punto di partenza per il driver.
Le procedure consigliate per il ciclo di vita di sviluppo della sicurezza (SDL) e gli strumenti associati possono essere usati da IHV e OEM per migliorare la sicurezza dei propri prodotti. Per altre informazioni, vedere Raccomandazioni SDL per gli OEM.
Seguire le linee guida per la codifica sicura dei driver
Elemento dell'elenco di controllo per la sicurezza n. 6: esaminare il codice e rimuovere eventuali vulnerabilità del codice note.
L'attività principale della creazione di driver sicuri consiste nell'identificare le aree nel codice che devono essere modificate per evitare vulnerabilità software note. Molte di queste vulnerabilità software note gestiscono un monitoraggio rigoroso dell'uso della memoria per evitare problemi con altri utenti sovrascrivendo o comprendendo in altro modo i percorsi di memoria usati dal driver.
Gli strumenti di analisi del codice, ad esempio CodeQL e test specifici del driver, possono essere usati per individuare, alcuni, ma non tutti, di queste vulnerabilità. Questi strumenti e test sono descritti più avanti in questo argomento.
Buffer di memoria
Controllare sempre le dimensioni dei buffer di input e di output per assicurarsi che i buffer possano contenere tutti i dati richiesti. Per altre informazioni, vedere Errore di controllo delle dimensioni dei buffer.
Inizializzare correttamente tutti i buffer di output con zeri prima di restituirli al chiamante. Per altre informazioni, vedere Errore di inizializzazione dei buffer di output.
Convalidare i buffer a lunghezza variabile. Per altre informazioni, vedere Errore di convalida dei buffer a lunghezza variabile. Per altre informazioni sull'uso dei buffer e sull'uso di ProbeForRead e ProbeForWrite per convalidare l'indirizzo di un buffer, vedere Gestione del buffer.
Usare il metodo appropriato per accedere ai buffer di dati con IOCTLs
Una delle principali responsabilità di un driver Di Windows consiste nel trasferire i dati tra applicazioni in modalità utente e i dispositivi di un sistema. I tre metodi per l'accesso ai buffer di dati sono illustrati nella tabella seguente.
Tipo di buffer IOCTL | Riepilogo | Ulteriori informazioni |
---|---|---|
METHOD_BUFFERED | Consigliato per la maggior parte delle situazioni | Uso dell'I/O memorizzato nel buffer |
METHOD_IN_DIRECT o METHOD_OUT_DIRECT | Usato in alcune operazioni di I/O HW ad alta velocità | Uso dell'I/O diretto |
METHOD_NEITHER | Evitare, se possibile, | Uso né di I/O diretto né memorizzato nel buffer |
In generale, l'I/O memorizzato nel buffer è consigliato perché fornisce i metodi di buffering più sicuri. Tuttavia, anche quando si usa l'I/O memorizzato nel buffer esistono rischi, ad esempio puntatori incorporati che devono essere mitigati.
Per altre informazioni sull'uso dei buffer in IOCTLs, vedere Metodi per l'accesso ai buffer dei dati.
Errori nell'uso di I/O memorizzati nel buffer I/O IOCTL
Controllare le dimensioni dei buffer correlati a IOCTL. Per altre informazioni, vedere Errore di controllo delle dimensioni dei buffer.
Inizializzare correttamente i buffer di output. Per altre informazioni, vedere Errore di inizializzazione dei buffer di output.
Convalidare correttamente i buffer a lunghezza variabile. Per altre informazioni, vedere Errore di convalida dei buffer a lunghezza variabile.
Quando si usa l'I/O memorizzato nel buffer, assicurarsi e restituire la lunghezza corretta per OutputBuffer nel campo Informazioni struttura IO_STATUS_BLOCK . Non restituire direttamente la lunghezza direttamente da una richiesta READ. Si consideri, ad esempio, una situazione in cui i dati restituiti dallo spazio utente indicano che è presente un buffer 4K. Se il driver deve restituire effettivamente solo 200 byte, ma restituisce invece solo 4K nel campo Informazioni si è verificata una vulnerabilità di divulgazione di informazioni. Questo problema si verifica perché nelle versioni precedenti di Windows il buffer usato da Gestione I/O per L/O memorizzato nel buffer non è zero. Di conseguenza, l'app utente recupera i 200 byte originali di dati più 4K-200 byte di qualsiasi elemento nel buffer (contenuto del pool non di paging). Questo scenario può verificarsi con tutti gli usi di I/O memorizzati nel buffer e non solo con IOCTLs.
Errori nell'I/O diretto I/O IOCTL
Gestire correttamente i buffer di lunghezza zero. Per altre informazioni, vedere Errori in I/O diretto.
Errori nel riferimento agli indirizzi dello spazio utente
Convalidare i puntatori incorporati nelle richieste di I/O memorizzate nel buffer. Per altre informazioni, vedere Errori in Riferimento agli indirizzi dello spazio utente.
Convalidare qualsiasi indirizzo nello spazio utente prima di provare a usarlo, usando API come ProbeForRead e ProbeForWrite quando appropriato.
Letture e scritture specifiche del modello MSR
Gli intrinseci del compilatore, ad esempio __readmsr e __writemsr , possono essere usati per accedere ai registri specifici del modello. Se questo accesso è necessario, il driver deve sempre verificare che il registro in lettura o scrittura in sia vincolato all'indice o all'intervallo previsto.
Per altre informazioni ed esempi di codice, vedere Fornire la possibilità di leggere/scrivere richieste msr nelle procedure consigliate per la sicurezza di sviluppo per sviluppatori di driver Windows.
Vulnerabilità TOCTOU
Esiste un potenziale tempo di verifica del tempo di utilizzo (TOCTOU) vulnerabilità quando si usa l'I/O diretto (per IOCTLs o per lettura/scrittura). Tenere presente che il driver accede al buffer dei dati utente, l'utente può accedervi contemporaneamente.
Per gestire questo rischio, copiare tutti i parametri che devono essere convalidati dal buffer dei dati utente alla memoria che è accessibile esclusivamente dalla modalità kernel, ad esempio lo stack o il pool. Dopo aver eseguito l'accesso ai dati dall'applicazione utente, convalidare e quindi operare sui dati passati.
Il codice del driver deve usare correttamente la memoria
Tutte le allocazioni del pool di driver devono trovarsi nel pool non eseguibile (NX). L'uso di pool di memoria NX è intrinsecamente più sicuro rispetto all'uso di pool eseguibili non di paging (NP) e offre una migliore protezione dagli attacchi di overflow.
I driver di dispositivo devono gestire correttamente varie modalità utente, nonché il kernel per l'I/O del kernel, le richieste.
Per consentire ai driver di supportare la virtualizzazione HVCI, sono previsti requisiti di memoria aggiuntivi. Per altre informazioni, vedere Implementare codice compatibile con HVCI più avanti in questo articolo.
Handle
- Convalidare gli handle passati tra la memoria in modalità utente e quella in modalità kernel. Per altre informazioni, vedere Gestire la gestione e l'errore di convalida degli handle di oggetti.
Oggetti dispositivo
Proteggere gli oggetti dispositivo. Per altre informazioni, vedere Protezione degli oggetti dispositivo.
Convalidare gli oggetti dispositivo. Per altre informazioni, vedere Errore di convalida degli oggetti dispositivo.
IRP
WDF e IRP
Un vantaggio dell'uso di WDF è che i driver WDF in genere non accedono direttamente ai runtime di integrazione. Ad esempio, il framework converte i runtime di integrazione WDM che rappresentano operazioni di lettura, scrittura e controllo I/O del dispositivo in oggetti richiesta framework che KMDF/UMDF ricevono nelle code di I/O.
Se si scrive un driver WDM, esaminare le indicazioni seguenti.
Gestire correttamente i buffer di I/O IRP
Gli articoli seguenti forniscono 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
Problemi di sicurezza per i codici di controllo di I/O
Valutare la possibilità di convalidare i valori associati a un IRP, ad esempio gli indirizzi e le lunghezze del buffer.
Se si sceglie di usare Nessuna delle due operazioni di I/O, tenere presente che a differenza di Lettura e scrittura e diversamente da I/O memorizzati nel buffer e I/O diretto, quando si usano I/O IOCTL i puntatori e le lunghezze del buffer non vengono convalidati da Gestione I/O.
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 di runtime di integrazione.
Gestire lo stato di IRP del driver in sospeso
Il driver deve contrassegnare l'IRP in sospeso prima di salvare l'IRP e deve prendere in considerazione la possibilità di includere sia la chiamata a IoMarkIrpPending che l'assegnazione in una sequenza interlocked. Per altre informazioni, vedere Errore di controllo dello stato di un driver e mantenimento degli IRP in ingresso quando un dispositivo viene sospeso.
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 andare inosservati per molto tempo, perché questo codice in genere non viene eseguito di frequente 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 consigliato per ridurre al minimo i problemi di sincronizzazione associati alle operazioni di annullamento consiste nell'implementare una coda IRP sicura per l'annullamento.
Gestire correttamente le operazioni di pulizia e chiusura di IRP
Assicurarsi di comprendere la differenza tra IRP_MJ_CLEANUP e richieste di IRP_MJ_CLOSE. 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 che tutte le richieste di I/O per l'oggetto file sono state completate o annullate. Per altre informazioni, vedere gli articoli 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.
Altri problemi di sicurezza
Usare un blocco o una sequenza interlocked per evitare condizioni di raceing. Per altre informazioni, vedere Errori in un ambiente multiprocessore.
Assicurarsi che i driver di dispositivo gestisca correttamente varie modalità utente e kernel per le richieste di I/O del kernel.
Assicurarsi che non siano installati filtri o LSP TDI dal driver o dai pacchetti software associati durante l'installazione o l'utilizzo.
Usare funzioni sicure
Usare funzioni stringa sicure. Per altre informazioni, vedere Uso di funzioni di stringa sicure.
Usare funzioni aritmetiche sicure. Per altre informazioni, vedere Routine della libreria integer sicura
Usare funzioni di conversione sicure.
Vulnerabilità del codice aggiuntive
Oltre alle possibili vulnerabilità descritte in questo articolo, questo articolo fornisce informazioni aggiuntive sul miglioramento della sicurezza del codice del driver in modalità kernel: Creazione di driver in modalità kernel affidabili.
Per altre informazioni sulla codifica sicura C e C++, vedere Proteggere le risorse di codifica alla fine di questo articolo.
Gestire il controllo di accesso dei driver
Elemento elenco di controllo per la sicurezza n. 7: esaminare il driver per assicurarsi di controllare correttamente l'accesso.
Gestione del controllo di accesso dei driver - WDF
I driver devono funzionare per impedire agli utenti di accedere in modo non appropriato ai dispositivi e ai file di un computer. Per impedire l'accesso non autorizzato a dispositivi e file, è necessario:
Assegnare un nome agli oggetti dispositivo solo quando necessario. Gli oggetti dispositivo denominati sono in genere necessari solo per motivi legacy, ad esempio se si dispone di un'applicazione che prevede di aprire il dispositivo usando un nome specifico o se si usa un dispositivo/controllo non PNP. Si noti che i driver WDF non devono denominare il relativo FDO del dispositivo PnP per creare un collegamento simbolico usando WdfDeviceCreateSymbolicLink.
Proteggere l'accesso a oggetti e interfacce del dispositivo.
Per consentire alle applicazioni o ad altri driver WDF di accedere al PDO del dispositivo PnP, è consigliabile usare le interfacce del dispositivo. Per altre informazioni, vedere Uso delle interfacce del dispositivo. Un'interfaccia del dispositivo funge da collegamento simbolico al PDO dello stack di dispositivi.
Uno dei modi migliori per controllare l'accesso al PDO consiste nel specificare una stringa SDDL in INF. Se la stringa SDDL non è presente nel file INF, Windows applicherà un descrittore di sicurezza predefinito. Per altre informazioni, vedere Protezione di oggetti dispositivo e SDDL per oggetti dispositivo.
Per altre informazioni sul controllo dell'accesso, vedere gli articoli seguenti:
Controllo dell'accesso ai dispositivi nei driver KMDF
Nomi, descrittori di sicurezza e classi di dispositivi - Rendere accessibili gli oggetti dispositivo... e SAFE da gennaio 2017 La newsletter NT Insider pubblicata da OSR.
Gestione del controllo di accesso dei driver - WDM
Se si usa un driver WDM e si usa un oggetto dispositivo denominato, è possibile usare IoCreateDeviceSecure e specificare un SDDL per proteggerlo. Quando si implementa IoCreateDeviceSecure , specificare sempre un GUID di classe personalizzato per DeviceClassGuid. Non è consigliabile specificare un GUID di classe esistente qui. In questo modo è possibile interrompere le impostazioni di sicurezza o la compatibilità per altri dispositivi appartenenti a tale classe. Per altre informazioni, vedere WdmlibIoCreateDeviceSecure.
Per altre informazioni, vedere gli articoli seguenti:
Controllo dell'accesso ai dispositivi
Controllo dell'accesso agli spazi dei nomi dei dispositivi
Modello di sicurezza di Windows per sviluppatori di driver
Gerarchia dei rischi degli identificatori di sicurezza (SID)
La sezione seguente descrive la gerarchia di rischi dei SID comuni usati nel codice del driver. Per informazioni generali su SDDL, vedere SDDL per oggetti dispositivo, stringhe SID e sintassi di stringhe SDDL.
È importante comprendere che se i chiamanti con privilegi inferiori sono autorizzati ad accedere al kernel, il rischio di codice è aumentato. In questo diagramma di riepilogo, il rischio aumenta man mano che si consentono agli SID con privilegi inferiori di accedere alle funzionalità del driver.
SY (System)
\/
BA (Built-in Administrators)
\/
LS (Local Service)
\/
BU (Built-in User)
\/
AC (Application Container)
Seguendo il principio di sicurezza dei privilegi minimi generali, configurare solo il livello minimo di accesso necessario per il funzionamento del driver.
Controllo di sicurezza IOCTL granulare WDM
Per gestire ulteriormente la sicurezza quando IOCTLs vengono inviati dai chiamanti in modalità utente, il codice del driver può includere la funzione IoValidateDeviceIoControlAccess . Questa funzione consente a un driver di controllare i diritti di accesso. Dopo aver ricevuto un IOCTL, un driver può chiamare IoValidateDeviceIoControlAccess, specificando FILE_READ_ACCESS, FILE_WRITE_ACCESS o entrambi.
L'implementazione di un controllo di sicurezza IOCTL granulare non sostituisce la necessità di gestire l'accesso ai driver usando le tecniche descritte in precedenza.
Per altre informazioni, vedere gli articoli seguenti:
Definizione dei codici di controllo di I/O
Implementare codice compatibile con HVCI
Elemento dell'elenco di controllo di sicurezza n. 8: verificare che il driver usi memoria in modo che sia compatibile con HVCI.
Utilizzo della memoria e compatibilità HVCI
HVCI usa la tecnologia hardware e la virtualizzazione per isolare la funzione decisionale di integrità del codice (CI) dal resto del sistema operativo. Quando si usa la sicurezza basata su virtualizzazione per isolare l'integrazione continua, l'unico modo in cui la memoria del kernel può diventare eseguibile è tramite una verifica ci. Ciò significa che le pagine di memoria kernel non possono mai essere scrivibili e eseguibili (W+X) e il codice eseguibile non può essere modificato direttamente.
Per implementare il codice compatibile con HVCI, assicurarsi che il codice del driver esee segue:
- Acconsentire esplicitamente a NX per impostazione predefinita
- Usa API/flag NX per l'allocazione di memoria (NonPagedPoolNx)
- Non usa sezioni sia scrivibili che eseguibili
- Non tenta di modificare direttamente la memoria di sistema eseguibile
- Non usa codice dinamico nel kernel
- Non carica i file di dati come eseguibile
- L'allineamento delle sezioni è un multiplo di 0x1000 (PAGE_SIZE). Ad esempio, DRIVER_ALIGNMENT=0x1000
Per altre informazioni sull'uso dello strumento e un elenco di chiamate di memoria incompatibili, vedere Implementare il codice compatibile con HVCI.
Per altre informazioni sul test di sicurezza dei concetti fondamentali del sistema correlato, vedere Test di conformità dell'integrità del codice HyperVisor e Integrità del codice protetto da Hypervisor.For more information about the related system fundamentals security test, see HyperVisor Code Integrity Readiness Test and Hypervisor-Protected Code Integrity (HVCI).
Seguire le procedure consigliate per il codice specifico della tecnologia
Elemento dell'elenco di controllo per la sicurezza n. 9: esaminare le linee guida specifiche della tecnologia seguenti per il driver.
File system
Per altre informazioni sulla sicurezza dei driver del file system, vedere gli articoli seguenti:
Introduzione alla sicurezza dei file system
Problemi di sicurezza del file system
Funzionalità di sicurezza per i file system
Coesistenza con altri driver di filtro del file system
NDIS - Rete
Per informazioni sulla sicurezza dei driver NDIS, vedere Problemi di sicurezza per i driver di rete.
Schermo
Per informazioni sulla sicurezza dei driver di visualizzazione, vedere <Contenuto in sospeso>.
Printers
Per informazioni sulla sicurezza dei driver della stampante, vedere Considerazioni sulla sicurezza del driver della stampante V4.
Problemi di sicurezza per i driver windows di acquisizione di immagini (WIA)
Per informazioni sulla sicurezza wia, vedi Problemi di sicurezza per i driver windows di acquisizione di immagini (WIA).
Migliorare la sicurezza dell'installazione dei dispositivi
Elemento elenco di controllo per la sicurezza n. 10: esaminare le linee guida per la creazione e l'installazione dei driver per assicurarsi di seguire le procedure consigliate.
Quando si crea il codice che installa il driver, è necessario assicurarsi che l'installazione del dispositivo venga sempre eseguita in modo sicuro. Un'installazione sicura del dispositivo è una delle operazioni seguenti:
- Limita l'accesso al dispositivo e alle relative classi di interfaccia dispositivo
- Limita l'accesso ai servizi driver creati per il dispositivo
- Protegge i file driver dalla modifica o dall'eliminazione
- Limita l'accesso alle voci del Registro di sistema del dispositivo
- Limita l'accesso alle classi WMI del dispositivo
- Usa correttamente le funzioni SetupAPI
Per altre informazioni, vedere gli articoli seguenti:
Creazione di installazioni di dispositivi sicuri
Linee guida per l'uso di SetupAPI
Uso delle funzioni di installazione dei dispositivi
Argomenti avanzati sull'installazione di dispositivi e driver
Eseguire la revisione del codice peer
Elemento elenco di controllo per la sicurezza n. 11: Eseguire la revisione del codice peer per cercare i problemi non rilevati dagli altri strumenti e processi
Cercare revisori esperti del codice per cercare problemi che potrebbero non essere stati rilevati. Un secondo set di occhi spesso vedrà problemi che potresti aver trascurato.
Se non si dispone di personale adatto per esaminare il codice internamente, prendere in considerazione l'impegno esterno per questo scopo.
Eseguire la firma corretta del driver di versione
Elemento elenco di controllo per la sicurezza n. 12: usare il portale per i partner windows per firmare correttamente il driver per la distribuzione.
Prima di rilasciare un pacchetto driver al pubblico, è consigliabile inviare il pacchetto per la certificazione. Per altre informazioni, vedere Testare le prestazioni e la compatibilità, Introduzione al programma hardware, Servizi dashboard hardware e Firma di attestazione di un driver kernel per la versione pubblica.
Usare CodeQL per controllare il codice del driver
Elemento dell'elenco di controllo per la sicurezza n. 13: usare CodeQL per verificare la presenza di vulnerabilità nel codice del driver.
CodeQL, di GitHub, è un motore di analisi del codice semantico e la combinazione di una vasta gamma di query di sicurezza insieme a una solida piattaforma lo rende uno strumento prezioso per la protezione del codice driver. Per altre informazioni, vedere CodeQL e il test del logo degli strumenti statici.
Aggiungere annotazioni SAL al codice driver
Elemento dell'elenco di controllo per la sicurezza n. 14: aggiungere annotazioni SAL a nel codice del driver.
Il linguaggio di annotazione del codice sorgente (SAL) fornisce un set di annotazioni che è possibile usare per descrivere come una funzione usa i relativi parametri, i presupposti su di essi e le garanzie che rende al termine. Le annotazioni vengono definite nel file sal.h
di intestazione . L'analisi del codice di Visual Studio per C++ usa annotazioni SAL per modificarne l'analisi delle funzioni. Per altre informazioni su SAL 2.0 per lo sviluppo di driver Windows, vedere ANNOtazioni SAL 2.0 per i driver Windows e Uso delle annotazioni SAL per ridurre i difetti del codice C/C++.
Per informazioni generali su SAL, vedere questo articolo disponibile in OSR. https://www.osr.com/blog/2015/02/23/sal-annotations-dont-hate-im-beautiful/
Usare Driver Verifier per verificare la presenza di vulnerabilità
Elemento dell'elenco di controllo per la sicurezza n. 15: usare Driver Verifier per verificare la presenza di vulnerabilità nel codice del driver.
Driver Verifier usa un set di regole di interfaccia e un modello del sistema operativo per determinare se il driver interagisce correttamente con il sistema operativo Windows. DV rileva i difetti nel codice del driver che potrebbero puntare a potenziali bug nei driver.
Driver Verifier consente il test in tempo reale del driver. Driver Verifier monitora driver e driver grafici in modalità kernel di Windows per rilevare chiamate di funzione o azioni non valide che potrebbero danneggiare il sistema. Driver Verifier può sottoporre i driver di Windows a un'ampia gamma di stress e test per individuare comportamenti non corretti. Per altre informazioni, vedere Driver Verifier.
Si noti che solo alcuni tipi di driver sono supportati da DV. Per altre informazioni sui driver che DV può verificare, vedere Driver supportati. Per informazioni sui test DV disponibili per il tipo di driver in uso, vedere le pagine seguenti.
- Regole per i driver WDM
- Regole per i driver KMDF
- Regole per i driver NDIS
- Regole per i driver Storport
- Regole per i driver audio
- Regole per i driver AVStream
Per acquisire familiarità con DV, è possibile usare uno dei driver di esempio (ad esempio, l'esempio di tostapane in primo piano: https://github.com/Microsoft/Windows-driver-samples/tree/main/general/toaster/toastDrv/kmdf/func/featured).
Controllare il codice con l'analizzatore binario BinSkim
Elemento dell'elenco di controllo di sicurezza n. 16: seguire questa procedura per usare BinSkim per verificare che le opzioni di compilazione e compilazione siano configurate per ridurre al minimo i problemi di sicurezza noti.
Usare BinSkim per esaminare i file binari per identificare le procedure di codifica e compilazione che possono potenzialmente rendere vulnerabile il file binario.
BinSkim verifica la presenza di:
- Uso di set di strumenti del compilatore obsoleti: i file binari devono essere compilati con i set di strumenti del compilatore più recenti, laddove possibile, per ottimizzare l'uso delle mitigazioni di sicurezza correnti a livello di compilatore e del sistema operativo.
- Impostazioni di compilazione non sicure: i file binari devono essere compilati con le impostazioni più sicure possibili per abilitare le mitigazioni della sicurezza fornite dal sistema operativo, ottimizzare gli errori del compilatore e segnalare avvisi interattivi, tra le altre cose.
- Problemi di firma: i file binari firmati devono essere firmati con algoritmi con crittografia avanzata.
BinSkim è uno strumento open source e genera file di output che usano il formato SARIF (Static Analysis Results Interchange Format). BinSkim sostituisce l'ex strumento BinScope .
Per altre informazioni su BinSkim, vedere la Guida dell'utente di BinSkim.
Seguire questa procedura per verificare che le opzioni di compilazione della sicurezza siano configurate correttamente nel codice da spedire.
Scaricare e installare .NET Core SDK multipiattaforma.
Verificare che Visual Studio sia installato. Per informazioni sul download e l'installazione di Visual Studio, vedere Installare Visual Studio.
Sono disponibili diverse opzioni per scaricare BinSkim, ad esempio un pacchetto NuGet. In questo esempio si userà l'opzione git clone per scaricarla da qui: https://github.com/microsoft/binskim e installarla in un PC Windows a 64 bit.
Aprire una finestra del prompt dei comandi per gli sviluppatori di Visual Studio e creare una directory, ad esempio
C:\binskim-master
.C:\> Md \binskim-master
Passare alla directory appena creata.
C:\> Cd \binskim-master
Usare il comando git clone per scaricare tutti i file necessari.
C:\binskim-master> git clone --recurse-submodules https://github.com/microsoft/binskim.git
Passare alla nuova
binskim
dirctory creata dal comando clone.C:\> Cd \binskim-master\binskim
Eseguire BuildAndTest.cmd per assicurarsi che la build di versione abbia esito positivo e che tutti i test vengano superati.
C:\binskim-master\binskim> BuildAndTest.cmd Welcome to .NET Core 3.1! --------------------- SDK Version: 3.1.101 ... C:\binskim-master\binskim\bld\bin\AnyCPU_Release\Publish\netcoreapp2.0\win-x64\BinSkim.Sdk.dll 1 File(s) copied C:\binskim-master\binskim\bld\bin\AnyCPU_Release\Publish\netcoreapp2.0\linux-x64\BinSkim.Sdk.dll 1 File(s) copied ...
Il processo di compilazione crea un set di directory con gli eseguibili BinSkim. Passare alla directory di output di compilazione win-x64.
C:\binskim-master\binskim> Cd \binskim-master\bld\bin\AnyCPU_Release\Publish\netcoreapp2.0\win-x64>
Visualizzare la Guida per l'opzione di analisi.
C:\binskim-master\binskim\bld\bin\AnyCPU_Release\Publish\netcoreapp2.0\win-x64> BinSkim help analyze
BinSkim PE/MSIL Analysis Driver 1.6.0.0
--sympath Symbols path value, e.g., SRV*http://msdl.microsoft.com/download/symbols or Cache*d:\symbols;Srv*http://symweb. See
https://video2.skills-academy.com/windows-hardware/drivers/debugger/advanced-symsrv-use for syntax information. Note that BinSkim will clear the
_NT_SYMBOL_PATH environment variable at runtime. Use this argument for symbol information instead.
--local-symbol-directories A set of semicolon-delimited local directory paths that will be examined when attempting to locate PDBs.
-o, --output File path to which analysis output will be written.
--verbose Emit verbose output. The resulting comprehensive report is designed to provide appropriate evidence for compliance scenarios.
...
Impostazione del percorso del simbolo
Se si sta compilando tutto il codice che si sta analizzando nello stesso computer in cui si esegue BinSkim, in genere non è necessario impostare il percorso del simbolo. Ciò è dovuto al fatto che i file di simboli sono disponibili nella casella locale in cui è stata compilata. Se si usa un sistema di compilazione più complesso o si reindirizzano i simboli a un percorso diverso (non insieme al file binario compilato), usare --local-symbol-directories
per aggiungere questi percorsi alla ricerca dei file di simboli.
Se il codice fa riferimento a un file binario compilato che non fa parte del codice, il debugger window sympath può essere usato per recuperare i simboli per verificare la sicurezza di queste dipendenze del codice. Se si rileva un problema in queste dipendenze, potrebbe non essere possibile risolverli. Può tuttavia essere utile essere consapevoli di eventuali rischi per la sicurezza accettati prendendo in considerazione tali dipendenze.
Suggerimento
Quando si aggiunge un percorso di simbolo (che fa riferimento a un server di simboli di rete), aggiungere un percorso della cache locale per specificare un percorso locale per memorizzare nella cache i simboli. Questa operazione non può compromettere notevolmente le prestazioni di BinSkim. Nell'esempio seguente viene specificata una cache locale in d:\symbols.
--sympath Cache*d:\symbols;Srv*http://symweb
Per altre informazioni sul percorso simbolico, vedere Percorso dei simboli per i debugger di Windows.
Eseguire il comando seguente per analizzare un file binario del driver compilato. Aggiornare il percorso di destinazione in modo che punti al file .sys driver rispettato.
C:\binskim-master\binskim\bld\bin\AnyCPU_Release\Publish\netcoreapp2.0\win-x64> BinSkim analyze "C:\Samples\KMDF_Echo_Driver\echo.sys"
Per altre informazioni, aggiungere l'opzione dettagliata in questo modo.
C:\binskim-master\binskim\bld\bin\AnyCPU_Release\Publish\netcoreapp2.0\win-x64> BinSkim analyze "C:\Samples\KMDF_Echo_Driver\osrusbfx2.sys" --verbose
Nota
L'opzione --verbose produrrà risultati espliciti di pass/fail per ogni controllo. Se non fornisci dettagli, vedrai solo i difetti rilevati da BinSkim. L'opzione --verbose in genere non è consigliata per i sistemi di automazione effettivi a causa della maggiore dimensione dei file di log e perché rende più difficile raccogliere singoli errori quando si verificano, in quanto verranno incorporati in mezzo a un numero elevato di risultati "pass".
Esaminare l'output del comando per cercare i possibili problemi. Questo output di esempio mostra tre test superati. Altre informazioni sulle regole, ad esempio BA2002, sono disponibili nella Guida dell'utente di BinSkim.
Analyzing... Analyzing 'osrusbfx2.sys'... ... C:\Samples\KMDF_Echo_Driver\osrusbfx2.sys\Debug\osrusbfx2.sys: pass BA2002: 'osrusbfx2.sys' does not incorporate any known vulnerable dependencies, as configured by current policy. C:\Samples\KMDF_Echo_Driver\Debug\osrusbfx2.sys: pass BA2005: 'osrusbfx2.sys' is not known to be an obsolete binary that is vulnerable to one or more security problems. C:\Samples\KMDF_Echo_Driver\osrusbfx2.sys: pass BA2006: All linked modules of 'osrusbfx2.sys' generated by the Microsoft front-end satisfy configured policy (compiler minimum version 17.0.65501.17013).
Questo output mostra che il test BA3001 non viene eseguito come lo strumento indica che il driver non è un file binario ELF.
... C:\Samples\KMDF_Echo_Driver\Debug\osrusbfx2.sys: notapplicable BA3001: 'osrusbfx2.sys' was not evaluated for check 'EnablePositionIndependentExecutable' as the analysis is not relevant based on observed metadata: image is not an ELF binary.
Questo output mostra un errore per il test BA2007.
... C:\Samples\KMDF_Echo_Driver\Debug\osrusbfx2.sys: error BA2007: 'osrusbfx2.sys' disables compiler warning(s) which are required by policy. A compiler warning is typically required if it has a high likelihood of flagging memory corruption, information disclosure, or double-free vulnerabilities. To resolve this issue, enable the indicated warning(s) by removing /Wxxxx switches (where xxxx is a warning id indicated here) from your command line, and resolve any warnings subsequently raised during compilation.
Per abilitare questi avvisi in Visual Studio, in C/C++ nelle pagine delle proprietà del progetto rimuovere i valori che non si desidera escludere in Disabilita avvisi specifici.
Le opzioni di compilazione predefinite in Visual Studio per i progetti driver possono disabilitare avvisi come i seguenti. Questi avvisi verranno segnalati da BinSkim.
C4627 - 'description': ignorato quando si cerca l'uso dell'intestazione precompilata
C4986 - 'declaration': la specifica di eccezione non corrisponde alla dichiarazione precedente
Per altre informazioni sugli avvisi del compilatore, vedere Avvisi del compilatore per versione del compilatore.
Controllare il codice con i test del programma di compatibilità hardware
Elemento dell'elenco di controllo per la sicurezza n. 17: usare i test del programma di compatibilità hardware correlato alla sicurezza per verificare la presenza di problemi di sicurezza.
Il programma di compatibilità hardware include test correlati alla sicurezza che possono essere usati per cercare vulnerabilità del codice. Windows Hardware Compatibility Program sfrutta i test in Windows Hardware Lab Kit (HLK). I test HLK Device Fundamentals possono essere usati nella riga di comando per esercitare il codice del driver e verificare la debolezza. Per informazioni generali sui test fondamentali del dispositivo e sul programma di compatibilità hardware, vedere Windows Hardware Lab Kit.
I test seguenti sono esempi di test che possono essere utili per controllare il codice driver per alcuni comportamenti associati alle vulnerabilità del codice:
DF - Test IOCTL casuale fuzz (reliability)
DF - Test di apertura secondaria fuzz (affidabilità)
DF - Buffer di lunghezza zero fuzz test BUFFER BUFFER (affidabilità)
DF - Test FUzz casualE CONTTL (affidabilità)
DF - Test dell'API Misc Fuzz (Reliability)
È anche possibile usare il ritardo della sincronizzazione del kernel incluso in Driver Verifier.
I test chaos (simultanei hardware e sistema operativo) eseguono diversi test del driver PnP, test fuzz del driver di dispositivo e test del sistema di alimentazione simultaneamente. Per altre informazioni, vedere Chaos Tests (Device Fundamentals).
I test di penetrazione nozioni fondamentali sul dispositivo eseguono varie forme di attacchi di input, che sono un componente fondamentale dei test di sicurezza. I test di attacco e penetrazione possono aiutare a identificare le vulnerabilità nelle interfacce software. Per altre informazioni, vedere Test di penetrazione (Nozioni fondamentali sul dispositivo).
Usare Device Guard - Compliance Test, insieme agli altri strumenti descritti in questo articolo, per verificare che il driver sia compatibile con HVCI.
Strumenti di test personalizzati e specifici del dominio
Prendere in considerazione lo sviluppo di test di sicurezza personalizzati specifici del dominio. Per sviluppare test aggiuntivi, raccogliere input dai progettisti originali del software, nonché risorse di sviluppo non correlate familiari con il tipo specifico di driver in fase di sviluppo e una o più persone che hanno familiarità con l'analisi e la prevenzione delle intrusioni di sicurezza.
Esaminare le tecniche e le estensioni del debugger
Elemento dell'elenco di controllo per la sicurezza n. 18: esaminare questi strumenti del debugger e prendere in considerazione l'uso nel flusso di lavoro di debug dello sviluppo.
Comandi del debugger correlati alla sicurezza
L'estensione !acl formatta e visualizza il contenuto di un elenco di controllo di accesso (ACL). Per altre informazioni, vedere Determinazione dell'ACL di un oggetto e !acl.
L'estensione !token visualizza una visualizzazione formattata di un oggetto token di sicurezza. Per altre informazioni, vedere !token.
L'estensione !tokenfields visualizza i nomi e gli offset dei campi all'interno dell'oggetto token di accesso (la struttura TOKEN). Per altre informazioni, vedere !tokenfields.
L'estensione !sid visualizza l'identificatore di sicurezza (SID) nell'indirizzo specificato. Per altre informazioni, vedere !sid.
L'estensione !sd visualizza il descrittore di sicurezza in corrispondenza dell'indirizzo specificato. Per altre informazioni, vedere !sd.
Microsoft Vulnerabile e dannoso Driver Reporting Center
Chiunque può inviare un driver discutibile usando Microsoft Vulnerabile e Dannoso Driver Reporting Center. Fare riferimento a questa voce di blog per informazioni su come vengono inviati i driver per l'analisi - Migliorare la sicurezza del kernel con il nuovo Microsoft Vulnerabile e Dannoso Driver Reporting Center
Reporting Center può analizzare e analizzare i driver windows creati per architetture x86 e x64. I driver vulnerabili e dannosi analizzati vengono contrassegnati per l'analisi e l'analisi da parte del team di Driver vulnerabile di Microsoft. Dopo aver confermato i driver vulnerabili, viene visualizzata una notifica appropriata, che vengono aggiunte all'elenco di blocchi dei driver vulnerabili. Per altre informazioni, vedere Regole di blocco dei driver consigliate da Microsoft. Queste regole vengono applicate per impostazione predefinita ai dispositivi abilitati per l'integrità del codice protetto da Hypervisor (HVCI) e Windows 10 in modalità S.
Esaminare le risorse di codifica sicura
Elemento dell'elenco di controllo per la sicurezza n. 19: esaminare queste risorse per espandere la comprensione delle procedure consigliate per la codifica sicura applicabili agli sviluppatori di driver.
Esaminare queste risorse per altre informazioni sulla sicurezza dei driver
Linee guida per la codifica dei driver in modalità kernel sicura
Creazione di driver affidabili in modalità kernel
Proteggere le organizzazioni di codifica
Carnegie Mellon University SEI CERT
Carnegie Mellon University SEI CERT C Coding Standard: regole per lo sviluppo di sistemi sicuri, affidabili e sicuri (edizione 2016).
MITRE - Punti deboli risolti dallo standard di codifica sicura CERT C
Building Security In Maturity Model (BSIMM) - Building Security In Maturity Model (BSIMM) - https://www.bsimm.com/
SAFECode - https://safecode.org/
OSR
OSR offre servizi di formazione e consulenza per lo sviluppo di driver. Questi articoli della newsletter osr evidenziano i problemi di sicurezza dei driver.
È necessario usare la protezione - All'interno del driver e della sicurezza dei dispositivi
Blocco dei driver - Un sondaggio sulle tecniche
Meltdown e Spectre: Che ne dici dei conducenti?
Case study
Libri
24 peccati mortali della sicurezza del software: errori di programmazione e come risolverli da Michael Howard, David LeBlanc e John Viega
L'arte della valutazione della sicurezza del software: identificazione e prevenzione delle vulnerabilità software, Mark Dowd, John McDonald e Justin Schuh
Scrittura di Secure Software Second Edition, Michael Howard e David LeBlanc
L'arte della valutazione della sicurezza del software: identificazione e prevenzione delle vulnerabilità software, Mark Dowd e John McDonald
Codifica sicura in C e C++ (SEI Series in Software Engineering) 2nd Edition, Robert C. Seacord
Programmazione del modello di driver di Microsoft Windows (seconda edizione), Walter Oney
Sviluppo di driver con Windows Driver Foundation (Guida di riferimento per sviluppatori), Penny Orwick e Guy Smith
Formazione
Il training per le classi dei driver windows è disponibile dai fornitori, ad esempio i seguenti:
Il training online per la codifica sicura è disponibile da un'ampia gamma di origini. Ad esempio, questo corso è disponibile da coursera on:
Identificazione delle vulnerabilità di sicurezza nella programmazione C/C++.
SAFECode offre anche formazione gratuita:
Certificazione professionale
CERT offre una certificazione secure coding professional.
Riepilogo delle considerazioni chiave
La sicurezza dei driver è un'impresa complessa contenente molti elementi, ma ecco alcuni punti chiave da considerare:
I driver si trovano nel kernel windows e si verificano problemi durante l'esecuzione nel kernel espongono l'intero sistema operativo. Per questo motivo, prestare particolare attenzione alla sicurezza dei driver e alla progettazione tenendo conto della sicurezza.
Applicare il principio dei privilegi minimi:
a. Usare una stringa SDDL rigorosa per limitare l'accesso al driver
b. Limitare ulteriormente i singoli IOCTL
Creare un modello di minaccia per identificare i vettori di attacco e valutare se è possibile limitare ulteriormente qualsiasi elemento.
Prestare attenzione ai puntatori incorporati passati dalla modalità utente. È necessario eseguire il probe, accedere all'interno del tentativo, ad eccezione del fatto che sono soggetti a tempi di controllo dell'uso (ToCToU), a meno che il valore del buffer non venga acquisito e confrontato.
Se non si è certi, usare METHOD_BUFFERED come metodo di buffering IOCTL.
Usare le utilità di analisi del codice per cercare vulnerabilità del codice note e correggere eventuali problemi identificati.
Cercare revisori esperti del codice per cercare problemi che potrebbero non essere stati rilevati.
Usare i verificatori del driver e testare il driver con più input, inclusi i case degli angoli.