diff options
author | Raman Tenneti <rtenneti@google.com> | 2018-11-27 10:51:09 -0800 |
---|---|---|
committer | Tim Schumacher <timschumi@gmx.de> | 2019-06-04 14:14:36 +0200 |
commit | 3b76b4889786c2d35996c5ed7a0de1f49f72d767 (patch) | |
tree | be82dc7996f0c2ffd6a6b8f8b0868ae4bf7b7375 | |
parent | b1c43d73a05c8a4c9c087f020e0fe14ccfd9eb31 (diff) | |
download | android_packages_apps_UnifiedEmail-cm-11.0.tar.gz android_packages_apps_UnifiedEmail-cm-11.0.tar.bz2 android_packages_apps_UnifiedEmail-cm-11.0.zip |
AOSP/Email - Fixed - Security Vulnerability - Email App: Malicious appcm-11.0
is able to compose message with hidden attachments and bypass
attachments path checks attaching private files from
/data/data/com.android.email/*
+ Ported the following CLs. Code is different from gmail. Made the changes
to work with Email.
++ https://critique.corp.google.com/#review/136780360
+++ Add isExternal() to ComposeActivity.java and it always returns false.
Treat body and quoted text as plaintext if intent is external.
++ https://critique.corp.google.com/#review/137654162
+++ Don't let other apps use our EXTRA_MESSAGE.
Load EXTRA_MESSAGE only if action is LAUNCH_COMPOSE.
LAUNCH_COMPOSE action is an internal only action: b/32068883.
++ https://critique.corp.google.com/#review/142296051
+++ Don't let external Intent use EXTRA_MESSAGE
Bug: 32068883
Bug: 32502421
Bug: 32589229
Test: manual - Ran the following tests on Pixel phone. Tested the Email UI.
$ adb install -r out/target/product/marlin/system/app/Email/Email.apk
$ adb install -r app-debug.apk
Success
$ adb shell am start -n com.test.poc.poc32589229/.MainActivity -a android.intent.action.MAIN
Starting: Intent { act=android.intent.action.MAIN cmp=com.test.poc.poc32589229/.MainActivity }
Duplicated the steps in https://b.corp.google.com/issues/32589229#comment5
and didn't get the attachments after the fix (was getting attachments before the fix).
logcat output:
11-21 03:45:48.927 11705 11705 I poc-test: sending a hidden file attachment
11-21 03:45:48.929 11705 11705 I poc-test: Sending contentType: text/html, previewImage: null
11-21 03:45:48.935 914 4482 I ActivityManager: START u0 {act=com.android.mail.intent.action.LAUNCH_COMPOSE pkg=com.android.email cmp=com.android.email/.activity.ComposeActivityEmail (has extras)} from uid 10072
11-21 03:45:48.935 914 4482 W ActivityManager: Permission Denial: starting Intent { act=com.android.mail.intent.action.LAUNCH_COMPOSE pkg=com.android.email cmp=com.android.email/.activity.ComposeActivityEmail (has extras) } from ProcessRecord{6941817 11705:com.test.poc.poc32589229/u0a72} (pid=11705, uid=10072) not exported from uid 10062
11-21 03:45:48.937 11705 11705 D AndroidRuntime: Shutting down VM
--------- beginning of crash
11-21 03:45:48.940 11705 11705 E AndroidRuntime: FATAL EXCEPTION: main
11-21 03:45:48.940 11705 11705 E AndroidRuntime: Process: com.test.poc.poc32589229, PID: 11705
11-21 03:45:48.940 11705 11705 E AndroidRuntime: java.lang.IllegalStateException: Could not execute method for android:onClick
...
11-21 03:45:48.940 11705 11705 E AndroidRuntime: Caused by: java.lang.SecurityException: Permission Denial: starting Intent { act=com.android.mail.intent.action.LAUNCH_COMPOSE pkg=com.android.email cmp=com.android.email/.activity.ComposeActivityEmail (has extras) } from ProcessRecord{6941817 11705:com.test.poc.poc32589229/u0a72} (pid=11705, uid=10072) not exported from uid 10062
$ adb install -r out/target/product/marlin/testcases/EmailTests/EmailTests.apk
Performing Streamed Install
Success
$ adb shell am instrument -w com.android.email.tests
The number of failures are same as before (with or without this change).
Tests run: 158, Failures: 5
Change-Id: If6e2a2efa08b75675c980b72735cde8252e95760
(cherry picked from commit 3526a4ac552f93a83ea838ddae5de45e1e068af0)
-rw-r--r-- | src/com/android/mail/compose/ComposeActivity.java | 26 |
1 files changed, 25 insertions, 1 deletions
diff --git a/src/com/android/mail/compose/ComposeActivity.java b/src/com/android/mail/compose/ComposeActivity.java index b120c2e7b..b1bed47ee 100644 --- a/src/com/android/mail/compose/ComposeActivity.java +++ b/src/com/android/mail/compose/ComposeActivity.java @@ -466,6 +466,11 @@ public class ComposeActivity extends Activity implements OnClickListener, OnNavi launcher.startActivity(intent); } + /** Returns true if activity is started from an intent from an external application. */ + public boolean isExternal() { + return false; + } + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -475,6 +480,16 @@ public class ComposeActivity extends Activity implements OnClickListener, OnNavi checkValidAccounts(); } + /** Used for escaping plaintext. If the input is null, then it will return an empty String. */ + private static String escapeAndReplaceHtml(CharSequence text) { + if (text == null) { + return ""; + } + String body = Html.escapeHtml(text); + // Replace \r\n and \n with <br> tags + return body.replaceAll("( | )", "<br>"); + } + private void finishCreate() { final Bundle savedState = mInnerSavedState; findViews(); @@ -503,6 +518,9 @@ public class ComposeActivity extends Activity implements OnClickListener, OnNavi message = (Message) intent.getParcelableExtra(ORIGINAL_DRAFT_MESSAGE); previews = intent.getParcelableArrayListExtra(EXTRA_ATTACHMENT_PREVIEWS); mRefMessage = (Message) intent.getParcelableExtra(EXTRA_IN_REFERENCE_TO_MESSAGE); + if (isExternal() && mRefMessage != null && !TextUtils.isEmpty(mRefMessage.bodyHtml)) { + mRefMessage.bodyHtml = escapeAndReplaceHtml(mRefMessage.bodyHtml); + } mRefMessageUri = (Uri) intent.getParcelableExtra(EXTRA_IN_REFERENCE_TO_MESSAGE_URI); if (Analytics.isLoggable()) { @@ -1310,6 +1328,9 @@ public class ComposeActivity extends Activity implements OnClickListener, OnNavi } String body = intent.getStringExtra(EXTRA_BODY); if (body != null) { + if (isExternal()) { + body = escapeAndReplaceHtml(body); + } setBody(body, false /* withSignature */); } } @@ -1455,7 +1476,10 @@ public class ComposeActivity extends Activity implements OnClickListener, OnNavi } else if (EXTRA_BODY.equals(extra)) { setBody(value, true /* with signature */); } else if (EXTRA_QUOTED_TEXT.equals(extra)) { - initQuotedText(value, true /* shouldQuoteText */); + if (isExternal()) { + value = escapeAndReplaceHtml(value); + } + initQuotedText(value, true /* shouldQuoteText */); } } } |