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

Skip to content

Commit 6c3f44b

Browse files
committed
C++: Add more memcpy, memset, strcat and strcpy models. Also refine which strcpy functions can live in the std namespace.
1 parent 064d897 commit 6c3f44b

6 files changed

Lines changed: 168 additions & 29 deletions

File tree

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ private class MemcpyFunction extends ArrayFunction, DataFlowFunction, SideEffect
2424
or
2525
// bcopy(src, dest, num)
2626
// mempcpy(dest, src, num)
27-
this.hasGlobalName(["bcopy", mempcpy(), "__builtin___memcpy_chk"])
27+
// memccpy(dest, src, c, n)
28+
this.hasGlobalName(["bcopy", mempcpy(), "memccpy", "__builtin___memcpy_chk"])
2829
}
2930

3031
/**
@@ -41,7 +42,7 @@ private class MemcpyFunction extends ArrayFunction, DataFlowFunction, SideEffect
4142
/**
4243
* Gets the index of the parameter that is the size of the copy (in bytes).
4344
*/
44-
int getParamSize() { result = 2 }
45+
int getParamSize() { if this.hasGlobalName("memccpy") then result = 3 else result = 2 }
4546

4647
override predicate hasArrayInput(int bufParam) { bufParam = getParamSrc() }
4748

@@ -71,7 +72,10 @@ private class MemcpyFunction extends ArrayFunction, DataFlowFunction, SideEffect
7172
override predicate hasOnlySpecificWriteSideEffects() { any() }
7273

7374
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
74-
i = getParamDest() and buffer = true and mustWrite = true
75+
i = getParamDest() and
76+
buffer = true and
77+
// memccpy only writes until a given character `c` is found
78+
(if this.hasGlobalName("memccpy") then mustWrite = false else mustWrite = true)
7579
}
7680

7781
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
@@ -97,7 +101,7 @@ private class MemcpyFunction extends ArrayFunction, DataFlowFunction, SideEffect
97101
}
98102

99103
override predicate parameterIsAlwaysReturned(int index) {
100-
not this.hasGlobalName(["bcopy", mempcpy()]) and
104+
not this.hasGlobalName(["bcopy", mempcpy(), "memccpy"]) and
101105
index = getParamDest()
102106
}
103107
}

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

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import semmle.code.cpp.models.interfaces.SideEffect
1515
private class MemsetFunction extends ArrayFunction, DataFlowFunction, AliasFunction,
1616
SideEffectFunction {
1717
MemsetFunction() {
18-
hasGlobalName(["memset", "wmemset", "bzero", "__builtin_memset", "__builtin_memset_chk"]) or
18+
hasGlobalName(["memset", "wmemset", bzero(), "__builtin_memset", "__builtin_memset_chk"]) or
1919
hasQualifiedName("std", ["memset", "wmemset"])
2020
}
2121

@@ -28,17 +28,17 @@ private class MemsetFunction extends ArrayFunction, DataFlowFunction, AliasFunct
2828

2929
override predicate hasArrayWithVariableSize(int bufParam, int countParam) {
3030
bufParam = 0 and
31-
(if hasGlobalName("bzero") then countParam = 1 else countParam = 2)
31+
(if hasGlobalName(bzero()) then countParam = 1 else countParam = 2)
3232
}
3333

34-
override predicate parameterNeverEscapes(int index) { hasGlobalName("bzero") and index = 0 }
34+
override predicate parameterNeverEscapes(int index) { hasGlobalName(bzero()) and index = 0 }
3535

3636
override predicate parameterEscapesOnlyViaReturn(int index) {
37-
not hasGlobalName("bzero") and index = 0
37+
not hasGlobalName(bzero()) and index = 0
3838
}
3939

4040
override predicate parameterIsAlwaysReturned(int index) {
41-
not hasGlobalName("bzero") and index = 0
41+
not hasGlobalName(bzero()) and index = 0
4242
}
4343

4444
override predicate hasOnlySpecificReadSideEffects() { any() }
@@ -51,6 +51,8 @@ private class MemsetFunction extends ArrayFunction, DataFlowFunction, AliasFunct
5151

5252
override ParameterIndex getParameterSizeIndex(ParameterIndex i) {
5353
i = 0 and
54-
if hasGlobalName("bzero") then result = 1 else result = 2
54+
if hasGlobalName(bzero()) then result = 1 else result = 2
5555
}
5656
}
57+
58+
private string bzero() { result = ["bzero", "explicit_bzero"] }

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, Sid
2121
"_mbscat", // _mbscat(dst, src)
2222
"wcsncat", // wcsncat(dst, src, max_amount)
2323
"_mbsncat", // _mbsncat(dst, src, max_amount)
24-
"_mbsncat_l" // _mbsncat_l(dst, src, max_amount, locale)
24+
"_mbsncat_l", // _mbsncat_l(dst, src, max_amount, locale)
25+
"_mbsnbcat", // _mbsnbcat(dest, src, count)
26+
"_mbsnbcat_l" // _mbsnbcat_l(dest, src, count, locale)
2527
]
2628
}
2729

@@ -50,7 +52,7 @@ class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, Sid
5052
input.isParameter(2) and
5153
output.isParameterDeref(0)
5254
or
53-
getName() = "_mbsncat_l" and
55+
getName() = ["_mbsncat_l", "_mbsnbcat_l"] and
5456
input.isParameter(3) and
5557
output.isParameterDeref(0)
5658
or

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

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,25 +13,36 @@ import semmle.code.cpp.models.interfaces.SideEffect
1313
*/
1414
class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, SideEffectFunction {
1515
StrcpyFunction() {
16-
getName() =
17-
[
16+
this.hasGlobalOrStdName([
1817
"strcpy", // strcpy(dst, src)
1918
"wcscpy", // wcscpy(dst, src)
20-
"_mbscpy", // _mbscpy(dst, src)
2119
"strncpy", // strncpy(dst, src, max_amount)
22-
"_strncpy_l", // _strncpy_l(dst, src, max_amount, locale)
2320
"wcsncpy", // wcsncpy(dst, src, max_amount)
21+
"strxfrm", // strxfrm(dest, src, max_amount)
22+
"wcsxfrm" // wcsxfrm(dest, src, max_amount)
23+
])
24+
or
25+
this.hasGlobalName([
26+
"_mbscpy", // _mbscpy(dst, src)
27+
"_strncpy_l", // _strncpy_l(dst, src, max_amount, locale)
2428
"_wcsncpy_l", // _wcsncpy_l(dst, src, max_amount, locale)
2529
"_mbsncpy", // _mbsncpy(dst, src, max_amount)
26-
"_mbsncpy_l"
27-
] // _mbsncpy_l(dst, src, max_amount, locale)
30+
"_mbsncpy_l", // _mbsncpy_l(dst, src, max_amount, locale)
31+
"_strxfrm_l", // _strxfrm_l(dest, src, max_amount, locale)
32+
"wcsxfrm_l", // _strxfrm_l(dest, src, max_amount, locale)
33+
"_mbsnbcpy", // _mbsnbcpy(dest, src, max_amount)
34+
"stpcpy", // stpcpy(dest, src)
35+
"stpncpy" // stpcpy(dest, src, max_amount)
36+
])
2837
or
29-
getName() =
30-
[
31-
"strcpy_s", // strcpy_s(dst, max_amount, src)
32-
"wcscpy_s", // wcscpy_s(dst, max_amount, src)
33-
"_mbscpy_s"
34-
] and // _mbscpy_s(dst, max_amount, src)
38+
(
39+
this.hasGlobalOrStdName([
40+
"strcpy_s", // strcpy_s(dst, max_amount, src)
41+
"wcscpy_s" // wcscpy_s(dst, max_amount, src)
42+
])
43+
or
44+
this.hasGlobalName("_mbscpy_s") // _mbscpy_s(dst, max_amount, src)
45+
) and
3546
// exclude the 2-parameter template versions
3647
// that find the size of a fixed size destination buffer.
3748
getNumberOfParameters() = 3
@@ -48,10 +59,10 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid
4859
int getParamSize() {
4960
if isSVariant()
5061
then result = 1
51-
else
52-
if exists(getName().indexOf("ncpy"))
53-
then result = 2
54-
else none()
62+
else (
63+
getName().matches(["%ncpy%", "%nbcpy%", "%xfrm%"]) and
64+
result = 2
65+
)
5566
}
5667

5768
/**

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

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5883,6 +5883,75 @@
58835883
| taint.cpp:510:10:510:15 | source | taint.cpp:510:2:510:8 | call to _strset | |
58845884
| taint.cpp:510:18:510:18 | 0 | taint.cpp:510:2:510:8 | call to _strset | TAINT |
58855885
| taint.cpp:510:18:510:18 | 0 | taint.cpp:510:10:510:15 | ref arg source | |
5886+
| taint.cpp:518:24:518:29 | source | taint.cpp:520:14:520:19 | source | |
5887+
| taint.cpp:519:6:519:6 | x | taint.cpp:520:11:520:11 | x | |
5888+
| taint.cpp:519:6:519:6 | x | taint.cpp:521:7:521:7 | x | |
5889+
| taint.cpp:520:10:520:11 | & ... | taint.cpp:520:2:520:8 | call to mempcpy | |
5890+
| taint.cpp:520:10:520:11 | ref arg & ... | taint.cpp:520:11:520:11 | x [inner post update] | |
5891+
| taint.cpp:520:10:520:11 | ref arg & ... | taint.cpp:521:7:521:7 | x | |
5892+
| taint.cpp:520:11:520:11 | x | taint.cpp:520:10:520:11 | & ... | |
5893+
| taint.cpp:520:14:520:19 | source | taint.cpp:520:2:520:8 | call to mempcpy | TAINT |
5894+
| taint.cpp:520:14:520:19 | source | taint.cpp:520:10:520:11 | ref arg & ... | TAINT |
5895+
| taint.cpp:528:24:528:29 | source | taint.cpp:530:16:530:21 | source | |
5896+
| taint.cpp:529:6:529:9 | dest | taint.cpp:530:10:530:13 | dest | |
5897+
| taint.cpp:529:6:529:9 | dest | taint.cpp:530:35:530:38 | dest | |
5898+
| taint.cpp:529:6:529:9 | dest | taint.cpp:531:7:531:10 | dest | |
5899+
| taint.cpp:530:10:530:13 | dest | taint.cpp:530:2:530:8 | call to memccpy | |
5900+
| taint.cpp:530:10:530:13 | ref arg dest | taint.cpp:531:7:531:10 | dest | |
5901+
| taint.cpp:530:16:530:21 | source | taint.cpp:530:2:530:8 | call to memccpy | TAINT |
5902+
| taint.cpp:530:16:530:21 | source | taint.cpp:530:10:530:13 | ref arg dest | TAINT |
5903+
| taint.cpp:538:24:538:28 | dest1 | taint.cpp:539:9:539:13 | dest1 | |
5904+
| taint.cpp:538:24:538:28 | dest1 | taint.cpp:540:7:540:11 | dest1 | |
5905+
| taint.cpp:538:37:538:41 | dest2 | taint.cpp:542:9:542:13 | dest2 | |
5906+
| taint.cpp:538:37:538:41 | dest2 | taint.cpp:543:7:543:11 | dest2 | |
5907+
| taint.cpp:538:50:538:54 | clean | taint.cpp:542:16:542:20 | clean | |
5908+
| taint.cpp:538:63:538:68 | source | taint.cpp:539:16:539:21 | source | |
5909+
| taint.cpp:539:9:539:13 | dest1 | taint.cpp:539:2:539:7 | call to strcat | |
5910+
| taint.cpp:539:9:539:13 | dest1 | taint.cpp:539:9:539:13 | ref arg dest1 | TAINT |
5911+
| taint.cpp:539:9:539:13 | ref arg dest1 | taint.cpp:540:7:540:11 | dest1 | |
5912+
| taint.cpp:539:16:539:21 | source | taint.cpp:539:9:539:13 | ref arg dest1 | TAINT |
5913+
| taint.cpp:542:9:542:13 | dest2 | taint.cpp:542:2:542:7 | call to strcat | |
5914+
| taint.cpp:542:9:542:13 | dest2 | taint.cpp:542:9:542:13 | ref arg dest2 | TAINT |
5915+
| taint.cpp:542:9:542:13 | ref arg dest2 | taint.cpp:543:7:543:11 | dest2 | |
5916+
| taint.cpp:542:16:542:20 | clean | taint.cpp:542:9:542:13 | ref arg dest2 | TAINT |
5917+
| taint.cpp:550:37:550:41 | dest1 | taint.cpp:552:36:552:40 | dest1 | |
5918+
| taint.cpp:550:37:550:41 | dest1 | taint.cpp:553:7:553:11 | dest1 | |
5919+
| taint.cpp:550:37:550:41 | dest1 | taint.cpp:554:8:554:12 | dest1 | |
5920+
| taint.cpp:550:65:550:67 | ptr | taint.cpp:552:43:552:45 | ptr | |
5921+
| taint.cpp:550:65:550:67 | ptr | taint.cpp:558:43:558:45 | ptr | |
5922+
| taint.cpp:550:85:550:89 | dest3 | taint.cpp:558:36:558:40 | dest3 | |
5923+
| taint.cpp:550:85:550:89 | dest3 | taint.cpp:559:7:559:11 | dest3 | |
5924+
| taint.cpp:550:85:550:89 | dest3 | taint.cpp:560:8:560:12 | dest3 | |
5925+
| taint.cpp:551:32:551:36 | clean | taint.cpp:558:51:558:55 | clean | |
5926+
| taint.cpp:551:49:551:54 | source | taint.cpp:552:51:552:56 | source | |
5927+
| taint.cpp:551:61:551:61 | n | taint.cpp:552:48:552:48 | n | |
5928+
| taint.cpp:551:61:551:61 | n | taint.cpp:558:48:558:48 | n | |
5929+
| taint.cpp:552:25:552:34 | call to _mbsncat_l | taint.cpp:555:7:555:11 | dest2 | |
5930+
| taint.cpp:552:25:552:34 | call to _mbsncat_l | taint.cpp:556:8:556:12 | dest2 | |
5931+
| taint.cpp:552:36:552:40 | dest1 | taint.cpp:552:25:552:34 | call to _mbsncat_l | |
5932+
| taint.cpp:552:36:552:40 | dest1 | taint.cpp:552:36:552:40 | ref arg dest1 | TAINT |
5933+
| taint.cpp:552:36:552:40 | ref arg dest1 | taint.cpp:553:7:553:11 | dest1 | |
5934+
| taint.cpp:552:36:552:40 | ref arg dest1 | taint.cpp:554:8:554:12 | dest1 | |
5935+
| taint.cpp:552:43:552:45 | ptr | taint.cpp:552:36:552:40 | ref arg dest1 | TAINT |
5936+
| taint.cpp:552:48:552:48 | n | taint.cpp:552:36:552:40 | ref arg dest1 | TAINT |
5937+
| taint.cpp:552:51:552:56 | source | taint.cpp:552:36:552:40 | ref arg dest1 | TAINT |
5938+
| taint.cpp:553:7:553:11 | ref arg dest1 | taint.cpp:554:8:554:12 | dest1 | |
5939+
| taint.cpp:554:8:554:12 | dest1 | taint.cpp:554:7:554:12 | * ... | TAINT |
5940+
| taint.cpp:555:7:555:11 | ref arg dest2 | taint.cpp:556:8:556:12 | dest2 | |
5941+
| taint.cpp:556:8:556:12 | dest2 | taint.cpp:556:7:556:12 | * ... | TAINT |
5942+
| taint.cpp:558:25:558:34 | call to _mbsncat_l | taint.cpp:561:7:561:11 | dest4 | |
5943+
| taint.cpp:558:25:558:34 | call to _mbsncat_l | taint.cpp:562:8:562:12 | dest4 | |
5944+
| taint.cpp:558:36:558:40 | dest3 | taint.cpp:558:25:558:34 | call to _mbsncat_l | |
5945+
| taint.cpp:558:36:558:40 | dest3 | taint.cpp:558:36:558:40 | ref arg dest3 | TAINT |
5946+
| taint.cpp:558:36:558:40 | ref arg dest3 | taint.cpp:559:7:559:11 | dest3 | |
5947+
| taint.cpp:558:36:558:40 | ref arg dest3 | taint.cpp:560:8:560:12 | dest3 | |
5948+
| taint.cpp:558:43:558:45 | ptr | taint.cpp:558:36:558:40 | ref arg dest3 | TAINT |
5949+
| taint.cpp:558:48:558:48 | n | taint.cpp:558:36:558:40 | ref arg dest3 | TAINT |
5950+
| taint.cpp:558:51:558:55 | clean | taint.cpp:558:36:558:40 | ref arg dest3 | TAINT |
5951+
| taint.cpp:559:7:559:11 | ref arg dest3 | taint.cpp:560:8:560:12 | dest3 | |
5952+
| taint.cpp:560:8:560:12 | dest3 | taint.cpp:560:7:560:12 | * ... | TAINT |
5953+
| taint.cpp:561:7:561:11 | ref arg dest4 | taint.cpp:562:8:562:12 | dest4 | |
5954+
| taint.cpp:562:8:562:12 | dest4 | taint.cpp:562:7:562:12 | * ... | TAINT |
58865955
| vector.cpp:16:43:16:49 | source1 | vector.cpp:17:26:17:32 | source1 | |
58875956
| vector.cpp:16:43:16:49 | source1 | vector.cpp:31:38:31:44 | source1 | |
58885957
| vector.cpp:17:21:17:33 | call to vector | vector.cpp:19:14:19:14 | v | |

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

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -509,4 +509,55 @@ void test_strset_1(char* ptr, char source) {
509509
void test_strset_2(char* source) {
510510
_strset(source, 0);
511511
sink(source); // $ ast,ir
512-
}
512+
}
513+
514+
// --- mempcpy ---
515+
516+
void *mempcpy(void *dest, const void *src, size_t n);
517+
518+
void test_mempcpy(int *source) {
519+
int x;
520+
mempcpy(&x, source, sizeof(int));
521+
sink(x); // $ ast=518:24 MISSING: ir SPURIOUS: ast=519:6
522+
}
523+
524+
// --- memccpy ---
525+
526+
void *memccpy(void *dest, const void *src, int c, size_t n);
527+
528+
void test_memccpy(int *source) {
529+
int dest[16];
530+
memccpy(dest, source, 42, sizeof(dest));
531+
sink(dest); // $ ast=528:24 MISSING: ir SPURIOUS: ast=529:6
532+
}
533+
534+
// --- strcat and related functions ---
535+
536+
char* strcat (char*, const char*);
537+
538+
void test_strcat(char* dest1, char* dest2, char* clean, char* source) {
539+
strcat(dest1, source);
540+
sink(dest1); // $ ast,ir
541+
542+
strcat(dest2, clean);
543+
sink(dest2);
544+
}
545+
546+
typedef void* _locale_t;
547+
548+
unsigned char *_mbsncat_l(unsigned char *, const unsigned char *, int, _locale_t);
549+
550+
void test__mbsncat_l(unsigned char* dest1, unsigned const char* ptr, unsigned char* dest3,
551+
_locale_t clean, _locale_t source, int n) {
552+
unsigned char* dest2 = _mbsncat_l(dest1, ptr, n, source);
553+
sink(dest1); // $ SPURIOUS: ast,ir
554+
sink(*dest1); // $ ast,ir
555+
sink(dest2); // $ SPURIOUS: ir
556+
sink(*dest2); // $ ir
557+
558+
unsigned char* dest4 = _mbsncat_l(dest3, ptr, n, clean);
559+
sink(dest3);
560+
sink(*dest3);
561+
sink(dest4);
562+
sink(*dest4);
563+
}

0 commit comments

Comments
 (0)