@@ -8,70 +8,107 @@ import semmle.code.cpp.models.interfaces.SideEffect
8
8
*/
9
9
class StrcpyFunction extends ArrayFunction , DataFlowFunction , TaintFunction , SideEffectFunction {
10
10
StrcpyFunction ( ) {
11
- this .hasName ( "strcpy" ) or
12
- this .hasName ( "_mbscpy" ) or
13
- this .hasName ( "wcscpy" ) or
14
- this .hasName ( "strncpy" ) or
15
- this .hasName ( "_strncpy_l" ) or
16
- this .hasName ( "_mbsncpy" ) or
17
- this .hasName ( "_mbsncpy_l" ) or
18
- this .hasName ( "wcsncpy" ) or
19
- this .hasName ( "_wcsncpy_l" )
11
+ exists ( string name | name = getName ( ) |
12
+ // strcpy(dst, src)
13
+ name = "strcpy"
14
+ or
15
+ // wcscpy(dst, src)
16
+ name = "wcscpy"
17
+ or
18
+ // _mbscpy(dst, src)
19
+ name = "_mbscpy"
20
+ or
21
+ (
22
+ name = "strcpy_s" or // strcpy_s(dst, max_amount, src)
23
+ name = "wcscpy_s" or // wcscpy_s(dst, max_amount, src)
24
+ name = "_mbscpy_s" // _mbscpy_s(dst, max_amount, src)
25
+ ) and
26
+ // exclude the 2-parameter template versions
27
+ // that find the size of a fixed size destination buffer.
28
+ getNumberOfParameters ( ) = 3
29
+ or
30
+ // strncpy(dst, src, max_amount)
31
+ name = "strncpy"
32
+ or
33
+ // _strncpy_l(dst, src, max_amount, locale)
34
+ name = "_strncpy_l"
35
+ or
36
+ // wcsncpy(dst, src, max_amount)
37
+ name = "wcsncpy"
38
+ or
39
+ // _wcsncpy_l(dst, src, max_amount, locale)
40
+ name = "_wcsncpy_l"
41
+ or
42
+ // _mbsncpy(dst, src, max_amount)
43
+ name = "_mbsncpy"
44
+ or
45
+ // _mbsncpy_l(dst, src, max_amount, locale)
46
+ name = "_mbsncpy_l"
47
+ )
48
+ }
49
+
50
+ /**
51
+ * Holds if this is one of the `strcpy_s` variants.
52
+ */
53
+ private predicate isSVariant ( ) {
54
+ exists ( string name | name = getName ( ) | name .suffix ( name .length ( ) - 2 ) = "_s" )
55
+ }
56
+
57
+ /**
58
+ * Gets the index of the parameter that is the maximum size of the copy (in characters).
59
+ */
60
+ int getParamSize ( ) {
61
+ if isSVariant ( )
62
+ then result = 1
63
+ else
64
+ if exists ( getName ( ) .indexOf ( "ncpy" ) )
65
+ then result = 2
66
+ else none ( )
20
67
}
21
68
22
- override predicate hasArrayInput ( int bufParam ) { bufParam = 1 }
69
+ /**
70
+ * Gets the index of the parameter that is the source of the copy.
71
+ */
72
+ int getParamSrc ( ) { if isSVariant ( ) then result = 2 else result = 1 }
23
73
24
- override predicate hasArrayOutput ( int bufParam ) { bufParam = 0 }
74
+ /**
75
+ * Gets the index of the parameter that is the destination of the copy.
76
+ */
77
+ int getParamDest ( ) { result = 0 }
25
78
26
- override predicate hasArrayWithNullTerminator ( int bufParam ) { bufParam = 1 }
79
+ override predicate hasArrayInput ( int bufParam ) { bufParam = getParamSrc ( ) }
80
+
81
+ override predicate hasArrayOutput ( int bufParam ) { bufParam = getParamDest ( ) }
82
+
83
+ override predicate hasArrayWithNullTerminator ( int bufParam ) { bufParam = getParamSrc ( ) }
27
84
28
85
override predicate hasArrayWithVariableSize ( int bufParam , int countParam ) {
29
- (
30
- this .hasName ( "strncpy" ) or
31
- this .hasName ( "_strncpy_l" ) or
32
- this .hasName ( "_mbsncpy" ) or
33
- this .hasName ( "_mbsncpy_l" ) or
34
- this .hasName ( "wcsncpy" ) or
35
- this .hasName ( "_wcsncpy_l" )
36
- ) and
37
- bufParam = 0 and
38
- countParam = 2
86
+ bufParam = getParamDest ( ) and
87
+ countParam = getParamSize ( )
39
88
}
40
89
41
90
override predicate hasArrayWithUnknownSize ( int bufParam ) {
42
- (
43
- this .hasName ( "strcpy" ) or
44
- this .hasName ( "_mbscpy" ) or
45
- this .hasName ( "wcscpy" )
46
- ) and
47
- bufParam = 0
91
+ not exists ( getParamSize ( ) ) and
92
+ bufParam = getParamDest ( )
48
93
}
49
94
50
95
override predicate hasDataFlow ( FunctionInput input , FunctionOutput output ) {
51
- input .isParameterDeref ( 1 ) and
52
- output .isParameterDeref ( 0 )
96
+ input .isParameterDeref ( getParamSrc ( ) ) and
97
+ output .isParameterDeref ( getParamDest ( ) )
53
98
or
54
- input .isParameterDeref ( 1 ) and
99
+ input .isParameterDeref ( getParamSrc ( ) ) and
55
100
output .isReturnValueDeref ( )
56
101
or
57
- input .isParameter ( 0 ) and
102
+ input .isParameter ( getParamDest ( ) ) and
58
103
output .isReturnValue ( )
59
104
}
60
105
61
106
override predicate hasTaintFlow ( FunctionInput input , FunctionOutput output ) {
107
+ // these may do only a partial copy of the input buffer to the output
108
+ // buffer
109
+ input .isParameter ( getParamSize ( ) ) and
62
110
(
63
- // these may do only a partial copy of the input buffer to the output
64
- // buffer
65
- this .hasName ( "strncpy" ) or
66
- this .hasName ( "_strncpy_l" ) or
67
- this .hasName ( "_mbsncpy" ) or
68
- this .hasName ( "_mbsncpy_l" ) or
69
- this .hasName ( "wcsncpy" ) or
70
- this .hasName ( "_wcsncpy_l" )
71
- ) and
72
- input .isParameter ( 2 ) and
73
- (
74
- output .isParameterDeref ( 0 ) or
111
+ output .isParameterDeref ( getParamDest ( ) ) or
75
112
output .isReturnValueDeref ( )
76
113
)
77
114
}
@@ -81,17 +118,18 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid
81
118
override predicate hasOnlySpecificWriteSideEffects ( ) { any ( ) }
82
119
83
120
override predicate hasSpecificWriteSideEffect ( ParameterIndex i , boolean buffer , boolean mustWrite ) {
84
- i = 0 and
121
+ i = getParamDest ( ) and
85
122
buffer = true and
86
123
mustWrite = false
87
124
}
88
125
89
126
override predicate hasSpecificReadSideEffect ( ParameterIndex i , boolean buffer ) {
90
- i = 1 and
127
+ i = getParamSrc ( ) and
91
128
buffer = true
92
129
}
93
130
94
131
override ParameterIndex getParameterSizeIndex ( ParameterIndex i ) {
95
- hasArrayWithVariableSize ( i , result )
132
+ i = getParamDest ( ) and
133
+ result = getParamSize ( )
96
134
}
97
135
}
0 commit comments