Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit 57d008fd authored by Michael Bestas's avatar Michael Bestas
Browse files

Merge tag 'android-security-14.0.0_r14' of...

Merge tag 'android-security-14.0.0_r14' of https://android.googlesource.com/platform/frameworks/base into lineage-21.0

Android security 14.0.0 release 14

* tag 'android-security-14.0.0_r14' of https://android.googlesource.com/platform/frameworks/base:
  Restrict access to directories
  RESTRICT AUTOMERGE Clear app-provided shortcut icons
  Disallow device admin package and protected packages to be reinstalled as instant.
  Set no data transfer on function switch timeout for accessory mode
  Check more URIs in notifications
  RingtoneManager: allow video ringtone URI
  Remove authenticator data if it was disabled.

 Conflicts:
	core/java/android/app/Person.java
	core/java/android/widget/RemoteViews.java
	packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
	packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java
	packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java

Skipped commit 4677d3ee from the merge, will be applied separately

Change-Id: I27994822ef03e12452f1092476dfb81b0339b995
parents 6886e301 c0358908
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -921,9 +921,13 @@ public class RingtoneManager {
                        + " ignored: failure to find mimeType (no access from this context?)");
                return;
            }
            if (!(mimeType.startsWith("audio/") || mimeType.equals("application/ogg"))) {
            if (!(mimeType.startsWith("audio/") || mimeType.equals("application/ogg")
                    || mimeType.equals("application/x-flac")
                    // also check for video ringtones
                    || mimeType.startsWith("video/") || mimeType.equals("application/mp4"))) {
                Log.e(TAG, "setActualDefaultRingtoneUri for URI:" + ringtoneUri
                        + " ignored: associated mimeType:" + mimeType + " is not an audio type");
                        + " ignored: associated MIME type:" + mimeType
                        + " is not a recognized audio or video type");
                return;
            }
        }
+68 −11
Original line number Diff line number Diff line
@@ -16,8 +16,6 @@

package com.android.externalstorage;

import static java.util.regex.Pattern.CASE_INSENSITIVE;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.usage.StorageStatsManager;
@@ -61,12 +59,15 @@ import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.UUID;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * Presents content of the shared (a.k.a. "external") storage.
@@ -89,12 +90,9 @@ public class ExternalStorageProvider extends FileSystemProvider {
    private static final Uri BASE_URI =
            new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(AUTHORITY).build();

    /**
     * Regex for detecting {@code /Android/data/}, {@code /Android/obb/} and
     * {@code /Android/sandbox/} along with all their subdirectories and content.
     */
    private static final Pattern PATTERN_RESTRICTED_ANDROID_SUBTREES =
            Pattern.compile("^Android/(?:data|obb|sandbox)(?:/.+)?", CASE_INSENSITIVE);
    private static final String PRIMARY_EMULATED_STORAGE_PATH = "/storage/emulated/";

    private static final String STORAGE_PATH = "/storage/";

    private static final String[] DEFAULT_ROOT_PROJECTION = new String[] {
            Root.COLUMN_ROOT_ID, Root.COLUMN_FLAGS, Root.COLUMN_ICON, Root.COLUMN_TITLE,
@@ -309,10 +307,69 @@ public class ExternalStorageProvider extends FileSystemProvider {
            return false;
        }

        final String path = getPathFromDocId(documentId);
        return PATTERN_RESTRICTED_ANDROID_SUBTREES.matcher(path).matches();
        try {
            final RootInfo root = getRootFromDocId(documentId);
            final String canonicalPath = getPathFromDocId(documentId);
            return isRestrictedPath(root.rootId, canonicalPath);
        } catch (Exception e) {
            return true;
        }
    }

    /**
     * Based on the given root id and path, we restrict path access if file is Android/data or
     * Android/obb or Android/sandbox or one of their subdirectories.
     *
     * @param canonicalPath of the file
     * @return true if path is restricted
     */
    private boolean isRestrictedPath(String rootId, String canonicalPath) {
        if (rootId == null || canonicalPath == null) {
            return true;
        }

        final String rootPath;
        if (rootId.equalsIgnoreCase(ROOT_ID_PRIMARY_EMULATED)) {
            // Creates "/storage/emulated/<user-id>"
            rootPath = PRIMARY_EMULATED_STORAGE_PATH + UserHandle.myUserId();
        } else {
            // Creates "/storage/<volume-uuid>"
            rootPath = STORAGE_PATH + rootId;
        }
        List<java.nio.file.Path> restrictedPathList = Arrays.asList(
                Paths.get(rootPath, "Android", "data"),
                Paths.get(rootPath, "Android", "obb"),
                Paths.get(rootPath, "Android", "sandbox"));
        // We need to identify restricted parent paths which actually exist on the device
        List<java.nio.file.Path> validRestrictedPathsToCheck = restrictedPathList.stream().filter(
                Files::exists).collect(Collectors.toList());

        boolean isRestricted = false;
        java.nio.file.Path filePathToCheck = Paths.get(rootPath, canonicalPath);
        try {
            while (filePathToCheck != null) {
                for (java.nio.file.Path restrictedPath : validRestrictedPathsToCheck) {
                    if (Files.isSameFile(restrictedPath, filePathToCheck)) {
                        isRestricted = true;
                        Log.v(TAG, "Restricting access for path: " + filePathToCheck);
                        break;
                    }
                }
                if (isRestricted) {
                    break;
                }

                filePathToCheck = filePathToCheck.getParent();
            }
        } catch (Exception e) {
            Log.w(TAG, "Error in checking file equality check.", e);
            isRestricted = true;
        }

        return isRestricted;
    }


    /**
     * Check that the directory is the root of storage or blocked file from tree.
     * <p>
+7 −4
Original line number Diff line number Diff line
@@ -1972,7 +1972,7 @@ public class SettingsProvider extends ContentProvider {

        File cacheFile = getCacheFile(name, callingUserId);
        if (cacheFile != null) {
            if (!isValidAudioUri(name, value)) {
            if (!isValidMediaUri(name, value)) {
                return false;
            }
            // Invalidate any relevant cache files
@@ -2031,7 +2031,7 @@ public class SettingsProvider extends ContentProvider {
        return true;
    }

    private boolean isValidAudioUri(String name, String uri) {
    private boolean isValidMediaUri(String name, String uri) {
        if (uri != null) {
            Uri audioUri = Uri.parse(uri);
            if (Settings.AUTHORITY.equals(
@@ -2049,10 +2049,13 @@ public class SettingsProvider extends ContentProvider {
                return false;
            }
            if (!(mimeType.startsWith("audio/") || mimeType.equals("application/ogg")
                    || mimeType.equals("application/x-flac"))) {
                    || mimeType.equals("application/x-flac")
                    // also check for video ringtones
                    || mimeType.startsWith("video/") || mimeType.equals("application/mp4"))) {
                Slog.e(LOG_TAG,
                        "mutateSystemSetting for setting: " + name + " URI: " + audioUri
                        + " ignored: associated mimeType: " + mimeType + " is not an audio type");
                        + " ignored: associated MIME type: " + mimeType
                        + " is not a recognized audio or video type");
                return false;
            }
        }
+4 −0
Original line number Diff line number Diff line
@@ -1214,6 +1214,10 @@ public class AccountManagerService
                            obsoleteAuthType.add(type);
                            // And delete it from the TABLE_META
                            accountsDb.deleteMetaByAuthTypeAndUid(type, uid);
                        } else if (knownUid != null && knownUid != uid) {
                            Slog.w(TAG, "authenticator no longer exist for type " + type);
                            obsoleteAuthType.add(type);
                            accountsDb.deleteMetaByAuthTypeAndUid(type, uid);
                        }
                    }
                }
+5 −1
Original line number Diff line number Diff line
@@ -671,6 +671,9 @@ final class InstallPackageHelper {
                    (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
            final boolean fullApp =
                    (installFlags & PackageManager.INSTALL_FULL_APP) != 0;
            final boolean isPackageDeviceAdmin = mPm.isPackageDeviceAdmin(packageName, userId);
            final boolean isProtectedPackage = mPm.mProtectedPackages != null
                    && mPm.mProtectedPackages.isPackageStateProtected(userId, packageName);

            // writer
            synchronized (mPm.mLock) {
@@ -679,7 +682,8 @@ final class InstallPackageHelper {
                if (pkgSetting == null || pkgSetting.getPkg() == null) {
                    return Pair.create(PackageManager.INSTALL_FAILED_INVALID_URI, intentSender);
                }
                if (instantApp && (pkgSetting.isSystem() || pkgSetting.isUpdatedSystemApp())) {
                if (instantApp && (pkgSetting.isSystem() || pkgSetting.isUpdatedSystemApp()
                        || isPackageDeviceAdmin || isProtectedPackage)) {
                    return Pair.create(PackageManager.INSTALL_FAILED_INVALID_URI, intentSender);
                }
                if (!snapshot.canViewInstantApps(callingUid, UserHandle.getUserId(callingUid))) {
Loading