Not
Åtkomst till denna sida kräver auktorisation. Du kan prova att logga in eller byta katalog.
Åtkomst till denna sida kräver auktorisation. Du kan prova att byta katalog.
Ett av de vanligaste felen inom en drivrutin gäller bufferthantering, där buffertar är ogiltiga eller för små. Dessa fel kan tillåta buffertspill eller orsaka systemkrascher, vilket kan äventyra systemsäkerheten. I den här artikeln beskrivs några vanliga problem med bufferthantering och hur du undviker dem. Den identifierar också WDK-exempelkod som demonstrerar rätt metoder för bufferthantering.
Bufferttyper och ogiltiga adresser
Ur förarens perspektiv finns buffertar i en av två sorter:
Sidsidiga buffertar, som kanske eller kanske inte finns i minnet.
Buffertar som inte är sidsidiga, som måste finnas i minnet.
En ogiltig minnesadress är inte paged eller nonpaged. Eftersom operativsystemet fungerar för att lösa ett sidfel som orsakas av felaktig bufferthantering utför det följande steg:
Den isolerar den ogiltiga adressen till ett av "standard"-adressintervallen (sidade kerneladresser, icke-sidiga kerneladresser eller användaradresser).
Det ger upphov till rätt typ av fel. Systemet hanterar alltid buffertfel antingen genom en buggkontroll, till exempel PAGE_FAULT_IN_NONPAGED_AREA, eller med ett undantag som STATUS_ACCESS_VIOLATION. Om felet är en buggkontroll stoppar systemet åtgärden. Vid ett undantag anropar systemet stackbaserade undantagshanterare. Om ingen av undantagshanterarna hanterar undantaget anropar systemet en buggkontroll.
Oavsett är alla åtkomstvägar som ett program kan anropa och som gör att drivrutinen orsakar en buggkontroll en säkerhetsöverträdelse inom drivrutinen. En sådan överträdelse gör att ett program kan orsaka överbelastningsattacker i hela systemet.
Vanliga antaganden och misstag
Ett av de vanligaste problemen på det här området är att drivrutinsförfattare förutsätter för mycket om driftsmiljön. Några vanliga antaganden och misstag är:
En drivrutin kontrollerar bara om den höga biten har angetts i adressen. Att förlita sig på ett fast bitmönster för att fastställa adresstypen fungerar inte på alla system eller scenarier. Den här kontrollen fungerar till exempel inte på x86-baserade datorer när systemet använder 4GT (Four Gigabyte Tuning ). När 4GT används anger användarlägesadresser den höga biten för det tredje gigabytet av adressutrymmet.
En drivrutin som endast använder ProbeForRead och ProbeForWrite för att verifiera adressen. Dessa anrop säkerställer att adressen är en giltig adress i användarläge vid tidpunkten för avsökningen. Det finns dock inga garantier för att den här adressen förblir giltig efter avsökningsåtgärden. Således introducerar denna teknik ett subtilt konkurrenstillstånd som kan leda till periodiska oemotståndliga krascher.
ProbeForRead - och ProbeForWrite-anrop är fortfarande nödvändiga. Om en drivrutin utelämnar avsökningen kan användarna ange giltiga kernellägesadresser som ett
__tryoch__except-block (strukturerad undantagshantering) inte kan fånga upp, vilket öppnar för ett stort säkerhetshål.Slutsatsen är att både avsökning och strukturerad undantagshantering är nödvändiga:
Avsökning verifierar att adressen är en adress i användarläge och att buffertens längd ligger inom användaradressintervallet.
Ett
__try/__exceptblock skyddar mot åtkomst.
Observera att ProbeForRead endast verifierar att adressen och längden ligger inom det möjliga adressintervallet för användarläge (något under 2 GB för ett system utan till exempel 4GT), inte om minnesadressen är giltig. ProbeForWrite försöker däremot komma åt den första byte på varje sida med den längd som angetts för att kontrollera att dessa byte är giltiga minnesadresser.
En drivrutin som förlitar sig på minneshanteringsfunktioner som MmIsAddressValid för att säkerställa att adressen är giltig. Som beskrivs för avsökningsfunktionerna introducerar den här situationen ett konkurrenstillstånd som kan leda till oemotståndliga krascher.
En drivrutin som inte kan använda strukturerad undantagshantering. Funktionerna
__try/excepti kompilatorn använder stöd på operativsystemnivå för undantagshantering. Undantag på kernelnivå returneras till systemet via ett anrop till ExRaiseStatus eller någon av de relaterade funktionerna. En drivrutin som inte använder strukturerad undantagshantering runt alla anrop som kan generera ett undantag leder till en buggkontroll (vanligtvis KMODE_EXCEPTION_NOT_HANDLED).Det är ett misstag att använda strukturerad undantagshantering kring kod som inte förväntas generera fel. Den här användningen maskerar bara verkliga buggar som annars skulle hittas. Att placera en
__try/__exceptwrapper på den högsta sändningsnivån i din rutin är inte rätt lösning på det här problemet, även om det ibland är reflexlösningen som provas av drivrutinsförfattare.En drivrutin som förutsätter att innehållet i användarminnet förblir stabilt. Anta till exempel att en drivrutin skrev ett värde till en minnesplats i användarläge och senare i samma rutin som refererade till den minnesplatsen. Ett skadligt program kan aktivt ändra det minnet efter skrivning och därmed orsaka att drivrutinen kraschar.
För filsystem är dessa problem allvarliga eftersom filsystem vanligtvis förlitar sig på direkt åtkomst till användarbuffertar (METHOD_NEITHER överföringsmetod). Sådana drivrutiner manipulerar direkt användarbuffertar och måste därför införa försiktighetsmetoder för bufferthantering för att undvika krascher på operativsystemnivå. Snabb I/O skickar alltid råa minnespekare, så drivrutiner måste skydda mot liknande problem när snabb I/O stöds.
Exempelkod för bufferthantering
WDK innehåller flera exempel på buffertvalidering i exempelkoden för fastfat - och CDFS-filsystemdrivrutiner , inklusive:
Funktionen FatLockUserBuffer i fastfat\deviosup.c använder MmProbeAndLockPages för att låsa de fysiska sidorna bakom användarbufferten och MmGetSystemAddressForMdlSafe i FatMapUserBuffer för att skapa en virtuell mappning för de sidor som är låsta.
Funktionen FatGetVolumeBitmap i fastfat\fsctl.c använder ProbeForRead och ProbeForWrite för att verifiera användarbuffertar i defragmenterings-API:et.
Funktionen CdCommonRead i cdfs\read.c använder
__tryoch__exceptrunt kod för att nollställa användarbuffertar. Exempelkoden i CdCommonRead verkar använda nyckelordentryochexcept. I WDK-miljön definieras dessa nyckelord i C när det gäller kompilatortilläggen__tryoch__except. Alla som använder C++-kod måste använda de inbyggda kompilatortyperna för att hantera undantag korrekt, vilket__tryär ett C++-nyckelord, men inte ett C-nyckelord, och ger en form av C++-undantagshantering som inte är giltig för kerneldrivrutiner.