-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathStrncpyFlippedArgs.ql
More file actions
130 lines (124 loc) · 4.14 KB
/
StrncpyFlippedArgs.ql
File metadata and controls
130 lines (124 loc) · 4.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/**
* @name Possibly wrong buffer size in string copy
* @description Calling 'strncpy' with the size of the source buffer
* as the third argument may result in a buffer overflow.
* @kind problem
* @problem.severity warning
* @security-severity 9.3
* @precision medium
* @id cpp/bad-strncpy-size
* @tags reliability
* correctness
* security
* external/cwe/cwe-676
* external/cwe/cwe-119
* external/cwe/cwe-251
*/
import cpp
import Buffer
private import semmle.code.cpp.valuenumbering.GlobalValueNumbering
predicate isSizePlus(Expr e, BufferSizeExpr baseSize, int plus) {
// baseSize
e = baseSize and plus = 0
or
exists(AddExpr ae, Expr operand1, Expr operand2, int plusSub |
// baseSize + n or n + baseSize
ae = e and
operand1 = ae.getAnOperand() and
operand2 = ae.getAnOperand() and
operand1 != operand2 and
isSizePlus(operand1, baseSize, plusSub) and
plus = plusSub + operand2.getValue().toInt()
)
or
exists(SubExpr se, int plusSub |
// baseSize - n
se = e and
isSizePlus(se.getLeftOperand(), baseSize, plusSub) and
plus = plusSub - se.getRightOperand().getValue().toInt()
)
}
predicate strncpyFunction(Function f, int argDest, int argSrc, int argLimit) {
exists(string name | name = f.getName() |
(
name = "strcpy_s" or // strcpy_s(dst, max_amount, src)
name = "wcscpy_s" or // wcscpy_s(dst, max_amount, src)
name = "_mbscpy_s" // _mbscpy_s(dst, max_amount, src)
) and
argDest = 0 and
argSrc = 2 and
argLimit = 1
or
(
name = "strncpy" or // strncpy(dst, src, max_amount)
name = "strncpy_l" or // strncpy_l(dst, src, max_amount, locale)
name = "wcsncpy" or // wcsncpy(dst, src, max_amount)
name = "_wcsncpy_l" or // _wcsncpy_l(dst, src, max_amount, locale)
name = "_mbsncpy" or // _mbsncpy(dst, src, max_amount)
name = "_mbsncpy_l" // _mbsncpy_l(dst, src, max_amount, locale)
) and
argDest = 0 and
argSrc = 1 and
argLimit = 2
)
}
string nthString(int num) {
num = 0 and
result = "first"
or
num = 1 and
result = "second"
or
num = 2 and
result = "third"
}
/**
* Gets the size of the expression, if it is initialized
* with a fixed size array.
*/
int arrayExprFixedSize(Expr e) {
result = e.getUnspecifiedType().(ArrayType).getSize()
or
result = e.(NewArrayExpr).getAllocatedType().(ArrayType).getSize()
or
exists(SsaDefinition def, LocalVariable v |
not e.getUnspecifiedType() instanceof ArrayType and
e = def.getAUse(v) and
result = arrayExprFixedSize(def.getDefiningValue(v))
)
}
from
Function f, FunctionCall fc, int argDest, int argSrc, int argLimit, int charSize, Access copyDest,
Access copySource, string name, string nth
where
f = fc.getTarget() and
strncpyFunction(f, argDest, argSrc, argLimit) and
copyDest = fc.getArgument(argDest) and
copySource = fc.getArgument(argSrc) and
// Some of the functions operate on a larger char type, like `wchar_t`, so we
// need to take this into account in the fixed size case.
charSize = f.getParameter(argDest).getUnspecifiedType().(PointerType).getBaseType().getSize() and
(
if exists(fc.getArgument(argLimit).getValue().toInt())
then
// Fixed sized case
exists(int size |
size = arrayExprFixedSize(copyDest) and
size < charSize * fc.getArgument(argLimit).getValue().toInt() and
size != 0 // if the array has zero size, something special is going on
)
else
exists(Access takenSizeOf, BufferSizeExpr sizeExpr, int plus |
// Variable sized case
sizeExpr = fc.getArgument(argLimit).getAChild*() and
isSizePlus(fc.getArgument(argLimit), sizeExpr, plus) and
plus >= 0 and
takenSizeOf = sizeExpr.getArg() and
globalValueNumber(copySource) = globalValueNumber(takenSizeOf) and // e.g. strncpy(x, y, strlen(y))
globalValueNumber(copyDest) != globalValueNumber(takenSizeOf) // e.g. strncpy(y, y, strlen(y))
)
) and
name = fc.getTarget().getName() and
nth = nthString(argLimit)
select fc,
"Potentially unsafe call to " + name + "; " + nth + " argument should be size of destination."