Skip to content

Commit 3a62628

Browse files
authored
Merge pull request #14735 from jketema/strl
C++: Add models for `strlcpy` and `strlcat`
2 parents 18c0bce + b48d483 commit 3a62628

File tree

3 files changed

+79
-4
lines changed

3 files changed

+79
-4
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Added models for `strlcpy` and `strlcat`.

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

Lines changed: 63 additions & 0 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() {
@@ -90,3 +92,64 @@ class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, Sid
9092
buffer = true
9193
}
9294
}
95+
96+
/**
97+
* The `strlcat` function.
98+
*/
99+
class StrlcatFunction extends TaintFunction, 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() { 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 hasTaintFlow(FunctionInput input, FunctionOutput output) {
120+
(
121+
input.isParameter(2)
122+
or
123+
input.isParameterDeref(0)
124+
or
125+
input.isParameterDeref(1)
126+
) and
127+
output.isParameterDeref(0)
128+
}
129+
130+
override predicate hasArrayInput(int param) {
131+
param = 0 or
132+
param = 1
133+
}
134+
135+
override predicate hasArrayOutput(int param) { param = 0 }
136+
137+
override predicate hasArrayWithNullTerminator(int param) { param = 1 }
138+
139+
override predicate hasArrayWithUnknownSize(int param) { param = 0 }
140+
141+
override predicate hasOnlySpecificReadSideEffects() { any() }
142+
143+
override predicate hasOnlySpecificWriteSideEffects() { any() }
144+
145+
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
146+
i = 0 and
147+
buffer = true and
148+
mustWrite = false
149+
}
150+
151+
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
152+
(i = 0 or i = 1) and
153+
buffer = true
154+
}
155+
}

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

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid
3232
"wcsxfrm_l", // _strxfrm_l(dest, src, max_amount, locale)
3333
"_mbsnbcpy", // _mbsnbcpy(dest, src, max_amount)
3434
"stpcpy", // stpcpy(dest, src)
35-
"stpncpy" // stpcpy(dest, src, max_amount)
35+
"stpncpy", // stpncpy(dest, src, max_amount)
36+
"strlcpy" // strlcpy(dst, src, dst_size)
3637
])
3738
or
3839
(
@@ -53,14 +54,19 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid
5354
*/
5455
private predicate isSVariant() { this.getName().matches("%\\_s") }
5556

57+
/**
58+
* Holds if the function returns the total length the string would have had if the size was unlimited.
59+
*/
60+
private predicate returnsTotalLength() { this.getName() = "strlcpy" }
61+
5662
/**
5763
* Gets the index of the parameter that is the maximum size of the copy (in characters).
5864
*/
5965
int getParamSize() {
6066
if this.isSVariant()
6167
then result = 1
6268
else (
63-
this.getName().matches(["%ncpy%", "%nbcpy%", "%xfrm%"]) and
69+
this.getName().matches(["%ncpy%", "%nbcpy%", "%xfrm%", "strlcpy"]) and
6470
result = 2
6571
)
6672
}
@@ -100,6 +106,7 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid
100106
input.isParameterDeref(this.getParamSrc()) and
101107
output.isReturnValueDeref()
102108
or
109+
not this.returnsTotalLength() and
103110
input.isParameter(this.getParamDest()) and
104111
output.isReturnValue()
105112
}
@@ -110,8 +117,9 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid
110117
exists(this.getParamSize()) and
111118
input.isParameterDeref(this.getParamSrc()) and
112119
(
113-
output.isParameterDeref(this.getParamDest()) or
114-
output.isReturnValueDeref()
120+
output.isParameterDeref(this.getParamDest())
121+
or
122+
not this.returnsTotalLength() and output.isReturnValueDeref()
115123
)
116124
}
117125

0 commit comments

Comments
 (0)