Fix confused deputy vulnerability in termsActivity to access terms_disclaimer Uri only if the calling app has the permissions

1-P doc at: go/termsDisclaimerVulnerability

Before: https://hsv.googleplex.com/5163551739084800
After: https://hsv.googleplex.com/5207829722955776
https://paste.googleplex.com/5643054726512640

Flag: EXEMPT bug fix
Bug: 299928772
Test: Manual using test app provided by the reporter
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:5d67902f6a7498d016ee588d6c00710fb2d3ab98)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:68ff8bc959c104f1803e8b5e04ee180aaa542992)
Merged-In: I4c5ab64cb770c61db1cedc5169a4b8cdf0a4b0bd
Change-Id: I4c5ab64cb770c61db1cedc5169a4b8cdf0a4b0bd
diff --git a/src/com/android/managedprovisioning/parser/DisclaimersParserImpl.java b/src/com/android/managedprovisioning/parser/DisclaimersParserImpl.java
index fd20705..542bd7c 100644
--- a/src/com/android/managedprovisioning/parser/DisclaimersParserImpl.java
+++ b/src/com/android/managedprovisioning/parser/DisclaimersParserImpl.java
@@ -20,10 +20,13 @@
 import static com.android.managedprovisioning.common.StoreUtils.DIR_PROVISIONING_PARAMS_FILE_CACHE;
 
 import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Parcelable;
 import androidx.annotation.Nullable;
+import android.os.Binder;
 
 import android.text.TextUtils;
 import com.android.managedprovisioning.common.ProvisionLogger;
@@ -33,6 +36,7 @@
 import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Parser for {@link EXTRA_PROVISIONING_DISCLAIMERS} into {@link DisclaimersParam}
@@ -40,6 +44,9 @@
  */
 public class DisclaimersParserImpl implements DisclaimerParser {
     private static final int MAX_LENGTH = 3;
+    private static final String SCHEME_ANDROID_RESOURCE = "android.resource";
+    private static final String SCHEME_CONTENT = "content";
+
 
     private final Context mContext;
     private final long mProvisioningId;
@@ -75,7 +82,17 @@
                 ProvisionLogger.logw("Null disclaimer content uri in " + i + " element");
                 continue;
             }
-
+            try {
+                validateUriSchemeAndPermission(uri);
+            } catch (SecurityException e) {
+                ProvisionLogger.loge(
+                    "Skipping disclaimer in "
+                        + i
+                        + " element due to URI validation failure: "
+                        + e.getMessage(),
+                    e);
+                continue;
+            }
             File disclaimerFile = saveDisclaimerContentIntoFile(uri, i);
 
             if (disclaimerFile == null) {
@@ -90,6 +107,41 @@
     }
 
     /**
+     * Validates a {@link Uri} extra pointing to disclaimer content.
+     *
+     * <p>It checks that the URI scheme is one of {@code content} ({@link
+     * android.content.ContentResolver#SCHEME_CONTENT}) or {@code
+     * android.resource} ({@link
+     * android.content.ContentResolver#SCHEME_ANDROID_RESOURCE}). If a {@code
+     * content:} URI is passed, it also checks that the caller has grant read
+     * permission ({@link Intent#FLAG_GRANT_READ_URI_PERMISSION}).
+     *
+     * @throws SecurityException if the URI scheme is invalid or the caller
+     * does not have permission to access the URI.
+     */
+    private void validateUriSchemeAndPermission(Uri uri) throws SecurityException {
+        ProvisionLogger.logd("validateUriSchemeAndPermission: " + uri);
+        String scheme = uri.getScheme();
+        if (!Objects.equals(scheme, SCHEME_ANDROID_RESOURCE)
+            && !Objects.equals(scheme, SCHEME_CONTENT)) {
+            String errorMessage = "Invalid URI scheme: " + scheme;
+            throw new SecurityException(errorMessage);
+        }
+        int permissionCheck =
+            mContext.checkUriPermission(
+                uri,
+                Binder.getCallingPid(),
+                Binder.getCallingUid(),
+                Intent.FLAG_GRANT_READ_URI_PERMISSION);
+
+        if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
+            String errorMessage = "Caller does not have permission to access"
+                + " disclaimer URI: " + uri;
+            throw new SecurityException(errorMessage);
+        }
+    }
+
+    /**
      * @return {@link File} if the uri content is saved into the file successfully. Otherwise,
      * return null.
      */