Python: Move PathInjection to new dataflow API

This commit is contained in:
Rasmus Wriedt Larsen
2023-08-25 15:34:51 +02:00
parent 245c24077d
commit e97032909a
3 changed files with 61 additions and 6 deletions

View File

@@ -13,6 +13,8 @@ import semmle.python.dataflow.new.TaintTracking
import PathInjectionCustomizations::PathInjection
/**
* DEPRECATED: Use `PathInjectionFlow` module instead.
*
* A taint-tracking configuration for detecting "path injection" vulnerabilities.
*
* This configuration uses two flow states, `NotNormalized` and `NormalizedUnchecked`,
@@ -25,7 +27,7 @@ import PathInjectionCustomizations::PathInjection
*
* Such checks are ineffective in the `NotNormalized` state.
*/
class Configuration extends TaintTracking::Configuration {
deprecated class Configuration extends TaintTracking::Configuration {
Configuration() { this = "PathInjection" }
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
@@ -74,3 +76,52 @@ class NotNormalized extends DataFlow::FlowState {
class NormalizedUnchecked extends DataFlow::FlowState {
NormalizedUnchecked() { this = "NormalizedUnchecked" }
}
/**
* This configuration uses two flow states, `NotNormalized` and `NormalizedUnchecked`,
* to track the requirement that a file path must be first normalized and then checked
* before it is safe to use.
*
* At sources, paths are assumed not normalized. At normalization points, they change
* state to `NormalizedUnchecked` after which they can be made safe by an appropriate
* check of the prefix.
*
* Such checks are ineffective in the `NotNormalized` state.
*/
private module PathInjectionConfig implements DataFlow::StateConfigSig {
class FlowState = DataFlow::FlowState;
predicate isSource(DataFlow::Node source, FlowState state) {
source instanceof Source and state instanceof NotNormalized
}
predicate isSink(DataFlow::Node sink, FlowState state) {
sink instanceof Sink and
(
state instanceof NotNormalized or
state instanceof NormalizedUnchecked
)
}
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
predicate isBarrier(DataFlow::Node node, FlowState state) {
// Block `NotNormalized` paths here, since they change state to `NormalizedUnchecked`
node instanceof Path::PathNormalization and
state instanceof NotNormalized
or
node instanceof Path::SafeAccessCheck and
state instanceof NormalizedUnchecked
}
predicate isAdditionalFlowStep(
DataFlow::Node nodeFrom, FlowState stateFrom, DataFlow::Node nodeTo, FlowState stateTo
) {
nodeFrom = nodeTo.(Path::PathNormalization).getPathArg() and
stateFrom instanceof NotNormalized and
stateTo instanceof NormalizedUnchecked
}
}
/** Global taint-tracking for detecting "path injection" vulnerabilities. */
module PathInjectionFlow = TaintTracking::GlobalWithState<PathInjectionConfig>;

View File

@@ -18,9 +18,9 @@
import python
import semmle.python.security.dataflow.PathInjectionQuery
import DataFlow::PathGraph
import PathInjectionFlow::PathGraph
from Configuration config, DataFlow::PathNode source, DataFlow::PathNode sink
where config.hasFlowPath(source, sink)
from PathInjectionFlow::PathNode source, PathInjectionFlow::PathNode sink
where PathInjectionFlow::flowPath(source, sink)
select sink.getNode(), source, sink, "This path depends on a $@.", source.getNode(),
"user-provided value"

View File

@@ -53,7 +53,8 @@ edges
| path_injection.py:84:16:84:22 | ControlFlowNode for request | path_injection.py:84:16:84:27 | ControlFlowNode for Attribute |
| path_injection.py:84:16:84:27 | ControlFlowNode for Attribute | path_injection.py:84:16:84:47 | ControlFlowNode for Attribute() |
| path_injection.py:84:16:84:47 | ControlFlowNode for Attribute() | path_injection.py:84:5:84:12 | SSA variable filename |
| path_injection.py:85:5:85:24 | SSA variable possibly_unsafe_path | path_injection.py:87:18:87:37 | ControlFlowNode for possibly_unsafe_path |
| path_injection.py:85:5:85:24 | SSA variable possibly_unsafe_path | path_injection.py:86:24:86:43 | ControlFlowNode for possibly_unsafe_path |
| path_injection.py:86:24:86:43 | ControlFlowNode for possibly_unsafe_path | path_injection.py:87:18:87:37 | ControlFlowNode for possibly_unsafe_path |
| path_injection.py:91:20:91:25 | ControlFlowNode for foo_id | path_injection.py:93:5:93:8 | SSA variable path |
| path_injection.py:93:5:93:8 | SSA variable path | path_injection.py:94:14:94:17 | ControlFlowNode for path |
| path_injection.py:98:20:98:22 | ControlFlowNode for foo | path_injection.py:101:5:101:8 | SSA variable path |
@@ -78,7 +79,8 @@ edges
| path_injection.py:138:16:138:22 | ControlFlowNode for request | path_injection.py:138:16:138:27 | ControlFlowNode for Attribute |
| path_injection.py:138:16:138:27 | ControlFlowNode for Attribute | path_injection.py:138:16:138:47 | ControlFlowNode for Attribute() |
| path_injection.py:138:16:138:47 | ControlFlowNode for Attribute() | path_injection.py:138:5:138:12 | SSA variable filename |
| path_injection.py:139:5:139:8 | SSA variable path | path_injection.py:142:14:142:17 | ControlFlowNode for path |
| path_injection.py:139:5:139:8 | SSA variable path | path_injection.py:140:47:140:50 | ControlFlowNode for path |
| path_injection.py:140:47:140:50 | ControlFlowNode for path | path_injection.py:142:14:142:17 | ControlFlowNode for path |
| path_injection.py:149:5:149:12 | SSA variable filename | path_injection.py:151:9:151:12 | SSA variable path |
| path_injection.py:149:16:149:22 | ControlFlowNode for request | path_injection.py:149:16:149:27 | ControlFlowNode for Attribute |
| path_injection.py:149:16:149:27 | ControlFlowNode for Attribute | path_injection.py:149:16:149:47 | ControlFlowNode for Attribute() |
@@ -171,6 +173,7 @@ nodes
| path_injection.py:84:16:84:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| path_injection.py:84:16:84:47 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| path_injection.py:85:5:85:24 | SSA variable possibly_unsafe_path | semmle.label | SSA variable possibly_unsafe_path |
| path_injection.py:86:24:86:43 | ControlFlowNode for possibly_unsafe_path | semmle.label | ControlFlowNode for possibly_unsafe_path |
| path_injection.py:87:18:87:37 | ControlFlowNode for possibly_unsafe_path | semmle.label | ControlFlowNode for possibly_unsafe_path |
| path_injection.py:91:20:91:25 | ControlFlowNode for foo_id | semmle.label | ControlFlowNode for foo_id |
| path_injection.py:93:5:93:8 | SSA variable path | semmle.label | SSA variable path |
@@ -202,6 +205,7 @@ nodes
| path_injection.py:138:16:138:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| path_injection.py:138:16:138:47 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| path_injection.py:139:5:139:8 | SSA variable path | semmle.label | SSA variable path |
| path_injection.py:140:47:140:50 | ControlFlowNode for path | semmle.label | ControlFlowNode for path |
| path_injection.py:142:14:142:17 | ControlFlowNode for path | semmle.label | ControlFlowNode for path |
| path_injection.py:149:5:149:12 | SSA variable filename | semmle.label | SSA variable filename |
| path_injection.py:149:16:149:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |