Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 65c11683 authored by Anna Trostanetski's avatar Anna Trostanetski Committed by Android (Google) Code Review
Browse files

Merge "Add a compat change to opt-in to latest SELinux domain."

parents a74428b2 c3c2e4de
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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
+6 −0
Original line number Diff line number Diff line
@@ -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",
}
+33 −18
Original line number Diff line number Diff line
@@ -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));
+59 −0
Original line number Diff line number Diff line
@@ -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
+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