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

Commit a8fc0153 authored by felkachang's avatar felkachang
Browse files

Enforce the overlayable mechanism for self-targeting

The overlayable mechanism has defined which roles can overlay the
specified resources and which resources are overlayable.

In order to reduce the argument between platform and applications,
self-targeting applications should enforce the overlayable mechanism.
It makes the overlay range be defined in the overlayable list. It
also defines the limitation of what kind of package can overlay the
resources of the self-targeting application.

To fill the policy flag, OverlayManagerImpl.java gets the following
information and passes them as bool type to JNI OverlayManagerImpl.
* SYSTEM_PARTITION
* VENDOR_PARTITION
* PRODUCT_PARTITION
* ODM_PARTITION
* OEM_PARTITION
* SIGNATURE

Not support
* ACTOR_SIGNATURE
* CONFIG_SIGNATURE

JNI OverlayManagerImpl fills the policy flags according to the
information from the ApplicationInfo. 'enforce_overlayable'is true to
enforce checking overlayable before generating an idmap.

Fixes: 238061808
Bug: 205919743

Test: atest \
              OverlayHostTests \
              OverlayDeviceTests \
              SelfTargetingOverlayDeviceTests \
              OverlayRemountedTest \
              FrameworksServicesTests:com.android.server.om \
              CtsContentTestCases:android.content.om.cts \
              idmap2_tests

Change-Id: I749d1a90a00f0a91e7796bc0f9f668f9ecfdb8b0
parent 3170042b
Loading
Loading
Loading
Loading
+45 −10
Original line number Diff line number Diff line
@@ -38,9 +38,10 @@ namespace android::self_targeting {
constexpr const mode_t kIdmapFilePermission = S_IRUSR | S_IWUSR;  // u=rw-, g=---, o=---

extern "C" bool
CreateFrroFile(std::string& out_err_result, std::string& packageName, std::string& overlayName,
               std::string& targetPackageName, std::optional<std::string>& targetOverlayable,
               std::vector<FabricatedOverlayEntryParameters>& entries_params,
CreateFrroFile(std::string& out_err_result, const std::string& packageName,
               const std::string& overlayName, const std::string& targetPackageName,
               const std::optional<std::string>& targetOverlayable,
               const std::vector<FabricatedOverlayEntryParameters>& entries_params,
               const std::string& frro_file_path) {
    android::idmap2::FabricatedOverlay::Builder builder(packageName, overlayName,
                                                        targetPackageName);
@@ -90,9 +91,46 @@ CreateFrroFile(std::string& out_err_result, std::string& packageName, std::strin
    return true;
}

static PolicyBitmask GetFulfilledPolicy(const bool isSystem, const bool isVendor,
                                        const bool isProduct, const bool isTargetSignature,
                                        const bool isOdm, const bool isOem) {
    auto fulfilled_policy = static_cast<PolicyBitmask>(PolicyFlags::PUBLIC);

    if (isSystem) {
        fulfilled_policy |= PolicyFlags::SYSTEM_PARTITION;
    }
    if (isVendor) {
        fulfilled_policy |= PolicyFlags::VENDOR_PARTITION;
    }
    if (isProduct) {
        fulfilled_policy |= PolicyFlags::PRODUCT_PARTITION;
    }
    if (isOdm) {
        fulfilled_policy |= PolicyFlags::ODM_PARTITION;
    }
    if (isOem) {
        fulfilled_policy |= PolicyFlags::OEM_PARTITION;
    }
    if (isTargetSignature) {
        fulfilled_policy |= PolicyFlags::SIGNATURE;
    }

    // Not support actor_signature and config_overlay_signature
    fulfilled_policy &=
            ~(PolicyFlags::ACTOR_SIGNATURE | PolicyFlags::CONFIG_SIGNATURE);

    ALOGV(
            "fulfilled_policy = 0x%08x, isSystem = %d, isVendor = %d, isProduct = %d,"
            " isTargetSignature = %d, isOdm = %d, isOem = %d,",
            fulfilled_policy, isSystem, isVendor, isProduct, isTargetSignature, isOdm, isOem);
    return fulfilled_policy;
}

extern "C" bool
CreateIdmapFile(std::string& out_err, const std::string& targetPath, const std::string& overlayPath,
                const std::string& idmapPath, const std::string& overlayName) {
                const std::string& idmapPath, const std::string& overlayName,
                const bool isSystem, const bool isVendor, const bool isProduct,
                const bool isTargetSignature, const bool isOdm, const bool isOem) {
    // idmap files are mapped with mmap in libandroidfw. Deleting and recreating the idmap
    // guarantees that existing memory maps will continue to be valid and unaffected. The file must
    // be deleted before attempting to create the idmap, so that if idmap  creation fails, the
@@ -114,14 +152,11 @@ CreateIdmapFile(std::string& out_err, const std::string& targetPath, const std::
    }

    // Overlay self target process. Only allow self-targeting types.
    const auto fulfilled_policies = static_cast<PolicyBitmask>(
            PolicyFlags::PUBLIC | PolicyFlags::SYSTEM_PARTITION | PolicyFlags::VENDOR_PARTITION |
            PolicyFlags::PRODUCT_PARTITION | PolicyFlags::SIGNATURE | PolicyFlags::ODM_PARTITION |
            PolicyFlags::OEM_PARTITION | PolicyFlags::ACTOR_SIGNATURE |
            PolicyFlags::CONFIG_SIGNATURE);
    const auto fulfilled_policies = GetFulfilledPolicy(isSystem, isVendor, isProduct,
                                                       isTargetSignature, isOdm, isOem);

    const auto idmap = Idmap::FromContainers(**target, **overlay, overlayName,
                                             fulfilled_policies, false /* enforce_overlayable */);
                                             fulfilled_policies, true /* enforce_overlayable */);
    if (!idmap) {
        out_err = base::StringPrintf("Failed to create idmap because of %s",
                                     idmap.GetErrorMessage().c_str());
+34 −2
Original line number Diff line number Diff line
@@ -170,6 +170,16 @@ public class OverlayManagerImpl {
        mBasePath = baseFile.toPath();
    }

    private boolean isSameWithTargetSignature(final String targetPackage) {
        final PackageManager packageManager = mContext.getPackageManager();
        final String packageName = mContext.getPackageName();
        if (TextUtils.equals(packageName, targetPackage)) {
            return true;
        }
        return packageManager.checkSignatures(packageName, targetPackage)
                == PackageManager.SIGNATURE_MATCH;
    }

    /**
     * Check if the overlay name is valid or not.
     *
@@ -202,6 +212,9 @@ public class OverlayManagerImpl {
    /**
     * Save FabricatedOverlay instance as frro and idmap files.
     *
     * <p>In order to fill the overlayable policy, it's necessary to collect the information from
     * app. And then, the information is passed to native layer to fill the overlayable policy
     *
     * @param overlayInternal the FabricatedOverlayInternal to be saved.
     */
    public void registerFabricatedOverlay(@NonNull FabricatedOverlayInternal overlayInternal)
@@ -214,6 +227,9 @@ public class OverlayManagerImpl {
        final String overlayName = checkOverlayNameValid(overlayInternal.overlayName);
        checkPackageName(overlayInternal.packageName);
        checkPackageName(overlayInternal.targetPackageName);
        Preconditions.checkStringNotEmpty(
                overlayInternal.targetOverlayable,
                "Target overlayable should be neither null nor empty string.");

        final ApplicationInfo applicationInfo = mContext.getApplicationInfo();
        final String targetPackage = Preconditions.checkStringNotEmpty(
@@ -223,7 +239,17 @@ public class OverlayManagerImpl {

        createFrroFile(frroPath.toString(), overlayInternal);
        try {
            createIdmapFile(targetPackage, frroPath.toString(), idmapPath.toString(), overlayName);
            createIdmapFile(
                    targetPackage,
                    frroPath.toString(),
                    idmapPath.toString(),
                    overlayName,
                    applicationInfo.isSystemApp() || applicationInfo.isSystemExt() /* isSystem */,
                    applicationInfo.isVendor(),
                    applicationInfo.isProduct(),
                    isSameWithTargetSignature(overlayInternal.targetPackageName),
                    applicationInfo.isOdm(),
                    applicationInfo.isOem());
        } catch (IOException e) {
            if (!frroPath.toFile().delete()) {
                Log.w(TAG, "Failed to delete file " + frroPath);
@@ -315,7 +341,13 @@ public class OverlayManagerImpl {
            @NonNull String targetPath,
            @NonNull String overlayPath,
            @NonNull String idmapPath,
            @NonNull String overlayName)
            @NonNull String overlayName,
            boolean isSystem,
            boolean isVendor,
            boolean isProduct,
            boolean isSameWithTargetSignature,
            boolean isOdm,
            boolean isOem)
            throws IOException;

    private static native FabricatedOverlayInfo getFabricatedOverlayInfo(
+18 −6
Original line number Diff line number Diff line
@@ -123,8 +123,12 @@ public:

    bool callCreateIdmapFile(std::string& out_error, const std::string& targetPath,
                             const std::string& overlayPath, const std::string& idmapPath,
                             const std::string& overlayName) {
        return createIdmapFileFuncPtr_(out_error, targetPath, overlayPath, idmapPath, overlayName);
                             const std::string& overlayName, const bool isSystem,
                             const bool isVendor, const bool isProduct,
                             const bool isTargetSignature, const bool isOdm, const bool isOem) {
        return createIdmapFileFuncPtr_(out_error, targetPath, overlayPath, idmapPath, overlayName,
                                       isSystem, isVendor, isProduct, isTargetSignature, isOdm,
                                       isOem);
    }

    bool callGetFabricatedOverlayInfo(std::string& out_error, const std::string& overlay_path,
@@ -158,7 +162,10 @@ private:
    typedef bool (*CreateIdmapFileFunc)(std::string& out_error, const std::string& targetPath,
                                        const std::string& overlayPath,
                                        const std::string& idmapPath,
                                        const std::string& overlayName);
                                        const std::string& overlayName, const jboolean isSystem,
                                        const jboolean isVendor, const jboolean isProduct,
                                        const jboolean isSameWithTargetSignature,
                                        const jboolean isOdm, const jboolean isOem);

    typedef bool (*GetFabricatedOverlayInfoFunc)(std::string& out_error,
                                                 const std::string& overlay_path,
@@ -295,7 +302,9 @@ static void CreateFrroFile(JNIEnv* env, jclass /*clazz*/, jstring jsFrroFilePath
}

static void CreateIdmapFile(JNIEnv* env, jclass /* clazz */, jstring jsTargetPath,
                            jstring jsOverlayPath, jstring jsIdmapPath, jstring jsOverlayName) {
                            jstring jsOverlayPath, jstring jsIdmapPath, jstring jsOverlayName,
                            jboolean isSystem, jboolean isVendor, jboolean isProduct,
                            jboolean isTargetSignature, jboolean isOdm, jboolean isOem) {
    DynamicLibraryLoader& dlLoader = EnsureDynamicLibraryLoader(env);
    if (!dlLoader) {
        jniThrowNullPointerException(env, "libidmap2 is not loaded");
@@ -327,7 +336,10 @@ static void CreateIdmapFile(JNIEnv* env, jclass /* clazz */, jstring jsTargetPat

    std::string err_result;
    if (!dlLoader.callCreateIdmapFile(err_result, targetPath.c_str(), overlayPath.c_str(),
                                      idmapPath.c_str(), overlayName.c_str())) {
                                      idmapPath.c_str(), overlayName.c_str(),
                                      (isSystem == JNI_TRUE), (isVendor == JNI_TRUE),
                                      (isProduct == JNI_TRUE), (isTargetSignature == JNI_TRUE),
                                      (isOdm == JNI_TRUE), (isOem == JNI_TRUE))) {
        jniThrowException(env, kIOException, err_result.c_str());
        return;
    }
@@ -374,7 +386,7 @@ static const JNINativeMethod gOverlayManagerMethods[] = {
        {"createFrroFile", "(Ljava/lang/String;Landroid/os/FabricatedOverlayInternal;)V",
         reinterpret_cast<void*>(self_targeting::CreateFrroFile)},
        {"createIdmapFile",
         "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
         "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZZZZZ)V",
         reinterpret_cast<void*>(self_targeting::CreateIdmapFile)},
        {"getFabricatedOverlayInfo", "(Ljava/lang/String;)Landroid/os/FabricatedOverlayInfo;",
         reinterpret_cast<void*>(self_targeting::GetFabricatedOverlayInfo)},
+1 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ android_test {
        "androidx.test.rules",
        "androidx.test.runner",
        "androidx.test.ext.junit",
        "mockito-target-minus-junit4",
        "truth-prebuilt",
    ],

+84 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?><!--
  ~ 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.
  -->

<resources>
    <overlayable name="PublicOverlayable" actor="overlay://theme">
        <!-- The app with the same signature can overlay the below resources -->
        <policy type="public">
            <item type="color" name="public_overlayable_color" />
        </policy>
    </overlayable>

    <overlayable name="SignatureOverlayable" actor="overlay://theme">
        <!-- The app with the same signature can overlay the below resources -->
        <policy type="signature">
            <item type="color" name="mycolor" />
            <item type="color" name="signature_overlayable_color" />
            <item type="string" name="mystring" />
            <item type="drawable" name="mydrawable" />
        </policy>
    </overlayable>

    <overlayable name="SystemAppOverlayable" actor="overlay://theme">
        <!-- The app in system partition can overlay the below resources -->
        <policy type="system">
            <item type="color" name="system_app_overlayable_color" />
        </policy>
    </overlayable>

    <overlayable name="OdmOverlayable" actor="overlay://theme">
        <!-- The app with the same signature can overlay the below resources -->
        <policy type="odm">
            <item type="color" name="odm_overlayable_color" />
        </policy>
    </overlayable>

    <overlayable name="OemOverlayable" actor="overlay://theme">
        <!-- The app with the same signature can overlay the below resources -->
        <policy type="oem">
            <item type="color" name="oem_overlayable_color" />
        </policy>
    </overlayable>

    <overlayable name="VendorOverlayable" actor="overlay://theme">
        <!-- The app with the same signature can overlay the below resources -->
        <policy type="vendor">
            <item type="color" name="vendor_overlayable_color" />
        </policy>
    </overlayable>

    <overlayable name="ProductOverlayable" actor="overlay://theme">
        <!-- The app with the same signature can overlay the below resources -->
        <policy type="product">
            <item type="color" name="product_overlayable_color" />
        </policy>
    </overlayable>

    <overlayable name="ActorOverlayable" actor="overlay://theme">
        <!-- The app with the same signature can overlay the below resources -->
        <policy type="actor">
            <item type="color" name="actor_overlayable_color" />
        </policy>
    </overlayable>

    <overlayable name="ConfigOverlayable" actor="overlay://theme">
        <!-- The app with the same signature can overlay the below resources -->
        <policy type="config_signature">
            <item type="color" name="config_overlayable_color" />
        </policy>
    </overlayable>

</resources>
Loading