Skip to content

Commit 9b1ec03

Browse files
committed
Python: type tracking to API graph
using the new subscript node
1 parent bc963b2 commit 9b1ec03

File tree

1 file changed

+28
-60
lines changed
  • python/ql/src/experimental/semmle/python/frameworks

1 file changed

+28
-60
lines changed

python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll

Lines changed: 28 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -45,81 +45,50 @@ private module NoSql {
4545

4646
/**
4747
* Gets a reference to a `Mongo` DB instance.
48-
*/
49-
private DataFlow::LocalSourceNode mongoDBInstance(DataFlow::TypeTracker t) {
50-
t.start() and
51-
(
52-
exists(SubscriptNode subscript |
53-
subscript.getObject() = mongoClientInstance().getAValueReachableFromSource().asCfgNode() and
54-
result.asCfgNode() = subscript
55-
)
56-
or
57-
result.(DataFlow::AttrRead).getObject() = mongoClientInstance().getAValueReachableFromSource()
58-
or
59-
result = mongoEngine().getMember(["get_db", "connect"]).getACall()
60-
or
61-
result = mongoEngine().getMember("connection").getMember(["get_db", "connect"]).getACall()
62-
or
63-
result = flask_MongoEngine().getMember("get_db").getACall()
64-
or
65-
// see https://pymongo.readthedocs.io/en/stable/api/pymongo/mongo_client.html#pymongo.mongo_client.MongoClient.get_default_database
66-
// see https://pymongo.readthedocs.io/en/stable/api/pymongo/mongo_client.html#pymongo.mongo_client.MongoClient.get_database
67-
result = mongoClientInstance().getMember(["get_default_database", "get_database"]).getACall()
68-
)
69-
or
70-
exists(DataFlow::TypeTracker t2 | result = mongoDBInstance(t2).track(t2, t))
71-
}
72-
73-
/**
74-
* Gets a reference to a `Mongo` DB use.
7548
*
7649
* ```py
7750
* from flask_pymongo import PyMongo
7851
* mongo = PyMongo(app)
7952
* mongo.db.user.find({'name': safe_search})
8053
* ```
8154
*
82-
* `mongo.db` would be a use of a `Mongo` instance, and so the result.
55+
* `mongo.db` would be a `Mongo` instance.
8356
*/
84-
private DataFlow::Node mongoDBInstance() {
85-
mongoDBInstance(DataFlow::TypeTracker::end()).flowsTo(result)
86-
}
87-
88-
/**
89-
* Gets a reference to a `Mongo` collection use.
90-
*/
91-
private DataFlow::LocalSourceNode mongoCollection(DataFlow::TypeTracker t) {
92-
t.start() and
93-
(
94-
exists(SubscriptNode subscript | result.asCfgNode() = subscript |
95-
subscript.getObject() = mongoDBInstance().asCfgNode()
96-
)
97-
or
98-
result.(DataFlow::AttrRead).getObject() = mongoDBInstance()
99-
or
100-
// see https://pymongo.readthedocs.io/en/stable/api/pymongo/database.html#pymongo.database.Database.get_collection
101-
// see https://pymongo.readthedocs.io/en/stable/api/pymongo/database.html#pymongo.database.Database.create_collection
102-
result
103-
.(DataFlow::MethodCallNode)
104-
.calls(mongoDBInstance(), ["get_collection", "create_collection"])
105-
)
57+
private API::Node mongoDBInstance() {
58+
result = mongoClientInstance().getASubscript()
59+
or
60+
result = mongoClientInstance().getAMember()
61+
or
62+
result = mongoEngine().getMember(["get_db", "connect"]).getReturn()
10663
or
107-
exists(DataFlow::TypeTracker t2 | result = mongoCollection(t2).track(t2, t))
64+
result = mongoEngine().getMember("connection").getMember(["get_db", "connect"]).getReturn()
65+
or
66+
result = flask_MongoEngine().getMember("get_db").getReturn()
67+
or
68+
// see https://pymongo.readthedocs.io/en/stable/api/pymongo/mongo_client.html#pymongo.mongo_client.MongoClient.get_default_database
69+
// see https://pymongo.readthedocs.io/en/stable/api/pymongo/mongo_client.html#pymongo.mongo_client.MongoClient.get_database
70+
result = mongoClientInstance().getMember(["get_default_database", "get_database"]).getReturn()
10871
}
10972

11073
/**
111-
* Gets a reference to a `Mongo` collection use.
74+
* Gets a reference to a `Mongo` collection.
11275
*
11376
* ```py
11477
* from flask_pymongo import PyMongo
11578
* mongo = PyMongo(app)
11679
* mongo.db.user.find({'name': safe_search})
11780
* ```
11881
*
119-
* `mongo.db.user` would be a use of a `Mongo` collection, and so the result.
82+
* `mongo.db.user` would be a `Mongo` collection.
12083
*/
121-
private DataFlow::Node mongoCollection() {
122-
mongoCollection(DataFlow::TypeTracker::end()).flowsTo(result)
84+
private API::Node mongoCollection() {
85+
result = mongoDBInstance().getASubscript()
86+
or
87+
result = mongoDBInstance().getAMember()
88+
or
89+
// see https://pymongo.readthedocs.io/en/stable/api/pymongo/database.html#pymongo.database.Database.get_collection
90+
// see https://pymongo.readthedocs.io/en/stable/api/pymongo/database.html#pymongo.database.Database.create_collection
91+
result = mongoDBInstance().getMember(["get_collection", "create_collection"]).getReturn()
12392
}
12493

12594
/** This class represents names of find_* relevant `Mongo` collection-level operation methods. */
@@ -141,11 +110,10 @@ private module NoSql {
141110
* mongo.db.user.find({'name': safe_search})
142111
* ```
143112
*
144-
* `mongo.db.user.find` would be a collection method, and so the result.
113+
* `mongo.db.user.find` would be a collection method.
145114
*/
146-
private DataFlow::Node mongoCollectionMethod() {
147-
mongoCollection() = result.(DataFlow::AttrRead).getObject() and
148-
result.(DataFlow::AttrRead).getAttributeName() instanceof MongoCollectionMethodNames
115+
private API::Node mongoCollectionMethod() {
116+
result = mongoCollection().getMember(any(MongoCollectionMethodNames m))
149117
}
150118

151119
/**
@@ -160,7 +128,7 @@ private module NoSql {
160128
* `mongo.db.user.find({'name': safe_search})` would be a collection method call, and so the result.
161129
*/
162130
private class MongoCollectionCall extends DataFlow::CallCfgNode, NoSqlQuery::Range {
163-
MongoCollectionCall() { this.getFunction() = mongoCollectionMethod() }
131+
MongoCollectionCall() { this = mongoCollectionMethod().getACall() }
164132

165133
override DataFlow::Node getQuery() { result = this.getArg(0) }
166134
}

0 commit comments

Comments
 (0)