Ruby: configsig rb/shell-command-constructed-from-input

This commit is contained in:
Alex Ford
2023-09-03 15:51:09 +01:00
parent f03f670312
commit f79796a644
2 changed files with 37 additions and 6 deletions

View File

@@ -2,8 +2,9 @@
* Provides a taint tracking configuration for reasoning about shell command
* constructed from library input vulnerabilities
*
* Note, for performance reasons: only import this file if `Configuration` is needed,
* otherwise `UnsafeShellCommandConstructionCustomizations` should be imported instead.
* Note, for performance reasons: only import this file if
* `UnsafeShellCommandConstructionFlow` is needed, otherwise
* `UnsafeShellCommandConstructionCustomizations` should be imported instead.
*/
import codeql.ruby.DataFlow
@@ -14,8 +15,9 @@ private import codeql.ruby.dataflow.BarrierGuards
/**
* A taint-tracking configuration for detecting shell command constructed from library input vulnerabilities.
* DEPRECATED: Use `UnsafeShellCommandConstructionFlow`
*/
class Configuration extends TaintTracking::Configuration {
deprecated class Configuration extends TaintTracking::Configuration {
Configuration() { this = "UnsafeShellCommandConstruction" }
override predicate isSource(DataFlow::Node source) { source instanceof Source }
@@ -39,3 +41,30 @@ class Configuration extends TaintTracking::Configuration {
set.isElementOfTypeOrUnknown("int")
}
}
private module UnsafeShellCommandConstructionConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof Source }
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
predicate isBarrier(DataFlow::Node node) {
node instanceof CommandInjection::Sanitizer or // using all sanitizers from `rb/command-injection`
node instanceof StringConstCompareBarrier or
node instanceof StringConstArrayInclusionCallBarrier
}
// override to require the path doesn't have unmatched return steps
DataFlow::FlowFeature getAFeature() { result instanceof DataFlow::FeatureHasSourceCallContext }
predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet set) {
// allow implicit reads of array elements
isSink(node) and
set.isElementOfTypeOrUnknown("int")
}
}
/**
* Taint-tracking for detecting shell command constructed from library input vulnerabilities.
*/
module UnsafeShellCommandConstructionFlow =
TaintTracking::Global<UnsafeShellCommandConstructionConfig>;

View File

@@ -15,11 +15,13 @@
*/
import codeql.ruby.security.UnsafeShellCommandConstructionQuery
import DataFlow::PathGraph
import UnsafeShellCommandConstructionFlow::PathGraph
from Configuration config, DataFlow::PathNode source, DataFlow::PathNode sink, Sink sinkNode
from
UnsafeShellCommandConstructionFlow::PathNode source,
UnsafeShellCommandConstructionFlow::PathNode sink, Sink sinkNode
where
config.hasFlowPath(source, sink) and
UnsafeShellCommandConstructionFlow::flowPath(source, sink) and
sinkNode = sink.getNode()
select sinkNode.getStringConstruction(), source, sink,
"This " + sinkNode.describe() + " which depends on $@ is later used in a $@.", source.getNode(),