22 * Provides taint-tracking configurations for detecting "path injection" vulnerabilities.
33 *
44 * Note, for performance reasons: only import this file if
5- * the Configurations or the `pathInjection` predicate are needed, otherwise
5+ * `PathInjection::Configuration` is needed, otherwise
66 * `PathInjectionCustomizations` should be imported instead.
77 */
88
99private import python
1010private import semmle.python.Concepts
11- private import semmle.python.dataflow.new.DataFlow
11+ import semmle.python.dataflow.new.DataFlow
12+ import semmle.python.dataflow.new.TaintTracking
13+
14+ /**
15+ * Provides a taint-tracking configuration for detecting "path injection" vulnerabilities.
16+ */
17+ module PathInjection {
18+ import PathInjectionCustomizations:: PathInjection
19+
20+ /**
21+ * A taint-tracking configuration for detecting "path injection" vulnerabilities.
22+ *
23+ * This configuration uses two flow states, `NotNormalized` and `NormalizedUnchecked`,
24+ * to track the requirement that a file path must be first normalized and then checked
25+ * before it is safe to use.
26+ *
27+ * At sources, paths are assumed not normalized. At normalization points, they change
28+ * state to `NormalizedUnchecked` after which they can be made safe by an appropriate
29+ * check of the prefix.
30+ *
31+ * Such checks are ineffective in the `NotNormalized` state.
32+ */
33+ class Configuration extends TaintTracking:: Configuration {
34+ Configuration ( ) { this = "PathInjection" }
35+
36+ override predicate isSource ( DataFlow:: Node source , DataFlow:: FlowState state ) {
37+ source instanceof Source and state instanceof NotNormalized
38+ }
39+
40+ override predicate isSink ( DataFlow:: Node sink , DataFlow:: FlowState state ) {
41+ sink instanceof Sink and
42+ (
43+ state instanceof NotNormalized or
44+ state instanceof NormalizedUnchecked
45+ )
46+ }
47+
48+ override predicate isSanitizer ( DataFlow:: Node node ) { node instanceof Sanitizer }
49+
50+ override predicate isBarrier ( DataFlow:: Node node , DataFlow:: FlowState state ) {
51+ // Block `NotNormalized` paths here, since they change state to `NormalizedUnchecked`
52+ node instanceof Path:: PathNormalization and
53+ state instanceof NotNormalized
54+ or
55+ node = any ( Path:: SafeAccessCheck c ) .getAGuardedNode ( ) and
56+ state instanceof NormalizedUnchecked
57+ }
58+
59+ override predicate isSanitizerGuard ( DataFlow:: BarrierGuard guard ) {
60+ guard instanceof SanitizerGuard
61+ }
62+
63+ override predicate isAdditionalFlowStep (
64+ DataFlow:: Node nodeFrom , DataFlow:: FlowState stateFrom , DataFlow:: Node nodeTo ,
65+ DataFlow:: FlowState stateTo
66+ ) {
67+ nodeFrom = nodeTo .( Path:: PathNormalization ) .getPathArg ( ) and
68+ stateFrom instanceof NotNormalized and
69+ stateTo instanceof NormalizedUnchecked
70+ }
71+ }
72+
73+ /** A state signifying that the file path has not been normalized. */
74+ class NotNormalized extends DataFlow:: FlowState {
75+ NotNormalized ( ) { this = "NotNormalized" }
76+ }
77+
78+ /** A state signifying that the file path has been normalized, but not checked. */
79+ class NormalizedUnchecked extends DataFlow:: FlowState {
80+ NormalizedUnchecked ( ) { this = "NormalizedUnchecked" }
81+ }
82+ }
83+
84+ // ---------------------------------------------------------------------------
85+ // Old, deprecated code
86+ // ---------------------------------------------------------------------------
1287private import semmle.python.dataflow.new.DataFlow2
13- private import semmle.python.dataflow.new.TaintTracking
1488private import semmle.python.dataflow.new.TaintTracking2
15- import ChainedConfigs12
89+ private import ChainedConfigs12
1690import PathInjectionCustomizations:: PathInjection
1791
1892// ---------------------------------------------------------------------------
1993// Case 1. The path is never normalized.
2094// ---------------------------------------------------------------------------
21- /** Configuration to find paths from sources to sinks that contain no normalization. */
22- class PathNotNormalizedConfiguration extends TaintTracking:: Configuration {
95+ /**
96+ * DEPRECATED: Use `PathInjection::Configuration` instead
97+ *
98+ * Configuration to find paths from sources to sinks that contain no normalization.
99+ */
100+ deprecated class PathNotNormalizedConfiguration extends TaintTracking:: Configuration {
23101 PathNotNormalizedConfiguration ( ) { this = "PathNotNormalizedConfiguration" }
24102
25103 override predicate isSource ( DataFlow:: Node source ) { source instanceof Source }
@@ -38,18 +116,24 @@ class PathNotNormalizedConfiguration extends TaintTracking::Configuration {
38116}
39117
40118/**
119+ * DEPRECATED: Use `PathInjection::Configuration` instead
120+ *
41121 * Holds if there is a path injection from source to sink, where the (python) path is
42122 * not normalized.
43123 */
44- predicate pathNotNormalized ( CustomPathNode source , CustomPathNode sink ) {
124+ deprecated predicate pathNotNormalized ( CustomPathNode source , CustomPathNode sink ) {
45125 any ( PathNotNormalizedConfiguration config ) .hasFlowPath ( source .asNode1 ( ) , sink .asNode1 ( ) )
46126}
47127
48128// ---------------------------------------------------------------------------
49129// Case 2. The path is normalized at least once, but never checked afterwards.
50130// ---------------------------------------------------------------------------
51- /** Configuration to find paths from sources to normalizations that contain no prior normalizations. */
52- class FirstNormalizationConfiguration extends TaintTracking:: Configuration {
131+ /**
132+ * DEPRECATED: Use `PathInjection::Configuration` instead
133+ *
134+ * Configuration to find paths from sources to normalizations that contain no prior normalizations.
135+ */
136+ deprecated class FirstNormalizationConfiguration extends TaintTracking:: Configuration {
53137 FirstNormalizationConfiguration ( ) { this = "FirstNormalizationConfiguration" }
54138
55139 override predicate isSource ( DataFlow:: Node source ) { source instanceof Source }
@@ -65,8 +149,12 @@ class FirstNormalizationConfiguration extends TaintTracking::Configuration {
65149 }
66150}
67151
68- /** Configuration to find paths from normalizations to sinks that do not go through a check. */
69- class NormalizedPathNotCheckedConfiguration extends TaintTracking2:: Configuration {
152+ /**
153+ * DEPRECATED: Use `PathInjection::Configuration` instead
154+ *
155+ * Configuration to find paths from normalizations to sinks that do not go through a check.
156+ */
157+ deprecated class NormalizedPathNotCheckedConfiguration extends TaintTracking2:: Configuration {
70158 NormalizedPathNotCheckedConfiguration ( ) { this = "NormalizedPathNotCheckedConfiguration" }
71159
72160 override predicate isSource ( DataFlow:: Node source ) { source instanceof Path:: PathNormalization }
@@ -83,10 +171,12 @@ class NormalizedPathNotCheckedConfiguration extends TaintTracking2::Configuratio
83171}
84172
85173/**
174+ * DEPRECATED: Use `PathInjection::Configuration` instead
175+ *
86176 * Holds if there is a path injection from source to sink, where the (python) path is
87177 * normalized at least once, but never checked afterwards.
88178 */
89- predicate pathNotCheckedAfterNormalization ( CustomPathNode source , CustomPathNode sink ) {
179+ deprecated predicate pathNotCheckedAfterNormalization ( CustomPathNode source , CustomPathNode sink ) {
90180 exists (
91181 FirstNormalizationConfiguration config , DataFlow:: PathNode mid1 , DataFlow2:: PathNode mid2 ,
92182 NormalizedPathNotCheckedConfiguration config2
@@ -100,8 +190,12 @@ predicate pathNotCheckedAfterNormalization(CustomPathNode source, CustomPathNode
100190// ---------------------------------------------------------------------------
101191// Query: Either case 1 or case 2.
102192// ---------------------------------------------------------------------------
103- /** Holds if there is a path injection from source to sink */
104- predicate pathInjection ( CustomPathNode source , CustomPathNode sink ) {
193+ /**
194+ * DEPRECATED: Use `PathInjection::Configuration` instead
195+ *
196+ * Holds if there is a path injection from source to sink
197+ */
198+ deprecated predicate pathInjection ( CustomPathNode source , CustomPathNode sink ) {
105199 pathNotNormalized ( source , sink )
106200 or
107201 pathNotCheckedAfterNormalization ( source , sink )
0 commit comments