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

Commit c4ce4c82 authored by Oli Lan's avatar Oli Lan Committed by Automerger Merge Worker
Browse files

Merge "Prevent non-admin users from deleting system apps." into tm-dev am:...

Merge "Prevent non-admin users from deleting system apps." into tm-dev am: 81f66910 am: 05a032e4 am: 9834aed1

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/19569853



Change-Id: I36aeae026f1eb573381f18ccaaabfa990c96bfae
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents e77753f4 9834aed1
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ import android.content.pm.PackageChangeEvent;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.SharedLibraryInfo;
import android.content.pm.UserInfo;
import android.content.pm.VersionedPackage;
import android.net.Uri;
import android.os.Binder;
@@ -163,6 +164,18 @@ final class DeletePackageHelper {
                return PackageManager.DELETE_FAILED_INTERNAL_ERROR;
            }

            if (PackageManagerServiceUtils.isSystemApp(uninstalledPs)
                    && ((deleteFlags & PackageManager.DELETE_SYSTEM_APP) == 0)) {
                UserInfo userInfo = mUserManagerInternal.getUserInfo(userId);
                if (userInfo == null || (!userInfo.isAdmin() && !mUserManagerInternal.getUserInfo(
                        mUserManagerInternal.getProfileParentId(userId)).isAdmin())) {
                    Slog.w(TAG, "Not removing package " + packageName
                            + " as only admin user (or their profile) may downgrade system apps");
                    EventLog.writeEvent(0x534e4554, "170646036", -1, packageName);
                    return PackageManager.DELETE_FAILED_USER_RESTRICTED;
                }
            }

            disabledSystemPs = mPm.mSettings.getDisabledSystemPkgLPr(packageName);
            // Static shared libs can be declared by any package, so let us not
            // allow removing a package if it provides a lib others depend on.
+148 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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 android.content.pm.PackageManager
import android.content.pm.UserInfo
import android.os.Build
import android.util.Log
import com.android.server.testutils.any
import com.android.server.testutils.spy
import com.android.server.testutils.whenever
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.mockito.Mockito.doAnswer

@RunWith(JUnit4::class)
class DeletePackageHelperTest {

    @Rule
    @JvmField
    val rule = MockSystemRule()

    private lateinit var mPms: PackageManagerService
    private lateinit var mUserManagerInternal: UserManagerInternal

    @Before
    @Throws(Exception::class)
    fun setup() {
        Log.i("system.out", "setup", Exception())
        rule.system().stageNominalSystemState()
        rule.system().stageScanExistingPackage(
            "a.data.package", 1L, rule.system().dataAppDirectory)

        mUserManagerInternal = rule.mocks().injector.userManagerInternal
        whenever(mUserManagerInternal.getUserIds()).thenReturn(intArrayOf(0, 1))

        mPms = createPackageManagerService()
        doAnswer { false }.`when`(mPms).isPackageDeviceAdmin(any(), any())
        doAnswer { null }.`when`(mPms).freezePackageForDelete(any(), any(), any(), any())
    }

    private fun createPackageManagerService(): PackageManagerService {
        return spy(PackageManagerService(rule.mocks().injector,
            false /*coreOnly*/,
            false /*factoryTest*/,
            MockSystem.DEFAULT_VERSION_INFO.fingerprint,
            false /*isEngBuild*/,
            false /*isUserDebugBuild*/,
            Build.VERSION_CODES.CUR_DEVELOPMENT,
            Build.VERSION.INCREMENTAL))
    }

    @Test
    fun deleteSystemPackageFailsIfNotAdminAndNotProfile() {
        val ps = mPms.mSettings.getPackageLPr("a.data.package")
        whenever(PackageManagerServiceUtils.isSystemApp(ps)).thenReturn(true)
        whenever(mUserManagerInternal.getUserInfo(1)).thenReturn(UserInfo(1, "test", 0))
        whenever(mUserManagerInternal.getProfileParentId(1)).thenReturn(1)

        val dph = DeletePackageHelper(mPms)
        val result = dph.deletePackageX("a.data.package", 1L, 1, 0, false)

        assertThat(result).isEqualTo(PackageManager.DELETE_FAILED_USER_RESTRICTED)
    }

    @Test
    fun deleteSystemPackageFailsIfProfileOfNonAdmin() {
        val userId = 1
        val parentId = 5
        val ps = mPms.mSettings.getPackageLPr("a.data.package")
        whenever(PackageManagerServiceUtils.isSystemApp(ps)).thenReturn(true)
        whenever(mUserManagerInternal.getUserInfo(userId)).thenReturn(
            UserInfo(userId, "test", UserInfo.FLAG_PROFILE))
        whenever(mUserManagerInternal.getProfileParentId(userId)).thenReturn(parentId)
        whenever(mUserManagerInternal.getUserInfo(parentId)).thenReturn(
            UserInfo(userId, "testparent", 0))

        val dph = DeletePackageHelper(mPms)
        val result = dph.deletePackageX("a.data.package", 1L, userId, 0, false)

        assertThat(result).isEqualTo(PackageManager.DELETE_FAILED_USER_RESTRICTED)
    }

    @Test
    fun deleteSystemPackageSucceedsIfAdmin() {
        val ps = mPms.mSettings.getPackageLPr("a.data.package")
        whenever(PackageManagerServiceUtils.isSystemApp(ps)).thenReturn(true)
        whenever(mUserManagerInternal.getUserInfo(1)).thenReturn(
            UserInfo(1, "test", UserInfo.FLAG_ADMIN))

        val dph = DeletePackageHelper(mPms)
        val result = dph.deletePackageX("a.data.package", 1L, 1,
            PackageManager.DELETE_SYSTEM_APP, false)

        assertThat(result).isEqualTo(PackageManager.DELETE_SUCCEEDED)
    }

    @Test
    fun deleteSystemPackageSucceedsIfProfileOfAdmin() {
        val userId = 1
        val parentId = 5
        val ps = mPms.mSettings.getPackageLPr("a.data.package")
        whenever(PackageManagerServiceUtils.isSystemApp(ps)).thenReturn(true)
        whenever(mUserManagerInternal.getUserInfo(userId)).thenReturn(
            UserInfo(userId, "test", UserInfo.FLAG_PROFILE))
        whenever(mUserManagerInternal.getProfileParentId(userId)).thenReturn(parentId)
        whenever(mUserManagerInternal.getUserInfo(parentId)).thenReturn(
            UserInfo(userId, "testparent", UserInfo.FLAG_ADMIN))

        val dph = DeletePackageHelper(mPms)
        val result = dph.deletePackageX("a.data.package", 1L, userId,
            PackageManager.DELETE_SYSTEM_APP, false)

        assertThat(result).isEqualTo(PackageManager.DELETE_SUCCEEDED)
    }

    @Test
    fun deleteSystemPackageSucceedsIfNotAdminButDeleteSystemAppSpecified() {
        val ps = mPms.mSettings.getPackageLPr("a.data.package")
        whenever(PackageManagerServiceUtils.isSystemApp(ps)).thenReturn(true)
        whenever(mUserManagerInternal.getUserInfo(1)).thenReturn(UserInfo(1, "test", 0))
        whenever(mUserManagerInternal.getProfileParentId(1)).thenReturn(1)

        val dph = DeletePackageHelper(mPms)
        val result = dph.deletePackageX("a.data.package", 1L, 1,
                PackageManager.DELETE_SYSTEM_APP, false)

        assertThat(result).isEqualTo(PackageManager.DELETE_SUCCEEDED)
    }
}