From: yuemingw Date: Tue, 30 Jan 2018 17:27:54 +0000 (+0000) Subject: Block adb from changing certain settings value when corresponding user X-Git-Tag: android-x86-9.0-r1~198^2~27^2~1 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=4140f6c4e3de454dfbcf060112517408ac69e96c;p=android-x86%2Fframeworks-base.git Block adb from changing certain settings value when corresponding user restriction is on. Check calling uid in isSettingRestrictedForUser(which is called by settingsprovider), and only allow system_uid when certain user restriction is on, so that user won't be able to change these settings with adb: Settings.Secure.LOCATION_MODE, Settings.Secure.PROVIDERS_ALLOWED, Settings.System.SCREEN_BRIGHTNESS, Settings.System.SCREEN_BRIGHTNESS_MODE, Settings.System.SCREEN_OFF_TIMEOUT, Settings.Global.AUTO_TIME, Settings.Global.AUTO_TIME_ZONE. This check also prevents 3rd party apps from modifying system settings value when corresponding user restriction is on. In addition, any attempt to change AUTO_TIME will also go through the check for dpm.getAutoTimeRequired(). Test: manually by running the adb command with restriction set and not set Bug: 72549013 Bug: 72548203 Bug: 72548533 Bug: 72686466 Bug: 72687105 Bug: 72940551 Bug: 72940562 Change-Id: Idfe0f1758d57958b836207ab3d55b2a292e1ae0d --- diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl index 5e23932c48cc..ad0d9fd0aca2 100644 --- a/core/java/android/os/IUserManager.aidl +++ b/core/java/android/os/IUserManager.aidl @@ -101,4 +101,5 @@ interface IUserManager { boolean requestQuietModeEnabled(String callingPackage, boolean enableQuietMode, int userHandle, in IntentSender target); long getUserStartRealtime(); long getUserUnlockRealtime(); + boolean isSettingRestrictedForUser(String setting, int userId, String value); } diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 185620066454..1248b548e931 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -2731,6 +2731,25 @@ public class UserManager { } /** + * Checks whether changing a setting to a value is prohibited by the corresponding user + * restriction. + * + *

See also {@link com.android.server.pm.UserRestrictionsUtils#applyUserRestriction( + * Context, int, String, boolean)}, which should be in sync with this method. + * + * @return true if the change is prohibited, false if the change is allowed. + * + * @hide + */ + public boolean isSettingRestrictedForUser(String setting, int userId, String value) { + try { + return mService.isSettingRestrictedForUser(setting, userId, value); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * @hide * User that enforces a restriction. * diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index bbb4fc86efe7..2d061352559c 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -16,6 +16,10 @@ package com.android.providers.settings; +import static android.os.Process.ROOT_UID; +import static android.os.Process.SHELL_UID; +import static android.os.Process.SYSTEM_UID; + import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; @@ -60,9 +64,9 @@ import android.os.UserHandle; import android.os.UserManager; import android.os.UserManagerInternal; import android.provider.Settings; -import android.provider.SettingsValidators; import android.provider.Settings.Global; import android.provider.Settings.Secure; +import android.provider.SettingsValidators; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; @@ -96,13 +100,10 @@ import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.regex.Pattern; + import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; -import static android.os.Process.ROOT_UID; -import static android.os.Process.SHELL_UID; -import static android.os.Process.SYSTEM_UID; - /** *

@@ -1017,8 +1018,7 @@ public class SettingsProvider extends ContentProvider { // If this is a setting that is currently restricted for this user, do not allow // unrestricting changes. - if (name != null && isGlobalOrSecureSettingRestrictedForUser(name, callingUserId, value, - Binder.getCallingUid())) { + if (name != null && mUserManager.isSettingRestrictedForUser(name, callingUserId, value)) { return false; } @@ -1325,8 +1325,7 @@ public class SettingsProvider extends ContentProvider { // If this is a setting that is currently restricted for this user, do not allow // unrestricting changes. - if (name != null && isGlobalOrSecureSettingRestrictedForUser(name, callingUserId, value, - Binder.getCallingUid())) { + if (name != null && mUserManager.isSettingRestrictedForUser(name, callingUserId, value)) { return false; } @@ -1466,6 +1465,10 @@ public class SettingsProvider extends ContentProvider { // Resolve the userId on whose behalf the call is made. final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(runAsUserId); + if (name != null && mUserManager.isSettingRestrictedForUser(name, callingUserId, value)) { + return false; + } + // Enforce what the calling package can mutate the system settings. enforceRestrictedSystemSettingsMutationForCallingPackage(operation, name, callingUserId); @@ -1579,106 +1582,6 @@ public class SettingsProvider extends ContentProvider { return false; } - /** - * Checks whether changing a setting to a value is prohibited by the corresponding user - * restriction. - * - *

See also {@link com.android.server.pm.UserRestrictionsUtils#applyUserRestriction( - * Context, int, String, boolean)}, which should be in sync with this method. - * - * @return true if the change is prohibited, false if the change is allowed. - */ - private boolean isGlobalOrSecureSettingRestrictedForUser(String setting, int userId, - String value, int callingUid) { - String restriction; - boolean checkAllUser = false; - switch (setting) { - case Settings.Secure.LOCATION_MODE: - // Note LOCATION_MODE will be converted into LOCATION_PROVIDERS_ALLOWED - // in android.provider.Settings.Secure.putStringForUser(), so we shouldn't come - // here normally, but we still protect it here from a direct provider write. - if (String.valueOf(Settings.Secure.LOCATION_MODE_OFF).equals(value)) return false; - restriction = UserManager.DISALLOW_SHARE_LOCATION; - break; - - case Settings.Secure.LOCATION_PROVIDERS_ALLOWED: - // See SettingsProvider.updateLocationProvidersAllowedLocked. "-" is to disable - // a provider, which should be allowed even if the user restriction is set. - if (value != null && value.startsWith("-")) return false; - restriction = UserManager.DISALLOW_SHARE_LOCATION; - break; - - case Settings.Secure.INSTALL_NON_MARKET_APPS: - if ("0".equals(value)) return false; - restriction = UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES; - break; - - case Settings.Global.ADB_ENABLED: - if ("0".equals(value)) return false; - restriction = UserManager.DISALLOW_DEBUGGING_FEATURES; - break; - - case Settings.Global.PACKAGE_VERIFIER_ENABLE: - case Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB: - if ("1".equals(value)) return false; - restriction = UserManager.ENSURE_VERIFY_APPS; - break; - - case Settings.Global.PREFERRED_NETWORK_MODE: - restriction = UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS; - break; - - case Settings.Secure.ALWAYS_ON_VPN_APP: - case Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN: - // Whitelist system uid (ConnectivityService) and root uid to change always-on vpn - final int appId = UserHandle.getAppId(callingUid); - if (appId == Process.SYSTEM_UID || appId == Process.ROOT_UID) { - return false; - } - restriction = UserManager.DISALLOW_CONFIG_VPN; - break; - - case Settings.Global.SAFE_BOOT_DISALLOWED: - if ("1".equals(value)) return false; - restriction = UserManager.DISALLOW_SAFE_BOOT; - break; - - case Settings.Global.AIRPLANE_MODE_ON: - if ("0".equals(value)) return false; - restriction = UserManager.DISALLOW_AIRPLANE_MODE; - break; - - case Settings.Secure.DOZE_ENABLED: - case Settings.Secure.DOZE_ALWAYS_ON: - case Settings.Secure.DOZE_PULSE_ON_PICK_UP: - case Settings.Secure.DOZE_PULSE_ON_LONG_PRESS: - case Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP: - if ("0".equals(value)) return false; - restriction = UserManager.DISALLOW_AMBIENT_DISPLAY; - break; - - case Global.LOCATION_GLOBAL_KILL_SWITCH: - if ("0".equals(value)) return false; - restriction = UserManager.DISALLOW_CONFIG_LOCATION; - checkAllUser = true; - break; - - default: - if (setting != null && setting.startsWith(Settings.Global.DATA_ROAMING)) { - if ("0".equals(value)) return false; - restriction = UserManager.DISALLOW_DATA_ROAMING; - break; - } - return false; - } - - if (checkAllUser) { - return mUserManager.hasUserRestrictionOnAnyUser(restriction); - } else { - return mUserManager.hasUserRestriction(restriction, UserHandle.of(userId)); - } - } - private int resolveOwningUserIdForSecureSettingLocked(int userId, String setting) { return resolveOwningUserIdLocked(userId, sSecureCloneToManagedSettings, setting); } @@ -1878,8 +1781,9 @@ public class SettingsProvider extends ContentProvider { * But helper functions in android.providers.Settings can enable or disable * a single provider by using a "+" or "-" prefix before the provider name. * - *

See also {@link #isGlobalOrSecureSettingRestrictedForUser()}. If DISALLOW_SHARE_LOCATION - * is set, the said method will only allow values with the "-" prefix. + *

See also {@link UserManager#isSettingRestrictedForUser()}. + * If DISALLOW_SHARE_LOCATION is set, the said method will only allow values with + * the "-" prefix. * * @returns whether the enabled location providers changed. */ diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index de7e21acc521..4d658a0284f9 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -31,6 +31,7 @@ import android.app.IActivityManager; import android.app.IStopUserCallback; import android.app.KeyguardManager; import android.app.PendingIntent; +import android.app.admin.DevicePolicyManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -71,6 +72,7 @@ import android.os.UserManager.EnforcingUser; import android.os.UserManagerInternal; import android.os.UserManagerInternal.UserRestrictionsListener; import android.os.storage.StorageManager; +import android.provider.Settings; import android.security.GateKeeper; import android.service.gatekeeper.IGateKeeperService; import android.util.AtomicFile; @@ -4038,4 +4040,158 @@ public class UserManagerService extends IUserManager.Stub { + " does not match the calling uid " + callingUid); } } + + @Override + public boolean isSettingRestrictedForUser(String setting, int userId, String value) { + final int callingUid = Binder.getCallingUid(); + if (setting == null) { + return false; + } + String restriction; + boolean checkAllUser = false; + switch (setting) { + case android.provider.Settings.Secure.LOCATION_MODE: + if (hasUserRestriction(UserManager.DISALLOW_CONFIG_LOCATION, userId) + && callingUid != Process.SYSTEM_UID) { + return true; + } else if (String.valueOf(Settings.Secure.LOCATION_MODE_OFF).equals(value)) { + // Note LOCATION_MODE will be converted into LOCATION_PROVIDERS_ALLOWED + // in android.provider.Settings.Secure.putStringForUser(), so we shouldn't come + // here normally, but we still protect it here from a direct provider write. + return false; + } + restriction = UserManager.DISALLOW_SHARE_LOCATION; + break; + + case android.provider.Settings.Secure.LOCATION_PROVIDERS_ALLOWED: + if (hasUserRestriction(UserManager.DISALLOW_CONFIG_LOCATION, userId) + && callingUid != Process.SYSTEM_UID) { + return true; + } else if (value != null && value.startsWith("-")) { + // See SettingsProvider.updateLocationProvidersAllowedLocked. "-" is to disable + // a provider, which should be allowed even if the user restriction is set. + return false; + } + restriction = UserManager.DISALLOW_SHARE_LOCATION; + break; + + case android.provider.Settings.Secure.INSTALL_NON_MARKET_APPS: + if ("0".equals(value)) { + return false; + } + restriction = UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES; + break; + + case android.provider.Settings.Global.ADB_ENABLED: + if ("0".equals(value)) { + return false; + } + restriction = UserManager.DISALLOW_DEBUGGING_FEATURES; + break; + + case android.provider.Settings.Global.PACKAGE_VERIFIER_ENABLE: + case android.provider.Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB: + if ("1".equals(value)) { + return false; + } + restriction = UserManager.ENSURE_VERIFY_APPS; + break; + + case android.provider.Settings.Global.PREFERRED_NETWORK_MODE: + restriction = UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS; + break; + + case android.provider.Settings.Secure.ALWAYS_ON_VPN_APP: + case android.provider.Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN: + // Whitelist system uid (ConnectivityService) and root uid to change always-on vpn + final int appId = UserHandle.getAppId(callingUid); + if (appId == Process.SYSTEM_UID || appId == Process.ROOT_UID) { + return false; + } + restriction = UserManager.DISALLOW_CONFIG_VPN; + break; + + case android.provider.Settings.Global.SAFE_BOOT_DISALLOWED: + if ("1".equals(value)) { + return false; + } + restriction = UserManager.DISALLOW_SAFE_BOOT; + break; + + case android.provider.Settings.Global.AIRPLANE_MODE_ON: + if ("0".equals(value)) { + return false; + } + restriction = UserManager.DISALLOW_AIRPLANE_MODE; + break; + + case android.provider.Settings.Secure.DOZE_ENABLED: + case android.provider.Settings.Secure.DOZE_ALWAYS_ON: + case android.provider.Settings.Secure.DOZE_PULSE_ON_PICK_UP: + case android.provider.Settings.Secure.DOZE_PULSE_ON_LONG_PRESS: + case android.provider.Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP: + if ("0".equals(value)) { + return false; + } + restriction = UserManager.DISALLOW_AMBIENT_DISPLAY; + break; + + case android.provider.Settings.Global.LOCATION_GLOBAL_KILL_SWITCH: + if ("0".equals(value)) { + return false; + } + restriction = UserManager.DISALLOW_CONFIG_LOCATION; + checkAllUser = true; + break; + + case android.provider.Settings.System.SCREEN_BRIGHTNESS: + case android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE: + if (callingUid == Process.SYSTEM_UID) { + return false; + } + restriction = UserManager.DISALLOW_CONFIG_BRIGHTNESS; + break; + + case android.provider.Settings.Global.AUTO_TIME: + DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class); + if (dpm != null && dpm.getAutoTimeRequired() + && "0".equals(value)) { + return true; + } else if (callingUid == Process.SYSTEM_UID) { + return false; + } + restriction = UserManager.DISALLOW_CONFIG_DATE_TIME; + break; + + case android.provider.Settings.Global.AUTO_TIME_ZONE: + if (callingUid == Process.SYSTEM_UID) { + return false; + } + restriction = UserManager.DISALLOW_CONFIG_DATE_TIME; + break; + + case android.provider.Settings.System.SCREEN_OFF_TIMEOUT: + if (callingUid == Process.SYSTEM_UID) { + return false; + } + restriction = UserManager.DISALLOW_CONFIG_SCREEN_TIMEOUT; + break; + + default: + if (setting.startsWith(Settings.Global.DATA_ROAMING)) { + if ("0".equals(value)) { + return false; + } + restriction = UserManager.DISALLOW_DATA_ROAMING; + break; + } + return false; + } + + if (checkAllUser) { + return hasUserRestrictionOnAnyUser(restriction); + } else { + return hasUserRestriction(restriction, userId); + } + } } diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java index 41570c48c474..462e8e374335 100644 --- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java +++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java @@ -439,8 +439,7 @@ public class UserRestrictionsUtils { /** * Apply each user restriction. * - *

See also {@link - * com.android.providers.settings.SettingsProvider#isGlobalOrSecureSettingRestrictedForUser}, + *

See also {@link android.os.UserManager#isSettingRestrictedForUser()}, * which should be in sync with this method. */ private static void applyUserRestriction(Context context, int userId, String key,