mirror of
https://github.com/github/codeql.git
synced 2026-04-29 18:55:14 +02:00
Python: Make Sanitizer available for urlsplit taint
It isn't used by default, it has to *actively* be enabled.
This commit is contained in:
@@ -195,3 +195,62 @@ class ExternalFileObject extends TaintKind {
|
||||
name = "read" and result = this.getValue()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Temporary sanitizer for the tainted result from `urlsplit` and `urlparse`. Can be used to reduce FPs until
|
||||
* we have better support for namedtuples.
|
||||
*
|
||||
* Will clear **all** taint on a test of the kind. That is, on the true edge of any matching test,
|
||||
* all fields/indexes will be cleared of taint.
|
||||
*
|
||||
* Handles:
|
||||
* - `if splitres.netloc == "KNOWN_VALUE"`
|
||||
* - `if splitres[0] == "KNOWN_VALUE"`
|
||||
*/
|
||||
class UrlsplitUrlparseTempSanitizer extends Sanitizer {
|
||||
// TODO: remove this once we have better support for named tuples
|
||||
|
||||
UrlsplitUrlparseTempSanitizer() { this = "UrlsplitUrlparseTempSanitizer" }
|
||||
|
||||
override predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) {
|
||||
(
|
||||
taint instanceof ExternalUrlSplitResult
|
||||
or
|
||||
taint instanceof ExternalUrlParseResult
|
||||
) and
|
||||
exists(ControlFlowNode foobar |
|
||||
foobar.(SubscriptNode).getObject() = test.getInput().getAUse()
|
||||
or
|
||||
foobar.(AttrNode).getObject() = test.getInput().getAUse()
|
||||
|
|
||||
clears_taint(_, foobar, test.getTest(), test.getSense())
|
||||
)
|
||||
}
|
||||
|
||||
private predicate clears_taint(ControlFlowNode final_test, ControlFlowNode tainted, ControlFlowNode test, boolean sense) {
|
||||
test_equality_with_const(final_test, tainted, sense)
|
||||
or
|
||||
test.(UnaryExprNode).getNode().getOp() instanceof Not and
|
||||
exists(ControlFlowNode nested_test |
|
||||
nested_test = test.(UnaryExprNode).getOperand() and
|
||||
clears_taint(final_test, tainted, nested_test, sense.booleanNot())
|
||||
)
|
||||
}
|
||||
|
||||
/** holds for `== "KNOWN_VALUE"` on `true` edge, and `!= "KNOWN_VALUE"` on `false` edge */
|
||||
private predicate test_equality_with_const(CompareNode cmp, ControlFlowNode operand, boolean sense) {
|
||||
exists(ControlFlowNode const, Cmpop op |
|
||||
const.getNode() instanceof StrConst
|
||||
|
|
||||
(
|
||||
cmp.operands(const, op, operand)
|
||||
or
|
||||
cmp.operands(operand, op, const)
|
||||
) and (
|
||||
op instanceof Eq and sense = true
|
||||
or
|
||||
op instanceof NotEq and sense = false
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,3 +25,23 @@ class DictSource extends TaintSource {
|
||||
|
||||
override string toString() { result = "dict taint source" }
|
||||
}
|
||||
|
||||
class TestConfig extends TaintTracking::Configuration {
|
||||
TestConfig() { this = "TestConfig" }
|
||||
|
||||
override predicate isSanitizer(Sanitizer sanitizer) {
|
||||
sanitizer instanceof UrlsplitUrlparseTempSanitizer
|
||||
}
|
||||
|
||||
override predicate isSource(TaintTracking::Source source) {
|
||||
source instanceof SimpleSource
|
||||
or
|
||||
source instanceof ListSource
|
||||
or
|
||||
source instanceof DictSource
|
||||
}
|
||||
|
||||
override predicate isSink(TaintTracking::Sink sink) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
| test.py:13 | test_basic | c | externally controlled string |
|
||||
| test.py:13 | test_basic | d | externally controlled string |
|
||||
| test.py:13 | test_basic | urlsplit_res | [externally controlled string] |
|
||||
| test.py:20 | test_sanitizer | Attribute | externally controlled string |
|
||||
| test.py:23 | test_sanitizer | Subscript | externally controlled string |
|
||||
| test.py:20 | test_sanitizer | Attribute | NO TAINT |
|
||||
| test.py:23 | test_sanitizer | Subscript | NO TAINT |
|
||||
| test.py:33 | test_namedtuple | a | NO TAINT |
|
||||
| test.py:33 | test_namedtuple | b | NO TAINT |
|
||||
| test.py:33 | test_namedtuple | c | NO TAINT |
|
||||
|
||||
@@ -17,10 +17,10 @@ def test_sanitizer():
|
||||
urlsplit_res = urlsplit(tainted_string)
|
||||
|
||||
if urlsplit_res.netloc == "OK":
|
||||
test(urlsplit_res.netloc) # TODO: FP, should not be tainted here
|
||||
test(urlsplit_res.netloc)
|
||||
|
||||
if urlsplit_res[2] == "OK":
|
||||
test(urlsplit_res[0]) # TODO: FP, should not be tainted here
|
||||
test(urlsplit_res[0])
|
||||
|
||||
def test_namedtuple():
|
||||
tainted_string = TAINTED_STRING
|
||||
|
||||
Reference in New Issue
Block a user