11/**
22 * @name Find all problematic implicit casts
33 * @description Find all implicit casts that may be problematic. That is, casts that may result in unexpected truncation, reinterpretation or widening of values.
4- * @kind problem
4+ * @kind path- problem
55 * @id tob/cpp/unsafe-implicit-conversions
66 * @tags security
7- * @problem.severity warning
8- * @precision medium
7+ * @problem.severity error
8+ * @precision high
99 */
1010
1111import cpp
@@ -15,17 +15,16 @@ private import experimental.semmle.code.cpp.rangeanalysis.ExtendedRangeAnalysis
1515private import experimental.semmle.code.cpp.models.interfaces.SimpleRangeAnalysisDefinition
1616private import experimental.semmle.code.cpp.rangeanalysis.RangeAnalysis
1717private import semmle.code.cpp.ir.IR
18- private import semmle.code.cpp.ir.ValueNumbering
19- import semmle.code.cpp.dataflow.new.TaintTracking
20- import semmle.code.cpp.models.interfaces.FlowSource
18+ private import semmle.code.cpp.ir.dataflow.TaintTracking
19+ private import semmle.code.cpp.security.FlowSources
2120
2221/**
2322 * Models standard I/O functions that return a length value bounded by their size argument
2423 * with possible -1 error return value
2524 */
2625private class LenApproxFunc extends SimpleRangeAnalysisExpr , FunctionCall {
2726 LenApproxFunc ( ) {
28- this .getTarget ( ) .hasName ( [ "recvfrom" , "recv" , "sendto" , "send" , "read" , "write" ] )
27+ this .getTarget ( ) .hasName ( [ "recvfrom" , "recv" , "sendto" , "send" , "read" , "write" , "readv" ] )
2928 }
3029
3130 override float getLowerBounds ( ) { result = - 1 }
@@ -36,18 +35,19 @@ private class LenApproxFunc extends SimpleRangeAnalysisExpr, FunctionCall {
3635}
3736
3837/*
39- * Uncomment the class below to silent findings that require large strings
40- * to be passed to strlen to be exploitable.
38+ * Silent findings that require passing large strings to strlen to be exploitable.
39+ * Remove this class to report unsafe implicit conversions from large strlen results
4140 */
41+ private class StrlenFunAssumption extends SimpleRangeAnalysisExpr , FunctionCall {
42+ StrlenFunAssumption ( ) { this .getTarget ( ) .hasName ( "strlen" ) }
43+
44+ override float getLowerBounds ( ) { result = 0 }
45+
46+ override float getUpperBounds ( ) { result = 536870912 }
47+
48+ override predicate dependsOnChild ( Expr child ) { none ( ) }
49+ }
4250
43- // private class StrlenFunAssumption extends SimpleRangeAnalysisExpr, FunctionCall {
44- // StrlenFunAssumption() {
45- // this.getTarget().hasName("strlen")
46- // }
47- // override float getLowerBounds() { result = 0 }
48- // override float getUpperBounds() { result = 536870912 }
49- // override predicate dependsOnChild(Expr child) { none() }
50- // }
5151/**
5252 * Determines if a function's address is taken in the codebase.
5353 * This indicates that the function may be called while
@@ -220,32 +220,33 @@ predicate safeBounds(Expr cast, IntegralType toType) {
220220
221221/*
222222 * Taint tracking from user-controlled inputs to implicit conversions
223- * UNUSED: uncomment code below and the code near "select" statement at the bottom of the file
224223 */
224+ module UserInputToImplicitConversionConfig implements DataFlow:: ConfigSig {
225+ predicate isSource ( DataFlow:: Node source ) {
226+ exists ( RemoteFlowSourceFunction remoteFlow | remoteFlow = source .asExpr ( ) .( Call ) .getTarget ( ) )
227+ or
228+ exists ( LocalFlowSourceFunction localFlow | localFlow = source .asExpr ( ) .( Call ) .getTarget ( ) )
229+ or
230+ source instanceof RemoteFlowSource
231+ or
232+ source instanceof LocalFlowSource
233+ }
234+
235+ predicate isSink ( DataFlow:: Node sink ) {
236+ exists ( IntegralConversion cast |
237+ cast .isImplicit ( ) and
238+ cast .getExpr ( ) = sink .asExpr ( )
239+ )
240+ }
241+ }
242+
243+ module UserInputToImplicitConversionConfigFlow = TaintTracking:: Global< UserInputToImplicitConversionConfig > ;
244+ import UserInputToImplicitConversionConfigFlow:: PathGraph
225245
226- // module UnsafeUserInputConversionConfig implements DataFlow::ConfigSig {
227- // predicate isSource(DataFlow::Node source) {
228- // exists(RemoteFlowSourceFunction remoteFlow |
229- // remoteFlow = source.asExpr().(Call).getTarget() and
230- // remoteFlow.hasRemoteFlowSource(_, _)
231- // )
232- // or
233- // exists(LocalFlowSourceFunction localFlow |
234- // localFlow = source.asExpr().(Call).getTarget() and
235- // localFlow.hasLocalFlowSource(_, _)
236- // )
237- // }
238- // predicate isSink(DataFlow::Node sink) {
239- // exists(IntegralConversion cast |
240- // cast.isImplicit() and
241- // cast.getExpr() = sink.asExpr()
242- // )
243- // }
244- // }
245- // module UnsafeUserInputConversionFlow = TaintTracking::Global<UnsafeUserInputConversionConfig>;
246246from
247247 IntegralConversion cast , IntegralType fromType , IntegralType toType , Expr castExpr ,
248- string problemType
248+ string problemType , UserInputToImplicitConversionConfigFlow:: PathNode source ,
249+ UserInputToImplicitConversionConfigFlow:: PathNode sink
249250where
250251 cast .getExpr ( ) = castExpr and
251252 // only implicit conversions
@@ -308,7 +309,7 @@ where
308309 upperBound ( secondHandSide ) < ( typeUpperBound ( toType ) + typeLowerBound ( fromType ) )
309310 )
310311 ) and
311- // skip unused function
312+ // skip unused functions
312313 (
313314 exists ( FunctionCall fc | fc .getTarget ( ) = cast .getEnclosingFunction ( ) )
314315 or
@@ -317,10 +318,9 @@ where
317318 cast .getEnclosingFunction ( ) .getName ( ) = "main"
318319 or
319320 addressIsTaken ( cast .getEnclosingFunction ( ) )
320- )
321- // UNUSED: Uncomment to report conversions with untrusted inputs only
322- // and exists(DataFlow::Node source, DataFlow::Node sink |
323- // castExpr = sink.asExpr() and
324- // UnsafeUserInputConversionFlow::flow(source, sink)
325- // )
326- select cast , "Implicit cast from " + fromType + " to " + toType + " (" + problemType + ")"
321+ ) and
322+ // tainted by user-provided data
323+ castExpr = sink .getNode ( ) .asExpr ( ) and
324+ UserInputToImplicitConversionConfigFlow:: flowPath ( source , sink )
325+ select sink .getNode ( ) , source , sink ,
326+ "Implicit cast from " + fromType + " to " + toType + " (" + problemType + ")"
0 commit comments