Merge "Add ephemeral whitelist for SettingsProvider"
This commit is contained in:
committed by
Android (Google) Code Review
commit
6ba5dccd50
@@ -50,6 +50,7 @@ import android.net.ConnectivityManager;
|
||||
import android.net.Uri;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.os.BatteryManager;
|
||||
import android.os.Binder;
|
||||
import android.os.Build.VERSION_CODES;
|
||||
import android.os.Bundle;
|
||||
import android.os.DropBoxManager;
|
||||
@@ -1596,6 +1597,24 @@ public final class Settings {
|
||||
// with a partial enable/disable state in multi-threaded situations.
|
||||
private static final Object mLocationSettingsLock = new Object();
|
||||
|
||||
// Used in system server calling uid workaround in call()
|
||||
private static boolean sInSystemServer = false;
|
||||
private static final Object sInSystemServerLock = new Object();
|
||||
|
||||
/** @hide */
|
||||
public static void setInSystemServer() {
|
||||
synchronized (sInSystemServerLock) {
|
||||
sInSystemServer = true;
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public static boolean isInSystemServer() {
|
||||
synchronized (sInSystemServerLock) {
|
||||
return sInSystemServer;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SettingNotFoundException extends AndroidException {
|
||||
public SettingNotFoundException(String msg) {
|
||||
super(msg);
|
||||
@@ -1804,7 +1823,23 @@ public final class Settings {
|
||||
}
|
||||
}
|
||||
}
|
||||
Bundle b = cp.call(cr.getPackageName(), mCallGetCommand, name, args);
|
||||
Bundle b;
|
||||
// If we're in system server and in a binder transaction we need to clear the
|
||||
// calling uid. This works around code in system server that did not call
|
||||
// clearCallingIdentity, previously this wasn't needed because reading settings
|
||||
// did not do permission checking but thats no longer the case.
|
||||
// Long term this should be removed and callers should properly call
|
||||
// clearCallingIdentity or use a ContentResolver from the caller as needed.
|
||||
if (Settings.isInSystemServer() && Binder.getCallingUid() != Process.myUid()) {
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
b = cp.call(cr.getPackageName(), mCallGetCommand, name, args);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
} else {
|
||||
b = cp.call(cr.getPackageName(), mCallGetCommand, name, args);
|
||||
}
|
||||
if (b != null) {
|
||||
String value = b.getString(Settings.NameValueTable.VALUE);
|
||||
// Don't update our cache for reads of other users' data
|
||||
@@ -1864,7 +1899,19 @@ public final class Settings {
|
||||
try {
|
||||
Bundle queryArgs = ContentResolver.createSqlQueryBundle(
|
||||
NAME_EQ_PLACEHOLDER, new String[]{name}, null);
|
||||
c = cp.query(cr.getPackageName(), mUri, SELECT_VALUE_PROJECTION, queryArgs, null);
|
||||
// Same workaround as above.
|
||||
if (Settings.isInSystemServer() && Binder.getCallingUid() != Process.myUid()) {
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
c = cp.query(cr.getPackageName(), mUri, SELECT_VALUE_PROJECTION, queryArgs,
|
||||
null);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
} else {
|
||||
c = cp.query(cr.getPackageName(), mUri, SELECT_VALUE_PROJECTION, queryArgs,
|
||||
null);
|
||||
}
|
||||
if (c == null) {
|
||||
Log.w(TAG, "Can't get key " + name + " from " + mUri);
|
||||
return null;
|
||||
@@ -4020,6 +4067,22 @@ public final class Settings {
|
||||
outMap.putAll(CLONE_FROM_PARENT_ON_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* System settings which can be accessed by ephemeral apps.
|
||||
* @hide
|
||||
*/
|
||||
public static final Set<String> EPHEMERAL_SETTINGS = new ArraySet<>();
|
||||
static {
|
||||
EPHEMERAL_SETTINGS.add(TEXT_AUTO_REPLACE);
|
||||
EPHEMERAL_SETTINGS.add(TEXT_AUTO_CAPS);
|
||||
EPHEMERAL_SETTINGS.add(TEXT_AUTO_PUNCTUATE);
|
||||
EPHEMERAL_SETTINGS.add(TEXT_SHOW_PASSWORD);
|
||||
EPHEMERAL_SETTINGS.add(DATE_FORMAT);
|
||||
EPHEMERAL_SETTINGS.add(FONT_SCALE);
|
||||
EPHEMERAL_SETTINGS.add(HAPTIC_FEEDBACK_ENABLED);
|
||||
EPHEMERAL_SETTINGS.add(TIME_12_24);
|
||||
}
|
||||
|
||||
/**
|
||||
* When to use Wi-Fi calling
|
||||
*
|
||||
@@ -6898,6 +6961,20 @@ public final class Settings {
|
||||
outKeySet.addAll(CLONE_TO_MANAGED_PROFILE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Secure settings which can be accessed by ephemeral apps.
|
||||
* @hide
|
||||
*/
|
||||
public static final Set<String> EPHEMERAL_SETTINGS = new ArraySet<>();
|
||||
static {
|
||||
EPHEMERAL_SETTINGS.add(ENABLED_ACCESSIBILITY_SERVICES);
|
||||
EPHEMERAL_SETTINGS.add(ACCESSIBILITY_SPEAK_PASSWORD);
|
||||
EPHEMERAL_SETTINGS.add(ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
|
||||
|
||||
EPHEMERAL_SETTINGS.add(DEFAULT_INPUT_METHOD);
|
||||
EPHEMERAL_SETTINGS.add(ENABLED_INPUT_METHODS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for determining if a location provider is enabled.
|
||||
*
|
||||
@@ -9906,6 +9983,20 @@ public final class Settings {
|
||||
* @hide
|
||||
*/
|
||||
public static final String CELL_ON = "cell_on";
|
||||
|
||||
/**
|
||||
* Global settings which can be accessed by ephemeral apps.
|
||||
* @hide
|
||||
*/
|
||||
public static final Set<String> EPHEMERAL_SETTINGS = new ArraySet<>();
|
||||
static {
|
||||
EPHEMERAL_SETTINGS.add(WAIT_FOR_DEBUGGER);
|
||||
EPHEMERAL_SETTINGS.add(DEVICE_PROVISIONED);
|
||||
EPHEMERAL_SETTINGS.add(DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES);
|
||||
EPHEMERAL_SETTINGS.add(DEVELOPMENT_FORCE_RTL);
|
||||
EPHEMERAL_SETTINGS.add(EPHEMERAL_COOKIE_MAX_SIZE_BYTES);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -271,6 +271,7 @@ public class SettingsProvider extends ContentProvider {
|
||||
|
||||
@Override
|
||||
public boolean onCreate() {
|
||||
Settings.setInSystemServer();
|
||||
synchronized (mLock) {
|
||||
mUserManager = UserManager.get(getContext());
|
||||
mPackageManager = AppGlobals.getPackageManager();
|
||||
@@ -829,7 +830,8 @@ public class SettingsProvider extends ContentProvider {
|
||||
SettingsState settingsState = mSettingsRegistry.getSettingsLocked(
|
||||
SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM);
|
||||
|
||||
List<String> names = settingsState.getSettingNamesLocked();
|
||||
List<String> names = getSettingsNamesLocked(SETTINGS_TYPE_GLOBAL,
|
||||
UserHandle.USER_SYSTEM);
|
||||
|
||||
final int nameCount = names.size();
|
||||
|
||||
@@ -852,6 +854,9 @@ public class SettingsProvider extends ContentProvider {
|
||||
Slog.v(LOG_TAG, "getGlobalSetting(" + name + ")");
|
||||
}
|
||||
|
||||
// Ensure the caller can access the setting.
|
||||
enforceSettingReadable(name, SETTINGS_TYPE_GLOBAL, UserHandle.getCallingUserId());
|
||||
|
||||
// Get the value.
|
||||
synchronized (mLock) {
|
||||
return mSettingsRegistry.getSettingLocked(SETTINGS_TYPE_GLOBAL,
|
||||
@@ -954,8 +959,7 @@ public class SettingsProvider extends ContentProvider {
|
||||
final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(userId);
|
||||
|
||||
synchronized (mLock) {
|
||||
List<String> names = mSettingsRegistry.getSettingsNamesLocked(
|
||||
SETTINGS_TYPE_SECURE, callingUserId);
|
||||
List<String> names = getSettingsNamesLocked(SETTINGS_TYPE_SECURE, callingUserId);
|
||||
|
||||
final int nameCount = names.size();
|
||||
|
||||
@@ -997,6 +1001,9 @@ public class SettingsProvider extends ContentProvider {
|
||||
// Resolve the userId on whose behalf the call is made.
|
||||
final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId);
|
||||
|
||||
// Ensure the caller can access the setting.
|
||||
enforceSettingReadable(name, SETTINGS_TYPE_SECURE, callingUserId);
|
||||
|
||||
// Determine the owning user as some profile settings are cloned from the parent.
|
||||
final int owningUserId = resolveOwningUserIdForSecureSettingLocked(callingUserId, name);
|
||||
|
||||
@@ -1159,8 +1166,7 @@ public class SettingsProvider extends ContentProvider {
|
||||
final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(userId);
|
||||
|
||||
synchronized (mLock) {
|
||||
List<String> names = mSettingsRegistry.getSettingsNamesLocked(
|
||||
SETTINGS_TYPE_SYSTEM, callingUserId);
|
||||
List<String> names = getSettingsNamesLocked(SETTINGS_TYPE_SYSTEM, callingUserId);
|
||||
|
||||
final int nameCount = names.size();
|
||||
|
||||
@@ -1191,6 +1197,9 @@ public class SettingsProvider extends ContentProvider {
|
||||
// Resolve the userId on whose behalf the call is made.
|
||||
final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId);
|
||||
|
||||
// Ensure the caller can access the setting.
|
||||
enforceSettingReadable(name, SETTINGS_TYPE_SYSTEM, callingUserId);
|
||||
|
||||
// Determine the owning user as some profile settings are cloned from the parent.
|
||||
final int owningUserId = resolveOwningUserIdForSystemSettingLocked(callingUserId, name);
|
||||
|
||||
@@ -1409,9 +1418,15 @@ public class SettingsProvider extends ContentProvider {
|
||||
&& (parentId = getGroupParentLocked(userId)) != userId) {
|
||||
// The setting has a dependency and the profile has a parent
|
||||
String dependency = sSystemCloneFromParentOnDependency.get(setting);
|
||||
Setting settingObj = getSecureSetting(dependency, userId);
|
||||
if (settingObj != null && settingObj.getValue().equals("1")) {
|
||||
return parentId;
|
||||
// Lookup the dependency setting as ourselves, some callers may not have access to it.
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
Setting settingObj = getSecureSetting(dependency, userId);
|
||||
if (settingObj != null && settingObj.getValue().equals("1")) {
|
||||
return parentId;
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
return resolveOwningUserIdLocked(userId, sSystemCloneToManagedSettings, setting);
|
||||
@@ -1479,6 +1494,55 @@ public class SettingsProvider extends ContentProvider {
|
||||
}
|
||||
}
|
||||
|
||||
private Set<String> getEphemeralAccessibleSettings(int settingsType) {
|
||||
switch (settingsType) {
|
||||
case SETTINGS_TYPE_GLOBAL:
|
||||
return Settings.Global.EPHEMERAL_SETTINGS;
|
||||
case SETTINGS_TYPE_SECURE:
|
||||
return Settings.Secure.EPHEMERAL_SETTINGS;
|
||||
case SETTINGS_TYPE_SYSTEM:
|
||||
return Settings.System.EPHEMERAL_SETTINGS;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid settings type: " + settingsType);
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> getSettingsNamesLocked(int settingsType, int userId) {
|
||||
ApplicationInfo ai = getCallingApplicationInfoOrThrow(userId);
|
||||
if (ai.isEphemeralApp()) {
|
||||
return new ArrayList<String>(getEphemeralAccessibleSettings(settingsType));
|
||||
} else {
|
||||
return mSettingsRegistry.getSettingsNamesLocked(settingsType, userId);
|
||||
}
|
||||
}
|
||||
|
||||
private void enforceSettingReadable(String settingName, int settingsType, int userId) {
|
||||
if (UserHandle.getAppId(Binder.getCallingUid()) < Process.FIRST_APPLICATION_UID) {
|
||||
return;
|
||||
}
|
||||
ApplicationInfo ai = getCallingApplicationInfoOrThrow(userId);
|
||||
if (!ai.isEphemeralApp()) {
|
||||
return;
|
||||
}
|
||||
if (!getEphemeralAccessibleSettings(settingsType).contains(settingName)) {
|
||||
throw new SecurityException("Setting " + settingName + " is not accessible from"
|
||||
+ " ephemeral package " + getCallingPackage());
|
||||
}
|
||||
}
|
||||
|
||||
private ApplicationInfo getCallingApplicationInfoOrThrow(int userId) {
|
||||
ApplicationInfo ai = null;
|
||||
try {
|
||||
ai = mPackageManager.getApplicationInfo(getCallingPackage(), 0 , userId);
|
||||
} catch (RemoteException ignored) {
|
||||
}
|
||||
if (ai == null) {
|
||||
throw new IllegalStateException("Failed to lookup info for package "
|
||||
+ getCallingPackage());
|
||||
}
|
||||
return ai;
|
||||
}
|
||||
|
||||
private PackageInfo getCallingPackageInfoOrThrow(int userId) {
|
||||
try {
|
||||
PackageInfo packageInfo = mPackageManager.getPackageInfo(
|
||||
@@ -1548,7 +1612,7 @@ public class SettingsProvider extends ContentProvider {
|
||||
value = value.substring(1);
|
||||
|
||||
Setting settingValue = getSecureSetting(
|
||||
Settings.Secure.LOCATION_PROVIDERS_ALLOWED, owningUserId);
|
||||
Settings.Secure.LOCATION_PROVIDERS_ALLOWED, owningUserId);
|
||||
if (settingValue == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user