summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author atrost <atrost@google.com> 2019-11-29 11:27:27 +0000
committer atrost <atrost@google.com> 2019-12-03 15:01:03 +0000
commitc3c2e4de2d24e17cc05482abccb2d63abd811d75 (patch)
tree8941ef95b8a8dd7d2aca9044ef443db35407a741
parent5605a0fe1190ceb9d7070b59f3b4e2d3a730808c (diff)
Add a compat change to opt-in to latest SELinux domain.
Refactor getSeInfo into a method, if the app doesn't share a sharedUserId, and the change is enabled use targetSdkVersion R (1000) for the seInfo domain. Add a listener to the compat change that checks if seInfo has changed (as a result of enabling/disabling the change), and if it did updates it, and calls prepareAppDataAfterInstallLIF to make sure the data is correctly labeled. The listener will be called when an override is introduced or removed for the change. Bug: 143539591 Test: atest com.android.server.pm.SELinuxMMAXTest Test: Install facebook (target SDK 28), login +download a photo, turn on the change, open facebook, download another photo, disable change, open facebook again, download another photo. Everything works as expected, photos are accessible, profile is setup. Change-Id: If5ecf490e781db13d84656b36d0740a00ee124b5
-rw-r--r--Android.bp1
-rw-r--r--services/core/Android.bp6
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java51
-rw-r--r--services/core/java/com/android/server/pm/SELinuxMMAC.java59
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java80
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ScanTests.java5
6 files changed, 184 insertions, 18 deletions
diff --git a/Android.bp b/Android.bp
index c1f6860980de..3c08056b7db9 100644
--- a/Android.bp
+++ b/Android.bp
@@ -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
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 2eb2f334981c..203bc61c2022 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -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",
+}
+
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 8439a0de3a06..4e0e4ffb3a13 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -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();
@@ -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));
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index b464988d5871..d20f20ffec46 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -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;
@@ -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;
@@ -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.
@@ -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
diff --git a/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java b/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java
new file mode 100644
index 000000000000..4b7dd36a382a
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java
@@ -0,0 +1,80 @@
+/*
+ * 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));
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
index 3ea3b3cff7e8..74ef034082a0 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
@@ -48,6 +48,8 @@ import android.os.UserManagerInternal;
import android.platform.test.annotations.Presubmit;
import android.util.Pair;
+import com.android.server.compat.PlatformCompat;
+
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
@@ -71,12 +73,15 @@ public class ScanTests {
@Mock
UserManagerInternal mMockUserManager;
@Mock
+ PlatformCompat mMockCompatibility;
+ @Mock
PackageManagerService.Injector mMockInjector;
@Before
public void setupInjector() {
when(mMockInjector.getAbiHelper()).thenReturn(mMockPackageAbiHelper);
when(mMockInjector.getUserManagerInternal()).thenReturn(mMockUserManager);
+ when(mMockInjector.getCompatibility()).thenReturn(mMockCompatibility);
}
@Before