Skip to content

Commit 702fc80

Browse files
authored
Merge pull request #1166 from Semmle/rc/1.20
Merge rc/1.20 into master
2 parents 010bb61 + 23eed30 commit 702fc80

File tree

16 files changed

+317
-4
lines changed

16 files changed

+317
-4
lines changed

python/ql/src/semmle/python/pointsto/Base.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ ClassObject simple_types(Object obj) {
5050
obj.getOrigin() instanceof Module and result = theModuleType()
5151
or
5252
result = builtin_object_type(obj)
53+
or
54+
obj = unknownValue() and result = theUnknownType()
5355
}
5456

5557
private ClassObject comprehension(Expr e) {

python/ql/src/semmle/python/security/TaintTracking.qll

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1237,7 +1237,7 @@ library module TaintFlowImplementation {
12371237
)
12381238
|
12391239
not Filters::isinstance(test.getTest(), _, var.getSourceVariable().getAUse()) and
1240-
not test.getTest() = var.getSourceVariable().getAUse()
1240+
not boolean_filter(test.getTest(), var.getSourceVariable().getAUse())
12411241
or
12421242
exists(ControlFlowNode c, ClassObject cls |
12431243
Filters::isinstance(test.getTest(), c, var.getSourceVariable().getAUse())
@@ -1248,10 +1248,42 @@ library module TaintFlowImplementation {
12481248
test.getSense() = false and not kind.getClass().getAnImproperSuperType() = cls
12491249
)
12501250
or
1251-
test.getTest() = var.getSourceVariable().getAUse() and kind.booleanValue() = test.getSense()
1251+
test.getSense() = test_evaluates(test.getTest(), var.getSourceVariable().getAUse(), kind)
12521252
)
12531253
}
12541254

1255+
/** Gets the operand of a unary `not` expression. */
1256+
private ControlFlowNode not_operand(ControlFlowNode expr) {
1257+
expr.(UnaryExprNode).getNode().getOp() instanceof Not and
1258+
result = expr.(UnaryExprNode).getOperand()
1259+
}
1260+
1261+
/** Holds if `test` is the test in a branch and `use` is that test
1262+
* with all the `not` prefixes removed.
1263+
*/
1264+
private predicate boolean_filter(ControlFlowNode test, ControlFlowNode use) {
1265+
any(PyEdgeRefinement ref).getTest() = test and
1266+
(
1267+
use = test
1268+
or
1269+
exists(ControlFlowNode notuse |
1270+
boolean_filter(test, notuse) and
1271+
use = not_operand(notuse)
1272+
)
1273+
)
1274+
}
1275+
1276+
/** Gets the boolean value that `test` evaluates to when `use` is tainted with `kind`
1277+
* and `test` and `use` are part of a test in a branch.
1278+
*/
1279+
private boolean test_evaluates(ControlFlowNode test, ControlFlowNode use, TaintKind kind) {
1280+
boolean_filter(_, use) and
1281+
kind.taints(use) and
1282+
test = use and result = kind.booleanValue()
1283+
or
1284+
result = test_evaluates(not_operand(test), use, kind).booleanNot()
1285+
}
1286+
12551287
pragma [noinline]
12561288
predicate tainted_argument(ArgumentRefinement def, CallContext context, TaintedNode origin) {
12571289
tainted_var(def.getInput(), context, origin)

python/ql/src/semmle/python/types/Extensions.qll

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
*
44
* This should be considered an advance feature. Modifying the points-to analysis
55
* can cause queries to give strange and misleading results, if not done with care.
6+
*
7+
* WARNING:
8+
* This module interacts with the internals of points-to analysis and
9+
* the classes here are more likely to change than the rest of the library.
610
*/
711

812
import python
@@ -34,6 +38,18 @@ abstract class CustomPointsToOriginFact extends CustomPointsToFact {
3438

3539
}
3640

41+
/* Custom points-to fact with inferred class */
42+
abstract class CustomPointsToObjectFact extends CustomPointsToFact {
43+
44+
abstract predicate pointsTo(Object value);
45+
46+
override predicate pointsTo(Context context, Object value, ClassObject cls, ControlFlowNode origin) {
47+
this.pointsTo(value) and cls = simple_types(value) and origin = this and context.appliesTo(this)
48+
}
49+
50+
}
51+
52+
3753
/** INTERNAL -- Do not use */
3854
abstract class CustomPointsToAttribute extends Object {
3955

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
| test.py:4:1:4:3 | ControlFlowNode for one | int 1 |
22
| test.py:5:1:5:3 | ControlFlowNode for two | int 2 |
33
| test.py:8:1:8:1 | ControlFlowNode for IntegerLiteral | int 1 |
4-
| test.py:8:1:8:7 | ControlFlowNode for Tuple | Tuple |
4+
| test.py:8:1:8:11 | ControlFlowNode for Tuple | Tuple |
55
| test.py:8:3:8:3 | ControlFlowNode for IntegerLiteral | int 2 |
66
| test.py:8:5:8:5 | ControlFlowNode for IntegerLiteral | int 3 |
77
| test.py:8:7:8:7 | ControlFlowNode for IntegerLiteral | int 4 |
8+
| test.py:8:9:8:9 | ControlFlowNode for IntegerLiteral | int 5 |
9+
| test.py:8:11:8:11 | ControlFlowNode for IntegerLiteral | int 6 |
810
| test.py:10:1:10:2 | ControlFlowNode for a3 | int 3 |
911
| test.py:10:6:10:7 | ControlFlowNode for Tuple | Tuple |
1012
| test.py:10:6:10:13 | ControlFlowNode for Attribute | int 3 |
@@ -13,3 +15,5 @@
1315
| test.py:11:6:11:15 | ControlFlowNode for Attribute | int 4 |
1416
| test.py:13:1:13:2 | ControlFlowNode for a3 | int 3 |
1517
| test.py:14:1:14:2 | ControlFlowNode for a4 | int 4 |
18+
| test.py:16:1:16:4 | ControlFlowNode for five | int 5 |
19+
| test.py:17:1:17:3 | ControlFlowNode for six | int 6 |

python/ql/test/library-tests/PointsTo/extensions/Extend.ql

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,19 @@ class AttributeExtension extends CustomPointsToAttribute {
3838

3939
}
4040

41+
class NoClassExtension extends CustomPointsToObjectFact {
42+
43+
NoClassExtension() { this = this }
44+
45+
override predicate pointsTo(Object value) {
46+
this.(NameNode).getId() = "five" and value.(NumericObject).intValue() = 5
47+
or
48+
this.(NameNode).getId() = "six" and value.(NumericObject).intValue() = 6
49+
}
50+
51+
}
52+
53+
4154
from ControlFlowNode f, Object o
4255
where f.getLocation().getFile().getBaseName() = "test.py" and f.refersTo(o)
4356
select f, o.toString()

python/ql/test/library-tests/PointsTo/extensions/test.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@
55
two
66

77
#Make sure values exist in DB
8-
1,2,3,4
8+
1,2,3,4,5,6
99

1010
a3 = ().three
1111
a4 = False.four
1212

1313
a3
1414
a4
15+
16+
five
17+
six

python/ql/test/library-tests/taint/general/TaintLib.qll

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,3 +334,35 @@ class OsCommand extends TaintSink {
334334
}
335335

336336
}
337+
338+
339+
class Falsey extends TaintKind {
340+
341+
Falsey() { this = "falsey" }
342+
343+
override boolean booleanValue() {
344+
result = false
345+
}
346+
347+
}
348+
349+
class FalseySource extends TaintSource {
350+
351+
FalseySource() {
352+
this.(NameNode).getId() = "FALSEY"
353+
}
354+
355+
override predicate isSourceOf(TaintKind kind) {
356+
kind instanceof Falsey
357+
}
358+
359+
override string toString() {
360+
result = "falsey.source"
361+
}
362+
363+
}
364+
365+
366+
367+
368+

0 commit comments

Comments
 (0)