Skip to content

Commit c0049bf

Browse files
authored
Merge pull request #229 from github/hvitved/api-graphs/remove-mk-module
API graphs: Remove `MkModule`
2 parents e8f6cb6 + ae837d9 commit c0049bf

3 files changed

Lines changed: 46 additions & 67 deletions

File tree

ql/src/codeql_ruby/ApiGraphs.qll

Lines changed: 23 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -198,13 +198,9 @@ module API {
198198
}
199199

200200
/** A node corresponding to the use of an API component. */
201-
class Use extends Node, Impl::TUse {
201+
class Use extends Node, Impl::MkUse {
202202
override string toString() {
203-
exists(string type |
204-
this = Impl::MkUse(_) and type = "Use "
205-
or
206-
this = Impl::MkModule(_) and type = "ModuleUse "
207-
|
203+
exists(string type | this = Impl::MkUse(_) and type = "Use " |
208204
result = type + getPath()
209205
or
210206
not exists(this.getPath()) and result = type + "with no path"
@@ -216,27 +212,15 @@ module API {
216212
Root root() { any() }
217213

218214
/**
219-
* Gets a node corresponding to an import of module `m`.
215+
* Gets a node corresponding to a top-level member `m` (typically a module).
216+
*
217+
* This is equivalent to `root().getAMember("m")`.
220218
*
221219
* Note: You should only use this predicate for top level modules or classes. If you want nodes corresponding to a nested module or class,
222220
* you should use `.getMember` on the parent module/class. For example, for nodes corresponding to the class `Gem::Version`,
223-
* use `moduleImport("Gem").getMember("Version")`.
221+
* use `getTopLevelMember("Gem").getMember("Version")`.
224222
*/
225-
Node moduleImport(string m) {
226-
result = Impl::MkModule(m) and not m.matches("%::%")
227-
or
228-
result = Impl::MkUse(unresolvedModuleReference(m))
229-
}
230-
231-
DataFlow::Node unresolvedModuleReference(string m) {
232-
exists(ConstantReadAccess iexpr, DataFlow::Node node |
233-
not exists(resolveScopeExpr(iexpr)) and
234-
not exists(iexpr.getScopeExpr()) and
235-
m = iexpr.getName() and
236-
result = node and
237-
node.asExpr().getExpr() = iexpr
238-
)
239-
}
223+
Node getTopLevelMember(string m) { result = root().getMember(m) }
240224

241225
/**
242226
* Provides the actual implementation of API graphs, cached for performance.
@@ -266,23 +250,29 @@ module API {
266250
newtype TApiNode =
267251
/** The root of the API graph. */
268252
MkRoot() or
269-
/** An abstract representative for imports of the module called `name`. */
270-
MkModule(string name) { exists(TResolved(name)) } or
271253
/** A use of an API member at the node `nd`. */
272-
MkUse(DataFlow::Node nd) {
273-
use(_, _, nd)
274-
or
275-
nd = unresolvedModuleReference(_)
276-
}
277-
278-
class TUse = MkModule or MkUse;
254+
MkUse(DataFlow::Node nd) { use(_, _, nd) }
279255

280256
/**
281257
* Holds if `ref` is a use of a node that should have an incoming edge from `base` labeled
282258
* `lbl` in the API graph.
283259
*/
284260
cached
285261
predicate use(TApiNode base, string lbl, DataFlow::Node ref) {
262+
base = MkRoot() and
263+
exists(string name, ExprNodes::ConstantAccessCfgNode access, ConstantReadAccess read |
264+
access = ref.asExpr() and
265+
lbl = Label::member(read.getName()) and
266+
read = access.getExpr()
267+
|
268+
TResolved(name) = resolveScopeExpr(read) and
269+
not name.matches("%::%")
270+
or
271+
name = read.getName() and
272+
not exists(resolveScopeExpr(read)) and
273+
not exists(read.getScopeExpr())
274+
)
275+
or
286276
exists(DataFlow::LocalSourceNode src, DataFlow::LocalSourceNode pred |
287277
// First, we find a predecessor of the node `ref` that we want to determine. The predecessor
288278
// is any node that is a type-tracked use of a data flow node (`src`), which is itself a
@@ -331,16 +321,7 @@ module API {
331321
* Holds if `ref` is a use of node `nd`.
332322
*/
333323
cached
334-
predicate use(TApiNode nd, DataFlow::Node ref) {
335-
exists(string name, ExprNodes::ConstantAccessCfgNode access, ConstantReadAccess read |
336-
access = ref.asExpr() and
337-
nd = MkModule(name) and
338-
read = access.getExpr() and
339-
TResolved(name) = resolveScopeExpr(read)
340-
)
341-
or
342-
nd = MkUse(ref)
343-
}
324+
predicate use(TApiNode nd, DataFlow::Node ref) { nd = MkUse(ref) }
344325

345326
/**
346327
* Gets a data-flow node to which `src`, which is a use of an API-graph node, flows.
@@ -370,14 +351,6 @@ module API {
370351
*/
371352
cached
372353
predicate edge(TApiNode pred, string lbl, TApiNode succ) {
373-
/* There's an edge from the root node for each imported module. */
374-
exists(string m |
375-
pred = MkRoot() and
376-
lbl = Label::mod(m)
377-
|
378-
succ = moduleImport(m)
379-
)
380-
or
381354
/* Every node that is a use of an API component is itself added to the API graph. */
382355
exists(DataFlow::LocalSourceNode ref |
383356
use(pred, lbl, ref) and
@@ -397,11 +370,6 @@ module API {
397370
}
398371

399372
private module Label {
400-
/** Gets the edge label for the module `m`. */
401-
bindingset[m]
402-
bindingset[result]
403-
string mod(string m) { result = "moduleImport(\"" + m + "\")" }
404-
405373
/** Gets the `member` edge label for member `m`. */
406374
bindingset[m]
407375
bindingset[result]

ql/src/queries/security/cwe-732/WeakFilePermissions.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ class PermissionArgument extends DataFlow::Node {
4949

5050
PermissionArgument() {
5151
exists(string methodName |
52-
call = API::moduleImport(["File", "FileUtils"]).getAMethodCall(methodName)
52+
call = API::getTopLevelMember(["File", "FileUtils"]).getAMethodCall(methodName)
5353
|
5454
methodName in ["chmod", "chmod_R", "lchmod"] and this = call.getArgument(0)
5555
or
Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,24 @@
1-
MyModule #$ use=moduleImport("MyModule")
2-
print MyModule.foo #$ use=moduleImport("MyModule").getReturn("foo")
3-
Kernel.print(e) #$ use=moduleImport("Kernel").getReturn("print")
4-
Object::Kernel #$ use=moduleImport("Kernel")
5-
Object::Kernel.print(e) #$ use=moduleImport("Kernel").getReturn("print")
1+
MyModule #$ use=getMember("MyModule")
2+
print MyModule.foo #$ use=getMember("MyModule").getReturn("foo")
3+
Kernel.print(e) #$ use=getMember("Kernel").getReturn("print")
4+
Object::Kernel #$ use=getMember("Kernel")
5+
Object::Kernel.print(e) #$ use=getMember("Kernel").getReturn("print")
66
begin
7-
print MyModule.bar #$ use=moduleImport("MyModule").getReturn("bar")
8-
raise AttributeError #$ use=moduleImport("AttributeError")
9-
rescue AttributeError => e #$ use=moduleImport("AttributeError")
10-
Kernel.print(e) #$ use=moduleImport("Kernel").getReturn("print")
7+
print MyModule.bar #$ use=getMember("MyModule").getReturn("bar")
8+
raise AttributeError #$ use=getMember("AttributeError")
9+
rescue AttributeError => e #$ use=getMember("AttributeError")
10+
Kernel.print(e) #$ use=getMember("Kernel").getReturn("print")
1111
end
12-
Unknown.new.run #$ use=moduleImport("Unknown").instance.getReturn("run")
13-
Foo::Bar::Baz #$ use=moduleImport("Foo").getMember("Bar").getMember("Baz")
12+
Unknown.new.run #$ use=getMember("Unknown").instance.getReturn("run")
13+
Foo::Bar::Baz #$ use=getMember("Foo").getMember("Bar").getMember("Baz")
14+
15+
Const = [1, 2, 3]
16+
Const.each do |c| #$ use=getMember("Const").getReturn("each")
17+
puts c
18+
end
19+
20+
foo = Foo #$ use=getMember("Foo")
21+
foo::Bar::Baz #$ use=getMember("Foo").getMember("Bar").getMember("Baz")
22+
23+
FooAlias = Foo #$ use=getMember("Foo")
24+
FooAlias::Bar::Baz #$ use=getMember("Foo").getMember("Bar").getMember("Baz")

0 commit comments

Comments
 (0)