Skip to content

Commit e4c8406

Browse files
committed
C++: Split strlcat off in a separate model
1 parent a051a57 commit e4c8406

File tree

1 file changed

+70
-3
lines changed
  • cpp/ql/lib/semmle/code/cpp/models/implementations

1 file changed

+70
-3
lines changed

cpp/ql/lib/semmle/code/cpp/models/implementations/Strcat.qll

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import semmle.code.cpp.models.interfaces.SideEffect
1010

1111
/**
1212
* The standard function `strcat` and its wide, sized, and Microsoft variants.
13+
*
14+
* Does not include `strlcat`, which is covered by `StrlcatFunction`
1315
*/
1416
class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, SideEffectFunction {
1517
StrcatFunction() {
@@ -25,8 +27,7 @@ class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, Sid
2527
"_mbsncat", // _mbsncat(dst, src, max_amount)
2628
"_mbsncat_l", // _mbsncat_l(dst, src, max_amount, locale)
2729
"_mbsnbcat", // _mbsnbcat(dest, src, count)
28-
"_mbsnbcat_l", // _mbsnbcat_l(dest, src, count, locale)
29-
"strlcat" // strlcat(dst, src, dst_size)
30+
"_mbsnbcat_l" // _mbsnbcat_l(dest, src, count, locale)
3031
])
3132
}
3233

@@ -52,7 +53,7 @@ class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, Sid
5253

5354
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
5455
(
55-
this.getName() = ["strncat", "strlcat", "wcsncat", "_mbsncat", "_mbsncat_l"] and
56+
this.getName() = ["strncat", "wcsncat", "_mbsncat", "_mbsncat_l"] and
5657
input.isParameter(2)
5758
or
5859
this.getName() = ["_mbsncat_l", "_mbsnbcat_l"] and
@@ -91,3 +92,69 @@ class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, Sid
9192
buffer = true
9293
}
9394
}
95+
96+
/**
97+
* The `strlcat` function.
98+
*/
99+
class StrlcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, SideEffectFunction {
100+
StrlcatFunction() {
101+
this.hasGlobalName("strlcat") // strlcat(dst, src, dst_size)
102+
}
103+
104+
/**
105+
* Gets the index of the parameter that is the size of the copy (in characters).
106+
*/
107+
int getParamSize() { exists(this.getParameter(2)) and result = 2 }
108+
109+
/**
110+
* Gets the index of the parameter that is the source of the copy.
111+
*/
112+
int getParamSrc() { result = 1 }
113+
114+
/**
115+
* Gets the index of the parameter that is the destination to be appended to.
116+
*/
117+
int getParamDest() { result = 0 }
118+
119+
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
120+
input.isParameter(0) and
121+
output.isReturnValue()
122+
}
123+
124+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
125+
(
126+
input.isParameter(2)
127+
or
128+
input.isParameterDeref(0)
129+
or
130+
input.isParameterDeref(1)
131+
) and
132+
(output.isParameterDeref(0) or output.isReturnValueDeref())
133+
}
134+
135+
override predicate hasArrayInput(int param) {
136+
param = 0 or
137+
param = 1
138+
}
139+
140+
override predicate hasArrayOutput(int param) { param = 0 }
141+
142+
override predicate hasArrayWithNullTerminator(int param) { param = 1 }
143+
144+
override predicate hasArrayWithUnknownSize(int param) { param = 0 }
145+
146+
override predicate hasOnlySpecificReadSideEffects() { any() }
147+
148+
override predicate hasOnlySpecificWriteSideEffects() { any() }
149+
150+
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
151+
i = 0 and
152+
buffer = true and
153+
mustWrite = false
154+
}
155+
156+
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
157+
(i = 0 or i = 1) and
158+
buffer = true
159+
}
160+
}

0 commit comments

Comments
 (0)