Skip to content

JS: Generalize global access paths to include local ones - #2224

Merged
semmle-qlci merged 8 commits into
github:masterfrom
asger-semmle:access-paths-with-source-node-root
Nov 7, 2019
Merged

JS: Generalize global access paths to include local ones#2224
semmle-qlci merged 8 commits into
github:masterfrom
asger-semmle:access-paths-with-source-node-root

Conversation

@asger-semmle

Copy link
Copy Markdown
Contributor

Renames the GlobalAccessPath module to AccessPath and generalizes it to deal with access paths relative to a given SourceNode root.

The predicates GlobalAccessPath::{fromReference,fromRhs} are helpful internally, but felt clunky as part of the public API so we now expose AccessPath::{getAReferenceTo,getAnAssignmentTo} instead.

Type tracking can step through these access paths. This is modelled as store/loads edges that step into/out of the root node using the whole access path as if it was a single property name.

This means we treat x.foo.bar and x["foo.bar"] as the same thing, which is a bit sleazy but probably fine for type tracking purposes. We could tag the strings to avoid this potential clash if we're willing to pay the overhead.

There is a modest performance cost and an equally modest number of new call edges.

@asger-semmle
asger-semmle requested a review from a team as a code owner October 29, 2019 14:55
@asger-semmle asger-semmle changed the title Generalize global access paths to include local ones JS: Generalize global access paths to include local ones Oct 29, 2019

@esbena esbena left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow. That is a nice generalisation.
I only have two optimizer-related comments.

exists(Expr predExpr, Expr succExpr |
pred = valueNode(predExpr) and succ = valueNode(succExpr)
|
predExpr = succExpr.(ParExpr).getExpression()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make the optimizer unhappy if we use Expr::getUnderlyingValue instead of all these explicit cases? (I know this is just a port of some steps, feel free to ignore)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know about the optimizer, but it doesn't do quite the same thing. getUnderlyingValue goes all the way to the bottom in one step, whereas we generally want the individual steps here.

For example, suppose you add type casts as a sanitizer in a data flow query. In this case, getUnderlyingValue would simply skip over the type cast, bypassing the sanitizer.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I suppose we could look into letting Expr expose the non-recursive version as getImmediatelyUnderlyingValue in another PR.

result = fromReference(node)
DataFlow::Node getAReferenceTo(Root root, string path) {
path = fromReference(result, root) and
not root.isGlobal()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is not root.isGlobal() used to help the optimizer? Or is it just done to encourage not using DataFlow::globalAccessPathRootPseudoNode() explicitly?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's mainly to avoid exposing the pseudo-node, yes.

@esbena esbena left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but doesn't this require a full dist-compare? The type tracking improvements seem fundamental enough to me that they require a full evaluation.

@max-schaefer max-schaefer left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but I agree with Esben about doing a full evaluation.

Comment thread javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll Outdated
@asger-semmle

asger-semmle commented Oct 30, 2019

Copy link
Copy Markdown
Contributor Author

There's an evaluation on default.slugs from a slightly earlier version but that's the security suite only. I'll do a full evaluation.

@asger-semmle
asger-semmle force-pushed the access-paths-with-source-node-root branch from 8d9c34c to cdd6825 Compare October 30, 2019 11:46
@max-schaefer

Copy link
Copy Markdown
Contributor

@asger-semmle, I think you mentioned that there were new evaluation results? Or are you still rerunning?

@asger-semmle

asger-semmle commented Nov 5, 2019

Copy link
Copy Markdown
Contributor Author

Here's the full evaluation. I messed up the re-run of the slowest slugs, a new one is underway.

@asger-semmle

Copy link
Copy Markdown
Contributor Author

The re-run of the 10 slowest slugs looks much better.

@asger-semmle
asger-semmle force-pushed the access-paths-with-source-node-root branch from cdd6825 to 81723ab Compare November 6, 2019 11:59
@asger-semmle

Copy link
Copy Markdown
Contributor Author

I'd like to merge this unless you have any further change requests @max-schaefer?

@semmle-qlci
semmle-qlci merged commit f79c2a7 into github:master Nov 7, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants