Loading Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -444,6 +444,7 @@ java_library { "services-platform-compat-config", "media-provider-platform-compat-config", "services-devicepolicy-platform-compat-config", "services-core-platform-compat-config", ], static_libs: [ // If MimeMap ever becomes its own APEX, then this dependency would need to be removed Loading services/core/Android.bp +6 −0 Original line number Diff line number Diff line Loading @@ -162,3 +162,9 @@ prebuilt_etc { name: "protolog.conf.json.gz", src: ":services.core.json.gz", } platform_compat_config { name: "services-core-platform-compat-config", src: ":services.core.unboosted", } services/core/java/com/android/server/pm/PackageManagerService.java +33 −18 Original line number Diff line number Diff line Loading @@ -2364,6 +2364,37 @@ public class PackageManagerService extends IPackageManager.Stub PackageManagerService m = new PackageManagerService(injector, factoryTest, onlyCore); t.traceEnd(); // "create package manager" injector.getCompatibility().registerListener(SELinuxMMAC.SELINUX_LATEST_CHANGES, packageName -> { synchronized (m.mInstallLock) { final PackageParser.Package pkg; final SharedUserSetting sharedUser; synchronized (m.mLock) { PackageSetting ps = m.mSettings.getPackageLPr(packageName); if (ps == null) { Slog.e(TAG, "Failed to find package setting " + packageName); return; } pkg = ps.pkg; sharedUser = ps.sharedUser; } if (pkg == null) { Slog.e(TAG, "Failed to find package " + packageName); return; } final String newSeInfo = SELinuxMMAC.getSeInfo(pkg, sharedUser, m.mInjector.getCompatibility()); if (!newSeInfo.equals(pkg.applicationInfo.seInfo)) { Slog.i(TAG, "Updating seInfo for package " + packageName + " from: " + pkg.applicationInfo.seInfo + " to: " + newSeInfo); pkg.applicationInfo.seInfo = newSeInfo; m.prepareAppDataAfterInstallLIF(pkg); } } }); m.installWhitelistedSystemPackages(); ServiceManager.addService("package", m); final PackageManagerNative pmn = m.new PackageManagerNative(); Loading Loading @@ -10784,24 +10815,8 @@ public class PackageManagerService extends IPackageManager.Stub pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; } // Apps which share a sharedUserId must be placed in the same selinux domain. If this // package is the first app installed as this shared user, set seInfoTargetSdkVersion to its // targetSdkVersion. These are later adjusted in PackageManagerService's constructor to be // the lowest targetSdkVersion of all apps within the shared user, which corresponds to the // least restrictive selinux domain. // NOTE: As new packages are installed / updated, the shared user's seinfoTargetSdkVersion // will NOT be modified until next boot, even if a lower targetSdkVersion is used. This // ensures that all packages continue to run in the same selinux domain. final int targetSdkVersion = ((sharedUserSetting != null) && (sharedUserSetting.packages.size() != 0)) ? sharedUserSetting.seInfoTargetSdkVersion : pkg.applicationInfo.targetSdkVersion; // TODO(b/71593002): isPrivileged for sharedUser and appInfo should never be out of sync. // They currently can be if the sharedUser apps are signed with the platform key. final boolean isPrivileged = (sharedUserSetting != null) ? sharedUserSetting.isPrivileged() | pkg.isPrivileged() : pkg.isPrivileged(); pkg.applicationInfo.seInfo = SELinuxMMAC.getSeInfo(pkg, isPrivileged, targetSdkVersion); pkg.applicationInfo.seInfo = SELinuxMMAC.getSeInfo(pkg, sharedUserSetting, injector.getCompatibility()); pkg.applicationInfo.seInfoUser = SELinuxUtil.assignSeinfoUser(pkgSetting.readUserState( userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId)); services/core/java/com/android/server/pm/SELinuxMMAC.java +59 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.server.pm; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; import android.content.pm.PackageParser; import android.content.pm.PackageParser.SigningDetails; import android.content.pm.Signature; Loading @@ -23,6 +25,8 @@ import android.os.Environment; import android.util.Slog; import android.util.Xml; import com.android.server.compat.PlatformCompat; import libcore.io.IoUtils; import org.xmlpull.v1.XmlPullParser; Loading Loading @@ -72,6 +76,19 @@ public final class SELinuxMMAC { // Append targetSdkVersion=n to existing seinfo label where n is the app's targetSdkVersion private static final String TARGETSDKVERSION_STR = ":targetSdkVersion="; /** * This change gates apps access to untrusted_app_R-targetSDk SELinux domain. Allows opt-in * to R targetSdkVersion enforced changes without changing target SDK. Turning this change * off for an app targeting R is a no-op. * * <p>Has no effect for apps using shared user id. * * TODO(b/143539591): Update description with relevant SELINUX changes this opts in to. */ @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.Q) @ChangeId static final long SELINUX_LATEST_CHANGES = 143539591L; // Only initialize sMacPermissions once. static { // Platform mac permissions. Loading Loading @@ -319,6 +336,48 @@ public final class SELinuxMMAC { } } private static int getTargetSdkVersionForSeInfo(PackageParser.Package pkg, SharedUserSetting sharedUserSetting, PlatformCompat compatibility) { // Apps which share a sharedUserId must be placed in the same selinux domain. If this // package is the first app installed as this shared user, set seInfoTargetSdkVersion to its // targetSdkVersion. These are later adjusted in PackageManagerService's constructor to be // the lowest targetSdkVersion of all apps within the shared user, which corresponds to the // least restrictive selinux domain. // NOTE: As new packages are installed / updated, the shared user's seinfoTargetSdkVersion // will NOT be modified until next boot, even if a lower targetSdkVersion is used. This // ensures that all packages continue to run in the same selinux domain. if ((sharedUserSetting != null) && (sharedUserSetting.packages.size() != 0)) { return sharedUserSetting.seInfoTargetSdkVersion; } if (compatibility.isChangeEnabled(SELINUX_LATEST_CHANGES, pkg.applicationInfo)) { return android.os.Build.VERSION_CODES.R; } return pkg.applicationInfo.targetSdkVersion; } /** * Selects a security label to a package based on input parameters and the seinfo tag taken * from a matched policy. All signature based policy stanzas are consulted and, if no match * is found, the default seinfo label of 'default' is used. The security label is attached to * the ApplicationInfo instance of the package. * * @param pkg object representing the package to be labeled. * @param sharedUserSetting if the app shares a sharedUserId, then this has the shared setting. * @param compatibility the PlatformCompat service to ask about state of compat changes. * @return String representing the resulting seinfo. */ public static String getSeInfo(PackageParser.Package pkg, SharedUserSetting sharedUserSetting, PlatformCompat compatibility) { final int targetSdkVersion = getTargetSdkVersionForSeInfo(pkg, sharedUserSetting, compatibility); // TODO(b/71593002): isPrivileged for sharedUser and appInfo should never be out of sync. // They currently can be if the sharedUser apps are signed with the platform key. final boolean isPrivileged = (sharedUserSetting != null) ? sharedUserSetting.isPrivileged() | pkg.isPrivileged() : pkg.isPrivileged(); return getSeInfo(pkg, isPrivileged, targetSdkVersion); } /** * Selects a security label to a package based on input parameters and the seinfo tag taken * from a matched policy. All signature based policy stanzas are consulted and, if no match Loading services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java 0 → 100644 +80 −0 Original line number Diff line number Diff line /* * 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 com.android.server.pm; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; import static org.mockito.Mockito.when; import android.content.pm.PackageParser; import android.platform.test.annotations.Presubmit; import com.android.server.compat.PlatformCompat; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; /** * {@link SELinuxMMAC} tests. */ @RunWith(MockitoJUnitRunner.class) @Presubmit public class SELinuxMMACTest { private static final String PACKAGE_NAME = "my.package"; private static final int OPT_IN_VERSION = android.os.Build.VERSION_CODES.R; @Mock PlatformCompat mMockCompatibility; PackageParser.Package mPkg; @Before public void setUp() { mPkg = new PackageParser.Package(PACKAGE_NAME); mPkg.applicationInfo.targetSdkVersion = 28; } @Test public void getSeInfoOptInToLatest() { when(mMockCompatibility.isChangeEnabled(SELinuxMMAC.SELINUX_LATEST_CHANGES, mPkg.applicationInfo)).thenReturn(true); assertThat(SELinuxMMAC.getSeInfo(mPkg, null, mMockCompatibility), is("default:targetSdkVersion=" + OPT_IN_VERSION)); } @Test public void getSeInfoNoOptIn() { when(mMockCompatibility.isChangeEnabled(SELinuxMMAC.SELINUX_LATEST_CHANGES, mPkg.applicationInfo)).thenReturn(false); assertThat(SELinuxMMAC.getSeInfo(mPkg, null, mMockCompatibility), is("default:targetSdkVersion=28")); } @Test public void getSeInfoNoOptInButAlreadyR() { mPkg.applicationInfo.targetSdkVersion = OPT_IN_VERSION; when(mMockCompatibility.isChangeEnabled(SELinuxMMAC.SELINUX_LATEST_CHANGES, mPkg.applicationInfo)).thenReturn(false); assertThat(SELinuxMMAC.getSeInfo(mPkg, null, mMockCompatibility), is("default:targetSdkVersion=" + OPT_IN_VERSION)); } } Loading
Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -444,6 +444,7 @@ java_library { "services-platform-compat-config", "media-provider-platform-compat-config", "services-devicepolicy-platform-compat-config", "services-core-platform-compat-config", ], static_libs: [ // If MimeMap ever becomes its own APEX, then this dependency would need to be removed Loading
services/core/Android.bp +6 −0 Original line number Diff line number Diff line Loading @@ -162,3 +162,9 @@ prebuilt_etc { name: "protolog.conf.json.gz", src: ":services.core.json.gz", } platform_compat_config { name: "services-core-platform-compat-config", src: ":services.core.unboosted", }
services/core/java/com/android/server/pm/PackageManagerService.java +33 −18 Original line number Diff line number Diff line Loading @@ -2364,6 +2364,37 @@ public class PackageManagerService extends IPackageManager.Stub PackageManagerService m = new PackageManagerService(injector, factoryTest, onlyCore); t.traceEnd(); // "create package manager" injector.getCompatibility().registerListener(SELinuxMMAC.SELINUX_LATEST_CHANGES, packageName -> { synchronized (m.mInstallLock) { final PackageParser.Package pkg; final SharedUserSetting sharedUser; synchronized (m.mLock) { PackageSetting ps = m.mSettings.getPackageLPr(packageName); if (ps == null) { Slog.e(TAG, "Failed to find package setting " + packageName); return; } pkg = ps.pkg; sharedUser = ps.sharedUser; } if (pkg == null) { Slog.e(TAG, "Failed to find package " + packageName); return; } final String newSeInfo = SELinuxMMAC.getSeInfo(pkg, sharedUser, m.mInjector.getCompatibility()); if (!newSeInfo.equals(pkg.applicationInfo.seInfo)) { Slog.i(TAG, "Updating seInfo for package " + packageName + " from: " + pkg.applicationInfo.seInfo + " to: " + newSeInfo); pkg.applicationInfo.seInfo = newSeInfo; m.prepareAppDataAfterInstallLIF(pkg); } } }); m.installWhitelistedSystemPackages(); ServiceManager.addService("package", m); final PackageManagerNative pmn = m.new PackageManagerNative(); Loading Loading @@ -10784,24 +10815,8 @@ public class PackageManagerService extends IPackageManager.Stub pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; } // Apps which share a sharedUserId must be placed in the same selinux domain. If this // package is the first app installed as this shared user, set seInfoTargetSdkVersion to its // targetSdkVersion. These are later adjusted in PackageManagerService's constructor to be // the lowest targetSdkVersion of all apps within the shared user, which corresponds to the // least restrictive selinux domain. // NOTE: As new packages are installed / updated, the shared user's seinfoTargetSdkVersion // will NOT be modified until next boot, even if a lower targetSdkVersion is used. This // ensures that all packages continue to run in the same selinux domain. final int targetSdkVersion = ((sharedUserSetting != null) && (sharedUserSetting.packages.size() != 0)) ? sharedUserSetting.seInfoTargetSdkVersion : pkg.applicationInfo.targetSdkVersion; // TODO(b/71593002): isPrivileged for sharedUser and appInfo should never be out of sync. // They currently can be if the sharedUser apps are signed with the platform key. final boolean isPrivileged = (sharedUserSetting != null) ? sharedUserSetting.isPrivileged() | pkg.isPrivileged() : pkg.isPrivileged(); pkg.applicationInfo.seInfo = SELinuxMMAC.getSeInfo(pkg, isPrivileged, targetSdkVersion); pkg.applicationInfo.seInfo = SELinuxMMAC.getSeInfo(pkg, sharedUserSetting, injector.getCompatibility()); pkg.applicationInfo.seInfoUser = SELinuxUtil.assignSeinfoUser(pkgSetting.readUserState( userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId));
services/core/java/com/android/server/pm/SELinuxMMAC.java +59 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.server.pm; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; import android.content.pm.PackageParser; import android.content.pm.PackageParser.SigningDetails; import android.content.pm.Signature; Loading @@ -23,6 +25,8 @@ import android.os.Environment; import android.util.Slog; import android.util.Xml; import com.android.server.compat.PlatformCompat; import libcore.io.IoUtils; import org.xmlpull.v1.XmlPullParser; Loading Loading @@ -72,6 +76,19 @@ public final class SELinuxMMAC { // Append targetSdkVersion=n to existing seinfo label where n is the app's targetSdkVersion private static final String TARGETSDKVERSION_STR = ":targetSdkVersion="; /** * This change gates apps access to untrusted_app_R-targetSDk SELinux domain. Allows opt-in * to R targetSdkVersion enforced changes without changing target SDK. Turning this change * off for an app targeting R is a no-op. * * <p>Has no effect for apps using shared user id. * * TODO(b/143539591): Update description with relevant SELINUX changes this opts in to. */ @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.Q) @ChangeId static final long SELINUX_LATEST_CHANGES = 143539591L; // Only initialize sMacPermissions once. static { // Platform mac permissions. Loading Loading @@ -319,6 +336,48 @@ public final class SELinuxMMAC { } } private static int getTargetSdkVersionForSeInfo(PackageParser.Package pkg, SharedUserSetting sharedUserSetting, PlatformCompat compatibility) { // Apps which share a sharedUserId must be placed in the same selinux domain. If this // package is the first app installed as this shared user, set seInfoTargetSdkVersion to its // targetSdkVersion. These are later adjusted in PackageManagerService's constructor to be // the lowest targetSdkVersion of all apps within the shared user, which corresponds to the // least restrictive selinux domain. // NOTE: As new packages are installed / updated, the shared user's seinfoTargetSdkVersion // will NOT be modified until next boot, even if a lower targetSdkVersion is used. This // ensures that all packages continue to run in the same selinux domain. if ((sharedUserSetting != null) && (sharedUserSetting.packages.size() != 0)) { return sharedUserSetting.seInfoTargetSdkVersion; } if (compatibility.isChangeEnabled(SELINUX_LATEST_CHANGES, pkg.applicationInfo)) { return android.os.Build.VERSION_CODES.R; } return pkg.applicationInfo.targetSdkVersion; } /** * Selects a security label to a package based on input parameters and the seinfo tag taken * from a matched policy. All signature based policy stanzas are consulted and, if no match * is found, the default seinfo label of 'default' is used. The security label is attached to * the ApplicationInfo instance of the package. * * @param pkg object representing the package to be labeled. * @param sharedUserSetting if the app shares a sharedUserId, then this has the shared setting. * @param compatibility the PlatformCompat service to ask about state of compat changes. * @return String representing the resulting seinfo. */ public static String getSeInfo(PackageParser.Package pkg, SharedUserSetting sharedUserSetting, PlatformCompat compatibility) { final int targetSdkVersion = getTargetSdkVersionForSeInfo(pkg, sharedUserSetting, compatibility); // TODO(b/71593002): isPrivileged for sharedUser and appInfo should never be out of sync. // They currently can be if the sharedUser apps are signed with the platform key. final boolean isPrivileged = (sharedUserSetting != null) ? sharedUserSetting.isPrivileged() | pkg.isPrivileged() : pkg.isPrivileged(); return getSeInfo(pkg, isPrivileged, targetSdkVersion); } /** * Selects a security label to a package based on input parameters and the seinfo tag taken * from a matched policy. All signature based policy stanzas are consulted and, if no match Loading
services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java 0 → 100644 +80 −0 Original line number Diff line number Diff line /* * 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 com.android.server.pm; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; import static org.mockito.Mockito.when; import android.content.pm.PackageParser; import android.platform.test.annotations.Presubmit; import com.android.server.compat.PlatformCompat; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; /** * {@link SELinuxMMAC} tests. */ @RunWith(MockitoJUnitRunner.class) @Presubmit public class SELinuxMMACTest { private static final String PACKAGE_NAME = "my.package"; private static final int OPT_IN_VERSION = android.os.Build.VERSION_CODES.R; @Mock PlatformCompat mMockCompatibility; PackageParser.Package mPkg; @Before public void setUp() { mPkg = new PackageParser.Package(PACKAGE_NAME); mPkg.applicationInfo.targetSdkVersion = 28; } @Test public void getSeInfoOptInToLatest() { when(mMockCompatibility.isChangeEnabled(SELinuxMMAC.SELINUX_LATEST_CHANGES, mPkg.applicationInfo)).thenReturn(true); assertThat(SELinuxMMAC.getSeInfo(mPkg, null, mMockCompatibility), is("default:targetSdkVersion=" + OPT_IN_VERSION)); } @Test public void getSeInfoNoOptIn() { when(mMockCompatibility.isChangeEnabled(SELinuxMMAC.SELINUX_LATEST_CHANGES, mPkg.applicationInfo)).thenReturn(false); assertThat(SELinuxMMAC.getSeInfo(mPkg, null, mMockCompatibility), is("default:targetSdkVersion=28")); } @Test public void getSeInfoNoOptInButAlreadyR() { mPkg.applicationInfo.targetSdkVersion = OPT_IN_VERSION; when(mMockCompatibility.isChangeEnabled(SELinuxMMAC.SELINUX_LATEST_CHANGES, mPkg.applicationInfo)).thenReturn(false); assertThat(SELinuxMMAC.getSeInfo(mPkg, null, mMockCompatibility), is("default:targetSdkVersion=" + OPT_IN_VERSION)); } }