Skip to content

Java: Fix performance of the query User-controlled bypass of sensitive method#6600

Merged
aschackmull merged 9 commits intogithub:mainfrom
atorralba:atorralba/fix-conditionalbypass
Sep 17, 2021
Merged

Java: Fix performance of the query User-controlled bypass of sensitive method#6600
aschackmull merged 9 commits intogithub:mainfrom
atorralba:atorralba/fix-conditionalbypass

Conversation

@atorralba
Copy link
Copy Markdown
Contributor

@atorralba atorralba commented Sep 3, 2021

The query User-controlled bypass of sensitive method (java/user-controlled-bypass) has shown bad performance on certain projects.

This PR aims to solve that by, mainly, changing the sources from UserInput to RemoteFlowSource, i.e. stop considering local inputs. This should have a positive impact in FP ratio as well.

General improvements are added in this PR too, namely creating the ConditionalBypassQuery.qll library and refactoring the query tests to use InlineExpectationsTest.

Also, some improvements were made to the heuristics used to find sensitive (i.e. authentication/authorization) actions (added some exceptions for things like author) and to the conditionsControlMethod predicate, to not consider conditions that exit with a throw or return without actually executing the important parts after the "bypassed" authentication.

Evaluation

After the changes, a subset of 1077 projects with results was reduced to 155. All the removed results seemed to be FP.

A differences job run to see the actual reduction on performance is needed.

@atorralba atorralba requested a review from a team as a code owner September 3, 2021 13:48
@github-actions github-actions bot added the Java label Sep 3, 2021
@atorralba atorralba marked this pull request as draft September 3, 2021 13:48
@atorralba atorralba removed the request for review from a team September 3, 2021 13:49
@atorralba atorralba changed the title Fix performance of the query User-controlled bypass of sensitive method Java: Fix performance of the query User-controlled bypass of sensitive method Sep 3, 2021
@atorralba atorralba force-pushed the atorralba/fix-conditionalbypass branch from d8edb62 to 0640b41 Compare September 14, 2021 11:45
@atorralba atorralba marked this pull request as ready for review September 14, 2021 11:48
@atorralba atorralba requested a review from a team September 14, 2021 11:49
Comment on lines +18 to +21
not cb.controls(any(SensitiveExecutionMethod sem).getAReference().getBasicBlock(),
cond.booleanNot()) and
not cb.controls(any(ThrowStmt t).getBasicBlock(), _) and
not cb.controls(any(ReturnStmt r).getBasicBlock(), _) and
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.

You've made 3 changes here. The first line seems sensible and is covered by a test case, but the other two are less clear. Could you elaborate on those choices and add some tests for them? In particular, why is the branch not important for throw and return statements?

Copy link
Copy Markdown
Contributor Author

@atorralba atorralba Sep 14, 2021

Choose a reason for hiding this comment

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

During the evaluation I saw a lot of FP that matched the following pattern:

if (!taintedCondition) {
    throw new Exception();
    // or
    return errorCode;
}

doLogin();
doOtherSensitiveStuff();

Before the change, the query was assuming that the if block was a way of bypassing the authentication, but actually it interrupts the execution flow with an error and nothing sensitive is executed.

Of course this approach has tradeoffs (since the heuristic nature of the query makes it hard to be 100% precise), in which a block containing a return or throw statement does something sensitive first, but it seemed that the FP reduction was worth a limited FN increase. Happy to discuss it further, though.

In any case, I wanted to add tests for this but I forgot, I'll do it now.

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.

So for this example it seems like you want
not cb.controls(any(ThrowStmt t).getBasicBlock(), cond.booleanNot())
in order to say that the throw statement is in the other branch, right?
I'm a little less convinced by the return statement, but if it really does help to filter FPs then I guess it should also specify the branch to be cond.booleanNot(), right?

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.

Good catch! By adding this, a MISSING test case gets fixed, so thank you :) See 21079a1.

Regarding the return statement, I can run one evaluation with the query as-is and one without the exception for return statements to see what's its real impact on FP, if you think it makes sense.

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.

Yeah, if it should be there it should probably be not cb.controls(any(ReturnStmt r).getBasicBlock(), cond.booleanNot()), but an evaluation to check its impact is probably good.

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 ran this, and when the return exception is not applied, the results go up from 155 to 365 projects. After a cursory review, most of those 210 extra projects' results seem to be FPs.

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.

Thanks for checking. Makes sense to keep it then.

Note that a FN test case was added
Exceptions for throw and return statements were missing the appropriate condition
@aschackmull aschackmull merged commit 2cbad4a into github:main Sep 17, 2021
@atorralba atorralba deleted the atorralba/fix-conditionalbypass branch September 17, 2021 14:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants