Skip to content

Commit b79a5fe

Browse files
authored
Merge pull request #14637 from MathiasVP/dataflow-for-realloc
C++: Add a taint model for `realloc`
2 parents ceb3d14 + 377da9f commit b79a5fe

File tree

9 files changed

+55
-7
lines changed

9 files changed

+55
-7
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 taint models for `realloc` and related functions.

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66

77
import semmle.code.cpp.models.interfaces.Allocation
8+
import semmle.code.cpp.models.interfaces.Taint
89

910
/**
1011
* An allocation function (such as `malloc`) that has an argument for the size
@@ -121,7 +122,7 @@ private class CallocAllocationFunction extends AllocationFunction {
121122
* An allocation function (such as `realloc`) that has an argument for the size
122123
* in bytes, and an argument for an existing pointer that is to be reallocated.
123124
*/
124-
private class ReallocAllocationFunction extends AllocationFunction {
125+
private class ReallocAllocationFunction extends AllocationFunction, TaintFunction {
125126
int sizeArg;
126127
int reallocArg;
127128

@@ -151,6 +152,10 @@ private class ReallocAllocationFunction extends AllocationFunction {
151152
override int getSizeArg() { result = sizeArg }
152153

153154
override int getReallocPtrArg() { result = reallocArg }
155+
156+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
157+
input.isParameterDeref(this.getReallocPtrArg()) and output.isReturnValueDeref()
158+
}
154159
}
155160

156161
/**

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

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,17 @@ import semmle.code.cpp.models.interfaces.DataFlow
99
import semmle.code.cpp.models.interfaces.Alias
1010
import semmle.code.cpp.models.interfaces.SideEffect
1111

12-
/**
13-
* The standard function `memset` and its assorted variants
14-
*/
15-
private class MemsetFunction extends ArrayFunction, DataFlowFunction, AliasFunction,
12+
private class MemsetFunctionModel extends ArrayFunction, DataFlowFunction, AliasFunction,
1613
SideEffectFunction
1714
{
18-
MemsetFunction() {
15+
MemsetFunctionModel() {
1916
this.hasGlobalOrStdOrBslName("memset")
2017
or
2118
this.hasGlobalOrStdName("wmemset")
2219
or
23-
this.hasGlobalName([bzero(), "__builtin_memset", "__builtin_memset_chk"])
20+
this.hasGlobalName([
21+
bzero(), "__builtin_memset", "__builtin_memset_chk", "RtlZeroMemory", "RtlSecureZeroMemory"
22+
])
2423
}
2524

2625
override predicate hasArrayOutput(int bufParam) { bufParam = 0 }
@@ -60,3 +59,8 @@ private class MemsetFunction extends ArrayFunction, DataFlowFunction, AliasFunct
6059
}
6160

6261
private string bzero() { result = ["bzero", "explicit_bzero"] }
62+
63+
/**
64+
* The standard function `memset` and its assorted variants
65+
*/
66+
class MemsetFunction extends Function instanceof MemsetFunctionModel { }

cpp/ql/src/Security/CWE/CWE-497/ExposedSystemData.ql

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import cpp
1616
import semmle.code.cpp.ir.dataflow.TaintTracking
1717
import semmle.code.cpp.models.interfaces.FlowSource
18+
import semmle.code.cpp.models.implementations.Memset
1819
import ExposedSystemData::PathGraph
1920
import SystemData
2021

@@ -28,6 +29,10 @@ module ExposedSystemDataConfig implements DataFlow::ConfigSig {
2829
fc.getArgument(arg).getAChild*() = sink.asIndirectExpr()
2930
)
3031
}
32+
33+
predicate isBarrier(DataFlow::Node node) {
34+
node.asIndirectArgument() = any(MemsetFunction func).getACallToThisFunction().getAnArgument()
35+
}
3136
}
3237

3338
module ExposedSystemData = TaintTracking::Global<ExposedSystemDataConfig>;

cpp/ql/src/Security/CWE/CWE-497/PotentiallyExposedSystemData.ql

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import cpp
2828
import semmle.code.cpp.ir.dataflow.TaintTracking
2929
import semmle.code.cpp.models.interfaces.FlowSource
3030
import semmle.code.cpp.security.OutputWrite
31+
import semmle.code.cpp.models.implementations.Memset
3132
import PotentiallyExposedSystemData::PathGraph
3233
import SystemData
3334

@@ -49,6 +50,10 @@ module PotentiallyExposedSystemDataConfig implements DataFlow::ConfigSig {
4950
else child = sink.asExpr()
5051
)
5152
}
53+
54+
predicate isBarrier(DataFlow::Node node) {
55+
node.asIndirectArgument() = any(MemsetFunction func).getACallToThisFunction().getAnArgument()
56+
}
5257
}
5358

5459
module PotentiallyExposedSystemData = TaintTracking::Global<PotentiallyExposedSystemDataConfig>;

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6643,6 +6643,9 @@ WARNING: Module TaintTracking has been deprecated and may be removed in future (
66436643
| taint.cpp:729:27:729:32 | endptr | taint.cpp:729:26:729:32 | & ... | |
66446644
| taint.cpp:731:7:731:12 | ref arg endptr | taint.cpp:732:8:732:13 | endptr | |
66456645
| taint.cpp:732:8:732:13 | endptr | taint.cpp:732:7:732:13 | * ... | TAINT |
6646+
| taint.cpp:738:17:738:31 | call to indirect_source | taint.cpp:739:30:739:35 | source | |
6647+
| taint.cpp:739:22:739:28 | call to realloc | taint.cpp:740:7:740:10 | dest | |
6648+
| taint.cpp:739:30:739:35 | source | taint.cpp:739:22:739:28 | call to realloc | TAINT |
66466649
| vector.cpp:16:43:16:49 | source1 | vector.cpp:17:26:17:32 | source1 | |
66476650
| vector.cpp:16:43:16:49 | source1 | vector.cpp:31:38:31:44 | source1 | |
66486651
| 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: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -730,4 +730,12 @@ void test_strtol(char *source) {
730730
sink(l); // $ ast,ir
731731
sink(endptr); // $ ast,ir
732732
sink(*endptr); // $ ast,ir
733+
}
734+
735+
void *realloc(void *, size_t);
736+
737+
void test_realloc() {
738+
char *source = indirect_source();
739+
char *dest = (char*)realloc(source, 16);
740+
sink(dest); // $ ir MISSING: ast
733741
}

cpp/ql/test/query-tests/Security/CWE/CWE-497/semmle/tests/PotentiallyExposedSystemData.expected

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ edges
1010
| tests.cpp:131:14:131:35 | call to getenv indirection | tests.cpp:107:30:107:32 | msg indirection |
1111
| tests.cpp:132:14:132:35 | call to getenv indirection | tests.cpp:114:30:114:32 | msg indirection |
1212
| tests.cpp:133:14:133:35 | call to getenv indirection | tests.cpp:122:30:122:32 | msg indirection |
13+
| tests.cpp:139:17:139:22 | call to getenv indirection | tests.cpp:141:15:141:20 | secret indirection |
1314
| tests_passwd.cpp:16:8:16:15 | call to getpwnam indirection | tests_passwd.cpp:18:29:18:31 | pwd indirection |
1415
| tests_passwd.cpp:16:8:16:15 | call to getpwnam indirection | tests_passwd.cpp:19:26:19:28 | pwd indirection |
1516
nodes
@@ -37,6 +38,8 @@ nodes
3738
| tests.cpp:132:14:132:35 | call to getenv indirection | semmle.label | call to getenv indirection |
3839
| tests.cpp:133:14:133:35 | call to getenv indirection | semmle.label | call to getenv indirection |
3940
| tests.cpp:133:14:133:35 | call to getenv indirection | semmle.label | call to getenv indirection |
41+
| tests.cpp:139:17:139:22 | call to getenv indirection | semmle.label | call to getenv indirection |
42+
| tests.cpp:141:15:141:20 | secret indirection | semmle.label | secret indirection |
4043
| tests_passwd.cpp:16:8:16:15 | call to getpwnam indirection | semmle.label | call to getpwnam indirection |
4144
| tests_passwd.cpp:18:29:18:31 | pwd indirection | semmle.label | pwd indirection |
4245
| tests_passwd.cpp:19:26:19:28 | pwd indirection | semmle.label | pwd indirection |
@@ -56,5 +59,6 @@ subpaths
5659
| tests.cpp:119:7:119:12 | buffer indirection | tests.cpp:132:14:132:35 | call to getenv indirection | tests.cpp:119:7:119:12 | buffer indirection | This operation potentially exposes sensitive system data from $@. | tests.cpp:132:14:132:35 | call to getenv indirection | call to getenv indirection |
5760
| tests.cpp:124:15:124:17 | msg indirection | tests.cpp:133:14:133:35 | call to getenv indirection | tests.cpp:124:15:124:17 | msg indirection | This operation potentially exposes sensitive system data from $@. | tests.cpp:133:14:133:35 | call to getenv indirection | call to getenv indirection |
5861
| tests.cpp:133:14:133:35 | call to getenv indirection | tests.cpp:133:14:133:35 | call to getenv indirection | tests.cpp:133:14:133:35 | call to getenv indirection | This operation potentially exposes sensitive system data from $@. | tests.cpp:133:14:133:35 | call to getenv indirection | call to getenv indirection |
62+
| tests.cpp:141:15:141:20 | secret indirection | tests.cpp:139:17:139:22 | call to getenv indirection | tests.cpp:141:15:141:20 | secret indirection | This operation potentially exposes sensitive system data from $@. | tests.cpp:139:17:139:22 | call to getenv indirection | call to getenv indirection |
5963
| tests_passwd.cpp:18:29:18:31 | pwd indirection | tests_passwd.cpp:16:8:16:15 | call to getpwnam indirection | tests_passwd.cpp:18:29:18:31 | pwd indirection | This operation potentially exposes sensitive system data from $@. | tests_passwd.cpp:16:8:16:15 | call to getpwnam indirection | call to getpwnam indirection |
6064
| tests_passwd.cpp:19:26:19:28 | pwd indirection | tests_passwd.cpp:16:8:16:15 | call to getpwnam indirection | tests_passwd.cpp:19:26:19:28 | pwd indirection | This operation potentially exposes sensitive system data from $@. | tests_passwd.cpp:16:8:16:15 | call to getpwnam indirection | call to getpwnam indirection |

cpp/ql/test/query-tests/Security/CWE/CWE-497/semmle/tests/tests.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,13 @@ void test5()
132132
myOutputFn4(getenv("SECRET_TOKEN")); // BAD: outputs the SECRET_TOKEN environment variable
133133
myOutputFn5(getenv("SECRET_TOKEN")); // BAD: outputs the SECRET_TOKEN environment variable
134134
}
135+
136+
void RtlZeroMemory(void* dst, size_t len);
137+
138+
void test_clear_memory(char *username) {
139+
char* secret = getenv("SECRET_TOKEN");
140+
141+
printf("%s", secret); // BAD
142+
RtlZeroMemory(secret, 1024);
143+
printf("%s", secret); // GOOD
144+
}

0 commit comments

Comments
 (0)