Skip to content

Commit 39e710e

Browse files
committed
Actions: Refactor logic for identifying command substitution
Extract helper predicates for `$(...)` command interpolation and backtick-quoted commands. Add some doc comments and meaningful variable names.
1 parent ef210b8 commit 39e710e

File tree

1 file changed

+47
-21
lines changed

1 file changed

+47
-21
lines changed

actions/ql/lib/codeql/actions/Bash.qll

Lines changed: 47 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,29 +8,55 @@ class BashShellScript extends ShellScript {
88
)
99
}
1010

11-
private string lineProducer(int i) {
12-
result = this.getRawScript().regexpReplaceAll("\\\\\\s*\n", "").splitAt("\n", i)
11+
/**
12+
* Gets the line at 0-based index `lineIndex` within this shell script,
13+
* assuming newlines as separators.
14+
*/
15+
private string lineProducer(int lineIndex) {
16+
result = this.getRawScript().regexpReplaceAll("\\\\\\s*\n", "").splitAt("\n", lineIndex)
1317
}
1418

15-
private predicate cmdSubstitutionReplacement(string cmdSubs, string id, int k) {
16-
exists(string line | line = this.lineProducer(k) |
17-
exists(int i, int j |
18-
cmdSubs =
19-
// $() cmd substitution
20-
line.regexpFind("\\$\\((?:[^()]+|\\((?:[^()]+|\\([^()]*\\))*\\))*\\)", i, j)
21-
.regexpReplaceAll("^\\$\\(", "")
22-
.regexpReplaceAll("\\)$", "") and
23-
id = "cmdsubs:" + k + ":" + i + ":" + j
24-
)
25-
or
26-
exists(int i, int j |
27-
// `...` cmd substitution
28-
cmdSubs =
29-
line.regexpFind("\\`[^\\`]+\\`", i, j)
30-
.regexpReplaceAll("^\\`", "")
31-
.regexpReplaceAll("\\`$", "") and
32-
id = "cmd:" + k + ":" + i + ":" + j
33-
)
19+
private predicate cmdSubstitutionReplacement(string command, string id, int lineIndex) {
20+
this.commandInSubstitution(lineIndex, command, id)
21+
or
22+
this.commandInBackticks(lineIndex, command, id)
23+
}
24+
25+
/**
26+
* Holds if there is a command substitution `$(command)` in
27+
* the line at `lineIndex` in the shell script,
28+
* and `id` is a unique identifier for this command.
29+
*/
30+
private predicate commandInSubstitution(int lineIndex, string command, string id) {
31+
exists(int occurrenceIndex, int occurrenceOffset |
32+
command =
33+
// Look for the command inside a $(...) command substitution
34+
this.lineProducer(lineIndex)
35+
.regexpFind("\\$\\((?:[^()]+|\\((?:[^()]+|\\([^()]*\\))*\\))*\\)", occurrenceIndex,
36+
occurrenceOffset)
37+
// trim starting $( - TODO do this in first regex
38+
.regexpReplaceAll("^\\$\\(", "")
39+
// trim ending ) - TODO do this in first regex
40+
.regexpReplaceAll("\\)$", "") and
41+
id = "cmdsubs:" + lineIndex + ":" + occurrenceIndex + ":" + occurrenceOffset
42+
)
43+
}
44+
45+
/**
46+
* Holds if `command` is a command in backticks `` `...` `` in
47+
* the line at `lineIndex` in the shell script,
48+
* and `id` is a unique identifier for this command.
49+
*/
50+
private predicate commandInBackticks(int lineIndex, string command, string id) {
51+
exists(int occurrenceIndex, int occurrenceOffset |
52+
command =
53+
this.lineProducer(lineIndex)
54+
.regexpFind("\\`[^\\`]+\\`", occurrenceIndex, occurrenceOffset)
55+
// trim leading backtick - TODO do this in first regex
56+
.regexpReplaceAll("^\\`", "")
57+
// trim trailing backtick - TODO do this in first regex
58+
.regexpReplaceAll("\\`$", "") and
59+
id = "cmd:" + lineIndex + ":" + occurrenceIndex + ":" + occurrenceOffset
3460
)
3561
}
3662

0 commit comments

Comments
 (0)