diff --git a/cmds/idmap2/libidmap2/ResourceContainer.cpp b/cmds/idmap2/libidmap2/ResourceContainer.cpp index 9147ccaaa17aa..c147f6a6024bb 100644 --- a/cmds/idmap2/libidmap2/ResourceContainer.cpp +++ b/cmds/idmap2/libidmap2/ResourceContainer.cpp @@ -323,7 +323,7 @@ ApkResourceContainer::ApkResourceContainer(std::unique_ptr zi Result> ApkResourceContainer::FromPath( const std::string& path) { - auto zip_assets = ZipAssetsProvider::Create(path); + auto zip_assets = ZipAssetsProvider::Create(path, 0 /* flags */); if (zip_assets == nullptr) { return Error("failed to load zip assets"); } diff --git a/cmds/idmap2/tests/XmlParserTests.cpp b/cmds/idmap2/tests/XmlParserTests.cpp index eaf10a7d9282f..016c5c3a01a5e 100644 --- a/cmds/idmap2/tests/XmlParserTests.cpp +++ b/cmds/idmap2/tests/XmlParserTests.cpp @@ -26,7 +26,7 @@ namespace android::idmap2 { Result CreateTestParser(const std::string& test_file) { - auto zip = ZipAssetsProvider::Create(GetTestDataPath() + "/target/target.apk"); + auto zip = ZipAssetsProvider::Create(GetTestDataPath() + "/target/target.apk", 0 /* flags */); if (zip == nullptr) { return Error("Failed to open zip file"); } diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index 0733a3e7c51cf..90a6f32b2344d 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -1289,6 +1289,10 @@ public final class LoadedApk { throw new AssertionError("null split not found"); } + if (Process.myUid() == mApplicationInfo.uid) { + ResourcesManager.getInstance().initializeApplicationPaths(mResDir, splitPaths); + } + mResources = ResourcesManager.getInstance().getResources(null, mResDir, splitPaths, mLegacyOverlayDirs, mOverlayPaths, mApplicationInfo.sharedLibraryFiles, null, null, getCompatibilityInfo(), diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index 792336d9be9ec..f28c760d54d95 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -39,6 +39,7 @@ import android.os.IBinder; import android.os.Process; import android.os.Trace; import android.util.ArrayMap; +import android.util.ArraySet; import android.util.DisplayMetrics; import android.util.Log; import android.util.Pair; @@ -260,6 +261,12 @@ public class ResourcesManager { */ private final UpdateHandler mUpdateCallbacks = new UpdateHandler(); + /** + * The set of APK paths belonging to this process. This is used to disable incremental + * installation crash protections on these APKs so the app either behaves as expects or crashes. + */ + private final ArraySet mApplicationOwnedApks = new ArraySet<>(); + @UnsupportedAppUsage public ResourcesManager() { } @@ -424,6 +431,32 @@ public class ResourcesManager { } } + /** + * Initializes the set of APKs owned by the application running in this process. + */ + public void initializeApplicationPaths(@NonNull String sourceDir, + @Nullable String[] splitDirs) { + synchronized (mLock) { + if (mApplicationOwnedApks.isEmpty()) { + addApplicationPathsLocked(sourceDir, splitDirs); + } + } + } + + /** + * Updates the set of APKs owned by the application running in this process. + * + * This method only appends to the set of APKs owned by this process because the previous APKs + * paths still belong to the application running in this process. + */ + private void addApplicationPathsLocked(@NonNull String sourceDir, + @Nullable String[] splitDirs) { + mApplicationOwnedApks.add(sourceDir); + if (splitDirs != null) { + mApplicationOwnedApks.addAll(Arrays.asList(splitDirs)); + } + } + private static String overlayPathToIdmapPath(String path) { return "/data/resource-cache/" + path.substring(1).replace('/', '@') + "@idmap"; } @@ -445,13 +478,17 @@ public class ResourcesManager { } } - // We must load this from disk. + int flags = 0; + if (key.sharedLib) { + flags |= ApkAssets.PROPERTY_DYNAMIC; + } + if (mApplicationOwnedApks.contains(key.path)) { + flags |= ApkAssets.PROPERTY_DISABLE_INCREMENTAL_HARDENING; + } if (key.overlay) { - apkAssets = ApkAssets.loadOverlayFromPath(overlayPathToIdmapPath(key.path), - 0 /*flags*/); + apkAssets = ApkAssets.loadOverlayFromPath(overlayPathToIdmapPath(key.path), flags); } else { - apkAssets = ApkAssets.loadFromPath(key.path, - key.sharedLib ? ApkAssets.PROPERTY_DYNAMIC : 0); + apkAssets = ApkAssets.loadFromPath(key.path, flags); } synchronized (mLock) { @@ -1437,6 +1474,10 @@ public class ResourcesManager { String[] copiedResourceDirs = combinedOverlayPaths(appInfo.resourceDirs, appInfo.overlayPaths); + if (appInfo.uid == myUid) { + addApplicationPathsLocked(baseCodePath, copiedSplitDirs); + } + final ArrayMap updatedResourceKeys = new ArrayMap<>(); final int implCount = mResourceImpls.size(); for (int i = 0; i < implCount; i++) { diff --git a/core/java/android/content/res/ApkAssets.java b/core/java/android/content/res/ApkAssets.java index 224ff14c5df47..6fd2d05ad1357 100644 --- a/core/java/android/content/res/ApkAssets.java +++ b/core/java/android/content/res/ApkAssets.java @@ -69,6 +69,12 @@ public final class ApkAssets { */ private static final int PROPERTY_OVERLAY = 1 << 3; + /** + * The apk assets is owned by the application running in this process and incremental crash + * protections for this APK must be disabled. + */ + public static final int PROPERTY_DISABLE_INCREMENTAL_HARDENING = 1 << 4; + /** Flags that change the behavior of loaded apk assets. */ @IntDef(prefix = { "PROPERTY_" }, value = { PROPERTY_SYSTEM, diff --git a/core/jni/android_content_res_ApkAssets.cpp b/core/jni/android_content_res_ApkAssets.cpp index 9c8daec7919a4..1be84282f6db6 100644 --- a/core/jni/android_content_res_ApkAssets.cpp +++ b/core/jni/android_content_res_ApkAssets.cpp @@ -212,10 +212,11 @@ static jlong NativeLoad(JNIEnv* env, jclass /*clazz*/, const format_type_t forma std::unique_ptr apk_assets; switch (format) { case FORMAT_APK: { - auto assets = MultiAssetsProvider::Create(std::move(loader_assets), - ZipAssetsProvider::Create(path.c_str())); - apk_assets = ApkAssets::Load(std::move(assets), property_flags); - break; + auto assets = MultiAssetsProvider::Create(std::move(loader_assets), + ZipAssetsProvider::Create(path.c_str(), + property_flags)); + apk_assets = ApkAssets::Load(std::move(assets), property_flags); + break; } case FORMAT_IDMAP: apk_assets = ApkAssets::LoadOverlay(path.c_str(), property_flags); @@ -271,11 +272,13 @@ static jlong NativeLoadFromFd(JNIEnv* env, jclass /*clazz*/, const format_type_t std::unique_ptr apk_assets; switch (format) { case FORMAT_APK: { - auto assets = MultiAssetsProvider::Create( - std::move(loader_assets), - ZipAssetsProvider::Create(std::move(dup_fd), friendly_name_utf8.c_str())); - apk_assets = ApkAssets::Load(std::move(assets), property_flags); - break; + auto assets = + MultiAssetsProvider::Create(std::move(loader_assets), + ZipAssetsProvider::Create(std::move(dup_fd), + friendly_name_utf8.c_str(), + property_flags)); + apk_assets = ApkAssets::Load(std::move(assets), property_flags); + break; } case FORMAT_ARSC: apk_assets = ApkAssets::LoadTable( @@ -336,12 +339,16 @@ static jlong NativeLoadFromFdOffset(JNIEnv* env, jclass /*clazz*/, const format_ std::unique_ptr apk_assets; switch (format) { case FORMAT_APK: { - auto assets = MultiAssetsProvider::Create( - std::move(loader_assets), - ZipAssetsProvider::Create(std::move(dup_fd), friendly_name_utf8.c_str(), - static_cast(offset), static_cast(length))); - apk_assets = ApkAssets::Load(std::move(assets), property_flags); - break; + auto assets = + MultiAssetsProvider::Create(std::move(loader_assets), + ZipAssetsProvider::Create(std::move(dup_fd), + friendly_name_utf8.c_str(), + property_flags, + static_cast(offset), + static_cast( + length))); + apk_assets = ApkAssets::Load(std::move(assets), property_flags); + break; } case FORMAT_ARSC: apk_assets = ApkAssets::LoadTable( diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp index 26d836328b54e..2beb33abe782c 100755 --- a/libs/androidfw/ApkAssets.cpp +++ b/libs/androidfw/ApkAssets.cpp @@ -40,7 +40,7 @@ ApkAssets::ApkAssets(std::unique_ptr resources_asset, loaded_idmap_(std::move(loaded_idmap)) {} std::unique_ptr ApkAssets::Load(const std::string& path, package_property_t flags) { - return Load(ZipAssetsProvider::Create(path), flags); + return Load(ZipAssetsProvider::Create(path, flags), flags); } std::unique_ptr ApkAssets::LoadFromFd(base::unique_fd fd, @@ -91,7 +91,7 @@ std::unique_ptr ApkAssets::LoadOverlay(const std::string& idmap_path, overlay_assets = EmptyAssetsProvider::Create(overlay_path); } else { // The overlay should be an APK. - overlay_assets = ZipAssetsProvider::Create(overlay_path); + overlay_assets = ZipAssetsProvider::Create(overlay_path, flags); } if (overlay_assets == nullptr) { return {}; diff --git a/libs/androidfw/AssetsProvider.cpp b/libs/androidfw/AssetsProvider.cpp index 6c7a253072475..bce34d37c90bc 100644 --- a/libs/androidfw/AssetsProvider.cpp +++ b/libs/androidfw/AssetsProvider.cpp @@ -85,12 +85,14 @@ const std::string& ZipAssetsProvider::PathOrDebugName::GetDebugName() const { } ZipAssetsProvider::ZipAssetsProvider(ZipArchiveHandle handle, PathOrDebugName&& path, - time_t last_mod_time) + package_property_t flags, time_t last_mod_time) : zip_handle_(handle, ::CloseArchive), name_(std::forward(path)), + flags_(flags), last_mod_time_(last_mod_time) {} -std::unique_ptr ZipAssetsProvider::Create(std::string path) { +std::unique_ptr ZipAssetsProvider::Create(std::string path, + package_property_t flags) { ZipArchiveHandle handle; if (int32_t result = OpenArchive(path.c_str(), &handle); result != 0) { LOG(ERROR) << "Failed to open APK '" << path << "': " << ::ErrorCodeString(result); @@ -109,11 +111,12 @@ std::unique_ptr ZipAssetsProvider::Create(std::string path) { return std::unique_ptr( new ZipAssetsProvider(handle, PathOrDebugName{std::move(path), - true /* is_path */}, sb.st_mtime)); + true /* is_path */}, flags, sb.st_mtime)); } std::unique_ptr ZipAssetsProvider::Create(base::unique_fd fd, std::string friendly_name, + package_property_t flags, off64_t offset, off64_t len) { ZipArchiveHandle handle; @@ -140,7 +143,7 @@ std::unique_ptr ZipAssetsProvider::Create(base::unique_fd fd, return std::unique_ptr( new ZipAssetsProvider(handle, PathOrDebugName{std::move(friendly_name), - false /* is_path */}, sb.st_mtime)); + false /* is_path */}, flags, sb.st_mtime)); } std::unique_ptr ZipAssetsProvider::OpenInternal(const std::string& path, @@ -161,10 +164,11 @@ std::unique_ptr ZipAssetsProvider::OpenInternal(const std::string& path, const int fd = GetFileDescriptor(zip_handle_.get()); const off64_t fd_offset = GetFileDescriptorOffset(zip_handle_.get()); + const bool incremental_hardening = (flags_ & PROPERTY_DISABLE_INCREMENTAL_HARDENING) == 0U; incfs::IncFsFileMap asset_map; if (entry.method == kCompressDeflated) { if (!asset_map.Create(fd, entry.offset + fd_offset, entry.compressed_length, - name_.GetDebugName().c_str())) { + name_.GetDebugName().c_str(), incremental_hardening)) { LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << name_.GetDebugName() << "'"; return {}; @@ -181,7 +185,7 @@ std::unique_ptr ZipAssetsProvider::OpenInternal(const std::string& path, } if (!asset_map.Create(fd, entry.offset + fd_offset, entry.uncompressed_length, - name_.GetDebugName().c_str())) { + name_.GetDebugName().c_str(), incremental_hardening)) { LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << name_.GetDebugName() << "'"; return {}; } diff --git a/libs/androidfw/TEST_MAPPING b/libs/androidfw/TEST_MAPPING index 766714cd76941..8a5c06d1eef94 100644 --- a/libs/androidfw/TEST_MAPPING +++ b/libs/androidfw/TEST_MAPPING @@ -2,6 +2,9 @@ "presubmit": [ { "name": "CtsResourcesLoaderTests" + }, + { + "name": "ResourcesHardeningTest" } ] } \ No newline at end of file diff --git a/libs/androidfw/include/androidfw/AssetsProvider.h b/libs/androidfw/include/androidfw/AssetsProvider.h index ec51c65053bf2..966ec74c1786a 100644 --- a/libs/androidfw/include/androidfw/AssetsProvider.h +++ b/libs/androidfw/include/androidfw/AssetsProvider.h @@ -80,9 +80,12 @@ struct AssetsProvider { // Supplies assets from a zip archive. struct ZipAssetsProvider : public AssetsProvider { - static std::unique_ptr Create(std::string path); + static std::unique_ptr Create(std::string path, + package_property_t flags); + static std::unique_ptr Create(base::unique_fd fd, std::string friendly_name, + package_property_t flags, off64_t offset = 0, off64_t len = kUnknownLength); @@ -101,7 +104,8 @@ struct ZipAssetsProvider : public AssetsProvider { private: struct PathOrDebugName; - ZipAssetsProvider(ZipArchive* handle, PathOrDebugName&& path, time_t last_mod_time); + ZipAssetsProvider(ZipArchive* handle, PathOrDebugName&& path, package_property_t flags, + time_t last_mod_time); struct PathOrDebugName { PathOrDebugName(std::string&& value, bool is_path); @@ -119,6 +123,7 @@ struct ZipAssetsProvider : public AssetsProvider { std::unique_ptr zip_handle_; PathOrDebugName name_; + package_property_t flags_; time_t last_mod_time_; }; diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h index 9bbdede562930..b3d6a4dcb955c 100644 --- a/libs/androidfw/include/androidfw/LoadedArsc.h +++ b/libs/androidfw/include/androidfw/LoadedArsc.h @@ -92,6 +92,10 @@ enum : package_property_t { // The package is a RRO. PROPERTY_OVERLAY = 1U << 3U, + + // The apk assets is owned by the application running in this process and incremental crash + // protections for this APK must be disabled. + PROPERTY_DISABLE_INCREMENTAL_HARDENING = 1U << 4U, }; struct OverlayableInfo {