diff options
| -rw-r--r-- | core/java/android/provider/Settings.java | 73 | ||||
| -rw-r--r-- | packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java | 51 |
2 files changed, 96 insertions, 28 deletions
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index e3302d1ca9a0..13e5cda7cca3 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -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)) { - 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."); + 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." + ); + } 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); } /** diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index bce576d1e1d8..dd9a6eee7327 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -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)) { - 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."); + 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." + ); + } 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 + ); + } + } + } } } |