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

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

Change-Id: Iab1fdc7e85ac92aaa8a4e1cd2cd5710003854d9f
This commit is contained in:
Songchun Fan
2021-06-01 16:21:56 +00:00
committed by Automerger Merge Worker
2 changed files with 96 additions and 28 deletions

View File

@@ -2773,6 +2773,7 @@ public final class Settings {
private final ArraySet<String> mReadableFields; private final ArraySet<String> mReadableFields;
private final ArraySet<String> mAllFields; private final ArraySet<String> mAllFields;
private final ArrayMap<String, Integer> mReadableFieldsWithMaxTargetSdk;
@GuardedBy("this") @GuardedBy("this")
private GenerationTracker mGenerationTracker; private GenerationTracker mGenerationTracker;
@@ -2794,7 +2795,9 @@ public final class Settings {
mProviderHolder = providerHolder; mProviderHolder = providerHolder;
mReadableFields = new ArraySet<>(); mReadableFields = new ArraySet<>();
mAllFields = 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, 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. // Settings.Global and is not annotated as @Readable.
// Notice that a key string that is not defined in any of the Settings.* classes will // Notice that a key string that is not defined in any of the Settings.* classes will
// still be regarded as readable. // still be regarded as readable.
if (!isCallerExemptFromReadableRestriction() if (!isCallerExemptFromReadableRestriction() && mAllFields.contains(name)) {
&& mAllFields.contains(name) && !mReadableFields.contains(name)) { if (!mReadableFields.contains(name)) {
throw new SecurityException( throw new SecurityException(
"Settings key: <" + name + "> is not readable. From S+, settings keys " "Settings key: <" + name + "> is not readable. From S+, settings keys "
+ "annotated with @hide are restricted to system_server and system " + "annotated with @hide are restricted to system_server and "
+ "apps only, unless they are annotated with @Readable."); + "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()); final boolean isSelf = (userHandle == UserHandle.myUserId());
int currentGeneration = -1; int currentGeneration = -1;
if (isSelf) { if (isSelf) {
@@ -3225,10 +3249,12 @@ public final class Settings {
@Target({ ElementType.FIELD }) @Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
private @interface Readable { private @interface Readable {
int maxTargetSdk() default 0;
} }
private static <T extends NameValueTable> void getPublicSettingsForClass( 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(); final Field[] allFields = callerClass.getDeclaredFields();
try { try {
for (int i = 0; i < allFields.length; i++) { for (int i = 0; i < allFields.length; i++) {
@@ -3241,8 +3267,15 @@ public final class Settings {
continue; continue;
} }
allKeys.add((String) value); allKeys.add((String) value);
if (field.getAnnotation(Readable.class) != null) { final Readable annotation = field.getAnnotation(Readable.class);
readableKeys.add((String) value);
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) { } catch (IllegalAccessException ignored) {
@@ -3404,8 +3437,10 @@ public final class Settings {
} }
/** @hide */ /** @hide */
public static void getPublicSettings(Set<String> allKeys, Set<String> readableKeys) { public static void getPublicSettings(Set<String> allKeys, Set<String> readableKeys,
getPublicSettingsForClass(System.class, allKeys, readableKeys); ArrayMap<String, Integer> readableKeysWithMaxTargetSdk) {
getPublicSettingsForClass(System.class, allKeys, readableKeys,
readableKeysWithMaxTargetSdk);
} }
/** /**
@@ -5734,8 +5769,10 @@ public final class Settings {
} }
/** @hide */ /** @hide */
public static void getPublicSettings(Set<String> allKeys, Set<String> readableKeys) { public static void getPublicSettings(Set<String> allKeys, Set<String> readableKeys,
getPublicSettingsForClass(Secure.class, allKeys, readableKeys); ArrayMap<String, Integer> readableKeysWithMaxTargetSdk) {
getPublicSettingsForClass(Secure.class, allKeys, readableKeys,
readableKeysWithMaxTargetSdk);
} }
/** /**
@@ -11023,7 +11060,7 @@ public final class Settings {
* @hide * @hide
*/ */
@UnsupportedAppUsage @UnsupportedAppUsage
@Readable @Readable(maxTargetSdk = Build.VERSION_CODES.R)
public static final String MOBILE_DATA = "mobile_data"; public static final String MOBILE_DATA = "mobile_data";
/** /**
@@ -14965,8 +15002,10 @@ public final class Settings {
} }
/** @hide */ /** @hide */
public static void getPublicSettings(Set<String> allKeys, Set<String> readableKeys) { public static void getPublicSettings(Set<String> allKeys, Set<String> readableKeys,
getPublicSettingsForClass(Global.class, allKeys, readableKeys); ArrayMap<String, Integer> readableKeysWithMaxTargetSdk) {
getPublicSettingsForClass(Global.class, allKeys, readableKeys,
readableKeysWithMaxTargetSdk);
} }
/** /**

View File

@@ -310,20 +310,29 @@ public class SettingsProvider extends ContentProvider {
private static final Set<String> sAllSecureSettings = new ArraySet<>(); private static final Set<String> sAllSecureSettings = new ArraySet<>();
private static final Set<String> sReadableSecureSettings = new ArraySet<>(); private static final Set<String> sReadableSecureSettings = new ArraySet<>();
private static final ArrayMap<String, Integer> sReadableSecureSettingsWithMaxTargetSdk =
new ArrayMap<>();
static { 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> sAllSystemSettings = new ArraySet<>();
private static final Set<String> sReadableSystemSettings = new ArraySet<>(); private static final Set<String> sReadableSystemSettings = new ArraySet<>();
private static final ArrayMap<String, Integer> sReadableSystemSettingsWithMaxTargetSdk =
new ArrayMap<>();
static { 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> sAllGlobalSettings = new ArraySet<>();
private static final Set<String> sReadableGlobalSettings = new ArraySet<>(); private static final Set<String> sReadableGlobalSettings = new ArraySet<>();
private static final ArrayMap<String, Integer> sReadableGlobalSettingsWithMaxTargetSdk =
new ArrayMap<>();
static { static {
Settings.Global.getPublicSettings(sAllGlobalSettings, sReadableGlobalSettings); Settings.Global.getPublicSettings(sAllGlobalSettings, sReadableGlobalSettings,
sReadableGlobalSettingsWithMaxTargetSdk);
} }
private final Object mLock = new Object(); private final Object mLock = new Object();
@@ -2065,7 +2074,7 @@ public class SettingsProvider extends ContentProvider {
} }
if ((ai.flags & ApplicationInfo.FLAG_TEST_ONLY) == 0) { if ((ai.flags & ApplicationInfo.FLAG_TEST_ONLY) == 0) {
// Skip checking readable annotations for test_only apps // 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 * 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 * 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 * 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 * Notice that a key string that is not defined in any of the Settings.* classes will still be
* regarded as readable. * 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> allFields;
final Set<String> readableFields; final Set<String> readableFields;
final ArrayMap<String, Integer> readableFieldsWithMaxTargetSdk;
switch (settingsType) { switch (settingsType) {
case SETTINGS_TYPE_GLOBAL: case SETTINGS_TYPE_GLOBAL:
allFields = sAllGlobalSettings; allFields = sAllGlobalSettings;
readableFields = sReadableGlobalSettings; readableFields = sReadableGlobalSettings;
readableFieldsWithMaxTargetSdk = sReadableGlobalSettingsWithMaxTargetSdk;
break; break;
case SETTINGS_TYPE_SYSTEM: case SETTINGS_TYPE_SYSTEM:
allFields = sAllSystemSettings; allFields = sAllSystemSettings;
readableFields = sReadableSystemSettings; readableFields = sReadableSystemSettings;
readableFieldsWithMaxTargetSdk = sReadableSystemSettingsWithMaxTargetSdk;
break; break;
case SETTINGS_TYPE_SECURE: case SETTINGS_TYPE_SECURE:
allFields = sAllSecureSettings; allFields = sAllSecureSettings;
readableFields = sReadableSecureSettings; readableFields = sReadableSecureSettings;
readableFieldsWithMaxTargetSdk = sReadableSecureSettingsWithMaxTargetSdk;
break; break;
default: default:
throw new IllegalArgumentException("Invalid settings type: " + settingsType); throw new IllegalArgumentException("Invalid settings type: " + settingsType);
} }
if (allFields.contains(settingName) && !readableFields.contains(settingName)) { if (allFields.contains(settingName)) {
throw new SecurityException( if (!readableFields.contains(settingName)) {
"Settings key: <" + settingName + "> is not readable. From S+, settings keys " throw new SecurityException(
+ "annotated with @hide are restricted to system_server and system " "Settings key: <" + settingName + "> is not readable. From S+, settings "
+ "apps only, unless they are annotated with @Readable."); + "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
);
}
}
}
} }
} }