Detect content:// leaving apps without grants.
Developers regularly put content:// Uris into Intents, but they can
easily forget to add FLAG_GRANT_READ_URI_PERMISSION to actually
extend a permission grant to the receiving app.
Also fix NPE when path is missing.
Test: builds, boots, common actions work without triggering
Bug: 32447617, 31900890
Change-Id: Ic6054b1d73de50967cf7fe66abc293c60a41b97e
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index 5162a73..ca3658b 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -853,14 +853,29 @@
* @hide
*/
public void prepareToLeaveProcess(boolean leavingPackage) {
+ prepareToLeaveProcess(leavingPackage, 0);
+ }
+
+ /**
+ * Prepare this {@link ClipData} to leave an app process.
+ *
+ * @hide
+ */
+ public void prepareToLeaveProcess(boolean leavingPackage, int intentFlags) {
final int size = mItems.size();
for (int i = 0; i < size; i++) {
final Item item = mItems.get(i);
if (item.mIntent != null) {
item.mIntent.prepareToLeaveProcess(leavingPackage);
}
- if (item.mUri != null && StrictMode.vmFileUriExposureEnabled() && leavingPackage) {
- item.mUri.checkFileUriExposed("ClipData.Item.getUri()");
+ if (item.mUri != null && leavingPackage) {
+ if (StrictMode.vmFileUriExposureEnabled()) {
+ item.mUri.checkFileUriExposed("ClipData.Item.getUri()");
+ }
+ if (StrictMode.vmContentUriWithoutPermissionEnabled()) {
+ item.mUri.checkContentUriWithoutPermission("ClipData.Item.getUri()",
+ intentFlags);
+ }
}
}
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 50589fe..a5d7999 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -9009,7 +9009,7 @@
mSelector.prepareToLeaveProcess(leavingPackage);
}
if (mClipData != null) {
- mClipData.prepareToLeaveProcess(leavingPackage);
+ mClipData.prepareToLeaveProcess(leavingPackage, getFlags());
}
if (mAction != null && mData != null && StrictMode.vmFileUriExposureEnabled()
@@ -9036,6 +9036,17 @@
mData.checkFileUriExposed("Intent.getData()");
}
}
+
+ if (mAction != null && mData != null && StrictMode.vmContentUriWithoutPermissionEnabled()
+ && leavingPackage) {
+ switch (mAction) {
+ case ACTION_PROVIDER_CHANGED:
+ // Ignore actions that don't need to grant
+ break;
+ default:
+ mData.checkContentUriWithoutPermission("Intent.getData()", getFlags());
+ }
+ }
}
/**
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index 67378bd..7396189 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -16,6 +16,7 @@
package android.net;
+import android.content.Intent;
import android.os.Environment;
import android.os.Parcel;
import android.os.Parcelable;
@@ -2342,12 +2343,25 @@
* @hide
*/
public void checkFileUriExposed(String location) {
- if ("file".equals(getScheme()) && !getPath().startsWith("/system/")) {
+ if ("file".equals(getScheme())
+ && (getPath() != null) && !getPath().startsWith("/system/")) {
StrictMode.onFileUriExposed(this, location);
}
}
/**
+ * If this is a {@code content://} Uri without access flags, it will be
+ * reported to {@link StrictMode}.
+ *
+ * @hide
+ */
+ public void checkContentUriWithoutPermission(String location, int flags) {
+ if ("content".equals(getScheme()) && !Intent.isAccessUriMode(flags)) {
+ StrictMode.onContentUriWithoutPermission(this, location);
+ }
+ }
+
+ /**
* Test if this is a path prefix match against the given Uri. Verifies that
* scheme, authority, and atomic path segments match.
*
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index ef79b66..f2519be 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -1800,6 +1800,13 @@
/**
* @hide
*/
+ public static boolean vmContentUriWithoutPermissionEnabled() {
+ return (sVmPolicyMask & DETECT_VM_FILE_URI_EXPOSURE) != 0;
+ }
+
+ /**
+ * @hide
+ */
public static boolean vmCleartextNetworkEnabled() {
return (sVmPolicyMask & DETECT_VM_CLEARTEXT_NETWORK) != 0;
}
@@ -1847,6 +1854,16 @@
/**
* @hide
*/
+ public static void onContentUriWithoutPermission(Uri uri, String location) {
+ final String message = uri + " exposed beyond app through " + location
+ + " without permission grant flags; did you forget"
+ + " FLAG_GRANT_READ_URI_PERMISSION?";
+ onVmPolicyViolation(null, new Throwable(message));
+ }
+
+ /**
+ * @hide
+ */
public static void onCleartextNetworkDetected(byte[] firstPacket) {
byte[] rawAddr = null;
if (firstPacket != null) {