@@ -15,177 +15,14 @@ import cpp
1515import semmle.code.cpp.dataflow.new.DataFlow
1616import semmle.code.cpp.ir.IR
1717import FlowAfterFree
18- import UseAfterFree:: PathGraph
18+ import UseAfterFree
19+ import UseAfterFreeTrace:: PathGraph
1920
20- /**
21- * Holds if `call` is a call to a function that obviously
22- * doesn't dereference its `i`'th argument.
23- */
24- private predicate externalCallNeverDereferences ( FormattingFunctionCall call , int arg ) {
25- exists ( int formatArg |
26- pragma [ only_bind_out ] ( call .getFormatArgument ( formatArg ) ) =
27- pragma [ only_bind_out ] ( call .getArgument ( arg ) ) and
28- call .getFormat ( ) .( FormatLiteral ) .getConvSpec ( formatArg ) != "%s"
29- )
30- }
31-
32- predicate isUse0 ( Expr e ) {
33- not isFree ( _, _, e , _) and
34- (
35- e = any ( PointerDereferenceExpr pde ) .getOperand ( )
36- or
37- e = any ( PointerFieldAccess pfa ) .getQualifier ( )
38- or
39- e = any ( ArrayExpr ae ) .getArrayBase ( )
40- or
41- e = any ( Call call ) .getQualifier ( )
42- or
43- // Assume any function without a body will dereference the pointer
44- exists ( int i , Call call , Function f |
45- e = call .getArgument ( i ) and
46- f = call .getTarget ( ) and
47- not f .hasEntryPoint ( ) and
48- // Exclude known functions we know won't dereference the pointer.
49- // For example, a call such as `printf("%p", myPointer)`.
50- not externalCallNeverDereferences ( call , i )
51- )
52- )
53- }
54-
55- module ParameterSinks {
56- import semmle.code.cpp.ir.ValueNumbering
57-
58- predicate flowsToUse ( DataFlow:: Node n ) {
59- isUse0 ( n .asExpr ( ) )
60- or
61- exists ( DataFlow:: Node succ |
62- flowsToUse ( succ ) and
63- DataFlow:: localFlowStep ( n , succ )
64- )
65- }
66-
67- private predicate flowsFromParam ( DataFlow:: Node n ) {
68- flowsToUse ( n ) and
69- (
70- n .asParameter ( ) .getUnspecifiedType ( ) instanceof PointerType
71- or
72- exists ( DataFlow:: Node prev |
73- flowsFromParam ( prev ) and
74- DataFlow:: localFlowStep ( prev , n )
75- )
76- )
77- }
78-
79- private predicate step ( DataFlow:: Node n1 , DataFlow:: Node n2 ) {
80- flowsFromParam ( n1 ) and
81- flowsFromParam ( n2 ) and
82- DataFlow:: localFlowStep ( n1 , n2 )
83- }
84-
85- private predicate paramToUse ( DataFlow:: Node n1 , DataFlow:: Node n2 ) = fastTC( step / 2 ) ( n1 , n2 )
86-
87- private predicate hasFlow (
88- DataFlow:: Node source , InitializeParameterInstruction init , DataFlow:: Node sink
89- ) {
90- pragma [ only_bind_out ] ( source .asParameter ( ) ) = pragma [ only_bind_out ] ( init .getParameter ( ) ) and
91- paramToUse ( source , sink ) and
92- isUse0 ( sink .asExpr ( ) )
93- }
94-
95- private InitializeParameterInstruction getAnAlwaysDereferencedParameter0 ( ) {
96- exists ( DataFlow:: Node source , DataFlow:: Node sink , IRBlock b1 , int i1 , IRBlock b2 , int i2 |
97- hasFlow ( pragma [ only_bind_into ] ( source ) , result , pragma [ only_bind_into ] ( sink ) ) and
98- source .hasIndexInBlock ( b1 , pragma [ only_bind_into ] ( i1 ) ) and
99- sink .hasIndexInBlock ( b2 , pragma [ only_bind_into ] ( i2 ) ) and
100- strictlyPostDominates ( b2 , i2 , b1 , i1 )
101- )
102- }
103-
104- private CallInstruction getAnAlwaysReachedCallInstruction ( ) {
105- exists ( IRFunction f | result .getBlock ( ) .postDominates ( f .getEntryBlock ( ) ) )
106- }
107-
108- pragma [ nomagic]
109- private predicate callHasTargetAndArgument ( Function f , int i , Instruction argument ) {
110- exists ( CallInstruction call |
111- call .getStaticCallTarget ( ) = f and
112- call .getArgument ( i ) = argument and
113- call = getAnAlwaysReachedCallInstruction ( )
114- )
115- }
116-
117- pragma [ nomagic]
118- private predicate initializeParameterInFunction ( Function f , int i ) {
119- exists ( InitializeParameterInstruction init |
120- pragma [ only_bind_out ] ( init .getEnclosingFunction ( ) ) = f and
121- init .hasIndex ( i ) and
122- init = getAnAlwaysDereferencedParameter ( )
123- )
124- }
125-
126- pragma [ nomagic]
127- private predicate alwaysDereferencedArgumentHasValueNumber ( ValueNumber vn ) {
128- exists ( int i , Function f , Instruction argument |
129- callHasTargetAndArgument ( f , i , argument ) and
130- initializeParameterInFunction ( pragma [ only_bind_into ] ( f ) , pragma [ only_bind_into ] ( i ) ) and
131- vn .getAnInstruction ( ) = argument
132- )
133- }
134-
135- InitializeParameterInstruction getAnAlwaysDereferencedParameter ( ) {
136- result = getAnAlwaysDereferencedParameter0 ( )
137- or
138- exists ( ValueNumber vn |
139- alwaysDereferencedArgumentHasValueNumber ( vn ) and
140- vn .getAnInstruction ( ) = result
141- )
142- }
143- }
144-
145- module IsUse {
146- private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplCommon
147-
148- predicate isUse ( DataFlow:: Node n , Expr e ) {
149- isUse0 ( e ) and n .asExpr ( ) = e
150- or
151- exists ( CallInstruction call , InitializeParameterInstruction init |
152- n .asOperand ( ) .getDef ( ) .getUnconvertedResultExpression ( ) = e and
153- pragma [ only_bind_into ] ( init ) = ParameterSinks:: getAnAlwaysDereferencedParameter ( ) and
154- viableParamArg ( call , DataFlow:: instructionNode ( init ) , n ) and
155- pragma [ only_bind_out ] ( init .getEnclosingFunction ( ) ) =
156- pragma [ only_bind_out ] ( call .getStaticCallTarget ( ) )
157- )
158- }
159- }
160-
161- import IsUse
162-
163- /**
164- * `dealloc1` is a deallocation expression, `e` is an expression that dereferences a
165- * pointer, and the `(dealloc1, e)` pair should be excluded by the `FlowFromFree` library.
166- */
167- bindingset [ dealloc1, e]
168- predicate isExcludeFreeUsePair ( DeallocationExpr dealloc1 , Expr e ) {
169- // From https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-mmfreepagesfrommdl:
170- // "After calling MmFreePagesFromMdl, the caller must also call ExFreePool
171- // to release the memory that was allocated for the MDL structure."
172- dealloc1 .( FunctionCall ) .getTarget ( ) .hasGlobalName ( "MmFreePagesFromMdl" ) and
173- isExFreePoolCall ( _, e )
174- }
175-
176- module UseAfterFreeParam implements FlowFromFreeParamSig {
177- predicate isSink = isUse / 2 ;
178-
179- predicate isExcluded = isExcludeFreeUsePair / 2 ;
180-
181- predicate sourceSinkIsRelated = defaultSourceSinkIsRelated / 2 ;
182- }
183-
184- module UseAfterFree = FlowFromFree< UseAfterFreeParam > ;
21+ module UseAfterFreeTrace = FlowFromFree< UseAfterFreeParam > ;
18522
186- from UseAfterFree :: PathNode source , UseAfterFree :: PathNode sink , DeallocationExpr dealloc
23+ from UseAfterFreeTrace :: PathNode source , UseAfterFreeTrace :: PathNode sink , DeallocationExpr dealloc
18724where
188- UseAfterFree :: flowPath ( source , sink ) and
25+ UseAfterFreeTrace :: flowPath ( source , sink ) and
18926 isFree ( source .getNode ( ) , _, _, dealloc )
19027select sink .getNode ( ) , source , sink , "Memory may have been previously freed by $@." , dealloc ,
19128 dealloc .toString ( )
0 commit comments