Skip to content

Commit f79796a

Browse files
committed
Ruby: configsig rb/shell-command-constructed-from-input
1 parent f03f670 commit f79796a

File tree

2 files changed

+37
-6
lines changed

2 files changed

+37
-6
lines changed

ruby/ql/lib/codeql/ruby/security/UnsafeShellCommandConstructionQuery.qll

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
* Provides a taint tracking configuration for reasoning about shell command
33
* constructed from library input vulnerabilities
44
*
5-
* Note, for performance reasons: only import this file if `Configuration` is needed,
6-
* otherwise `UnsafeShellCommandConstructionCustomizations` should be imported instead.
5+
* Note, for performance reasons: only import this file if
6+
* `UnsafeShellCommandConstructionFlow` is needed, otherwise
7+
* `UnsafeShellCommandConstructionCustomizations` should be imported instead.
78
*/
89

910
import codeql.ruby.DataFlow
@@ -14,8 +15,9 @@ private import codeql.ruby.dataflow.BarrierGuards
1415

1516
/**
1617
* A taint-tracking configuration for detecting shell command constructed from library input vulnerabilities.
18+
* DEPRECATED: Use `UnsafeShellCommandConstructionFlow`
1719
*/
18-
class Configuration extends TaintTracking::Configuration {
20+
deprecated class Configuration extends TaintTracking::Configuration {
1921
Configuration() { this = "UnsafeShellCommandConstruction" }
2022

2123
override predicate isSource(DataFlow::Node source) { source instanceof Source }
@@ -39,3 +41,30 @@ class Configuration extends TaintTracking::Configuration {
3941
set.isElementOfTypeOrUnknown("int")
4042
}
4143
}
44+
45+
private module UnsafeShellCommandConstructionConfig implements DataFlow::ConfigSig {
46+
predicate isSource(DataFlow::Node source) { source instanceof Source }
47+
48+
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
49+
50+
predicate isBarrier(DataFlow::Node node) {
51+
node instanceof CommandInjection::Sanitizer or // using all sanitizers from `rb/command-injection`
52+
node instanceof StringConstCompareBarrier or
53+
node instanceof StringConstArrayInclusionCallBarrier
54+
}
55+
56+
// override to require the path doesn't have unmatched return steps
57+
DataFlow::FlowFeature getAFeature() { result instanceof DataFlow::FeatureHasSourceCallContext }
58+
59+
predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet set) {
60+
// allow implicit reads of array elements
61+
isSink(node) and
62+
set.isElementOfTypeOrUnknown("int")
63+
}
64+
}
65+
66+
/**
67+
* Taint-tracking for detecting shell command constructed from library input vulnerabilities.
68+
*/
69+
module UnsafeShellCommandConstructionFlow =
70+
TaintTracking::Global<UnsafeShellCommandConstructionConfig>;

ruby/ql/src/queries/security/cwe-078/UnsafeShellCommandConstruction.ql

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@
1515
*/
1616

1717
import codeql.ruby.security.UnsafeShellCommandConstructionQuery
18-
import DataFlow::PathGraph
18+
import UnsafeShellCommandConstructionFlow::PathGraph
1919

20-
from Configuration config, DataFlow::PathNode source, DataFlow::PathNode sink, Sink sinkNode
20+
from
21+
UnsafeShellCommandConstructionFlow::PathNode source,
22+
UnsafeShellCommandConstructionFlow::PathNode sink, Sink sinkNode
2123
where
22-
config.hasFlowPath(source, sink) and
24+
UnsafeShellCommandConstructionFlow::flowPath(source, sink) and
2325
sinkNode = sink.getNode()
2426
select sinkNode.getStringConstruction(), source, sink,
2527
"This " + sinkNode.describe() + " which depends on $@ is later used in a $@.", source.getNode(),

0 commit comments

Comments
 (0)