Date post: | 18-Jan-2016 |
Category: |
Documents |
Upload: | berniece-kennedy |
View: | 225 times |
Download: | 0 times |
Static Analysis and Verification of Drivers
Jakob LichtenbergSoftware Development Engineer SDV
Adam ShapiroProgram ManagerDonn TerrySoftware Development Engineer PFD
Session OutlineStatic analysis tools:
What they areBenefits
PREfast for Drivers (PFD)Static Driver Verifier (SDV)Summary
What Is Static Analysis?
Compile-time analysis of the source program:
Like code inspection, but performed by a tool.
Compile-time type-checking a simple example.
Looks for violations of well-defined constraints:
Procedure contracts or API contracts .
Examples of bugs found by Static Analysis:
p = NULL;…f(p);
f() requires p to be non-NULL
Completing the same IRP twice:
IoCompleteRequest (IRP);
...
IoCompleteRequest (IRP);
Why Static Analysis?
Cheap bugs!Rule of thumb
“A defect that costs $1 to fix on the programmer’s desktop costs $100 tofix once it is incorporated into a complete program and many thousands of dollarsif it is identified only after the softwarehas been deployed in the field.”“Building a Better Bug Trap” – The Economist, June
2003
Tools That Make You More Effective
Push-button technology.
100% path coverage:
At little cost (let a computer do it)
Quickly (minutes or hours versus weeks)
Defects are discovered early:
Even before device hardware is available
Before designing test cases
Often while still coding
Defect reports are easy to use:
A direct reference to the defective path (or point)in the source code reduces cost of debugging
Static Analysis – How Does It Work?
The tool builds an abstract model of a driver and exhaustively inspects execution along all paths:
The abstract model is simpler: it’s reduced...
It’s so much simpler that it’s possible to have it inspected (“simulated”) exhaustively.
Over-approximation of the driver:The control part remains the same .
All paths are preserved and treated equally .
The data state is over-approximated.
if argument x is not constrained, assume any value .
if (x>0) guards the point of interest, keep track of Boolean (x>0),but not integer value of x: Boolean is simpler than integer.
if (x > 0) { IoCompleteRequest (Irp); }
Static Analysis – Not a Silver Bullet
Does not replace functional testing.
Targets violations of a given set of well-defined constraints.
Principal limitations:It doesn’t know about every possible error.
Algorithms are based on source code abstraction and heuristics, which results in both false positives and false negatives.
It is a useful tool.
Our Static Tools for Drivers
PREfast For Drivers (PFD):Lightweight and fast (runs in minutes).
Easy to use early in development – start early:
Use on any code that compiles.
Limited to procedure scope.
Works on any code, C and C++.
Finds many local violations.
Static Driver Verifier (SDV):Extremely deep analysis (runs in hours).
More useful in the later stages of development:
Requires complete driver.
Works over the whole driver (inter-procedural).
Limited to WDM and KMDF and to C (more planned).
Think: Compile –Time Driver Verifier.
Finds deep bugs.
Driver Tools Relationship
Easy Reproducibility Hard
Depth
DriverVerifier Static Driver
Verifier
PREfast for drivers
HardEase of Use
Complex
A problem has been detected and Windows has been shut down to prevent damage to your computer.
DRIVER_IRQL_NOT_LESS_OR_EQUAL
If this is the first time you've seen this stop error screen,restart your computer. If this screen appears again, followthese steps:
Check to make sure any new hardware or software is properly installed.If this is a new installation, ask your hardware or softwareManufacturer for any Windows updates you might need.
If problems continue, disable or remove any newly installed hardwareor software. Disable BIOS memory options such as caching or shadowing.If you need to use Safe Mode to remove or disable components, restartyour computer, press F8 to select Advanced Startup Options, and thenselect Safe Mode
Technical information:
*** STOP: 0x00000001 (0x0000000,00000002,0x00000000,0x00000000)
PFD: PREfast For DriversFast (2 to 5 times compile time, usually).
Finds many “inadvertent” errors and some “hard” ones.
Works on code that compiles; doesn’t need to run.
Some things it can find:Null pointer and uninitialized variable (along an unusual path)
Local leaks (memory and resource)
Mismatched parameters
Forgot to check result
Format/list mismatch
Misuse of IRQLs (some)
Various special cases that are easily missed (such as Cancel IRQL)
Proper use of callback/function pointers
PFD: Driver-Specific Resource Leakvoid LeakSample(BOOLEAN Option1){ NTSTATUS Status; KIRQL OldIrql; BufInfo *pBufInfo; KeAcquireSpinLock(MyLock,&OldIrql); //... if (Option1) { pBufInfo = ExAllocatePoolWithTag(NonPagedPool, sizeof(BufInfo), 'fuB_'); if (NULL==pBufInfo) { return STATUS_NO_MEMORY; } //...
KeReleaseSpinLock(MyLock, OldIrql); return STATUS_SUCCESS;}//...
void LeakSample(BOOLEAN Option1){ NTSTATUS Status; KIRQL OldIrql; BufInfo *pBufInfo; KeAcquireSpinLock(MyLock,&OldIrql); //... if (Option1) { pBufInfo = ExAllocatePoolWithTag(NonPagedPool, sizeof(BufInfo), 'fuB_'); if (NULL==pBufInfo) { return STATUS_NO_MEMORY; } //...
KeReleaseSpinLock(MyLock, OldIrql); return STATUS_SUCCESS;}//...
PFD: Driver-Specific Resource Leak
warning 28103: Leaking the resource stored in 'SpinLock:MyLock'.
void LeakSample(BOOLEAN Option1){ NTSTATUS Status; KIRQL OldIrql; BufInfo *pBufInfo; KeAcquireSpinLock(MyLock,&OldIrql); //... if (Option1) { pBufInfo = ExAllocatePoolWithTag(NonPagedPool, sizeof(BufInfo), 'fuB_'); if (NULL==pBufInfo) { KeReleaseSpinLock(MyLock, OldIrql); return STATUS_NO_MEMORY; } //...
KeReleaseSpinLock(MyLock, OldIrql); return STATUS_SUCCESS;}//…
PFD: Driver-Specific Resource Leak
Why Annotate?Good Engineering Practice
Precisely describe the “part” you’re building and the contract that represents.Enable automatic checking. Tells tools things they can’t infer.Effective (and checked) documentation:
Programmers don’t have to guess/experiment.
Code and documentation don’t drift apart.
Comments are nice, but…
Annotation BenefitsRecord and express the contract:
Developers know what the contract is.
Is the contract a good one?
Automatic checking: that is, “cheap” bugs:
The sooner a bug is found, the less expensive it is to fix.
Annotated code finds many more bugs (with less noise) than un-annotated code.
Code that enters test with fewer “easy” bugs makes testing far more efficient – less wasted time for finding and fixing easy bugs.
PFD: Annotations – Example
wchar_t * wmemset( __out_ecount(s) wchar_t *p, __in wchar_t v, __in size_t s);
__in: the parameter is input to the function
__out: the parameter is output from the function
__out_ecount(s): the parameter is a buffer with s elements
If the parameter p doesn’t contain at least s elements, PFD will yield a warning.
PFD - Callback Annotations
typedefVOIDDRIVER_CANCEL ( __in struct _DEVICE_OBJECT *DeviceObject, __in struct _IRP *Irp );
typedef DRIVER_CANCEL *PDRIVER_CANCEL;
wdm.h
Driver.h DRIVER_CANCEL MyCancel;
Driver.c VOIDMyCancel ( struct _DEVICE_OBJECT *DeviceObject, struct _IRP *Irp ) { … }
Problem: Floating Point
If your driver uses floating point, you must be very careful to protect the hardware.
It’s easy to forget that you used it.
It’s very hard to find in test, typically not repeatable, and blue-screen is the preferable symptom.
It can span multiple functions.
longintSqrt(long i){ return (long) sqrt((double)i);}
Example: Floating Point
Example: Floating Point
longintSqrt(long i){ return (long) sqrt((double)i);}
…if (KeSaveFloatingPointState(b)){ … intSqrt(…) … KeRestoreFloatingPointState(b);}else // deal with error
… intSqrt(…) ……
Example: Floating Point
__drv_floatUsedlongintSqrt(long i){ return (long) sqrt((double)i);}
…if (KeSaveFloatingPointState(b)){ … intSqrt(…) … KeRestoreFloatingPointState(b);}else // deal with error
… intSqrt(…) ……
Static Driver Verifier
Jakob LichtenbergSoftware Development EngineerMicrosoft Corporation
Static Analysis Tools for Drivers
Two complementary technologies provided in the WDK:
PREfast for Drivers: Look inside every procedure for possible violations.
Static Driver Verifier: Look along paths, cross inter-procedural boundaries.ReadFoo ( PIRP Irp )
{ PIRP p = NULL; ... if (status) { IoCompleteRequest(p); }}
ReadFoo ( PIRP Irp ) { ... status = Bar (Irp); if (status) { IoCompleteRequest(Irp); } }
Bar ( PIRP Irp ) { ... IoCompleteRequest(Irp); return STATUS_SUCCESS;}
XX
XX
Static Analysis Tools for DriversPREfast for Drivers (PFD):
Lightweight and fast (runs in minutes).
Easy to use early in development – start early.
Use on any code that compiles.
Limited to a procedure scope; each procedure analyzed independently.
Annotations improve precision.
Works on any code, C and C++.
Finds many local violations.
Static Driver Verifier (SDV):
Extremely deep analysis (runs in hours).
More useful in the later stages of development.
Requires complete driver.
Works over the whole driver, along every path, crossing inter-procedural boundaries.
Annotations not necessary.
Limited to WDM or KMDF and to C.
Finds a few deep bugs.
Static Driver Verifier
What Static Driver Verifier does:Global analysis of entire driver.
Looks for violations of DDI constraints.
SDV for WDM:68 rules covering aspects such as IRPs, IRQL, Plug and Play, and synchronization rules.
New: SDV for KMDF:52 rules covering aspects such as DDI ordering, device initialization, request completion, and request cancellation.
Availability: from Windows Longhorn Server WDK.
Limitations:Only pure C drivers.
Up to 50 K lines of code.
Example
Device DriverInterface
IoCompleteRequest
Driver
Dispatch Routine
I/O System
Irp
Irp Irp
Example
Device DriverInterface
IoCompleteRequest
Driver
Dispatch Routine
I/O System
Irp
Irp Irp
XX
Example
Parport driver sample in Win XP SP1 DDK
Example
One defect foundXX
First CompletionDouble Completion
Example
Rule Passesü
Server 2003 SP1 DDK
Example
PptDispatchClose ( Irp ) P4CompleteRequest ( Irp )
IoCompleteRequest( Irp );XX
PptFdoClose( Irp )
P4CompleteRequestReleaseRemLoc ( Irp )
IOMngr
Concepts
library.c
more_code.c
driver.c
üXXSDV
Concepts
SDVRules
Verification Engine
OS Model
library.c
more_code.c
driver.c
üXX
Rules
SDVVerificatio
n Engine
OS Model
library.c
more_code.c
driver.c
Rules
üXX
A DDI Constraint Is…A Rule
Rule 1
…One More Rule…
Rule 2
…And Yet Another Rule
Rule 3
Rules
SDV comes with:68 WDM rules52 KMDF rules
Each rule captures an aspect of an interface requirements.Rules are written in a C-like language and define:
State declarations in form of C-style variables.Events that are associated with DDI functions.
SpinLock Rule
Device DriverInterface
KeAcquire SpinLock
KeRelease
SpinLock
Driver
Entry Point
I/O System
SpinLock Rule
Device DriverInterface
KeAcquire SpinLock
KeRelease
SpinLock
Driver
Entry Point
I/O System
state { enum {unlocked, locked} s = unlocked;}
Abort
Acq
uir
e Rele
ase
Dri
ver
calle
d
Driv
er re
turn
s
Unlocked
Acquire
Driver r
eturn
s
Locked
Release
SpinLock Rule
Device DriverInterface
KeAcquire SpinLock
KeRelease
SpinLock
Driver
Entry Point
I/O System
RunDispatchFunction.exit{ if (s != unlocked) abort;}
KeAcquireSpinLock.entry{ if (s != unlocked) abort; else s = locked;}
KeReleaseSpinLock.entry{ if (s != locked) abort; else s = unlocked;}
state { enum {unlocked, locked} s = unlocked;}
Operating System Model
SDVVerificatio
n Engine
library.c
more_code.c
driver.c
Rules
OS Model
üXX
Operating System Model
Exercises the driver:Calls DriverEntryCalls Dispatch functionsCalls ISRs
Models certain aspects of the operating system state:
Like the current interrupt request level (IRQL)
Models device driver interface functions:
Like the IoCallDriver DDI
Device DriverInterface
Driver
I/O System
Operating System Model
Device DriverInterface
Driver
void main() { int choice, status; … status = DriverEntry(…); … status = AddDevice(…); … … switch (choice) { case 0: status = DriverRead(…); break; case 1: status = DriverWrite(…); break; … case 28: status = DriverCreate(…); break; default: status = DriverClose(…); break; }}
I/O System
Clos
e
Crea
te
Writ
e
Read
Dri
verE
ntr
y
AddD
evic
e
…
…
Operating System Model
Device DriverInterface
Driver
NTSTATUS IoCallDriver( …, PIRP Irp ) { int choice; … switch (choice) { case 0: … Irp->PendingReturned = 0; return STATUS_SUCCESS;
case 1: … Irp->PendingReturned = 0; return STATUS_UNSUCCESSFUL;
default: … Irp->PendingReturned = 1; return STATUS_PENDING;;
}}
I/O System
IoCallDriver
SUCC
ESS
UNSUCCE
SSFU
L
PENDIN
G
…
Verification Engine
SDVlibrary.c
more_code.c
driver.c
Rules
OS Model
Verification Engine
üXX
Verification Engine: Example
Executes:Your driver in the context of the operating system model.
While keeping track of the rule state.
While looking for rule violations.
Checks each and every path of the driver.
Implements worst-case behavior.
Symbolic model checker:Strategy: Throw away many irrelevant details through aggressive, but correct, abstraction.
Device DriverInterface
Driver
I/O System
IoCallDriver
SUCC
ESS
UNSUCCE
SSFU
L
PENDIN
G
Clos
e
Crea
te
Writ
e
Read
Dri
verE
ntr
y
AddD
evic
e
…
…
Verification Engine: Example
Device DriverInterface
Driver
I/O System
IoCallDriver
SUCC
ESS
UNSUCCE
SSFU
L
PENDIN
G
Clos
e
Crea
te
Writ
e
Read
Dri
verE
ntr
y
AddD
evic
e
…
… Read
Write
Create Close
…
SUCCESS ü ü ü ü …
UNSUCCESFUL ü ü ü …
PENDING ü ü ü ü …
… … … … … …
XX
Quality
Comprehensive path coverage:
Driver is exercised in a hostile environment.
Verifies all possible paths in the drivers.
Verifies cross-function calls.
Verifies driver together with supporting libraries.
But there are places where SDV is imprecise:
Only one driver (not the entire driver stack).
Operating system model imperfect.
The verification engine is not precise.
ExperienceFinds deep bugs not found by testing:
1 bug on average for a sample driver in Server 2003 DDK-3677.
Well-tested drivers are often clean.
A dozen true bugs in a fresh driver.
Low noise level:Less than 1 false bug reported per driver.
2 real bugs for 1 false bug on DDK-3677 samples.
Performance:WDM: Runs in a few hours, but may need to run overnight.
KMDF: Much, much faster.
New: SDV will take advantage of all available CPU cores.
Static Analysis Can…
The business case:Reduce risk of expensive after-deployment bugs.
Reduce time to market.
Reduce cost of code review and testing.
Improve code quality.
Achieve higher
test coverage.
The development case:
Find/prevent bugs earlier.
More directly and obviously.
Find/prevent “hard-to-test” bugs.
Make you more efficient.
Use Static Analysis... Wisely
It doesn’t know about all possible errors.It doesn’t make testing unnecessary.Both false positives and false negatives can be misleading.Static Analysis Tools complement testing.
Static Analysis Tools for Drivers
PREfast for Drivers
Static Driver Verifier
Driver Models
Any WDMKMDF
Applicability
C and C++ C only
Issues found
Local defectsEasy to fixHigh volume
Global defectsHarder to fixLow volume
Development Cycle
Apply early: “When the driver compiles”
Run often…
Apply later:“When the basic structure of the driver is in place”
Run ad hoc or overnight…
Disclaimer© 2007 Microsoft Corporation. All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries.
The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.