diff options
| author | 2019-10-11 17:00:23 -0700 | |
|---|---|---|
| committer | 2019-10-17 15:23:23 -0700 | |
| commit | 65fb2e4e40329856b07fb84e35e0ffb61e53f419 (patch) | |
| tree | 2df3b9fd41094d1b6b88c5fe8d0d76c275856edf | |
| parent | ad6c7044e5fc523416c80307e68f748f78c90d0b (diff) | |
Move UserManagerInternal into services.jar
Because SettingsProvider needs to call through the IUserManager
interface there is now a method to provide restricted-access information
via that route. It has the same protection as the implicit local
service call surface that was previously used: only system-uid callers
can invoke it.
Bug: 140833849
Test: system boots & runs normally
Change-Id: I05823ca57240ab10feb382c45590541212e406c1
| -rw-r--r-- | core/java/android/os/IUserManager.aidl | 3 | ||||
| -rw-r--r-- | core/java/android/os/IUserRestrictionsListener.aidl | 26 | ||||
| -rw-r--r-- | core/java/android/os/UserManager.java | 32 | ||||
| -rw-r--r-- | packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java | 187 | ||||
| -rw-r--r-- | services/core/java/android/os/UserManagerInternal.java (renamed from core/java/android/os/UserManagerInternal.java) | 2 | ||||
| -rw-r--r-- | services/core/java/com/android/server/pm/UserManagerService.java | 33 |
6 files changed, 192 insertions, 91 deletions
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl index c30491a3965c..e8cc73f43a3d 100644 --- a/core/java/android/os/IUserManager.aidl +++ b/core/java/android/os/IUserManager.aidl @@ -18,6 +18,7 @@ package android.os; import android.os.Bundle; +import android.os.IUserRestrictionsListener; import android.os.PersistableBundle; import android.os.UserManager; import android.content.pm.UserInfo; @@ -75,6 +76,8 @@ interface IUserManager { boolean hasBaseUserRestriction(String restrictionKey, int userHandle); boolean hasUserRestriction(in String restrictionKey, int userHandle); boolean hasUserRestrictionOnAnyUser(in String restrictionKey); + boolean isSettingRestrictedForUser(in String setting, int userId, in String value, int callingUid); + void addUserRestrictionsListener(IUserRestrictionsListener listener); void setUserRestriction(String key, boolean value, int userHandle); void setApplicationRestrictions(in String packageName, in Bundle restrictions, int userHandle); diff --git a/core/java/android/os/IUserRestrictionsListener.aidl b/core/java/android/os/IUserRestrictionsListener.aidl new file mode 100644 index 000000000000..e7d027ff6ac7 --- /dev/null +++ b/core/java/android/os/IUserRestrictionsListener.aidl @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +import android.os.Bundle; + +/** + * @hide + */ +oneway interface IUserRestrictionsListener { + void onUserRestrictionsChanged(int userId, in Bundle newRestrictions, in Bundle prevRestrictions); +} diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 3296f11298c8..c6b63cadd7d1 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -1986,6 +1986,38 @@ public class UserManager { } /** + * @hide + * + * Checks whether changing the given setting to the given value is prohibited + * by the corresponding user restriction in the given user. + * + * May only be called by the OS itself. + * + * @return {@code true} if the change is prohibited, {@code false} if the change is allowed. + */ + public boolean isSettingRestrictedForUser(String setting, @UserIdInt int userId, + String value, int callingUid) { + try { + return mService.isSettingRestrictedForUser(setting, userId, value, callingUid); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + /** + * @hide + * Register a binder callback for user restrictions changes. + * May only be called by the OS itself. + */ + public void addUserRestrictionsListener(final IUserRestrictionsListener listener) { + try { + mService.addUserRestrictionsListener(listener); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + /** * Return the serial number for a user. This is a device-unique * number assigned to that user; if the user is deleted and then a new * user created, the new users will not be given the same serial number. diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index a9c466ed7e9f..a0410024f2e9 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -56,6 +56,7 @@ import android.os.DropBoxManager; import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; +import android.os.IUserRestrictionsListener; import android.os.Looper; import android.os.Message; import android.os.ParcelFileDescriptor; @@ -65,7 +66,6 @@ import android.os.SELinux; import android.os.ServiceManager; import android.os.UserHandle; import android.os.UserManager; -import android.os.UserManagerInternal; import android.provider.DeviceConfig; import android.provider.Settings; import android.provider.Settings.Global; @@ -84,7 +84,6 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.content.PackageMonitor; import com.android.internal.os.BackgroundThread; import com.android.providers.settings.SettingsState.Setting; -import com.android.server.LocalServices; import com.android.server.SystemConfig; import com.google.android.collect.Sets; @@ -286,8 +285,6 @@ public class SettingsProvider extends ContentProvider { // We have to call in the user manager with no lock held, private volatile UserManager mUserManager; - private UserManagerInternal mUserManagerInternal; - // We have to call in the package manager with no lock held, private volatile IPackageManager mPackageManager; @@ -317,7 +314,6 @@ public class SettingsProvider extends ContentProvider { synchronized (mLock) { mUserManager = UserManager.get(getContext()); - mUserManagerInternal = LocalServices.getService(UserManagerInternal.class); mPackageManager = AppGlobals.getPackageManager(); mHandlerThread = new HandlerThread(LOG_TAG, Process.THREAD_PRIORITY_BACKGROUND); @@ -902,95 +898,100 @@ public class SettingsProvider extends ContentProvider { // TODO: The current design of settings looking different based on user restrictions // should be reworked to keep them separate and system code should check the setting // first followed by checking the user restriction before performing an operation. - UserManagerInternal userManager = LocalServices.getService(UserManagerInternal.class); - userManager.addUserRestrictionsListener((int userId, Bundle newRestrictions, - Bundle prevRestrictions) -> { - Set<String> changedRestrictions = getRestrictionDiff(prevRestrictions, newRestrictions); - // We are changing the settings affected by restrictions to their current - // value with a forced update to ensure that all cross profile dependencies - // are taken into account. Also make sure the settings update to.. the same - // value passes the security checks, so clear binder calling id. - if (changedRestrictions.contains(UserManager.DISALLOW_SHARE_LOCATION)) { - final long identity = Binder.clearCallingIdentity(); - try { - synchronized (mLock) { - Setting setting = getSecureSetting( - Settings.Secure.LOCATION_MODE, userId); - updateSecureSetting(Settings.Secure.LOCATION_MODE, - setting != null ? setting.getValue() : null, null, - true, userId, true); - setting = getSecureSetting( - Settings.Secure.LOCATION_PROVIDERS_ALLOWED, userId); - updateSecureSetting(Settings.Secure.LOCATION_PROVIDERS_ALLOWED, - setting != null ? setting.getValue() : null, null, - true, userId, true); + IUserRestrictionsListener listener = new IUserRestrictionsListener.Stub() { + @Override + public void onUserRestrictionsChanged(int userId, + Bundle newRestrictions, Bundle prevRestrictions) { + Set<String> changedRestrictions = + getRestrictionDiff(prevRestrictions, newRestrictions); + // We are changing the settings affected by restrictions to their current + // value with a forced update to ensure that all cross profile dependencies + // are taken into account. Also make sure the settings update to.. the same + // value passes the security checks, so clear binder calling id. + if (changedRestrictions.contains(UserManager.DISALLOW_SHARE_LOCATION)) { + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + Setting setting = getSecureSetting( + Settings.Secure.LOCATION_MODE, userId); + updateSecureSetting(Settings.Secure.LOCATION_MODE, + setting != null ? setting.getValue() : null, null, + true, userId, true); + setting = getSecureSetting( + Settings.Secure.LOCATION_PROVIDERS_ALLOWED, userId); + updateSecureSetting(Settings.Secure.LOCATION_PROVIDERS_ALLOWED, + setting != null ? setting.getValue() : null, null, + true, userId, true); + } + } finally { + Binder.restoreCallingIdentity(identity); } - } finally { - Binder.restoreCallingIdentity(identity); } - } - if (changedRestrictions.contains(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES) - || changedRestrictions.contains( - UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY)) { - final long identity = Binder.clearCallingIdentity(); - try { - synchronized (mLock) { - Setting setting = getGlobalSetting(Settings.Global.INSTALL_NON_MARKET_APPS); - String value = setting != null ? setting.getValue() : null; - updateGlobalSetting(Settings.Global.INSTALL_NON_MARKET_APPS, - value, null, true, userId, true); + if (changedRestrictions.contains(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES) + || changedRestrictions.contains( + UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY)) { + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + Setting setting = getGlobalSetting( + Settings.Global.INSTALL_NON_MARKET_APPS); + String value = setting != null ? setting.getValue() : null; + updateGlobalSetting(Settings.Global.INSTALL_NON_MARKET_APPS, + value, null, true, userId, true); + } + } finally { + Binder.restoreCallingIdentity(identity); } - } finally { - Binder.restoreCallingIdentity(identity); } - } - if (changedRestrictions.contains(UserManager.DISALLOW_DEBUGGING_FEATURES)) { - final long identity = Binder.clearCallingIdentity(); - try { - synchronized (mLock) { - Setting setting = getGlobalSetting(Settings.Global.ADB_ENABLED); - String value = setting != null ? setting.getValue() : null; - updateGlobalSetting(Settings.Global.ADB_ENABLED, - value, null, true, userId, true); + if (changedRestrictions.contains(UserManager.DISALLOW_DEBUGGING_FEATURES)) { + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + Setting setting = getGlobalSetting(Settings.Global.ADB_ENABLED); + String value = setting != null ? setting.getValue() : null; + updateGlobalSetting(Settings.Global.ADB_ENABLED, + value, null, true, userId, true); + } + } finally { + Binder.restoreCallingIdentity(identity); } - } finally { - Binder.restoreCallingIdentity(identity); } - } - if (changedRestrictions.contains(UserManager.ENSURE_VERIFY_APPS)) { - final long identity = Binder.clearCallingIdentity(); - try { - synchronized (mLock) { - Setting enable = getGlobalSetting( - Settings.Global.PACKAGE_VERIFIER_ENABLE); - String enableValue = enable != null ? enable.getValue() : null; - updateGlobalSetting(Settings.Global.PACKAGE_VERIFIER_ENABLE, - enableValue, null, true, userId, true); - Setting include = getGlobalSetting( - Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB); - String includeValue = include != null ? include.getValue() : null; - updateGlobalSetting(Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, - includeValue, null, true, userId, true); + if (changedRestrictions.contains(UserManager.ENSURE_VERIFY_APPS)) { + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + Setting enable = getGlobalSetting( + Settings.Global.PACKAGE_VERIFIER_ENABLE); + String enableValue = enable != null ? enable.getValue() : null; + updateGlobalSetting(Settings.Global.PACKAGE_VERIFIER_ENABLE, + enableValue, null, true, userId, true); + Setting include = getGlobalSetting( + Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB); + String includeValue = include != null ? include.getValue() : null; + updateGlobalSetting(Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, + includeValue, null, true, userId, true); + } + } finally { + Binder.restoreCallingIdentity(identity); } - } finally { - Binder.restoreCallingIdentity(identity); } - } - if (changedRestrictions.contains(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)) { - final long identity = Binder.clearCallingIdentity(); - try { - synchronized (mLock) { - Setting setting = getGlobalSetting( - Settings.Global.PREFERRED_NETWORK_MODE); - String value = setting != null ? setting.getValue() : null; - updateGlobalSetting(Settings.Global.PREFERRED_NETWORK_MODE, - value, null, true, userId, true); + if (changedRestrictions.contains(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)) { + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + Setting setting = getGlobalSetting( + Settings.Global.PREFERRED_NETWORK_MODE); + String value = setting != null ? setting.getValue() : null; + updateGlobalSetting(Settings.Global.PREFERRED_NETWORK_MODE, + value, null, true, userId, true); + } + } finally { + Binder.restoreCallingIdentity(identity); } - } finally { - Binder.restoreCallingIdentity(identity); } } - }); + }; + mUserManager.addUserRestrictionsListener(listener); } private static Set<String> getRestrictionDiff(Bundle prevRestrictions, Bundle newRestrictions) { @@ -1185,6 +1186,17 @@ public class SettingsProvider extends ContentProvider { MUTATION_OPERATION_RESET, false, mode); } + private boolean isSettingRestrictedForUser(String name, int userId, + String value, int callerUid) { + final long oldId = Binder.clearCallingIdentity(); + try { + return (name != null + && mUserManager.isSettingRestrictedForUser(name, userId, value, callerUid)); + } finally { + Binder.restoreCallingIdentity(oldId); + } + } + private boolean mutateGlobalSetting(String name, String value, String tag, boolean makeDefault, int requestingUserId, int operation, boolean forceNotify, int mode) { @@ -1196,8 +1208,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 && mUserManagerInternal.isSettingRestrictedForUser( - name, callingUserId, value, Binder.getCallingUid())) { + if (isSettingRestrictedForUser(name, callingUserId, value, Binder.getCallingUid())) { return false; } @@ -1505,8 +1516,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 && mUserManagerInternal.isSettingRestrictedForUser( - name, callingUserId, value, Binder.getCallingUid())) { + if (isSettingRestrictedForUser(name, callingUserId, value, Binder.getCallingUid())) { return false; } @@ -1646,8 +1656,7 @@ public class SettingsProvider extends ContentProvider { // Resolve the userId on whose behalf the call is made. final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(runAsUserId); - if (name != null && mUserManagerInternal.isSettingRestrictedForUser( - name, callingUserId, value, Binder.getCallingUid())) { + if (isSettingRestrictedForUser(name, callingUserId, value, Binder.getCallingUid())) { return false; } diff --git a/core/java/android/os/UserManagerInternal.java b/services/core/java/android/os/UserManagerInternal.java index 59fb3d9fcdad..e5f8b49c3f0c 100644 --- a/core/java/android/os/UserManagerInternal.java +++ b/services/core/java/android/os/UserManagerInternal.java @@ -11,7 +11,7 @@ * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and - * limitations under the License + * limitations under the License. */ package android.os; diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 95baa01923f5..8814f6dae7c3 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -54,6 +54,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.IProgressListener; import android.os.IUserManager; +import android.os.IUserRestrictionsListener; import android.os.Message; import android.os.ParcelFileDescriptor; import android.os.Parcelable; @@ -1606,6 +1607,36 @@ public class UserManagerService extends IUserManager.Stub { return false; } + @Override + public boolean isSettingRestrictedForUser(String setting, @UserIdInt int userId, + String value, int callingUid) { + if (Binder.getCallingUid() != Process.SYSTEM_UID) { + throw new SecurityException("Non-system caller"); + } + return UserRestrictionsUtils.isSettingRestrictedForUser(mContext, setting, userId, + value, callingUid); + } + + @Override + public void addUserRestrictionsListener(final IUserRestrictionsListener listener) { + if (Binder.getCallingUid() != Process.SYSTEM_UID) { + throw new SecurityException("Non-system caller"); + } + + // NOTE: unregistering not supported; only client is the settings provider, + // which installs a single static permanent listener. If that listener goes + // bad it implies the whole system process is going to crash. + mLocalService.addUserRestrictionsListener( + (int userId, Bundle newRestrict, Bundle prevRestrict) -> { + try { + listener.onUserRestrictionsChanged(userId, newRestrict, prevRestrict); + } catch (RemoteException re) { + Slog.e("IUserRestrictionsListener", + "Unable to invoke listener: " + re.getMessage()); + } + }); + } + /** * @hide * @@ -4410,7 +4441,7 @@ public class UserManagerService extends IUserManager.Stub { @Override public boolean isSettingRestrictedForUser(String setting, @UserIdInt int userId, String value, int callingUid) { - return UserRestrictionsUtils.isSettingRestrictedForUser(mContext, setting, userId, + return UserManagerService.this.isSettingRestrictedForUser(setting, userId, value, callingUid); } |