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

Commit 681ae40c authored by Songchun Fan's avatar Songchun Fan Committed by Automerger Merge Worker
Browse files

Merge "[SettingsProvider] add maxTargetSdk in @Readable" into sc-dev am: 52109a93

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/14744258

Change-Id: Iab1fdc7e85ac92aaa8a4e1cd2cd5710003854d9f
parents c31150a9 52109a93
Loading
Loading
Loading
Loading
+56 −17
Original line number Diff line number Diff line
@@ -2773,6 +2773,7 @@ public final class Settings {
        private final ArraySet<String> mReadableFields;
        private final ArraySet<String> mAllFields;
        private final ArrayMap<String, Integer> mReadableFieldsWithMaxTargetSdk;
        @GuardedBy("this")
        private GenerationTracker mGenerationTracker;
@@ -2794,7 +2795,9 @@ public final class Settings {
            mProviderHolder = providerHolder;
            mReadableFields = new ArraySet<>();
            mAllFields = new ArraySet<>();
            getPublicSettingsForClass(callerClass, mAllFields, mReadableFields);
            mReadableFieldsWithMaxTargetSdk = new ArrayMap<>();
            getPublicSettingsForClass(callerClass, mAllFields, mReadableFields,
                    mReadableFieldsWithMaxTargetSdk);
        }
        public boolean putStringForUser(ContentResolver cr, String name, String value,
@@ -2851,13 +2854,34 @@ public final class Settings {
            // Settings.Global and is not annotated as @Readable.
            // Notice that a key string that is not defined in any of the Settings.* classes will
            // still be regarded as readable.
            if (!isCallerExemptFromReadableRestriction()
                    && mAllFields.contains(name) && !mReadableFields.contains(name)) {
            if (!isCallerExemptFromReadableRestriction() && mAllFields.contains(name)) {
                if (!mReadableFields.contains(name)) {
                    throw new SecurityException(
                            "Settings key: <" + name + "> is not readable. From S+, settings keys "
                                + "annotated with @hide are restricted to system_server and system "
                                + "apps only, unless they are annotated with @Readable.");
                                    + "annotated with @hide are restricted to system_server and "
                                    + "system apps only, unless they are annotated with @Readable."
                    );
                } else {
                    // When the target settings key has @Readable annotation, if the caller app's
                    // target sdk is higher than the maxTargetSdk of the annotation, reject access.
                    if (mReadableFieldsWithMaxTargetSdk.containsKey(name)) {
                        final int maxTargetSdk = mReadableFieldsWithMaxTargetSdk.get(name);
                        final Application application = ActivityThread.currentApplication();
                        final boolean targetSdkCheckOk = application != null
                                && application.getApplicationInfo() != null
                                && application.getApplicationInfo().targetSdkVersion
                                <= maxTargetSdk;
                        if (!targetSdkCheckOk) {
                            throw new SecurityException(
                                    "Settings key: <" + name + "> is only readable to apps with "
                                            + "targetSdkVersion lower than or equal to: "
                                            + maxTargetSdk
                            );
                        }
                    }
                }
            }
            final boolean isSelf = (userHandle == UserHandle.myUserId());
            int currentGeneration = -1;
            if (isSelf) {
@@ -3225,10 +3249,12 @@ public final class Settings {
    @Target({ ElementType.FIELD })
    @Retention(RetentionPolicy.RUNTIME)
    private @interface Readable {
        int maxTargetSdk() default 0;
    }
    private static <T extends NameValueTable> void getPublicSettingsForClass(
            Class<T> callerClass, Set<String> allKeys, Set<String> readableKeys) {
            Class<T> callerClass, Set<String> allKeys, Set<String> readableKeys,
            ArrayMap<String, Integer> keysWithMaxTargetSdk) {
        final Field[] allFields = callerClass.getDeclaredFields();
        try {
            for (int i = 0; i < allFields.length; i++) {
@@ -3241,8 +3267,15 @@ public final class Settings {
                    continue;
                }
                allKeys.add((String) value);
                if (field.getAnnotation(Readable.class) != null) {
                    readableKeys.add((String) value);
                final Readable annotation = field.getAnnotation(Readable.class);
                if (annotation != null) {
                    final String key = (String) value;
                    final int maxTargetSdk = annotation.maxTargetSdk();
                    readableKeys.add(key);
                    if (maxTargetSdk != 0) {
                        keysWithMaxTargetSdk.put(key, maxTargetSdk);
                    }
                }
            }
        } catch (IllegalAccessException ignored) {
@@ -3404,8 +3437,10 @@ public final class Settings {
        }
        /** @hide */
        public static void getPublicSettings(Set<String> allKeys, Set<String> readableKeys) {
            getPublicSettingsForClass(System.class, allKeys, readableKeys);
        public static void getPublicSettings(Set<String> allKeys, Set<String> readableKeys,
                ArrayMap<String, Integer> readableKeysWithMaxTargetSdk) {
            getPublicSettingsForClass(System.class, allKeys, readableKeys,
                    readableKeysWithMaxTargetSdk);
        }
        /**
@@ -5734,8 +5769,10 @@ public final class Settings {
        }
        /** @hide */
        public static void getPublicSettings(Set<String> allKeys, Set<String> readableKeys) {
            getPublicSettingsForClass(Secure.class, allKeys, readableKeys);
        public static void getPublicSettings(Set<String> allKeys, Set<String> readableKeys,
                ArrayMap<String, Integer> readableKeysWithMaxTargetSdk) {
            getPublicSettingsForClass(Secure.class, allKeys, readableKeys,
                    readableKeysWithMaxTargetSdk);
        }
        /**
@@ -11023,7 +11060,7 @@ public final class Settings {
        * @hide
        */
        @UnsupportedAppUsage
        @Readable
        @Readable(maxTargetSdk = Build.VERSION_CODES.R)
        public static final String MOBILE_DATA = "mobile_data";
        /**
@@ -14965,8 +15002,10 @@ public final class Settings {
        }
        /** @hide */
        public static void getPublicSettings(Set<String> allKeys, Set<String> readableKeys) {
            getPublicSettingsForClass(Global.class, allKeys, readableKeys);
        public static void getPublicSettings(Set<String> allKeys, Set<String> readableKeys,
                ArrayMap<String, Integer> readableKeysWithMaxTargetSdk) {
            getPublicSettingsForClass(Global.class, allKeys, readableKeys,
                    readableKeysWithMaxTargetSdk);
        }
        /**
+40 −11
Original line number Diff line number Diff line
@@ -310,20 +310,29 @@ public class SettingsProvider extends ContentProvider {

    private static final Set<String> sAllSecureSettings = new ArraySet<>();
    private static final Set<String> sReadableSecureSettings = new ArraySet<>();
    private static final ArrayMap<String, Integer> sReadableSecureSettingsWithMaxTargetSdk =
            new ArrayMap<>();
    static {
        Settings.Secure.getPublicSettings(sAllSecureSettings, sReadableSecureSettings);
        Settings.Secure.getPublicSettings(sAllSecureSettings, sReadableSecureSettings,
                sReadableSecureSettingsWithMaxTargetSdk);
    }

    private static final Set<String> sAllSystemSettings = new ArraySet<>();
    private static final Set<String> sReadableSystemSettings = new ArraySet<>();
    private static final ArrayMap<String, Integer> sReadableSystemSettingsWithMaxTargetSdk =
            new ArrayMap<>();
    static {
        Settings.System.getPublicSettings(sAllSystemSettings, sReadableSystemSettings);
        Settings.System.getPublicSettings(sAllSystemSettings, sReadableSystemSettings,
                sReadableSystemSettingsWithMaxTargetSdk);
    }

    private static final Set<String> sAllGlobalSettings = new ArraySet<>();
    private static final Set<String> sReadableGlobalSettings = new ArraySet<>();
    private static final ArrayMap<String, Integer> sReadableGlobalSettingsWithMaxTargetSdk =
            new ArrayMap<>();
    static {
        Settings.Global.getPublicSettings(sAllGlobalSettings, sReadableGlobalSettings);
        Settings.Global.getPublicSettings(sAllGlobalSettings, sReadableGlobalSettings,
                sReadableGlobalSettingsWithMaxTargetSdk);
    }

    private final Object mLock = new Object();
@@ -2065,7 +2074,7 @@ public class SettingsProvider extends ContentProvider {
        }
        if ((ai.flags & ApplicationInfo.FLAG_TEST_ONLY) == 0) {
            // Skip checking readable annotations for test_only apps
            checkReadableAnnotation(settingsType, settingName);
            checkReadableAnnotation(settingsType, settingName, ai.targetSandboxVersion);
        }
        /**
         * some settings need additional permission check, this is to have a matching security
@@ -2101,35 +2110,55 @@ public class SettingsProvider extends ContentProvider {
    /**
     * Check if the target settings key is readable. Reject if the caller app is trying to access a
     * settings key defined in the Settings.Secure, Settings.System or Settings.Global and is not
     * annotated as @Readable.
     * annotated as @Readable. Reject if the caller app is targeting an SDK level that is higher
     * than the maxTargetSdk specified in the @Readable annotation.
     * Notice that a key string that is not defined in any of the Settings.* classes will still be
     * regarded as readable.
     */
    private void checkReadableAnnotation(int settingsType, String settingName) {
    private void checkReadableAnnotation(int settingsType, String settingName,
            int targetSdkVersion) {
        final Set<String> allFields;
        final Set<String> readableFields;
        final ArrayMap<String, Integer> readableFieldsWithMaxTargetSdk;
        switch (settingsType) {
            case SETTINGS_TYPE_GLOBAL:
                allFields = sAllGlobalSettings;
                readableFields = sReadableGlobalSettings;
                readableFieldsWithMaxTargetSdk = sReadableGlobalSettingsWithMaxTargetSdk;
                break;
            case SETTINGS_TYPE_SYSTEM:
                allFields = sAllSystemSettings;
                readableFields = sReadableSystemSettings;
                readableFieldsWithMaxTargetSdk = sReadableSystemSettingsWithMaxTargetSdk;
                break;
            case SETTINGS_TYPE_SECURE:
                allFields = sAllSecureSettings;
                readableFields = sReadableSecureSettings;
                readableFieldsWithMaxTargetSdk = sReadableSecureSettingsWithMaxTargetSdk;
                break;
            default:
                throw new IllegalArgumentException("Invalid settings type: " + settingsType);
        }

        if (allFields.contains(settingName) && !readableFields.contains(settingName)) {
        if (allFields.contains(settingName)) {
            if (!readableFields.contains(settingName)) {
                throw new SecurityException(
                    "Settings key: <" + settingName + "> is not readable. From S+, settings keys "
                            + "annotated with @hide are restricted to system_server and system "
                            + "apps only, unless they are annotated with @Readable.");
                        "Settings key: <" + settingName + "> is not readable. From S+, settings "
                                + "keys annotated with @hide are restricted to system_server and "
                                + "system apps only, unless they are annotated with @Readable."
                );
            } else {
                if (readableFieldsWithMaxTargetSdk.containsKey(settingName)) {
                    final int maxTargetSdk = readableFieldsWithMaxTargetSdk.get(settingName);
                    if (targetSdkVersion > maxTargetSdk) {
                        throw new SecurityException(
                                "Settings key: <" + settingName + "> is only readable to apps with "
                                        + "targetSdkVersion lower than or equal to: "
                                        + maxTargetSdk
                        );
                    }
                }
            }
        }
    }