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