Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Obecnou diskuzi o psaní zabezpečených ovladačů najdete v tématu Vytváření spolehlivých ovladačů Kernel-Mode.
Kromě následujících postupů bezpečného kódování a obecných pokynů k ovladačům zařízení by síťové ovladače měly zvýšit zabezpečení následujícím postupem:
- Všechny síťové ovladače by měly ověřit hodnoty, které čtou z registru. Konkrétně volající NdisReadConfiguration nebo NdisReadNetworkAddress nesmí provádět žádné předpoklady o hodnotách přečtených z registru a musí ověřit každou hodnotu registru, kterou čte. Pokud volající NdisReadConfiguration zjistí, že hodnota je mimo hranice, měla by místo toho použít výchozí hodnotu. Pokud volající NdisReadNetworkAddress určuje, že hodnota je mimo hranice, měla by místo toho použít adresu MAC (Permanent Medium Access Control) nebo výchozí adresu.
Problémy specifické pro OID
Ovladač miniportu ve funkcích MiniportOidRequest nebo MiniportCoOidRequest by měl ověřit libovolnou hodnotu identifikátoru objektu (OID), kterou ovladač požaduje k nastavení. Pokud ovladač zjistí, že hodnota, která má být nastavena, je mimo hranice, měl by požadavek na nastavení selhat. Další informace o identifikátorech objektů naleznete v tématu Získání a nastavení informací o ovladači miniportu a podporu NDIS pro rozhraní WMI.
Pokud funkce MiniportOidRequest zprostředkujícího ovladače nepředá operaci set do základního ovladače miniportu, měla by funkce ověřit hodnotu OID. Další informace naleznete v tématu Zprostředkující ovladač dotazu a nastavení operací.
Pokyny pro zabezpečení identifikátorů objektů (OID) dotazu
Většinu identifikátorů OID dotazů může vydat libovolná aplikace uživatelského režimu v systému. Postupujte podle těchto specifických pokynů pro identifikátory OID dotazů.
Vždy ověřte, že velikost vyrovnávací paměti je dostatečně velká pro výstup. Jakákoli obslužná rutina identifikátoru dotazu bez kontroly velikosti výstupní vyrovnávací paměti má chybu zabezpečení.
if (oid->DATA.QUERY_INFORMATION.InformationBufferLength < sizeof(ULONG)) { oid->DATA.QUERY_INFORMATION.BytesNeeded = sizeof(ULONG); return NDIS_STATUS_INVALID_LENGTH; }Vždy napište správnou a minimální hodnotu do BajtsWritten. Je to červený signál přiřazení
oid->BytesWritten = oid->InformationBufferLengthpodobně jako v následujícím příkladu.// ALWAYS WRONG oid->DATA.QUERY_INFORMATION.BytesWritten = DATA.QUERY_INFORMATION.InformationBufferLength;Operační systém zkopíruje zapsané bajty zpět do uživatelské aplikace. Pokud je bytesWritten větší než počet bajtů, které ovladač skutečně napsal, operační systém může skončit kopírováním zpět neinicializované paměti jádra do uživatelského režimu, což by bylo ohrožení zabezpečení spočívající ve zpřístupnění informací. Místo toho použijte kód podobný tomuto:
oid->DATA.QUERY_INFORMATION.BytesWritten = sizeof(ULONG);Nikdy nečtěte zpětně hodnoty z vyrovnávací paměti. V některých případech je výstupní vyrovnávací paměť identifikátoru OID přímo namapována na nepřátelský proces usermode. Nepřátelský proces může změnit výstupní vyrovnávací paměť po zápisu. Například níže uvedený kód může být napaden, protože útočník může po napsání změnit hodnotu NumElements:
output->NumElements = 4; for (i = 0 ; i < output->NumElements ; i++) { output->Element[i] = . . .; }Abyste se vyhnuli zpětnému čtení z vyrovnávací paměti, ponechte místní kopii. Pokud chcete například opravit výše uvedený příklad, vytvořte novou proměnnou zásobníku:
ULONG num = 4; output->NumElements = num; for (i = 0 ; i < num; i++) { output->Element[i] = . . .; }Při tomto přístupu smyčka for čte z proměnné zásobníku ovladače
num, nikoli z jeho výstupní vyrovnávací paměti. Ovladač by měl také označit výstupní vyrovnávací paměť klíčovým slovemvolatile, aby kompilátor neprovedl tuto opravu zpětně tiše.
Nastavení pokynů pro zabezpečení identifikátorů
Většinu sad identifikátorů OID může vydat aplikace běžící v uživatelském režimu ve skupinách zabezpečení Administrators nebo System. I když se jedná o obecně důvěryhodné aplikace, ovladač miniportu stále nesmí povolit poškození paměti nebo injektáž kódu jádra. Postupujte podle těchto specifických pravidel pro nastavení identifikátorů OID:
Vždy ověřte, že je vstup dostatečně velký. Jakákoli obslužná rutina sady identifikátorů bez kontroly velikosti vstupní vyrovnávací paměti má ohrožení zabezpečení.
if (oid->DATA.SET_INFORMATION.InformationBufferLength < sizeof(ULONG)) { return NDIS_STATUS_INVALID_LENGTH; }Při ověřování identifikátoru s vloženým posunem je nutné ověřit, že vložený buffer je v datové části OID. To vyžaduje několik kontrol. Například OID_PM_ADD_WOL_PATTERN může dodat vložený vzor, který je potřeba zkontrolovat. Správné ověření vyžaduje kontrolu:
InformationBufferSize >= sizeof(NDIS_PM_PACKET_PATTERN)
PmPattern = (PNDIS_PM_PACKET_PATTERN) InformationBuffer; if (InformationBufferLength < sizeof(NDIS_PM_PACKET_PATTERN)) { Status = NDIS_STATUS_BUFFER_TOO_SHORT; *BytesNeeded = sizeof(NDIS_PM_PACKET_PATTERN); break; }Pattern-PatternOffset> + Pattern-PatternSize> nepřeteče
ULONG TotalSize = 0; if (!NT_SUCCESS(RtlUlongAdd(Pattern->PatternOffset, Pattern->PatternSize, &TotalSize) || TotalSize > InformationBufferLength) { return NDIS_STATUS_INVALID_LENGTH; }Tyto dvě kontroly se dají kombinovat pomocí kódu jako v následujícím příkladu:
ULONG TotalSize = 0; if (InformationBufferLength < sizeof(NDIS_PM_PACKET_PATTERN) || !NT_SUCCESS(RtlUlongAdd(Pattern->PatternSize, Pattern->PatternOffset, &TotalSize) || TotalSize > InformationBufferLength) { return NDIS_STATUS_INVALID_LENGTH; }InformationBuffer + Pattern->PatternOffset + Pattern->PatternLength nepřeteče
ULONG TotalSize = 0; if (!NT_SUCCESS(RtlUlongAdd(Pattern->PatternOffset, Pattern->PatternLength, &TotalSize) || (!NT_SUCCESS(RtlUlongAdd(TotalSize, InformationBuffer, &TotalSize) || TotalSize > InformationBufferLength) { return NDIS_STATUS_INVALID_LENGTH; }Pattern-PatternOffset> + Pattern-PatternLength <>= InformationBufferSize
ULONG TotalSize = 0; if(!NT_SUCCESS(RtlUlongAdd(Pattern->PatternOffset, Pattern->PatternLength, &TotalSize) || TotalSize > InformationBufferLength)) { return NDIS_STATUS_INVALID_LENGTH; }
Pokyny pro zabezpečení metod OID
Identifikátory OID metody může vydávat aplikace v uživatelském režimu, která je spuštěná ve skupinách zabezpečení Administrators nebo System. Jedná se o kombinaci sady a dotazu, takže oba předchozí seznamy pokynů platí také pro identifikátory OID metody.
Další problémy se zabezpečením síťových ovladačů
Mnoho ovladačů miniportu NDIS zveřejňuje řídicí zařízení pomocí NdisRegisterDeviceEx. Ti, kteří to dělají, musí auditovat obslužné rutiny IOCTL se všemi stejnými pravidly zabezpečení jako ovladač WDM. Další informace najdete v tématu Problémy se zabezpečením kódů ovládacích prvků vstupně-výstupních operací.
Dobře navržené ovladače miniportu NDIS by se neměly spoléhat na to, že jsou volány v konkrétním kontextu procesu, ani velmi úzce spolupracovat s uživatelským módem, přičemž IOCTLs a OIDs jsou výjimkou. Bylo by varovným signálem vidět miniport, který otevřel otáčeče uživatelského režimu, prováděl čekání v uživatelském režimu, nebo přiděloval paměť využívající kvótu uživatelského režimu. Tento kód by měl být prošetřen.
Většina ovladačů miniportu NDIS by neměla být zapojena do analýzy datových částí paketů. V některých případech ale může být nutné. Pokud ano, tento kód by měl být auditován velmi pečlivě, protože ovladač analyzuje data z nedůvěryhodného zdroje.
Stejně jako je standard při přidělování paměti v režimu jádra, měly by ovladače NDIS používat vhodné mechanismy NX Pool Opt-In. V WDK 8 a novějších jsou řady funkcí správně zapojeny.