-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
Copy pathTaintedPath.ql
91 lines (80 loc) · 3.04 KB
/
TaintedPath.ql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
/**
* @name Uncontrolled data used in path expression
* @description Accessing paths influenced by users can allow an attacker to access unexpected resources.
* @kind path-problem
* @problem.severity error
* @security-severity 7.5
* @precision high
* @id rust/path-injection
* @tags security
* external/cwe/cwe-022
* external/cwe/cwe-023
* external/cwe/cwe-036
* external/cwe/cwe-073
* external/cwe/cwe-099
*/
import rust
import codeql.rust.dataflow.DataFlow
import codeql.rust.dataflow.TaintTracking
import codeql.rust.dataflow.internal.DataFlowImpl as DataflowImpl
import codeql.rust.Concepts
import codeql.rust.security.TaintedPathExtensions
newtype NormalizationState =
/** A state signifying that the file path has not been normalized. */
NotNormalized() or
/** A state signifying that the file path has been normalized, but not checked. */
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.
*/
module TaintedPathConfig implements DataFlow::StateConfigSig {
class FlowState = NormalizationState;
predicate isSource(DataFlow::Node source, FlowState state) {
source instanceof TaintedPath::Source and state instanceof NotNormalized
}
predicate isSink(DataFlow::Node sink, FlowState state) {
sink instanceof TaintedPath::Sink and
(
state instanceof NotNormalized or
state instanceof NormalizedUnchecked
)
}
predicate isBarrier(DataFlow::Node node) {
node instanceof TaintedPath::Barrier or node instanceof TaintedPath::SanitizerGuard
}
predicate isBarrier(DataFlow::Node node, FlowState state) {
// Block `NotNormalized` paths here, since they change state to `NormalizedUnchecked`
(
node instanceof Path::PathNormalization or
DataflowImpl::optionalBarrier(node, "normalize-path")
) 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() or
DataflowImpl::optionalStep(nodeFrom, "normalize-path", nodeTo)
) and
stateFrom instanceof NotNormalized and
stateTo instanceof NormalizedUnchecked
}
}
module TaintedPathFlow = TaintTracking::GlobalWithState<TaintedPathConfig>;
import TaintedPathFlow::PathGraph
from TaintedPathFlow::PathNode source, TaintedPathFlow::PathNode sink
where TaintedPathFlow::flowPath(source, sink)
select sink.getNode(), source, sink, "This path depends on a $@.", source.getNode(),
"user-provided value"