11import semmle.code.cpp.models.interfaces.ArrayFunction
22import semmle.code.cpp.models.interfaces.Taint
3+ import semmle.code.cpp.models.interfaces.DataFlow
34import semmle.code.cpp.models.interfaces.Alias
45import semmle.code.cpp.models.interfaces.SideEffect
56
@@ -8,7 +9,7 @@ import semmle.code.cpp.models.interfaces.SideEffect
89 * guaranteed to be side-effect free.
910 */
1011private class PureStrFunction extends AliasFunction , ArrayFunction , TaintFunction ,
11- SideEffectFunction
12+ SideEffectFunction , DataFlowFunction
1213{
1314 PureStrFunction ( ) {
1415 this .hasGlobalOrStdOrBslName ( [
@@ -25,23 +26,48 @@ private class PureStrFunction extends AliasFunction, ArrayFunction, TaintFunctio
2526 this .getParameter ( bufParam ) .getUnspecifiedType ( ) instanceof PointerType
2627 }
2728
29+ /** Holds if `i` is a locale parameter that does not carry taint. */
30+ private predicate isLocaleParameter ( ParameterIndex i ) {
31+ this .getName ( ) .matches ( "%\\_l" ) and i + 1 = this .getNumberOfParameters ( )
32+ }
33+
2834 override predicate hasTaintFlow ( FunctionInput input , FunctionOutput output ) {
35+ // For these functions we add taint flow according to the following rules:
36+ // 1. If the parameter is of a pointer type then there is taint from the
37+ // indirection of the parameter. Otherwise, there is taint from the
38+ // parameter.
39+ // 2. If the return value is of a pointer type then there is taint to the
40+ // indirection of the return. Otherwise, there is taint to the return.
2941 exists ( ParameterIndex i |
30- (
31- input .isParameter ( i ) and
32- exists ( this .getParameter ( i ) )
33- or
34- input .isParameterDeref ( i ) and
35- this .getParameter ( i ) .getUnspecifiedType ( ) instanceof PointerType
36- ) and
42+ exists ( this .getParameter ( i ) ) and
3743 // Functions that end with _l also take a locale argument (always as the last argument),
3844 // and we don't want taint from those arguments.
39- ( not this .getName ( ) .matches ( "%\\_l" ) or exists ( this .getParameter ( i + 1 ) ) )
45+ not this .isLocaleParameter ( i )
46+ |
47+ if this .getParameter ( i ) .getUnspecifiedType ( ) instanceof PointerType
48+ then input .isParameterDeref ( i )
49+ else input .isParameter ( i )
4050 ) and
4151 (
42- output .isReturnValueDeref ( ) and
43- this .getUnspecifiedType ( ) instanceof PointerType
44- or
52+ if this .getUnspecifiedType ( ) instanceof PointerType
53+ then output .isReturnValueDeref ( )
54+ else output .isReturnValue ( )
55+ )
56+ or
57+ // If there is taint flow from *input to *output then there is also taint
58+ // flow from input to output.
59+ this .hasTaintFlow ( input .getIndirectionInput ( ) , output .getIndirectionOutput ( ) ) and
60+ // No need to add taint flow if we already have data flow.
61+ not this .hasDataFlow ( input , output )
62+ }
63+
64+ override predicate hasDataFlow ( FunctionInput input , FunctionOutput output ) {
65+ exists ( int i |
66+ input .isParameter ( i ) and
67+ not this .isLocaleParameter ( i ) and
68+ // These functions always return the same pointer as they are given
69+ this .hasGlobalOrStdOrBslName ( [ strrev ( ) , strlwr ( ) , strupr ( ) ] ) and
70+ this .getParameter ( i ) .getUnspecifiedType ( ) instanceof PointerType and
4571 output .isReturnValue ( )
4672 )
4773 }
0 commit comments