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:
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user