Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ade6d10

Browse files
author
Dave Bartolomeo
committed
Merge remote-tracking branch 'upstream/main' into work
2 parents 2eaa4a4 + 8b084ff commit ade6d10

12 files changed

Lines changed: 162 additions & 85 deletions

File tree

change-notes/1.26/analysis-cpp.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,6 @@ The following changes in version 1.26 affect C/C++ analysis in all applications.
2626
* The models library now models many taint flows through `std::istream` and `std::ostream`.
2727
* The models library now models some taint flows through `std::shared_ptr`, `std::unique_ptr`, `std::make_shared` and `std::make_unique`.
2828
* The models library now models many taint flows through `std::pair`, `std::map`, `std::unordered_map`, `std::set` and `std::unordered_set`.
29+
* The models library now models `bcopy`.
2930
* The `SimpleRangeAnalysis` library now supports multiplications of the form
3031
`e1 * e2` and `x *= e2` when `e1` and `e2` are unsigned or constant.

cpp/ql/src/semmle/code/cpp/controlflow/Dereferenced.qll

Lines changed: 11 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,47 +4,25 @@
44

55
import cpp
66
import Nullness
7+
import semmle.code.cpp.models.interfaces.ArrayFunction
78

89
/**
910
* Holds if the call `fc` will dereference argument `i`.
1011
*/
1112
predicate callDereferences(FunctionCall fc, int i) {
12-
exists(string name |
13-
fc.getTarget().hasGlobalOrStdName(name) and
13+
exists(ArrayFunction af |
14+
fc.getTarget() = af and
1415
(
15-
name = "bcopy" and i in [0 .. 1]
16-
or
17-
name = "memcpy" and i in [0 .. 1]
18-
or
19-
name = "memmove" and i in [0 .. 1]
20-
or
21-
name = "strcpy" and i in [0 .. 1]
22-
or
23-
name = "strncpy" and i in [0 .. 1]
24-
or
25-
name = "strdup" and i = 0
26-
or
27-
name = "strndup" and i = 0
28-
or
29-
name = "strlen" and i = 0
30-
or
31-
name = "printf" and fc.getArgument(i).getType() instanceof PointerType
32-
or
33-
name = "fprintf" and fc.getArgument(i).getType() instanceof PointerType
34-
or
35-
name = "sprintf" and fc.getArgument(i).getType() instanceof PointerType
36-
or
37-
name = "snprintf" and fc.getArgument(i).getType() instanceof PointerType
38-
or
39-
name = "vprintf" and fc.getArgument(i).getType() instanceof PointerType
40-
or
41-
name = "vfprintf" and fc.getArgument(i).getType() instanceof PointerType
42-
or
43-
name = "vsprintf" and fc.getArgument(i).getType() instanceof PointerType
44-
or
45-
name = "vsnprintf" and fc.getArgument(i).getType() instanceof PointerType
16+
af.hasArrayInput(i) or
17+
af.hasArrayOutput(i)
4618
)
4719
)
20+
or
21+
exists(FormattingFunction ff |
22+
fc.getTarget() = ff and
23+
i >= ff.getFirstFormatArgumentIndex() and
24+
fc.getArgument(i).getType() instanceof PointerType
25+
)
4826
}
4927

5028
/**

cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll

Lines changed: 40 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -10,64 +10,76 @@ import semmle.code.cpp.models.interfaces.SideEffect
1010
import semmle.code.cpp.models.interfaces.Taint
1111

1212
/**
13-
* The standard functions `memcpy` and `memmove`, and the gcc variant
14-
* `__builtin___memcpy_chk`
13+
* The standard functions `memcpy`, `memmove` and `bcopy`; and the gcc variant
14+
* `__builtin___memcpy_chk`.
1515
*/
16-
class MemcpyFunction extends ArrayFunction, DataFlowFunction, SideEffectFunction, TaintFunction {
16+
class MemcpyFunction extends ArrayFunction, DataFlowFunction, SideEffectFunction {
1717
MemcpyFunction() {
18-
this.hasName("memcpy") or
19-
this.hasName("memmove") or
20-
this.hasName("__builtin___memcpy_chk")
18+
// memcpy(dest, src, num)
19+
// memmove(dest, src, num)
20+
// memmove(dest, src, num, remaining)
21+
this.hasName(["memcpy", "memmove", "__builtin___memcpy_chk"])
22+
or
23+
// bcopy(src, dest, num)
24+
this.hasGlobalOrStdName("bcopy")
2125
}
2226

23-
override predicate hasArrayInput(int bufParam) { bufParam = 1 }
27+
/**
28+
* Gets the index of the parameter that is the source buffer for the copy.
29+
*/
30+
int getParamSrc() { if this.hasGlobalOrStdName("bcopy") then result = 0 else result = 1 }
31+
32+
/**
33+
* Gets the index of the parameter that is the destination buffer for the
34+
* copy.
35+
*/
36+
int getParamDest() { if this.hasGlobalOrStdName("bcopy") then result = 1 else result = 0 }
37+
38+
/**
39+
* Gets the index of the parameter that is the size of the copy (in bytes).
40+
*/
41+
int getParamSize() { result = 2 }
42+
43+
override predicate hasArrayInput(int bufParam) { bufParam = getParamSrc() }
2444

25-
override predicate hasArrayOutput(int bufParam) { bufParam = 0 }
45+
override predicate hasArrayOutput(int bufParam) { bufParam = getParamDest() }
2646

2747
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
28-
input.isParameterDeref(1) and
29-
output.isParameterDeref(0)
48+
input.isParameterDeref(getParamSrc()) and
49+
output.isParameterDeref(getParamDest())
3050
or
31-
input.isParameterDeref(1) and
51+
input.isParameterDeref(getParamSrc()) and
3252
output.isReturnValueDeref()
3353
or
34-
input.isParameter(0) and
54+
input.isParameter(getParamDest()) and
3555
output.isReturnValue()
3656
}
3757

38-
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
39-
input.isParameter(2) and
40-
output.isParameterDeref(0)
41-
or
42-
input.isParameter(2) and
43-
output.isReturnValueDeref()
44-
}
45-
4658
override predicate hasArrayWithVariableSize(int bufParam, int countParam) {
4759
(
48-
bufParam = 0 or
49-
bufParam = 1
60+
bufParam = getParamDest() or
61+
bufParam = getParamSrc()
5062
) and
51-
countParam = 2
63+
countParam = getParamSize()
5264
}
5365

5466
override predicate hasOnlySpecificReadSideEffects() { any() }
5567

5668
override predicate hasOnlySpecificWriteSideEffects() { any() }
5769

5870
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
59-
i = 0 and buffer = true and mustWrite = true
71+
i = getParamDest() and buffer = true and mustWrite = true
6072
}
6173

6274
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
63-
i = 1 and buffer = true
75+
i = getParamSrc() and buffer = true
6476
}
6577

6678
override ParameterIndex getParameterSizeIndex(ParameterIndex i) {
67-
result = 2 and
79+
result = getParamSize() and
6880
(
69-
i = 0 or
70-
i = 1
81+
i = getParamDest() or
82+
i = getParamSrc()
7183
)
7284
}
7385
}

cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5481,8 +5481,6 @@
54815481
| taint.cpp:194:10:194:10 | x | taint.cpp:194:9:194:10 | & ... | |
54825482
| taint.cpp:194:13:194:18 | source | taint.cpp:194:2:194:7 | call to memcpy | TAINT |
54835483
| taint.cpp:194:13:194:18 | source | taint.cpp:194:9:194:10 | ref arg & ... | TAINT |
5484-
| taint.cpp:194:21:194:31 | sizeof(int) | taint.cpp:194:2:194:7 | call to memcpy | TAINT |
5485-
| taint.cpp:194:21:194:31 | sizeof(int) | taint.cpp:194:9:194:10 | ref arg & ... | TAINT |
54865484
| taint.cpp:207:6:207:11 | call to source | taint.cpp:207:2:207:13 | ... = ... | |
54875485
| taint.cpp:207:6:207:11 | call to source | taint.cpp:210:7:210:7 | x | |
54885486
| taint.cpp:207:6:207:11 | call to source | taint.cpp:213:12:213:12 | x | |
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
| test.cpp:23:8:23:8 | p | Value may be null; it should be checked before dereferencing. |
2+
| test.cpp:35:10:35:10 | q | Value may be null; it should be checked before dereferencing. |
3+
| test.cpp:43:13:43:13 | q | Value may be null; it should be checked before dereferencing. |
4+
| test.cpp:51:17:51:17 | q | Value may be null; it should be checked before dereferencing. |
5+
| test.cpp:58:8:58:8 | p | Value may be null; it should be checked before dereferencing. |
6+
| test.cpp:67:8:67:8 | p | Value may be null; it should be checked before dereferencing. |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Critical/MissingNullTest.ql
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
2+
#define NULL (0)
3+
4+
typedef unsigned long size_t;
5+
6+
void *memcpy(void *s1, const void *s2, size_t n);
7+
void bcopy(const void *source, void *dest, size_t amount);
8+
9+
void mycopyint(const int *source, int *dest)
10+
{
11+
*dest = *source;
12+
}
13+
14+
void test1(bool cond)
15+
{
16+
int x, y;
17+
18+
{
19+
int *p, *q;
20+
21+
y = *p; // BAD (p is uninitialized and could be 0) [NOT DETECTED]
22+
p = NULL;
23+
y = *p; // BAD (p is 0)
24+
p = &x;
25+
y = *p; // GOOD (p points to x)
26+
p = q;
27+
y = *p; // BAD (p is uninitialized and could be 0) [NOT DETECTED]
28+
}
29+
30+
{
31+
int *p = &x;
32+
int *q = 0;
33+
34+
memcpy(p, &y, sizeof(int)); // GOOD (p points to x)
35+
memcpy(q, &y, sizeof(int)); // BAD (p is 0)
36+
}
37+
38+
{
39+
int *p = &x;
40+
int *q = 0;
41+
42+
bcopy(&y, p, sizeof(int)); // GOOD (p points to x)
43+
bcopy(&y, q, sizeof(int)); // BAD (p is 0)
44+
}
45+
46+
{
47+
int *p = &x;
48+
int *q = 0;
49+
50+
mycopyint(&y, p); // GOOD (p points to x)
51+
mycopyint(&y, q); // BAD (p is 0)
52+
}
53+
54+
{
55+
int *p = 0;
56+
int *q = &x;
57+
58+
y = *p; // BAD (p is 0)
59+
memcpy(&p, &q, sizeof(p));
60+
y = *p; // GOOD (p points to x)
61+
}
62+
63+
{
64+
int *p = 0;
65+
int *q = &x;
66+
67+
y = *p; // BAD (p is 0)
68+
bcopy(&q, &p, sizeof(p));
69+
y = *p; // GOOD (p points to x)
70+
}
71+
}

javascript/ql/src/LanguageFeatures/TemplateSyntaxInStringLiteral.ql

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@ class CandidateStringLiteral extends StringLiteral {
6262
}
6363

6464
/**
65-
* Holds if `obj` has a property for each template variable in `lit` and they occur as arguments
66-
* to the same call.
65+
* Holds if there exists an object that has a property for each template variable in `lit` and
66+
* they occur as arguments to the same call.
6767
*
6868
* This recognises a typical pattern in which template arguments are passed along with a string,
6969
* for example:
@@ -73,14 +73,14 @@ class CandidateStringLiteral extends StringLiteral {
7373
* { url: url, name: name } );
7474
* ```
7575
*/
76-
predicate providesTemplateVariablesFor(ObjectExpr obj, CandidateStringLiteral lit) {
77-
exists(CallExpr call | call.getAnArgument() = obj and call.getAnArgument() = lit) and
78-
forex(string name | lit.getAReferencedVariable() = name | hasProperty(obj, name))
76+
predicate hasObjectProvidingTemplateVariables(CandidateStringLiteral lit) {
77+
exists(DataFlow::CallNode call, DataFlow::ObjectLiteralNode obj |
78+
call.getAnArgument().getALocalSource() = obj and
79+
call.getAnArgument().asExpr() = lit and
80+
forex(string name | name = lit.getAReferencedVariable() | exists(obj.getAPropertyWrite(name)))
81+
)
7982
}
8083

81-
/** Holds if `object` has a property with the given `name`. */
82-
predicate hasProperty(ObjectExpr object, string name) { name = object.getAProperty().getName() }
83-
8484
/**
8585
* Gets a declaration of variable `v` in `tl`, where `v` has the given `name` and
8686
* belongs to `scope`.
@@ -97,7 +97,7 @@ where
9797
decl = getDeclIn(v, s, name, lit.getTopLevel()) and
9898
lit.getAReferencedVariable() = name and
9999
lit.isInScope(s) and
100-
not exists(ObjectExpr obj | providesTemplateVariablesFor(obj, lit)) and
100+
not hasObjectProvidingTemplateVariables(lit) and
101101
not lit.getStringValue() = "${" + name + "}"
102102
select lit, "This string is not a template literal, but appears to reference the variable $@.",
103103
decl, v.getName()

javascript/ql/src/experimental/Security/CWE-090/LdapInjection.qll

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,12 @@ module LdapInjection {
1414
override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
1515

1616
override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
17+
18+
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
19+
exists(LdapjsParseFilter filter |
20+
pred = filter.getArgument(0) and
21+
succ = filter
22+
)
23+
}
1724
}
1825
}

javascript/ql/src/experimental/Security/CWE-090/LdapInjectionCustomizations.qll

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55
*/
66

77
import javascript
8-
import Ldapjs::Ldapjs
98

109
module LdapInjection {
10+
import Ldapjs::Ldapjs
11+
1112
/**
1213
* A data flow source for LDAP injection vulnerabilities.
1314
*/
@@ -70,16 +71,4 @@ module LdapInjection {
7071
)
7172
}
7273
}
73-
74-
/**
75-
* A step through the parseFilter API (https://github.com/ldapjs/node-ldapjs/issues/181).
76-
*/
77-
class StepThroughParseFilter extends TaintTracking::AdditionalTaintStep, DataFlow::CallNode {
78-
StepThroughParseFilter() { this instanceof LdapjsParseFilter }
79-
80-
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
81-
pred = this.getArgument(0) and
82-
succ = this
83-
}
84-
}
8574
}

0 commit comments

Comments
 (0)