diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2024-01-23 10:42:08 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2024-01-23 10:42:08 +0000 |
commit | b64cf12f491705c44d70006e4f0bec6ca279953a (patch) | |
tree | aa70a8f5bb39a1c41e2f11937a4de86d6cdcdc98 | |
parent | f4c9f244d30b0941d4a33ae52e55eafd329e8162 (diff) | |
parent | d06ef9c908875cea6e0da8844ec041e840a8029c (diff) | |
download | base-android-platform-14.0.0_r5.tar.gz |
Merge cherrypicks of ['googleplex-android-review.googlesource.com/24112149', 'googleplex-android-review.googlesource.com/25529244', 'googleplex-android-review.googlesource.com/25263196', 'googleplex-android-review.googlesource.com/25557600', 'googleplex-android-review.googlesource.com/25647776', 'googleplex-android-review.googlesource.com/25715830', 'googleplex-android-review.googlesource.com/25787790'] into udc-platform-release.android-platform-14.0.0_r5
Change-Id: Ib3028f3df7246b2ed52ce67b9d9504a8acf6fd9e
8 files changed, 267 insertions, 16 deletions
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index 8e1e3d86146f..cba28f3a596f 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -189,6 +189,7 @@ public class AccountManagerService final MessageHandler mHandler; + private static final int TIMEOUT_DELAY_MS = 1000 * 60 * 15; // Messages that can be sent on mHandler private static final int MESSAGE_TIMED_OUT = 3; private static final int MESSAGE_COPY_SHARED_ACCOUNT = 4; @@ -4903,6 +4904,7 @@ public class AccountManagerService synchronized (mSessions) { mSessions.put(toString(), this); } + scheduleTimeout(); if (response != null) { try { response.asBinder().linkToDeath(this, 0 /* flags */); @@ -5070,6 +5072,11 @@ public class AccountManagerService } } + private void scheduleTimeout() { + mHandler.sendMessageDelayed( + mHandler.obtainMessage(MESSAGE_TIMED_OUT, this), TIMEOUT_DELAY_MS); + } + public void cancelTimeout() { mHandler.removeMessages(MESSAGE_TIMED_OUT, this); } @@ -5107,6 +5114,9 @@ public class AccountManagerService public void onTimedOut() { IAccountManagerResponse response = getResponseAndClose(); + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.v(TAG, "Session.onTimedOut"); + } if (response != null) { try { response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java index 622cb6609630..d0304b43215e 100644 --- a/services/core/java/com/android/server/pm/InstallPackageHelper.java +++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java @@ -668,6 +668,9 @@ final class InstallPackageHelper { if (pkgSetting == null || pkgSetting.getPkg() == null) { return Pair.create(PackageManager.INSTALL_FAILED_INVALID_URI, intentSender); } + if (instantApp && (pkgSetting.isSystem() || pkgSetting.isUpdatedSystemApp())) { + return Pair.create(PackageManager.INSTALL_FAILED_INVALID_URI, intentSender); + } if (!snapshot.canViewInstantApps(callingUid, UserHandle.getUserId(callingUid))) { // only allow the existing package to be used if it's installed as a full // application for at least one user diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index a9115371413c..b99e66f68038 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -55,6 +55,7 @@ import android.content.pm.PackageItemInfo; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.content.pm.VersionedPackage; +import android.content.pm.parsing.FrameworkParsingPackageUtils; import android.graphics.Bitmap; import android.net.Uri; import android.os.Binder; @@ -665,17 +666,22 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements // App package name and label length is restricted so that really long strings aren't // written to disk. - if (params.appPackageName != null - && params.appPackageName.length() > SessionParams.MAX_PACKAGE_NAME_LENGTH) { + if (params.appPackageName != null && !isValidPackageName(params.appPackageName)) { params.appPackageName = null; } params.appLabel = TextUtils.trimToSize(params.appLabel, PackageItemInfo.MAX_SAFE_LABEL_LENGTH); - String requestedInstallerPackageName = (params.installerPackageName != null - && params.installerPackageName.length() < SessionParams.MAX_PACKAGE_NAME_LENGTH) - ? params.installerPackageName : installerPackageName; + // Validate installer package name. + if (params.installerPackageName != null && !isValidPackageName( + params.installerPackageName)) { + params.installerPackageName = null; + } + + var requestedInstallerPackageName = + params.installerPackageName != null ? params.installerPackageName + : installerPackageName; if (PackageManagerServiceUtils.isRootOrShell(callingUid) || PackageInstallerSession.isSystemDataLoaderInstallation(params) @@ -1085,6 +1091,19 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements return Integer.parseInt(sessionId); } + private static boolean isValidPackageName(@NonNull String packageName) { + if (packageName.length() > SessionParams.MAX_PACKAGE_NAME_LENGTH) { + return false; + } + // "android" is a valid package name + var errorMessage = FrameworkParsingPackageUtils.validateName( + packageName, /* requireSeparator= */ false, /* requireFilename */ true); + if (errorMessage != null) { + return false; + } + return true; + } + private File getTmpSessionDir(String volumeUuid) { return Environment.getDataAppDirectory(volumeUuid); } diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index b03fb31fbb1e..80e1c7e9697b 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -2667,7 +2667,8 @@ public class UserManagerService extends IUserManager.Stub { } } - private void setUserRestrictionInner(int userId, @NonNull String key, boolean value) { + @VisibleForTesting + void setUserRestrictionInner(int userId, @NonNull String key, boolean value) { if (!UserRestrictionsUtils.isValidRestriction(key)) { Slog.e(LOG_TAG, "Setting invalid restriction " + key); return; @@ -3704,7 +3705,8 @@ public class UserManagerService extends IUserManager.Stub { if (type == XmlPullParser.START_TAG) { final String name = parser.getName(); if (name.equals(TAG_USER)) { - UserData userData = readUserLP(parser.getAttributeInt(null, ATTR_ID)); + UserData userData = readUserLP(parser.getAttributeInt(null, ATTR_ID), + mUserVersion); if (userData != null) { synchronized (mUsersLock) { @@ -4277,11 +4279,11 @@ public class UserManagerService extends IUserManager.Stub { UserRestrictionsUtils.writeRestrictions(serializer, mDevicePolicyUserRestrictions.getRestrictions(UserHandle.USER_ALL), - TAG_DEVICE_POLICY_RESTRICTIONS); + TAG_DEVICE_POLICY_GLOBAL_RESTRICTIONS); UserRestrictionsUtils.writeRestrictions(serializer, mDevicePolicyUserRestrictions.getRestrictions(userInfo.id), - TAG_DEVICE_POLICY_RESTRICTIONS); + TAG_DEVICE_POLICY_LOCAL_RESTRICTIONS); } if (userData.account != null) { @@ -4385,7 +4387,7 @@ public class UserManagerService extends IUserManager.Stub { } @GuardedBy({"mPackagesLock"}) - private UserData readUserLP(int id) { + private UserData readUserLP(int id, int userVersion) { try (ResilientAtomicFile file = getUserFile(id)) { FileInputStream fis = null; try { @@ -4394,19 +4396,19 @@ public class UserManagerService extends IUserManager.Stub { Slog.e(LOG_TAG, "User info not found, returning null, user id: " + id); return null; } - return readUserLP(id, fis); + return readUserLP(id, fis, userVersion); } catch (Exception e) { // Remove corrupted file and retry. Slog.e(LOG_TAG, "Error reading user info, user id: " + id); file.failRead(fis, e); - return readUserLP(id); + return readUserLP(id, userVersion); } } } @GuardedBy({"mPackagesLock"}) @VisibleForTesting - UserData readUserLP(int id, InputStream is) throws IOException, + UserData readUserLP(int id, InputStream is, int userVersion) throws IOException, XmlPullParserException { int flags = 0; String userType = null; @@ -4499,7 +4501,17 @@ public class UserManagerService extends IUserManager.Stub { } else if (TAG_DEVICE_POLICY_RESTRICTIONS.equals(tag)) { legacyLocalRestrictions = UserRestrictionsUtils.readRestrictions(parser); } else if (TAG_DEVICE_POLICY_LOCAL_RESTRICTIONS.equals(tag)) { - localRestrictions = UserRestrictionsUtils.readRestrictions(parser); + if (userVersion < 10) { + // Prior to version 10, the local user restrictions were stored as sub tags + // grouped by the user id of the source user. The source is no longer stored + // on versions 10+ as this is now stored in the DevicePolicyEngine. + RestrictionsSet oldLocalRestrictions = + RestrictionsSet.readRestrictions( + parser, TAG_DEVICE_POLICY_LOCAL_RESTRICTIONS); + localRestrictions = oldLocalRestrictions.mergeAll(); + } else { + localRestrictions = UserRestrictionsUtils.readRestrictions(parser); + } } else if (TAG_DEVICE_POLICY_GLOBAL_RESTRICTIONS.equals(tag)) { globalRestrictions = UserRestrictionsUtils.readRestrictions(parser); } else if (TAG_ACCOUNT.equals(tag)) { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java index 9c1d765fe0f9..9f65a33185b5 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java @@ -30,6 +30,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AppGlobals; import android.app.BroadcastOptions; +import android.app.admin.BooleanPolicyValue; import android.app.admin.DevicePolicyIdentifiers; import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyState; @@ -133,6 +134,67 @@ final class DevicePolicyEngine { mEnforcingAdmins = new SparseArray<>(); } + private void maybeForceEnforcementRefreshLocked(@NonNull PolicyDefinition<?> policyDefinition) { + try { + if (shouldForceEnforcementRefresh(policyDefinition)) { + // This is okay because it's only true for user restrictions which are all <Boolean> + forceEnforcementRefreshLocked((PolicyDefinition<Boolean>) policyDefinition); + } + } catch (Throwable e) { + // Catch any possible exceptions just to be on the safe side + Log.e(TAG, "Exception throw during maybeForceEnforcementRefreshLocked", e); + } + } + + private boolean shouldForceEnforcementRefresh(@NonNull PolicyDefinition<?> policyDefinition) { + // These are all "not nullable" but for the purposes of maximum safety for a lightly tested + // change we check here + if (policyDefinition == null) { + return false; + } + PolicyKey policyKey = policyDefinition.getPolicyKey(); + if (policyKey == null) { + return false; + } + + if (policyKey instanceof UserRestrictionPolicyKey) { + // b/307481299 We must force all user restrictions to re-sync local + // + global on each set/clear + return true; + } + + return false; + } + + private void forceEnforcementRefreshLocked(PolicyDefinition<Boolean> policyDefinition) { + Binder.withCleanCallingIdentity(() -> { + // Sync global state + PolicyValue<Boolean> globalValue = new BooleanPolicyValue(false); + try { + PolicyState<Boolean> policyState = getGlobalPolicyStateLocked(policyDefinition); + globalValue = policyState.getCurrentResolvedPolicy(); + } catch (IllegalArgumentException e) { + // Expected for local-only policies + } + + enforcePolicy(policyDefinition, globalValue, UserHandle.USER_ALL); + + // Loop through each user and sync that user's state + for (UserInfo user : mUserManager.getUsers()) { + PolicyValue<Boolean> localValue = new BooleanPolicyValue(false); + try { + PolicyState<Boolean> localPolicyState = getLocalPolicyStateLocked( + policyDefinition, user.id); + localValue = localPolicyState.getCurrentResolvedPolicy(); + } catch (IllegalArgumentException e) { + // Expected for global-only policies + } + + enforcePolicy(policyDefinition, localValue, user.id); + } + }); + } + /** * Set the policy for the provided {@code policyDefinition} (see {@link PolicyDefinition}) and * {@code enforcingAdmin} to the provided {@code value}. @@ -174,6 +236,7 @@ final class DevicePolicyEngine { // No need to notify admins as no new policy is actually enforced, we're just filling in // the data structures. if (!skipEnforcePolicy) { + maybeForceEnforcementRefreshLocked(policyDefinition); if (policyChanged) { onLocalPolicyChangedLocked(policyDefinition, enforcingAdmin, userId); } @@ -262,6 +325,7 @@ final class DevicePolicyEngine { Objects.requireNonNull(enforcingAdmin); synchronized (mLock) { + maybeForceEnforcementRefreshLocked(policyDefinition); if (!hasLocalPolicyLocked(policyDefinition, userId)) { return; } @@ -425,6 +489,7 @@ final class DevicePolicyEngine { // No need to notify admins as no new policy is actually enforced, we're just filling in // the data structures. if (!skipEnforcePolicy) { + maybeForceEnforcementRefreshLocked(policyDefinition); if (policyChanged) { onGlobalPolicyChangedLocked(policyDefinition, enforcingAdmin); } @@ -474,6 +539,7 @@ final class DevicePolicyEngine { PolicyState<V> policyState = getGlobalPolicyStateLocked(policyDefinition); boolean policyChanged = policyState.removePolicy(enforcingAdmin); + maybeForceEnforcementRefreshLocked(policyDefinition); if (policyChanged) { onGlobalPolicyChangedLocked(policyDefinition, enforcingAdmin); } diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java index 35b9bc3b1e06..4a8d73d23904 100644 --- a/services/print/java/com/android/server/print/PrintManagerService.java +++ b/services/print/java/com/android/server/print/PrintManagerService.java @@ -254,12 +254,45 @@ public final class PrintManagerService extends SystemService { } final long identity = Binder.clearCallingIdentity(); try { - return userState.getCustomPrinterIcon(printerId); + Icon icon = userState.getCustomPrinterIcon(printerId); + return validateIconUserBoundary(icon); } finally { Binder.restoreCallingIdentity(identity); } } + /** + * Validates the custom printer icon to see if it's not in the calling user space. + * If the condition is not met, return null. Otherwise, return the original icon. + * + * @param icon + * @return icon (validated) + */ + private Icon validateIconUserBoundary(Icon icon) { + // Refer to Icon#getUriString for context. The URI string is invalid for icons of + // incompatible types. + if (icon != null && (icon.getType() == Icon.TYPE_URI + || icon.getType() == Icon.TYPE_URI_ADAPTIVE_BITMAP)) { + String encodedUser = icon.getUri().getEncodedUserInfo(); + + // If there is no encoded user, the URI is calling into the calling user space + if (encodedUser != null) { + int userId = Integer.parseInt(encodedUser); + // resolve encoded user + final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); + + synchronized (mLock) { + // Only the current group members can get the printer icons. + if (resolveCallingProfileParentLocked(resolvedUserId) + != getCurrentUserId()) { + return null; + } + } + } + } + return icon; + } + @Override public void cancelPrintJob(PrintJobId printJobId, int appId, int userId) { if (printJobId == null) { diff --git a/services/tests/servicestests/res/xml/user_100_v9.xml b/services/tests/servicestests/res/xml/user_100_v9.xml new file mode 100644 index 000000000000..03c08ed40828 --- /dev/null +++ b/services/tests/servicestests/res/xml/user_100_v9.xml @@ -0,0 +1,20 @@ +<user id="100" + serialNumber="0" + flags="3091" + type="android.os.usertype.full.SYSTEM" + created="0" + lastLoggedIn="0" + lastLoggedInFingerprint="0" + profileBadge="0"> + <restrictions no_oem_unlock="true" /> + <device_policy_local_restrictions> + <restrictions_user user_id="0"> + <restrictions no_camera="true" /> + </restrictions_user> + <restrictions_user user_id="100"> + <restrictions no_camera="true" /> + <restrictions no_install_unknown_sources="true" /> + </restrictions_user> + </device_policy_local_restrictions> + <ignorePrepareStorageErrors>false</ignorePrepareStorageErrors> +</user>
\ No newline at end of file diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java index 2273fcd22b38..429c58e768bf 100644 --- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java @@ -43,27 +43,33 @@ import android.annotation.UserIdInt; import android.app.PropertyInvalidatedCache; import android.content.pm.UserInfo; import android.content.pm.UserInfo.UserInfoFlag; +import android.content.res.Resources; import android.os.Looper; import android.os.Parcel; import android.os.UserHandle; import android.os.UserManager; import android.platform.test.annotations.Presubmit; import android.text.TextUtils; +import android.util.Xml; import androidx.test.InstrumentationRegistry; import androidx.test.filters.MediumTest; import androidx.test.runner.AndroidJUnit4; +import com.android.frameworks.servicestests.R; import com.android.server.LocalServices; import com.android.server.pm.UserManagerService.UserData; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlSerializer; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; +import java.nio.charset.StandardCharsets; import java.util.List; /** @@ -76,6 +82,7 @@ import java.util.List; @MediumTest public class UserManagerServiceUserInfoTest { private UserManagerService mUserManagerService; + private Resources mResources; @Before public void setup() { @@ -95,6 +102,8 @@ public class UserManagerServiceUserInfoTest { assertEquals("Multiple users so this test can't run.", 1, users.size()); assertEquals("Only user present isn't the system user.", UserHandle.USER_SYSTEM, users.get(0).id); + + mResources = InstrumentationRegistry.getTargetContext().getResources(); } @Test @@ -108,11 +117,51 @@ public class UserManagerServiceUserInfoTest { byte[] bytes = baos.toByteArray(); UserData read = mUserManagerService.readUserLP( - data.info.id, new ByteArrayInputStream(bytes)); + data.info.id, new ByteArrayInputStream(bytes), 0); assertUserInfoEquals(data.info, read.info, /* parcelCopy= */ false); } + /** Tests that device policy restrictions are written/read properly. */ + @Test + public void testWriteReadDevicePolicyUserRestrictions() throws Exception { + final String globalRestriction = UserManager.DISALLOW_FACTORY_RESET; + final String localRestriction = UserManager.DISALLOW_CONFIG_DATE_TIME; + + UserData data = new UserData(); + data.info = createUser(100, FLAG_FULL, "A type"); + + mUserManagerService.putUserInfo(data.info); + + // Set a global and user restriction so they get written out to the user file. + setUserRestrictions(data.info.id, globalRestriction, localRestriction, true); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(baos); + mUserManagerService.writeUserLP(data, out); + byte[] bytes = baos.toByteArray(); + + // Clear the restrictions to see if they are properly read in from the user file. + setUserRestrictions(data.info.id, globalRestriction, localRestriction, false); + + final int userVersion = 10; + //read the secondary and SYSTEM user file to fetch local/global device policy restrictions. + mUserManagerService.readUserLP(data.info.id, new ByteArrayInputStream(bytes), + userVersion); + + assertTrue(mUserManagerService.hasUserRestrictionOnAnyUser(globalRestriction)); + assertTrue(mUserManagerService.hasUserRestrictionOnAnyUser(localRestriction)); + } + + /** Sets a global and local restriction and verifies they were set properly **/ + private void setUserRestrictions(int id, String global, String local, boolean enabled) { + mUserManagerService.setUserRestrictionInner(UserHandle.USER_ALL, global, enabled); + assertEquals(mUserManagerService.hasUserRestrictionOnAnyUser(global), enabled); + + mUserManagerService.setUserRestrictionInner(id, local, enabled); + assertEquals(mUserManagerService.hasUserRestrictionOnAnyUser(local), enabled); + } + @Test public void testParcelUnparcelUserInfo() throws Exception { UserInfo info = createUser(); @@ -250,6 +299,45 @@ public class UserManagerServiceUserInfoTest { assertTrue(mUserManagerService.isUserOfType(106, USER_TYPE_FULL_DEMO)); } + /** Tests readUserLP upgrading from version 9 to 10+. */ + @Test + public void testUserRestrictionsUpgradeFromV9() throws Exception { + final String[] localRestrictions = new String[] { + UserManager.DISALLOW_CAMERA, + UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, + }; + + final int userId = 100; + UserData data = new UserData(); + data.info = createUser(userId, FLAG_FULL, "A type"); + + mUserManagerService.putUserInfo(data.info); + + for (String restriction : localRestrictions) { + assertFalse(mUserManagerService.hasBaseUserRestriction(restriction, userId)); + assertFalse(mUserManagerService.hasUserRestriction(restriction, userId)); + } + + // Convert the xml resource to the system storage xml format. + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream os = new DataOutputStream(baos); + XmlPullParser in = mResources.getXml(R.xml.user_100_v9); + XmlSerializer out = Xml.newBinarySerializer(); + out.setOutput(os, StandardCharsets.UTF_8.name()); + Xml.copy(in, out); + byte[] userBytes = baos.toByteArray(); + baos.reset(); + + final int userVersion = 9; + mUserManagerService.readUserLP(data.info.id, new ByteArrayInputStream(userBytes), + userVersion); + + for (String restriction : localRestrictions) { + assertFalse(mUserManagerService.hasBaseUserRestriction(restriction, userId)); + assertTrue(mUserManagerService.hasUserRestriction(restriction, userId)); + } + } + /** Creates a UserInfo with the given flags and userType. */ private UserInfo createUser(@UserIdInt int userId, @UserInfoFlag int flags, String userType) { return new UserInfo(userId, "A Name", "A path", flags, userType); |