Skip to content

Commit 6353dbf

Browse files
committed
Merge branch 'main' into rust-core-std-models
2 parents b6144c2 + 22074af commit 6353dbf

File tree

128 files changed

+4160
-2026
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

128 files changed

+4160
-2026
lines changed

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2006-2020 GitHub, Inc.
3+
Copyright (c) 2006-2025 GitHub, Inc.
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

actions/extractor/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ codeql_pkg_files(
44
name = "extractor",
55
srcs = [
66
"codeql-extractor.yml",
7+
"//:LICENSE",
78
] + glob(["tools/**"]),
89
strip_prefix = strip_prefix.from_pkg(),
910
visibility = ["//actions:__pkg__"],

cpp/ql/src/Security/CWE/CWE-078/ExecTainted.ql

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,17 @@ predicate interestingConcatenation(DataFlow::Node incoming, DataFlow::Node outgo
4949
call.getTarget() = op and
5050
op.hasQualifiedName("std", "operator+") and
5151
op.getType().(UserType).hasQualifiedName("std", "basic_string") and
52-
incoming.asIndirectArgument() = call.getArgument(1) and // left operand
52+
incoming.asIndirectArgument() = call.getArgument(1) and // right operand
5353
call = outgoing.asInstruction().getUnconvertedResultExpression()
5454
)
5555
}
5656

57+
/**
58+
* A state will represent the most recent concatenation that occurred in the data flow.
59+
* - `TConcatState` if the concetenation has not yet occurred.
60+
* - `TExecState(incoming, outgoing)`, representing the concatenation of data from `incoming`
61+
* into result `outgoing`.
62+
*/
5763
newtype TState =
5864
TConcatState() or
5965
TExecState(DataFlow::Node incoming, DataFlow::Node outgoing) {
@@ -74,7 +80,9 @@ class ExecState extends TExecState {
7480

7581
DataFlow::Node getOutgoingNode() { result = outgoing }
7682

77-
/** Holds if this is a possible `ExecState` for `sink`. */
83+
/**
84+
* Holds if this is a possible `ExecState` at `sink`, that is, if `outgoing` flows to `sink`.
85+
*/
7886
predicate isFeasibleForSink(DataFlow::Node sink) { ExecState::flow(outgoing, sink) }
7987

8088
string toString() { result = "ExecState" }
@@ -110,6 +118,12 @@ module ExecStateConfig implements DataFlow::ConfigSig {
110118

111119
module ExecState = TaintTracking::Global<ExecStateConfig>;
112120

121+
/**
122+
* A full `TaintTracking` configuration from source to concatenation to sink, using a flow
123+
* state to remember the concatenation. It's important that we track flow to the sink even though
124+
* as soon as we reach the concatenation we know it will get there (due to the check of
125+
* `isFeasibleForSink`), because this way we get a complete flow path.
126+
*/
113127
module ExecTaintConfig implements DataFlow::StateConfigSig {
114128
class FlowState = TState;
115129

cpp/ql/test/query-tests/Security/CWE/CWE-078/semmle/ExecTainted/ExecTainted.expected

Lines changed: 205 additions & 153 deletions
Large diffs are not rendered by default.

cpp/ql/test/query-tests/Security/CWE/CWE-078/semmle/ExecTainted/test.cpp

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ extern void encodeShellString(char *shellStr, int maxChars, const char* cStr);
1414

1515
int main(int argc, char** argv) {
1616
char *userName = argv[2];
17-
17+
1818
{
1919
// BAD: a string from the user is injected directly into
2020
// a command.
@@ -23,10 +23,10 @@ int main(int argc, char** argv) {
2323
system(command1);
2424
}
2525

26-
{
26+
{
2727
// GOOD: the user string is encoded by a library routine.
2828
char userNameQuoted[1000] = {0};
29-
encodeShellString(userNameQuoted, 1000, userName);
29+
encodeShellString(userNameQuoted, 1000, userName);
3030
char command2[1000] = {0};
3131
sprintf(command2, "userinfo -v %s", userNameQuoted);
3232
system(command2);
@@ -36,16 +36,16 @@ int main(int argc, char** argv) {
3636
void test2(char* arg2) {
3737
// GOOD?: the user string is the *first* part of the command, like $CC in many environments
3838
char *envCC = getenv("CC");
39-
39+
4040
char command[1000];
41-
sprintf("%s %s", envCC, arg2);
41+
sprintf(command, "%s %s", envCC, arg2);
4242
system(command);
4343
}
4444

4545
void test3(char* arg1) {
4646
// GOOD?: the user string is a `$CFLAGS` environment variable
4747
char *envCflags = getenv("CFLAGS");
48-
48+
4949
char command[1000];
5050
sprintf(command, "%s %s", arg1, envCflags);
5151
system(command);
@@ -54,6 +54,7 @@ void test3(char* arg1) {
5454
typedef unsigned long size_t;
5555
typedef void FILE;
5656
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
57+
char *strncpy(char *s1, const char *s2, size_t n);
5758
char *strncat(char *s1, const char *s2, size_t n);
5859

5960
void test4(FILE *f) {
@@ -160,7 +161,7 @@ void test15(FILE *f) {
160161
fread(temp, 1, 10, f);
161162

162163
int x = atoi(temp);
163-
164+
164165
char temp2[10];
165166
sprintf(temp2, "%d", x);
166167
sprintf(command, "tail -n %s foo.log", temp2);
@@ -222,4 +223,42 @@ void test19(FILE *f) {
222223
execl("/bin/sh", "sh", "-c", command);
223224
}
224225

226+
void test20() {
227+
// BAD: the user strings `var_b`, `var_c` are injected directly into a command
228+
char buffer[1024 * 4];
229+
230+
strncpy(buffer, getenv("var_a"), 1024);
231+
strncat(buffer, getenv("var_b"), 1024);
232+
strncat(buffer, getenv("var_c"), 1024);
233+
strncat(buffer, " ", 1024);
234+
system(buffer);
235+
}
236+
237+
void test21() {
238+
// BAD: the user strings `var_b`, `var_c` are injected directly into a command
239+
char buffer1[1024];
240+
char buffer2[1024];
241+
242+
sprintf(buffer1, "%s %s",
243+
getenv("var_a"),
244+
getenv("var_b"));
245+
sprintf(buffer2, "%s %s %s",
246+
" ",
247+
buffer1,
248+
getenv("var_c"));
249+
system(buffer2);
250+
}
251+
252+
void test22() {
253+
// BAD: the user strings `var_a` are injected directly into a command
254+
char buffer[1024 * 11];
255+
int i;
256+
257+
strncpy(buffer, "command ", 1024);
258+
for (i = 0; i < 10; i++) {
259+
strncat(buffer, getenv("var_a"), 1024);
260+
}
261+
system(buffer);
262+
}
263+
225264
// open question: do we want to report certain sources even when they're the start of the string?

csharp/ql/lib/CHANGELOG.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@
6868

6969
### Minor Analysis Improvements
7070

71-
* .NET 9 is now required to build the C# extractor.
7271
* The Models as Data models for .NET 8 Runtime now include generated models for higher order methods.
7372

7473
## 3.1.0

csharp/ql/lib/change-notes/released/3.1.1.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,4 @@
22

33
### Minor Analysis Improvements
44

5-
* .NET 9 is now required to build the C# extractor.
65
* The Models as Data models for .NET 8 Runtime now include generated models for higher order methods.

csharp/ql/lib/semmle/code/csharp/dataflow/internal/SsaImpl.qll

Lines changed: 11 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -734,15 +734,15 @@ private predicate variableReadPseudo(ControlFlow::BasicBlock bb, int i, Ssa::Sou
734734
}
735735

736736
pragma[noinline]
737-
private predicate adjacentDefRead(
737+
deprecated private predicate adjacentDefRead(
738738
Definition def, SsaInput::BasicBlock bb1, int i1, SsaInput::BasicBlock bb2, int i2,
739739
SsaInput::SourceVariable v
740740
) {
741741
Impl::adjacentDefRead(def, bb1, i1, bb2, i2) and
742742
v = def.getSourceVariable()
743743
}
744744

745-
private predicate adjacentDefReachesRead(
745+
deprecated private predicate adjacentDefReachesRead(
746746
Definition def, SsaInput::SourceVariable v, SsaInput::BasicBlock bb1, int i1,
747747
SsaInput::BasicBlock bb2, int i2
748748
) {
@@ -760,18 +760,7 @@ private predicate adjacentDefReachesRead(
760760
)
761761
}
762762

763-
/** Same as `adjacentDefRead`, but skips uncertain reads. */
764-
pragma[nomagic]
765-
private predicate adjacentDefSkipUncertainReads(
766-
Definition def, SsaInput::BasicBlock bb1, int i1, SsaInput::BasicBlock bb2, int i2
767-
) {
768-
exists(SsaInput::SourceVariable v |
769-
adjacentDefReachesRead(def, v, bb1, i1, bb2, i2) and
770-
SsaInput::variableRead(bb2, i2, v, true)
771-
)
772-
}
773-
774-
private predicate adjacentDefReachesUncertainRead(
763+
deprecated private predicate adjacentDefReachesUncertainRead(
775764
Definition def, SsaInput::BasicBlock bb1, int i1, SsaInput::BasicBlock bb2, int i2
776765
) {
777766
exists(SsaInput::SourceVariable v |
@@ -933,10 +922,8 @@ private module Cached {
933922
*/
934923
cached
935924
predicate firstReadSameVar(Definition def, ControlFlow::Node cfn) {
936-
exists(ControlFlow::BasicBlock bb1, int i1, ControlFlow::BasicBlock bb2, int i2 |
937-
def.definesAt(_, bb1, i1) and
938-
adjacentDefSkipUncertainReads(def, bb1, i1, bb2, i2) and
939-
cfn = bb2.getNode(i2)
925+
exists(ControlFlow::BasicBlock bb, int i |
926+
Impl::firstUse(def, bb, i, true) and cfn = bb.getNode(i)
940927
)
941928
}
942929

@@ -947,25 +934,17 @@ private module Cached {
947934
*/
948935
cached
949936
predicate adjacentReadPairSameVar(Definition def, ControlFlow::Node cfn1, ControlFlow::Node cfn2) {
950-
exists(ControlFlow::BasicBlock bb1, int i1, ControlFlow::BasicBlock bb2, int i2 |
937+
exists(
938+
ControlFlow::BasicBlock bb1, int i1, ControlFlow::BasicBlock bb2, int i2,
939+
Ssa::SourceVariable v
940+
|
941+
Impl::ssaDefReachesRead(v, def, bb1, i1) and
942+
Impl::adjacentUseUse(bb1, i1, bb2, i2, v, true) and
951943
cfn1 = bb1.getNode(i1) and
952-
variableReadActual(bb1, i1, _) and
953-
adjacentDefSkipUncertainReads(def, bb1, i1, bb2, i2) and
954944
cfn2 = bb2.getNode(i2)
955945
)
956946
}
957947

958-
cached
959-
predicate lastRefBeforeRedef(Definition def, ControlFlow::BasicBlock bb, int i, Definition next) {
960-
Impl::lastRefRedef(def, bb, i, next) and
961-
not SsaInput::variableRead(bb, i, def.getSourceVariable(), false)
962-
or
963-
exists(SsaInput::BasicBlock bb0, int i0 |
964-
Impl::lastRefRedef(def, bb0, i0, next) and
965-
adjacentDefReachesUncertainRead(def, bb, i, bb0, i0)
966-
)
967-
}
968-
969948
cached
970949
Definition uncertainWriteDefinitionInput(UncertainWriteDefinition def) {
971950
Impl::uncertainWriteDefinitionInput(def, result)

csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1190,11 +1190,11 @@
11901190
| cflow.cs:181:28:181:37 | enter (...) => ... | cflow.cs:181:28:181:37 | exit (...) => ... | 6 |
11911191
| cflow.cs:182:28:182:61 | enter delegate(...) { ... } | cflow.cs:182:28:182:61 | exit delegate(...) { ... } | 8 |
11921192
| cflow.cs:185:10:185:18 | enter LogicalOr | cflow.cs:187:13:187:18 | ... == ... | 6 |
1193-
| cflow.cs:187:13:187:28 | [false] ... \|\| ... | cflow.cs:187:13:187:28 | [false] ... \|\| ... | 1 |
1194-
| cflow.cs:187:13:187:50 | [false] ... \|\| ... | cflow.cs:187:13:187:50 | [false] ... \|\| ... | 1 |
1193+
| cflow.cs:187:13:187:28 | ... \|\| ... | cflow.cs:187:13:187:28 | ... \|\| ... | 1 |
1194+
| cflow.cs:187:13:187:50 | ... \|\| ... | cflow.cs:187:13:187:50 | ... \|\| ... | 1 |
11951195
| cflow.cs:187:23:187:23 | 2 | cflow.cs:187:23:187:28 | ... == ... | 3 |
11961196
| cflow.cs:187:34:187:34 | 1 | cflow.cs:187:34:187:39 | ... == ... | 3 |
1197-
| cflow.cs:187:34:187:49 | [false] ... && ... | cflow.cs:187:34:187:49 | [false] ... && ... | 1 |
1197+
| cflow.cs:187:34:187:49 | ... && ... | cflow.cs:187:34:187:49 | ... && ... | 1 |
11981198
| cflow.cs:190:13:190:52 | ...; | cflow.cs:185:10:185:18 | exit LogicalOr | 5 |
11991199
| cflow.cs:193:10:193:17 | enter Booleans | cflow.cs:195:17:195:32 | ... > ... | 8 |
12001200
| cflow.cs:193:10:193:17 | exit Booleans | cflow.cs:193:10:193:17 | exit Booleans | 1 |

csharp/ql/test/library-tests/controlflow/graph/Condition.expected

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2303,27 +2303,27 @@ conditionBlock
23032303
| cflow.cs:167:16:167:16 | access to local variable x | cflow.cs:174:9:176:9 | {...} | false |
23042304
| cflow.cs:173:32:173:32 | access to local variable i | cflow.cs:146:10:146:12 | exit For (normal) | false |
23052305
| cflow.cs:173:32:173:32 | access to local variable i | cflow.cs:174:9:176:9 | {...} | true |
2306-
| cflow.cs:185:10:185:18 | enter LogicalOr | cflow.cs:187:13:187:28 | [false] ... \|\| ... | false |
2307-
| cflow.cs:185:10:185:18 | enter LogicalOr | cflow.cs:187:13:187:50 | [false] ... \|\| ... | false |
2306+
| cflow.cs:185:10:185:18 | enter LogicalOr | cflow.cs:187:13:187:28 | ... \|\| ... | false |
2307+
| cflow.cs:185:10:185:18 | enter LogicalOr | cflow.cs:187:13:187:50 | ... \|\| ... | false |
23082308
| cflow.cs:185:10:185:18 | enter LogicalOr | cflow.cs:187:23:187:23 | 2 | false |
23092309
| cflow.cs:185:10:185:18 | enter LogicalOr | cflow.cs:187:34:187:34 | 1 | false |
2310-
| cflow.cs:185:10:185:18 | enter LogicalOr | cflow.cs:187:34:187:49 | [false] ... && ... | false |
2310+
| cflow.cs:185:10:185:18 | enter LogicalOr | cflow.cs:187:34:187:49 | ... && ... | false |
23112311
| cflow.cs:185:10:185:18 | enter LogicalOr | cflow.cs:190:13:190:52 | ...; | false |
2312-
| cflow.cs:187:13:187:28 | [false] ... \|\| ... | cflow.cs:187:13:187:50 | [false] ... \|\| ... | false |
2313-
| cflow.cs:187:13:187:28 | [false] ... \|\| ... | cflow.cs:187:34:187:34 | 1 | false |
2314-
| cflow.cs:187:13:187:28 | [false] ... \|\| ... | cflow.cs:187:34:187:49 | [false] ... && ... | false |
2315-
| cflow.cs:187:13:187:28 | [false] ... \|\| ... | cflow.cs:190:13:190:52 | ...; | false |
2316-
| cflow.cs:187:13:187:50 | [false] ... \|\| ... | cflow.cs:190:13:190:52 | ...; | false |
2317-
| cflow.cs:187:23:187:23 | 2 | cflow.cs:187:13:187:28 | [false] ... \|\| ... | false |
2318-
| cflow.cs:187:23:187:23 | 2 | cflow.cs:187:13:187:50 | [false] ... \|\| ... | false |
2312+
| cflow.cs:187:13:187:28 | ... \|\| ... | cflow.cs:187:13:187:50 | ... \|\| ... | false |
2313+
| cflow.cs:187:13:187:28 | ... \|\| ... | cflow.cs:187:34:187:34 | 1 | false |
2314+
| cflow.cs:187:13:187:28 | ... \|\| ... | cflow.cs:187:34:187:49 | ... && ... | false |
2315+
| cflow.cs:187:13:187:28 | ... \|\| ... | cflow.cs:190:13:190:52 | ...; | false |
2316+
| cflow.cs:187:13:187:50 | ... \|\| ... | cflow.cs:190:13:190:52 | ...; | false |
2317+
| cflow.cs:187:23:187:23 | 2 | cflow.cs:187:13:187:28 | ... \|\| ... | false |
2318+
| cflow.cs:187:23:187:23 | 2 | cflow.cs:187:13:187:50 | ... \|\| ... | false |
23192319
| cflow.cs:187:23:187:23 | 2 | cflow.cs:187:34:187:34 | 1 | false |
2320-
| cflow.cs:187:23:187:23 | 2 | cflow.cs:187:34:187:49 | [false] ... && ... | false |
2320+
| cflow.cs:187:23:187:23 | 2 | cflow.cs:187:34:187:49 | ... && ... | false |
23212321
| cflow.cs:187:23:187:23 | 2 | cflow.cs:190:13:190:52 | ...; | false |
2322-
| cflow.cs:187:34:187:34 | 1 | cflow.cs:187:13:187:50 | [false] ... \|\| ... | false |
2323-
| cflow.cs:187:34:187:34 | 1 | cflow.cs:187:34:187:49 | [false] ... && ... | false |
2322+
| cflow.cs:187:34:187:34 | 1 | cflow.cs:187:13:187:50 | ... \|\| ... | false |
2323+
| cflow.cs:187:34:187:34 | 1 | cflow.cs:187:34:187:49 | ... && ... | false |
23242324
| cflow.cs:187:34:187:34 | 1 | cflow.cs:190:13:190:52 | ...; | false |
2325-
| cflow.cs:187:34:187:49 | [false] ... && ... | cflow.cs:187:13:187:50 | [false] ... \|\| ... | false |
2326-
| cflow.cs:187:34:187:49 | [false] ... && ... | cflow.cs:190:13:190:52 | ...; | false |
2325+
| cflow.cs:187:34:187:49 | ... && ... | cflow.cs:187:13:187:50 | ... \|\| ... | false |
2326+
| cflow.cs:187:34:187:49 | ... && ... | cflow.cs:190:13:190:52 | ...; | false |
23272327
| cflow.cs:193:10:193:17 | enter Booleans | cflow.cs:195:39:195:43 | this access | true |
23282328
| cflow.cs:195:17:195:56 | ... && ... | cflow.cs:197:13:197:47 | [false] !... | false |
23292329
| cflow.cs:195:17:195:56 | ... && ... | cflow.cs:197:13:197:47 | [true] !... | true |
@@ -2964,11 +2964,11 @@ conditionFlow
29642964
| cflow.cs:173:32:173:41 | ... < ... | cflow.cs:146:10:146:12 | exit For (normal) | false |
29652965
| cflow.cs:173:32:173:41 | ... < ... | cflow.cs:174:9:176:9 | {...} | true |
29662966
| cflow.cs:187:13:187:18 | ... == ... | cflow.cs:187:23:187:23 | 2 | false |
2967-
| cflow.cs:187:13:187:28 | [false] ... \|\| ... | cflow.cs:187:34:187:34 | 1 | false |
2968-
| cflow.cs:187:13:187:50 | [false] ... \|\| ... | cflow.cs:190:13:190:52 | ...; | false |
2969-
| cflow.cs:187:23:187:28 | ... == ... | cflow.cs:187:13:187:28 | [false] ... \|\| ... | false |
2970-
| cflow.cs:187:34:187:39 | ... == ... | cflow.cs:187:34:187:49 | [false] ... && ... | false |
2971-
| cflow.cs:187:34:187:49 | [false] ... && ... | cflow.cs:187:13:187:50 | [false] ... \|\| ... | false |
2967+
| cflow.cs:187:13:187:28 | ... \|\| ... | cflow.cs:187:34:187:34 | 1 | false |
2968+
| cflow.cs:187:13:187:50 | ... \|\| ... | cflow.cs:190:13:190:52 | ...; | false |
2969+
| cflow.cs:187:23:187:28 | ... == ... | cflow.cs:187:13:187:28 | ... \|\| ... | false |
2970+
| cflow.cs:187:34:187:39 | ... == ... | cflow.cs:187:34:187:49 | ... && ... | false |
2971+
| cflow.cs:187:34:187:49 | ... && ... | cflow.cs:187:13:187:50 | ... \|\| ... | false |
29722972
| cflow.cs:195:17:195:32 | ... > ... | cflow.cs:195:17:195:56 | ... && ... | false |
29732973
| cflow.cs:195:17:195:32 | ... > ... | cflow.cs:195:39:195:43 | this access | true |
29742974
| cflow.cs:197:13:197:47 | [false] !... | cflow.cs:200:9:205:9 | if (...) ... | false |

0 commit comments

Comments
 (0)