Skip to content

Java: Promote android sensitive broadcast query #6599

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

joefarebrother
Copy link
Contributor

@joefarebrother joefarebrother commented Sep 3, 2021

This PR promotes the query contributed by #4512 from experimental.

Changes:

  • Moved everything from experimental and moved the main query logic to SensitiveBroadcastQuery.qll
  • Refactored the tests to use inline expectations
  • Replaced the extra cnfigurations with local flow
  • Added additional models to methods of Intent and Bundle
  • Allowed arbitrary read steps at the sink
  • Considered the (deprecated) sendStickyBroadcast methods as additional sinks
  • Minor qhelp changes

Considerations:

  • A similar vulnerability is in sending sensitive data via methods like startActivity and startService. Should sinks for those be part of this same query?
  • Should the additional models be a separate PR?

@github-actions
Copy link
Contributor

github-actions bot commented Sep 3, 2021

⚠️ The head of this PR and the base branch were compared for differences in the framework coverage reports. The generated reports are available in the artifacts of this workflow run. The differences will be picked up by the nightly job after the PR gets merged. The following differences were found:

java

Generated file changes for java

  • Changes to framework-coverage-java.rst:
-    Android,``android.*``,18,34,70,,,3,67,,,
+    Android,``android.*``,18,136,70,,,3,67,,,
-    Totals,,84,3495,398,13,6,6,107,33,1,66
+    Totals,,84,3597,398,13,6,6,107,33,1,66
  • Changes to framework-coverage-java.csv:
- android.content,8,,4,,,,,,,,,,,,,8,,,,,,4,
+ android.content,8,,44,,,,,,,,,,,,,8,,,,,,4,40
+ android.os,,,62,,,,,,,,,,,,,,,,,,,,62

"android.os;Bundle;true;putSizeF;;;Argument[0];MapKey of Argument[-1];value",
"android.os;Bundle;true;putSparseParcelableArray;;;Argument[1];MapValue of Argument[-1];value",
"android.os;Bundle;true;putStringArrayList;;;Argument[1];MapValue of Argument[-1];value",
"android.content;Intent;true;getExtras;();;SyntheticField[android.content.Intent.extras] of Argument[-1];ReturnValue;value",
Copy link
Contributor

Choose a reason for hiding this comment

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

Missing fluent mutators: addCategory, addFlags.

Copy link
Contributor

Choose a reason for hiding this comment

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

^^

Copy link
Contributor

@atorralba atorralba left a comment

Choose a reason for hiding this comment

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

Added some inline comments. I still need to review the CSV models in detail.

@atorralba
Copy link
Contributor

A similar vulnerability is in sending sensitive data via methods like startActivity and startService. Should sinks for those be part of this same query?

@joefarebrother IMHO yes, it would make sense, because you can send implicit (and thus, interceptable) Intents with those methods, although the exploitation is a little harder because the user needs to select the malicious app in a dialog for the Intent to reach it.

The query would need to identify implicit Intents (i.e. explicit component not set, just an action). I think some code from this PR could be reused for that.

@joefarebrother
Copy link
Contributor Author

The query would need to identify implicit Intents (i.e. explicit component not set, just an action).

Do the existing sanitizers for setCompoent and similar methods suffice for that?

@atorralba
Copy link
Contributor

The query would need to identify implicit Intents (i.e. explicit component not set, just an action).

Do the existing sanitizers for setCompoent and similar methods suffice for that?

Probably, now that you mention it. I was thinking that we could reuse some code since we're doing similar things, but the sanitizer approach is simpler. Adding the new sinks should be easier than I initially thought, then :)

Copy link
Contributor

@atorralba atorralba left a comment

Choose a reason for hiding this comment

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

Added some more comments regarding CSV models. This covers the Intent extras pretty nicely, and the rest of the Intent methods (like get/setPackage) are or can be handled in other PRs like #6397.

Also, this will need a doc review at some point.

@joefarebrother joefarebrother force-pushed the android-sensitive-communication branch from 4062949 to cd7a8a7 Compare September 14, 2021 16:53
@github-actions
Copy link
Contributor

⚠️ The head of this PR and the base branch were compared for differences in the framework coverage reports. The generated reports are available in the artifacts of this workflow run. The differences will be picked up by the nightly job after the PR gets merged. The following differences were found:

java

Generated file changes for java

  • Changes to framework-coverage-java.rst:
-    Android,``android.*``,18,34,70,,,3,67,,,
+    Android,``android.*``,18,148,70,,,3,67,,,
-    Totals,,116,3554,402,13,6,10,107,33,1,66
+    Totals,,116,3668,402,13,6,10,107,33,1,66
  • Changes to framework-coverage-java.csv:
- android.content,8,,4,,,,,,,,,,,,,8,,,,,,4,
+ android.content,8,,44,,,,,,,,,,,,,8,,,,,,4,40
+ android.os,,,74,,,,,,,,,,,,,,,,,,,2,72

@smowton
Copy link
Contributor

smowton commented Sep 16, 2021

@joefarebrother this has conflicts

}
}

private predicate isNullArg(Expr ex) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Bad name (this indicates may-be-null, not is-null).

Also simplify this and isEmptyArrayArg using DataFlow::localExprFlow

}

/**
* Holds if a `sendBroadcast` call doesn't specify receiver permission.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
* Holds if a `sendBroadcast` call doesn't specify receiver permission.
* Holds if a `sendBroadcast` call `sendBroadcastCall` doesn't specify receiver permission.

/**
* Holds if a `sendBroadcast` call doesn't specify receiver permission.
*/
private predicate isSensitiveBroadcastSink(DataFlow::Node sink) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
private predicate isSensitiveBroadcastSink(DataFlow::Node sink) {
private predicate isSensitiveBroadcastSink(DataFlow::Node sendBroadcastCall) {

override predicate isSanitizer(DataFlow::Node node) {
exists(MethodAccess setReceiverMa |
setReceiverMa.getMethod().hasName(["setPackage", "setClass", "setClassName", "setComponent"]) and
setReceiverMa.getQualifier().(VarAccess).getVariable().getAnAccess() = node.asExpr()
Copy link
Contributor

Choose a reason for hiding this comment

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

Use localFlow instead of specifically one layer of access? Or (check by experiment) this might work just sanitising the qualifier due to use-use dataflow allowing sanitisers like this to interrupt dataflow paths to subsequent uses

(For example, in l = in; l.append("a"); l.append("b"), in Java the dataflow edges go in -> l, defn of l -> use of l in l.append("a"), use of l in l.append("a") -> use of l in l.append("b"), rather than both uses flowing from the definition as you might suppose)

"android.os;Bundle;true;putSizeF;;;Argument[0];MapKey of Argument[-1];value",
"android.os;Bundle;true;putSparseParcelableArray;;;Argument[1];MapValue of Argument[-1];value",
"android.os;Bundle;true;putStringArrayList;;;Argument[1];MapValue of Argument[-1];value",
"android.content;Intent;true;getExtras;();;SyntheticField[android.content.Intent.extras] of Argument[-1];ReturnValue;value",
Copy link
Contributor

Choose a reason for hiding this comment

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

^^

@bananabr
Copy link
Contributor

The context and class of the Intent can also be determined at construction time so the sanitizer needs to account for that.

Something like:

    // Handle the cases where the PackageContext and Class are set at construction time
    //    Intent(Context packageContext, Class<?> cls)
    // Create an intent for a specific component.
    //    Intent(String action, Uri uri, Context packageContext, Class<?> cls)
    exists(ConstructorCall cc |
      cc.getConstructedType() instanceof TypeIntent and
      cc.getNumArgument() > 1 and
      (
        cc.getArgument(0).getType() instanceof TypeContext and
        not exists(Expr classArg |
          classArg instanceof NullLiteral and DataFlow::localExprFlow(classArg, cc.getArgument(1))
        )
        or
        cc.getArgument(2).getType() instanceof TypeContext and
        not exists(Expr classArg |
          classArg instanceof NullLiteral and DataFlow::localExprFlow(classArg, cc.getArgument(3))
        )
      ) and
      DataFlow::localExprFlow(cc, node.asExpr())
    )

@bananabr
Copy link
Contributor

There is also the case when the broadcast receiver is determined dynamically. An attacker can abuse the intent filter priority to make it the first available receiver. The current sanitizers would ignore this case as setClassName or setPackage are usually called.

I don't have the skills to propose a query for this case though.

Intent intent = new Intent("com.victim.ADD_CARD_ACTION");
intent.putExtra("credit_card_number", num.getText().toString());
intent.putExtra("holder_name", name.getText().toString());
//...
for(ResolveInfo info : getPackageManager().queryBroadcastReceivers(intent, 0)) {
    intent.setClassName(info.activityInfo.packageName, info.activityInfo.name);
    sendBroadcast(intent);
    return;
}

@joefarebrother joefarebrother force-pushed the android-sensitive-communication branch from 0511a17 to e815405 Compare September 23, 2021 11:11
@joefarebrother
Copy link
Contributor Author

Additional models have been split into #6739

@github-actions
Copy link
Contributor

⚠️ The head of this PR and the base branch were compared for differences in the framework coverage reports. The generated reports are available in the artifacts of this workflow run. The differences will be picked up by the nightly job after the PR gets merged. The following differences were found:

java

Generated file changes for java

  • Changes to framework-coverage-java.rst:
-    Android,``android.*``,18,94,70,,,3,67,,,
+    Android,``android.*``,18,208,70,,,3,67,,,
-    Totals,,116,4169,402,13,6,10,107,33,1,66
+    Totals,,116,4283,402,13,6,10,107,33,1,66
  • Changes to framework-coverage-java.csv:
- android.content,8,,4,,,,,,,,,,,,,8,,,,,,4,
+ android.content,8,,44,,,,,,,,,,,,,8,,,,,,4,40
+ android.os,,,74,,,,,,,,,,,,,,,,,,,2,72

@joefarebrother joefarebrother force-pushed the android-sensitive-communication branch from e815405 to b6c584c Compare October 20, 2021 16:10
@github-actions
Copy link
Contributor

⚠️ The head of this PR and the base branch were compared for differences in the framework coverage reports. A recent commit removed the previously reported differences.

Copy link
Contributor

@atorralba atorralba left a comment

Choose a reason for hiding this comment

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

Some tests are failing, and I added a minor inline comment. Otherwise, LGTM.

@@ -84,6 +84,7 @@ private module Frameworks {
private import semmle.code.java.frameworks.apache.Collections
private import semmle.code.java.frameworks.apache.Lang
private import semmle.code.java.frameworks.Flexjson
private import semmle.code.java.frameworks.android.Intent
Copy link
Contributor

Choose a reason for hiding this comment

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

Duplicates import in line 81.

Suggested change
private import semmle.code.java.frameworks.android.Intent

@atorralba atorralba added the ready-for-doc-review This PR requires and is ready for review from the GitHub docs team. label Oct 22, 2021
Co-authored-by: Tony Torralba <atorralba@users.noreply.github.com>
@mchammer01
Copy link
Contributor

Hi everyone 👋🏻 - Docs First Responder here, thanks for the ping.
I've added this PR to our review board ⚡

@mchammer01 mchammer01 self-requested a review October 25, 2021 09:43
hubwriter
hubwriter previously approved these changes Oct 25, 2021
Copy link
Contributor

@hubwriter hubwriter left a comment

Choose a reason for hiding this comment

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

LGTM. A couple of little editorial suggestions. 👍

@@ -0,0 +1,21 @@
/**
* @name Leaking sensitive information through an implicit Intent
Copy link
Contributor

Choose a reason for hiding this comment

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

For consistency, use lowercase for intent - as elsewhere:

Suggested change
* @name Leaking sensitive information through an implicit Intent
* @name Leaking sensitive information through an implicit intent

Copy link
Contributor

Choose a reason for hiding this comment

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

Isn't Intent the name of the class? I'm not sure this should be lower-cased.

Copy link
Contributor

Choose a reason for hiding this comment

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

If so we should make it Intent throughout.

Copy link
Contributor

Choose a reason for hiding this comment

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

Indeed, it's the name of a class (just like Activity or Service), so I would use uppercase everywhere. Since there's more Android work coming, maybe a dedicated PR standardizing capitalization for this kind of thing in all files is due.

Copy link
Contributor

Choose a reason for hiding this comment

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

Let's fix the query name and change note of this query here in this PR instead of postponing these particular instances to a dedicated PR. Even if we need a general sweep to standardize, I don't think we should add to those needed changes.

Co-authored-by: hubwriter <hubwriter@github.com>
@mchammer01
Copy link
Contributor

mchammer01 commented Oct 25, 2021

I had set myself as a reviewer for this this morning and had actually started a review, but as this has been already reviewed by a Docs team member, I'll unassign myself 😄

@mchammer01 mchammer01 removed their request for review October 25, 2021 15:16
Copy link
Contributor

@atorralba atorralba left a comment

Choose a reason for hiding this comment

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

As suggested by @aschackmull and @hubwriter, let's capitalize the first letter in all occurrences of terms like Intent, Activity or Service.

hubwriter
hubwriter previously approved these changes Oct 26, 2021
Copy link
Contributor

@hubwriter hubwriter left a comment

Choose a reason for hiding this comment

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

@atorralba - thanks for suggesting those changes.
LGTM 👍

Co-authored-by: Tony Torralba <atorralba@users.noreply.github.com>
@joefarebrother joefarebrother merged commit 02b440b into github:main Oct 26, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Java ready-for-doc-review This PR requires and is ready for review from the GitHub docs team.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants