mirror of
https://github.com/github/codeql.git
synced 2026-04-30 03:05:15 +02:00
Merge remote-tracking branch 'upstream/rc/1.20' into mergeback-2019-03-19
This commit is contained in:
@@ -15,6 +15,14 @@
|
||||
import python
|
||||
import semmle.python.Comparisons
|
||||
|
||||
/* Holds if the comparison `comp` is of the complex form `a op b op c` and not of
|
||||
* the simple form `a op b`.
|
||||
*/
|
||||
private predicate is_complex(Expr comp) {
|
||||
exists(comp.(Compare).getOp(1))
|
||||
or
|
||||
is_complex(comp.(UnaryExpr).getOperand())
|
||||
}
|
||||
|
||||
/** A test is useless if for every block that it controls there is another test that is at least as
|
||||
* strict and also controls that block.
|
||||
@@ -22,7 +30,7 @@ import semmle.python.Comparisons
|
||||
private predicate useless_test(Comparison comp, ComparisonControlBlock controls, boolean isTrue) {
|
||||
controls.impliesThat(comp.getBasicBlock(), comp, isTrue) and
|
||||
/* Exclude complex comparisons of form `a < x < y`, as we do not (yet) have perfect flow control for those */
|
||||
not exists(controls.getTest().getNode().(Compare).getOp(1))
|
||||
not is_complex(controls.getTest().getNode())
|
||||
}
|
||||
|
||||
private predicate useless_test_ast(AstNode comp, AstNode previous, boolean isTrue) {
|
||||
|
||||
@@ -95,6 +95,14 @@ predicate in_raises_test(Expr e) {
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if expression has the form of a Python 2 `print >> out, ...` statement */
|
||||
predicate python2_print(Expr e) {
|
||||
e.(BinaryExpr).getLeft().(Name).getId() = "print" and
|
||||
e.(BinaryExpr).getOp() instanceof RShift
|
||||
or
|
||||
python2_print(e.(Tuple).getElt(0))
|
||||
}
|
||||
|
||||
predicate no_effect(Expr e) {
|
||||
not e instanceof StrConst and
|
||||
not ((StrConst)e).isDocString() and
|
||||
@@ -107,7 +115,8 @@ predicate no_effect(Expr e) {
|
||||
not maybe_side_effecting_attribute(sub)
|
||||
) and
|
||||
not in_notebook(e) and
|
||||
not in_raises_test(e)
|
||||
not in_raises_test(e) and
|
||||
not python2_print(e)
|
||||
}
|
||||
|
||||
from ExprStmt stmt
|
||||
|
||||
3
python/ql/src/semmle/python/dataflow/TaintTracking.qll
Executable file
3
python/ql/src/semmle/python/dataflow/TaintTracking.qll
Executable file
@@ -0,0 +1,3 @@
|
||||
/* For compatibility with other language implementations */
|
||||
|
||||
import semmle.python.security.TaintTracking
|
||||
@@ -125,13 +125,6 @@ abstract class TaintKind extends string {
|
||||
*/
|
||||
predicate additionalFlowStepVar(EssaVariable fromvar, EssaVariable tovar) { none() }
|
||||
|
||||
/** Holds if this kind of taint can start from `expr`.
|
||||
* In other words, is `expr` a source of this kind of taint.
|
||||
*/
|
||||
final predicate startsFrom(ControlFlowNode expr) {
|
||||
expr.(TaintSource).isSourceOf(this, _)
|
||||
}
|
||||
|
||||
/** Holds if this kind of taint "taints" `expr`.
|
||||
*/
|
||||
final predicate taints(ControlFlowNode expr) {
|
||||
@@ -318,6 +311,18 @@ abstract class Sanitizer extends string {
|
||||
|
||||
}
|
||||
|
||||
/** Hold if `sanitizer` is valid. A sanitizer is valid if there is
|
||||
* a `TaintTracking::Configuration` that declares `sanitizer` or
|
||||
* there are no `TaintTracking::Configuration`s.
|
||||
*/
|
||||
private predicate valid_sanitizer(Sanitizer sanitizer) {
|
||||
not exists(TaintTracking::Configuration c)
|
||||
or
|
||||
exists(DataFlow::Configuration c | c.isSanitizer(sanitizer))
|
||||
or
|
||||
exists(TaintTracking::Configuration c | c.isSanitizer(sanitizer))
|
||||
}
|
||||
|
||||
/** DEPRECATED -- Use DataFlowExtension instead.
|
||||
* An extension to taint-flow. For adding library or framework specific flows.
|
||||
* Examples include flow from a request to untrusted part of that request or
|
||||
@@ -584,12 +589,19 @@ private newtype TTaintedNode =
|
||||
n.(TaintSource).isSourceOf(kind, context)
|
||||
)
|
||||
or
|
||||
exists(DataFlow::Configuration config, TaintKind kind |
|
||||
taint = TaintFlowImplementation::TTrackedTaint(kind) and
|
||||
config.isSource(n) and context.getDepth() = 0 and
|
||||
kind instanceof GenericFlowType
|
||||
)
|
||||
or
|
||||
TaintFlowImplementation::step(_, taint, context, n) and
|
||||
exists(TaintKind kind |
|
||||
kind = taint.(TaintFlowImplementation::TrackedTaint).getKind()
|
||||
or
|
||||
kind = taint.(TaintFlowImplementation::TrackedAttribute).getKind(_) |
|
||||
not exists(Sanitizer sanitizer |
|
||||
valid_sanitizer(sanitizer) and
|
||||
sanitizer.sanitizingNode(kind, n)
|
||||
)
|
||||
)
|
||||
@@ -839,26 +851,37 @@ library module TaintFlowImplementation {
|
||||
or
|
||||
call_taint_step(fromnode, totaint, tocontext, tonode)
|
||||
or
|
||||
fromnode.getNode().(DataFlowNode).getASuccessorNode() = tonode and
|
||||
fromnode.getContext() = tocontext and
|
||||
totaint = fromnode.getTrackedValue()
|
||||
or
|
||||
exists(CallNode call |
|
||||
fromnode.getNode().(DataFlowNode).getAReturnSuccessorNode(call) = tonode and
|
||||
fromnode.getContext() = tocontext.getCallee(call) and
|
||||
exists(DataFlowNode fromnodenode |
|
||||
fromnodenode = fromnode.getNode() and
|
||||
(
|
||||
not exists(TaintTracking::Configuration c)
|
||||
or
|
||||
exists(DataFlow::Configuration c | c.isExtension(fromnodenode))
|
||||
or
|
||||
exists(TaintTracking::Configuration c | c.isExtension(fromnodenode))
|
||||
)
|
||||
|
|
||||
fromnodenode.getASuccessorNode() = tonode and
|
||||
fromnode.getContext() = tocontext and
|
||||
totaint = fromnode.getTrackedValue()
|
||||
)
|
||||
or
|
||||
exists(CallNode call |
|
||||
fromnode.getNode().(DataFlowNode).getACalleeSuccessorNode(call) = tonode and
|
||||
fromnode.getContext().getCallee(call) = tocontext and
|
||||
totaint = fromnode.getTrackedValue()
|
||||
)
|
||||
or
|
||||
exists(TaintKind tokind |
|
||||
fromnode.getNode().(DataFlowNode).getASuccessorNode(fromnode.getTaintKind(), tokind) = tonode and
|
||||
totaint = fromnode.getTrackedValue().toKind(tokind) and
|
||||
tocontext = fromnode.getContext()
|
||||
or
|
||||
exists(CallNode call |
|
||||
fromnodenode.getAReturnSuccessorNode(call) = tonode and
|
||||
fromnode.getContext() = tocontext.getCallee(call) and
|
||||
totaint = fromnode.getTrackedValue()
|
||||
)
|
||||
or
|
||||
exists(CallNode call |
|
||||
fromnodenode.getACalleeSuccessorNode(call) = tonode and
|
||||
fromnode.getContext().getCallee(call) = tocontext and
|
||||
totaint = fromnode.getTrackedValue()
|
||||
)
|
||||
or
|
||||
exists(TaintKind tokind |
|
||||
fromnodenode.getASuccessorNode(fromnode.getTaintKind(), tokind) = tonode and
|
||||
totaint = fromnode.getTrackedValue().toKind(tokind) and
|
||||
tocontext = fromnode.getContext()
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(TaintKind tokind |
|
||||
@@ -1038,8 +1061,18 @@ library module TaintFlowImplementation {
|
||||
prev.(DataFlowVariable).getASuccessorVariable() = var
|
||||
)
|
||||
or
|
||||
origin.getNode().(DataFlowNode).getASuccessorVariable() = var and
|
||||
context = origin.getContext()
|
||||
exists(DataFlowNode originnode |
|
||||
originnode = origin.getNode() and
|
||||
(
|
||||
not exists(TaintTracking::Configuration c)
|
||||
or
|
||||
exists(DataFlow::Configuration c | c.isExtension(originnode))
|
||||
or
|
||||
exists(TaintTracking::Configuration c | c.isExtension(originnode))
|
||||
) and
|
||||
originnode.getASuccessorVariable() = var and
|
||||
context = origin.getContext()
|
||||
)
|
||||
or
|
||||
exists(TrackedTaint taint, EssaVariable prev |
|
||||
tainted_var(prev, context, origin) and
|
||||
@@ -1062,6 +1095,7 @@ library module TaintFlowImplementation {
|
||||
exists(TaintKind kind |
|
||||
kind = origin.getTaintKind() and
|
||||
not exists(Sanitizer san |
|
||||
valid_sanitizer(san) |
|
||||
san.sanitizingDefinition(kind, def)
|
||||
or
|
||||
san.sanitizingNode(kind, def.(EssaNodeDefinition).getDefiningNode())
|
||||
@@ -1184,6 +1218,7 @@ library module TaintFlowImplementation {
|
||||
exists(TaintKind kind |
|
||||
kind = origin.getTaintKind() |
|
||||
not exists(FunctionObject callee, Sanitizer sanitizer |
|
||||
valid_sanitizer(sanitizer) and
|
||||
callee.getACall() = call.getCall() and
|
||||
sanitizer.sanitizingCall(kind, callee)
|
||||
)
|
||||
@@ -1197,6 +1232,7 @@ library module TaintFlowImplementation {
|
||||
var = test.getInput() and
|
||||
tainted_var(var, context, origin) and
|
||||
not exists(Sanitizer sanitizer |
|
||||
valid_sanitizer(sanitizer) and
|
||||
sanitizer.sanitizingEdge(kind, test)
|
||||
)
|
||||
|
|
||||
@@ -1246,6 +1282,7 @@ library module TaintFlowImplementation {
|
||||
var = uniphi.getInput() and
|
||||
tainted_var(var, context, origin) and
|
||||
not exists(Sanitizer sanitizer |
|
||||
valid_sanitizer(sanitizer) and
|
||||
sanitizer.sanitizingSingleEdge(kind, uniphi)
|
||||
)
|
||||
)
|
||||
@@ -1438,6 +1475,109 @@ class CallContext extends TCallContext {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** Data flow module providing an interface compatible with
|
||||
* the other language implementations.
|
||||
*/
|
||||
module DataFlow {
|
||||
|
||||
class FlowType = TaintKind;
|
||||
|
||||
/** Generic taint kind, source and sink classes for convenience and
|
||||
* compatibility with other language libraries
|
||||
*/
|
||||
|
||||
class Node = ControlFlowNode;
|
||||
|
||||
class PathNode = TaintedNode;
|
||||
|
||||
class Extension = DataFlowExtension::DataFlowNode;
|
||||
|
||||
abstract class Configuration extends string {
|
||||
|
||||
bindingset[this]
|
||||
Configuration() { this = this }
|
||||
|
||||
abstract predicate isSource(Node source);
|
||||
|
||||
abstract predicate isSink(Node sink);
|
||||
|
||||
predicate isSanitizer(Sanitizer sanitizer) { none() }
|
||||
|
||||
predicate isExtension(Extension extension) { none() }
|
||||
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) {
|
||||
this.isSource(source.getNode()) and
|
||||
this.isSink(sink.getNode()) and
|
||||
source.getTaintKind() instanceof GenericFlowType and
|
||||
sink.getTaintKind() instanceof GenericFlowType
|
||||
}
|
||||
|
||||
predicate hasFlow(Node source, Node sink) {
|
||||
exists(PathNode psource, PathNode psink |
|
||||
psource.getNode() = source and
|
||||
psink.getNode() = sink and
|
||||
this.isSource(source) and
|
||||
this.isSink(sink) and
|
||||
this.hasFlowPath(psource, psink)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class GenericFlowType extends DataFlow::FlowType {
|
||||
|
||||
GenericFlowType() {
|
||||
this = "Generic taint kind" and
|
||||
exists(DataFlow::Configuration c)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module TaintTracking {
|
||||
|
||||
class Source = TaintSource;
|
||||
|
||||
class Sink = TaintSink;
|
||||
|
||||
class PathSource = TaintedPathSource;
|
||||
|
||||
class PathSink = TaintedPathSink;
|
||||
|
||||
class Extension = DataFlowExtension::DataFlowNode;
|
||||
|
||||
abstract class Configuration extends string {
|
||||
|
||||
bindingset[this]
|
||||
Configuration() { this = this }
|
||||
|
||||
abstract predicate isSource(Source source);
|
||||
|
||||
abstract predicate isSink(Sink sink);
|
||||
|
||||
predicate isSanitizer(Sanitizer sanitizer) { none() }
|
||||
|
||||
predicate isExtension(Extension extension) { none() }
|
||||
|
||||
predicate hasFlowPath(PathSource source, PathSink sink) {
|
||||
this.isSource(source.getNode()) and
|
||||
this.isSink(sink.getNode()) and
|
||||
source.flowsTo(sink)
|
||||
}
|
||||
|
||||
predicate hasFlow(Source source, Sink sink) {
|
||||
this.isSource(source) and
|
||||
this.isSink(sink) and
|
||||
source.flowsToSink(sink)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
pragma [noinline]
|
||||
private predicate dict_construct(ControlFlowNode itemnode, ControlFlowNode dictnode) {
|
||||
dictnode.(DictNode).getAValue() = itemnode
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
| 16 | 5 | 17 | 7 | ef |
|
||||
| 21 | 1 | 21 | 8 | string |
|
||||
| 24 | 1 | 24 | 10 | \n\n\n\n |
|
||||
| 27 | 1 | 27 | 14 | \\u0123\\u1234 |
|
||||
| 27 | 1 | 27 | 14 | \u0123\u1234 |
|
||||
| 30 | 1 | 30 | 9 | word |
|
||||
| 33 | 1 | 33 | 14 | \n\n\n\n0 |
|
||||
| 36 | 1 | 39 | 3 | \nline 0\nline 1\n |
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
| EncodingError.py:5:8:5:8 | Encoding Error | 'ascii' codec can't decode byte 0xc3 in position 47: ordinal not in range(128) |
|
||||
|
||||
@@ -1 +1 @@
|
||||
| bad_encoding.py:11:19:11:19 | Encoding Error | 'ascii' codec can't decode byte 0x82 in position 82: ordinal not in range(128) |
|
||||
| bad_encoding.py:11:19:11:19 | Encoding Error | 'utf8' codec can't decode byte 0x82 in position 82: invalid start byte |
|
||||
|
||||
@@ -1 +1 @@
|
||||
| nonsense.py:1:1:1:1 | Syntax Error | Syntax Error (in Python 2.7). |
|
||||
| nonsense.py:1:14:1:14 | Syntax Error | Syntax Error (in Python 2.7). |
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
`Twas brillig, and the slithy toves
|
||||
`Twas brillig, and the slithy toves
|
||||
Did gyre and gimble in the wabe:
|
||||
All mimsy were the borogoves,
|
||||
And the mome raths outgrabe.
|
||||
|
||||
@@ -86,3 +86,8 @@ def odasa6782_v3(protocol):
|
||||
pass
|
||||
else:
|
||||
raise ValueError()
|
||||
|
||||
#Inverted complex test
|
||||
if not (0 > stop >= step) and stop < 0:
|
||||
pass
|
||||
|
||||
|
||||
@@ -133,3 +133,7 @@ def do_action(action):
|
||||
stop()
|
||||
else:
|
||||
raise ValueError(action)
|
||||
|
||||
#Python 2 print
|
||||
print >> out, message
|
||||
|
||||
|
||||
Reference in New Issue
Block a user