@@ -8,70 +8,107 @@ import semmle.code.cpp.models.interfaces.SideEffect
88 */
99class StrcpyFunction extends ArrayFunction , DataFlowFunction , TaintFunction , SideEffectFunction {
1010 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 ( )
2067 }
2168
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 }
2373
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 }
2578
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 ( ) }
2784
2885 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 ( )
3988 }
4089
4190 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 ( )
4893 }
4994
5095 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 ( ) )
5398 or
54- input .isParameterDeref ( 1 ) and
99+ input .isParameterDeref ( getParamSrc ( ) ) and
55100 output .isReturnValueDeref ( )
56101 or
57- input .isParameter ( 0 ) and
102+ input .isParameter ( getParamDest ( ) ) and
58103 output .isReturnValue ( )
59104 }
60105
61106 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
62110 (
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
75112 output .isReturnValueDeref ( )
76113 )
77114 }
@@ -81,17 +118,18 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid
81118 override predicate hasOnlySpecificWriteSideEffects ( ) { any ( ) }
82119
83120 override predicate hasSpecificWriteSideEffect ( ParameterIndex i , boolean buffer , boolean mustWrite ) {
84- i = 0 and
121+ i = getParamDest ( ) and
85122 buffer = true and
86123 mustWrite = false
87124 }
88125
89126 override predicate hasSpecificReadSideEffect ( ParameterIndex i , boolean buffer ) {
90- i = 1 and
127+ i = getParamSrc ( ) and
91128 buffer = true
92129 }
93130
94131 override ParameterIndex getParameterSizeIndex ( ParameterIndex i ) {
95- hasArrayWithVariableSize ( i , result )
132+ i = getParamDest ( ) and
133+ result = getParamSize ( )
96134 }
97135}
0 commit comments