Skip to content

Commit b071a46

Browse files
authored
Merge pull request #19563 from jketema/jketema/win-flow
C++: Add Windows command line and environment models
2 parents 4c9c8bc + 10f6e1c commit b071a46

File tree

10 files changed

+129
-13
lines changed

10 files changed

+129
-13
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
category: feature
3+
---
4+
* Added the `pCmdLine` arguments of `WinMain` and `wWinMain` as local flow sources.
5+
* Added source models for `GetCommandLineA`, `GetCommandLineW`, `GetEnvironmentStringsA`, `GetEnvironmentStringsW`, `GetEnvironmentVariableA`, and `GetEnvironmentVariableW`.
6+
* Added summary models for `CommandLineToArgvA` and `CommandLineToArgvW`.

cpp/ql/lib/ext/Windows.model.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# partial model of windows system calls
2+
extensions:
3+
- addsTo:
4+
pack: codeql/cpp-all
5+
extensible: sourceModel
6+
data: # namespace, type, subtypes, name, signature, ext, output, kind, provenance
7+
# processenv.h
8+
- ["", "", False, "GetCommandLineA", "", "", "ReturnValue[*]", "local", "manual"]
9+
- ["", "", False, "GetCommandLineW", "", "", "ReturnValue[*]", "local", "manual"]
10+
- ["", "", False, "GetEnvironmentStringsA", "", "", "ReturnValue[*]", "local", "manual"]
11+
- ["", "", False, "GetEnvironmentStringsW", "", "", "ReturnValue[*]", "local", "manual"]
12+
- ["", "", False, "GetEnvironmentVariableA", "", "", "Argument[*1]", "local", "manual"]
13+
- ["", "", False, "GetEnvironmentVariableW", "", "", "Argument[*1]", "local", "manual"]
14+
- addsTo:
15+
pack: codeql/cpp-all
16+
extensible: summaryModel
17+
data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance
18+
# shellapi.h
19+
- ["", "", False, "CommandLineToArgvA", "", "", "Argument[*0]", "ReturnValue[**]", "taint", "manual"]
20+
- ["", "", False, "CommandLineToArgvW", "", "", "Argument[*0]", "ReturnValue[**]", "taint", "manual"]

cpp/ql/lib/semmle/code/cpp/security/FlowSources.qll

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ private class LocalModelSource extends LocalFlowSource {
5555
}
5656

5757
/**
58-
* A local data flow source that the `argv` parameter to `main` or `wmain`.
58+
* A local data flow source that is the `argv` parameter to `main` or `wmain`.
5959
*/
6060
private class ArgvSource extends LocalFlowSource {
6161
ArgvSource() {
@@ -69,6 +69,21 @@ private class ArgvSource extends LocalFlowSource {
6969
override string getSourceType() { result = "a command-line argument" }
7070
}
7171

72+
/**
73+
* A local data flow source that is the `pCmdLine` parameter to `WinMain` or `wWinMain`.
74+
*/
75+
private class CmdLineSource extends LocalFlowSource {
76+
CmdLineSource() {
77+
exists(Function main, Parameter pCmdLine |
78+
main.hasGlobalName(["WinMain", "wWinMain"]) and
79+
main.getParameter(2) = pCmdLine and
80+
this.asParameter(1) = pCmdLine
81+
)
82+
}
83+
84+
override string getSourceType() { result = "a command-line" }
85+
}
86+
7287
/**
7388
* A remote data flow source that is defined through 'models as data'.
7489
*/

cpp/ql/test/library-tests/dataflow/dataflow-tests/TestBase.qll

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,11 @@ module IRTest {
124124

125125
/** Common data flow configuration to be used by tests. */
126126
module IRTestAllocationConfig implements DataFlow::ConfigSig {
127+
private import semmle.code.cpp.security.FlowSources
128+
127129
predicate isSource(DataFlow::Node source) {
130+
source instanceof FlowSource
131+
or
128132
source.asExpr().(FunctionCall).getTarget().getName() = "source"
129133
or
130134
source.asIndirectExpr(1).(FunctionCall).getTarget().getName() = "indirect_source"

cpp/ql/test/library-tests/dataflow/dataflow-tests/test-source-sink.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,3 +337,4 @@ irFlow
337337
| true_upon_entry.cpp:70:11:70:16 | call to source | true_upon_entry.cpp:78:8:78:8 | x |
338338
| true_upon_entry.cpp:83:11:83:16 | call to source | true_upon_entry.cpp:86:8:86:8 | x |
339339
| true_upon_entry.cpp:98:11:98:16 | call to source | true_upon_entry.cpp:105:8:105:8 | x |
340+
| winmain.cpp:4:57:4:64 | *pCmdLine | winmain.cpp:6:8:6:16 | * ... |
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
void sink(char);
2+
void sink(char*);
3+
4+
int WinMain(void *hInstance, void *hPrevInstance, char *pCmdLine, int nCmdShow) { // $ ast-def=hInstance ast-def=hPrevInstance ast-def=pCmdLine ir-def=*hInstance ir-def=*hPrevInstance ir-def=*pCmdLine
5+
sink(pCmdLine);
6+
sink(*pCmdLine); // $ ir
7+
8+
return 0;
9+
}

cpp/ql/test/library-tests/dataflow/external-models/flow.expected

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,33 +10,44 @@ edges
1010
| asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:103:29:103:39 | *send_buffer | provenance | Sink:MaD:6 |
1111
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | provenance | |
1212
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:10 |
13-
| test.cpp:4:5:4:17 | [summary param] 0 in ymlStepManual | test.cpp:4:5:4:17 | [summary] to write: ReturnValue in ymlStepManual | provenance | MaD:23489 |
14-
| test.cpp:5:5:5:20 | [summary param] 0 in ymlStepGenerated | test.cpp:5:5:5:20 | [summary] to write: ReturnValue in ymlStepGenerated | provenance | MaD:23490 |
15-
| test.cpp:6:5:6:27 | [summary param] 0 in ymlStepManual_with_body | test.cpp:6:5:6:27 | [summary] to write: ReturnValue in ymlStepManual_with_body | provenance | MaD:23491 |
13+
| test.cpp:4:5:4:17 | [summary param] 0 in ymlStepManual | test.cpp:4:5:4:17 | [summary] to write: ReturnValue in ymlStepManual | provenance | MaD:23497 |
14+
| test.cpp:5:5:5:20 | [summary param] 0 in ymlStepGenerated | test.cpp:5:5:5:20 | [summary] to write: ReturnValue in ymlStepGenerated | provenance | MaD:23498 |
15+
| test.cpp:6:5:6:27 | [summary param] 0 in ymlStepManual_with_body | test.cpp:6:5:6:27 | [summary] to write: ReturnValue in ymlStepManual_with_body | provenance | MaD:23499 |
1616
| test.cpp:7:47:7:52 | value2 | test.cpp:7:64:7:69 | value2 | provenance | |
1717
| test.cpp:7:64:7:69 | value2 | test.cpp:7:5:7:30 | *ymlStepGenerated_with_body | provenance | |
18-
| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:10:10:10:18 | call to ymlSource | provenance | Src:MaD:23487 |
19-
| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:14:10:14:10 | x | provenance | Sink:MaD:23488 |
18+
| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:10:10:10:18 | call to ymlSource | provenance | Src:MaD:23495 |
19+
| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:14:10:14:10 | x | provenance | Sink:MaD:23496 |
2020
| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:17:24:17:24 | x | provenance | |
2121
| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:21:27:21:27 | x | provenance | |
2222
| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:25:35:25:35 | x | provenance | |
2323
| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:32:41:32:41 | x | provenance | |
2424
| test.cpp:17:10:17:22 | call to ymlStepManual | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | |
25-
| test.cpp:17:10:17:22 | call to ymlStepManual | test.cpp:18:10:18:10 | y | provenance | Sink:MaD:23488 |
25+
| test.cpp:17:10:17:22 | call to ymlStepManual | test.cpp:18:10:18:10 | y | provenance | Sink:MaD:23496 |
2626
| test.cpp:17:24:17:24 | x | test.cpp:4:5:4:17 | [summary param] 0 in ymlStepManual | provenance | |
27-
| test.cpp:17:24:17:24 | x | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | MaD:23489 |
27+
| test.cpp:17:24:17:24 | x | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | MaD:23497 |
2828
| test.cpp:21:10:21:25 | call to ymlStepGenerated | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | |
29-
| test.cpp:21:10:21:25 | call to ymlStepGenerated | test.cpp:22:10:22:10 | z | provenance | Sink:MaD:23488 |
29+
| test.cpp:21:10:21:25 | call to ymlStepGenerated | test.cpp:22:10:22:10 | z | provenance | Sink:MaD:23496 |
3030
| test.cpp:21:27:21:27 | x | test.cpp:5:5:5:20 | [summary param] 0 in ymlStepGenerated | provenance | |
31-
| test.cpp:21:27:21:27 | x | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | MaD:23490 |
31+
| test.cpp:21:27:21:27 | x | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | MaD:23498 |
3232
| test.cpp:25:11:25:33 | call to ymlStepManual_with_body | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | |
33-
| test.cpp:25:11:25:33 | call to ymlStepManual_with_body | test.cpp:26:10:26:11 | y2 | provenance | Sink:MaD:23488 |
33+
| test.cpp:25:11:25:33 | call to ymlStepManual_with_body | test.cpp:26:10:26:11 | y2 | provenance | Sink:MaD:23496 |
3434
| test.cpp:25:35:25:35 | x | test.cpp:6:5:6:27 | [summary param] 0 in ymlStepManual_with_body | provenance | |
35-
| test.cpp:25:35:25:35 | x | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | MaD:23491 |
35+
| test.cpp:25:35:25:35 | x | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | MaD:23499 |
3636
| test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | provenance | |
37-
| test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | test.cpp:33:10:33:11 | z2 | provenance | Sink:MaD:23488 |
37+
| test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | test.cpp:33:10:33:11 | z2 | provenance | Sink:MaD:23496 |
3838
| test.cpp:32:41:32:41 | x | test.cpp:7:47:7:52 | value2 | provenance | |
3939
| test.cpp:32:41:32:41 | x | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | provenance | |
40+
| windows.cpp:6:8:6:25 | [summary param] *0 in CommandLineToArgvA | windows.cpp:6:8:6:25 | [summary] to write: ReturnValue[**] in CommandLineToArgvA | provenance | MaD:331 |
41+
| windows.cpp:11:15:11:29 | *call to GetCommandLineA | windows.cpp:11:15:11:29 | *call to GetCommandLineA | provenance | Src:MaD:325 |
42+
| windows.cpp:11:15:11:29 | *call to GetCommandLineA | windows.cpp:13:8:13:11 | * ... | provenance | |
43+
| windows.cpp:11:15:11:29 | *call to GetCommandLineA | windows.cpp:16:36:16:38 | *cmd | provenance | |
44+
| windows.cpp:16:17:16:34 | **call to CommandLineToArgvA | windows.cpp:16:17:16:34 | **call to CommandLineToArgvA | provenance | |
45+
| windows.cpp:16:17:16:34 | **call to CommandLineToArgvA | windows.cpp:19:8:19:15 | * ... | provenance | |
46+
| windows.cpp:16:36:16:38 | *cmd | windows.cpp:6:8:6:25 | [summary param] *0 in CommandLineToArgvA | provenance | |
47+
| windows.cpp:16:36:16:38 | *cmd | windows.cpp:16:17:16:34 | **call to CommandLineToArgvA | provenance | MaD:331 |
48+
| windows.cpp:23:17:23:38 | *call to GetEnvironmentStringsA | windows.cpp:23:17:23:38 | *call to GetEnvironmentStringsA | provenance | Src:MaD:327 |
49+
| windows.cpp:23:17:23:38 | *call to GetEnvironmentStringsA | windows.cpp:25:10:25:13 | * ... | provenance | |
50+
| windows.cpp:28:36:28:38 | GetEnvironmentVariableA output argument | windows.cpp:30:10:30:13 | * ... | provenance | Src:MaD:329 |
4051
nodes
4152
| asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | semmle.label | [summary param] *0 in buffer |
4253
| asio_streams.cpp:56:18:56:23 | [summary] to write: ReturnValue in buffer | semmle.label | [summary] to write: ReturnValue in buffer |
@@ -78,9 +89,24 @@ nodes
7889
| test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | semmle.label | call to ymlStepGenerated_with_body |
7990
| test.cpp:32:41:32:41 | x | semmle.label | x |
8091
| test.cpp:33:10:33:11 | z2 | semmle.label | z2 |
92+
| windows.cpp:6:8:6:25 | [summary param] *0 in CommandLineToArgvA | semmle.label | [summary param] *0 in CommandLineToArgvA |
93+
| windows.cpp:6:8:6:25 | [summary] to write: ReturnValue[**] in CommandLineToArgvA | semmle.label | [summary] to write: ReturnValue[**] in CommandLineToArgvA |
94+
| windows.cpp:11:15:11:29 | *call to GetCommandLineA | semmle.label | *call to GetCommandLineA |
95+
| windows.cpp:11:15:11:29 | *call to GetCommandLineA | semmle.label | *call to GetCommandLineA |
96+
| windows.cpp:13:8:13:11 | * ... | semmle.label | * ... |
97+
| windows.cpp:16:17:16:34 | **call to CommandLineToArgvA | semmle.label | **call to CommandLineToArgvA |
98+
| windows.cpp:16:17:16:34 | **call to CommandLineToArgvA | semmle.label | **call to CommandLineToArgvA |
99+
| windows.cpp:16:36:16:38 | *cmd | semmle.label | *cmd |
100+
| windows.cpp:19:8:19:15 | * ... | semmle.label | * ... |
101+
| windows.cpp:23:17:23:38 | *call to GetEnvironmentStringsA | semmle.label | *call to GetEnvironmentStringsA |
102+
| windows.cpp:23:17:23:38 | *call to GetEnvironmentStringsA | semmle.label | *call to GetEnvironmentStringsA |
103+
| windows.cpp:25:10:25:13 | * ... | semmle.label | * ... |
104+
| windows.cpp:28:36:28:38 | GetEnvironmentVariableA output argument | semmle.label | GetEnvironmentVariableA output argument |
105+
| windows.cpp:30:10:30:13 | * ... | semmle.label | * ... |
81106
subpaths
82107
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | asio_streams.cpp:56:18:56:23 | [summary] to write: ReturnValue in buffer | asio_streams.cpp:100:44:100:62 | call to buffer |
83108
| test.cpp:17:24:17:24 | x | test.cpp:4:5:4:17 | [summary param] 0 in ymlStepManual | test.cpp:4:5:4:17 | [summary] to write: ReturnValue in ymlStepManual | test.cpp:17:10:17:22 | call to ymlStepManual |
84109
| test.cpp:21:27:21:27 | x | test.cpp:5:5:5:20 | [summary param] 0 in ymlStepGenerated | test.cpp:5:5:5:20 | [summary] to write: ReturnValue in ymlStepGenerated | test.cpp:21:10:21:25 | call to ymlStepGenerated |
85110
| test.cpp:25:35:25:35 | x | test.cpp:6:5:6:27 | [summary param] 0 in ymlStepManual_with_body | test.cpp:6:5:6:27 | [summary] to write: ReturnValue in ymlStepManual_with_body | test.cpp:25:11:25:33 | call to ymlStepManual_with_body |
86111
| test.cpp:32:41:32:41 | x | test.cpp:7:47:7:52 | value2 | test.cpp:7:5:7:30 | *ymlStepGenerated_with_body | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body |
112+
| windows.cpp:16:36:16:38 | *cmd | windows.cpp:6:8:6:25 | [summary param] *0 in CommandLineToArgvA | windows.cpp:6:8:6:25 | [summary] to write: ReturnValue[**] in CommandLineToArgvA | windows.cpp:16:17:16:34 | **call to CommandLineToArgvA |
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
| asio_streams.cpp:87:34:87:44 | read_until output argument | remote |
22
| test.cpp:10:10:10:18 | call to ymlSource | local |
3+
| windows.cpp:11:15:11:29 | *call to GetCommandLineA | local |
4+
| windows.cpp:23:17:23:38 | *call to GetEnvironmentStringsA | local |
5+
| windows.cpp:28:36:28:38 | GetEnvironmentVariableA output argument | local |

cpp/ql/test/library-tests/dataflow/external-models/steps.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
| test.cpp:28:35:28:35 | 0 | test.cpp:28:11:28:33 | call to ymlStepManual_with_body |
66
| test.cpp:32:38:32:38 | 0 | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body |
77
| test.cpp:35:38:35:38 | x | test.cpp:35:11:35:36 | call to ymlStepGenerated_with_body |
8+
| windows.cpp:16:36:16:38 | *cmd | windows.cpp:16:17:16:34 | **call to CommandLineToArgvA |
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
void sink(char);
2+
void sink(char*);
3+
void sink(char**);
4+
5+
char* GetCommandLineA();
6+
char** CommandLineToArgvA(char*, int*);
7+
char* GetEnvironmentStringsA();
8+
int GetEnvironmentVariableA(const char*, char*, int);
9+
10+
void getCommandLine() {
11+
char* cmd = GetCommandLineA();
12+
sink(cmd);
13+
sink(*cmd); // $ ir
14+
15+
int argc;
16+
char** argv = CommandLineToArgvA(cmd, &argc);
17+
sink(argv);
18+
sink(argv[1]);
19+
sink(*argv[1]); // $ ir
20+
}
21+
22+
void getEnvironment() {
23+
char* env = GetEnvironmentStringsA();
24+
sink(env);
25+
sink(*env); // $ ir
26+
27+
char buf[1024];
28+
GetEnvironmentVariableA("FOO", buf, sizeof(buf));
29+
sink(buf);
30+
sink(*buf); // $ ir
31+
}

0 commit comments

Comments
 (0)