Merge changes from topic "inc-dis" into sc-dev

* changes:
  Disable incremental hardening on own resources
  StringBlock incremental hardening default values
This commit is contained in:
Ryan Mitchell
2021-05-27 21:31:04 +00:00
committed by Android (Google) Code Review
16 changed files with 180 additions and 52 deletions

View File

@@ -323,7 +323,7 @@ ApkResourceContainer::ApkResourceContainer(std::unique_ptr<ZipAssetsProvider> zi
Result<std::unique_ptr<ApkResourceContainer>> ApkResourceContainer::FromPath( Result<std::unique_ptr<ApkResourceContainer>> ApkResourceContainer::FromPath(
const std::string& path) { const std::string& path) {
auto zip_assets = ZipAssetsProvider::Create(path); auto zip_assets = ZipAssetsProvider::Create(path, 0 /* flags */);
if (zip_assets == nullptr) { if (zip_assets == nullptr) {
return Error("failed to load zip assets"); return Error("failed to load zip assets");
} }

View File

@@ -26,7 +26,7 @@
namespace android::idmap2 { namespace android::idmap2 {
Result<XmlParser> CreateTestParser(const std::string& test_file) { Result<XmlParser> 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) { if (zip == nullptr) {
return Error("Failed to open zip file"); return Error("Failed to open zip file");
} }

View File

@@ -1289,6 +1289,10 @@ public final class LoadedApk {
throw new AssertionError("null split not found"); throw new AssertionError("null split not found");
} }
if (Process.myUid() == mApplicationInfo.uid) {
ResourcesManager.getInstance().initializeApplicationPaths(mResDir, splitPaths);
}
mResources = ResourcesManager.getInstance().getResources(null, mResDir, mResources = ResourcesManager.getInstance().getResources(null, mResDir,
splitPaths, mLegacyOverlayDirs, mOverlayPaths, splitPaths, mLegacyOverlayDirs, mOverlayPaths,
mApplicationInfo.sharedLibraryFiles, null, null, getCompatibilityInfo(), mApplicationInfo.sharedLibraryFiles, null, null, getCompatibilityInfo(),

View File

@@ -39,6 +39,7 @@ import android.os.IBinder;
import android.os.Process; import android.os.Process;
import android.os.Trace; import android.os.Trace;
import android.util.ArrayMap; import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import android.util.Log; import android.util.Log;
import android.util.Pair; import android.util.Pair;
@@ -260,6 +261,12 @@ public class ResourcesManager {
*/ */
private final UpdateHandler mUpdateCallbacks = new UpdateHandler(); 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<String> mApplicationOwnedApks = new ArraySet<>();
@UnsupportedAppUsage @UnsupportedAppUsage
public ResourcesManager() { 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) { private static String overlayPathToIdmapPath(String path) {
return "/data/resource-cache/" + path.substring(1).replace('/', '@') + "@idmap"; 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) { if (key.overlay) {
apkAssets = ApkAssets.loadOverlayFromPath(overlayPathToIdmapPath(key.path), apkAssets = ApkAssets.loadOverlayFromPath(overlayPathToIdmapPath(key.path), flags);
0 /*flags*/);
} else { } else {
apkAssets = ApkAssets.loadFromPath(key.path, apkAssets = ApkAssets.loadFromPath(key.path, flags);
key.sharedLib ? ApkAssets.PROPERTY_DYNAMIC : 0);
} }
synchronized (mLock) { synchronized (mLock) {
@@ -1437,6 +1474,10 @@ public class ResourcesManager {
String[] copiedResourceDirs = combinedOverlayPaths(appInfo.resourceDirs, String[] copiedResourceDirs = combinedOverlayPaths(appInfo.resourceDirs,
appInfo.overlayPaths); appInfo.overlayPaths);
if (appInfo.uid == myUid) {
addApplicationPathsLocked(baseCodePath, copiedSplitDirs);
}
final ArrayMap<ResourcesImpl, ResourcesKey> updatedResourceKeys = new ArrayMap<>(); final ArrayMap<ResourcesImpl, ResourcesKey> updatedResourceKeys = new ArrayMap<>();
final int implCount = mResourceImpls.size(); final int implCount = mResourceImpls.size();
for (int i = 0; i < implCount; i++) { for (int i = 0; i < implCount; i++) {

View File

@@ -69,6 +69,12 @@ public final class ApkAssets {
*/ */
private static final int PROPERTY_OVERLAY = 1 << 3; 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. */ /** Flags that change the behavior of loaded apk assets. */
@IntDef(prefix = { "PROPERTY_" }, value = { @IntDef(prefix = { "PROPERTY_" }, value = {
PROPERTY_SYSTEM, PROPERTY_SYSTEM,
@@ -334,13 +340,14 @@ public final class ApkAssets {
} }
} }
@Nullable
CharSequence getStringFromPool(int idx) { CharSequence getStringFromPool(int idx) {
if (mStringBlock == null) { if (mStringBlock == null) {
return null; return null;
} }
synchronized (this) { synchronized (this) {
return mStringBlock.get(idx); return mStringBlock.getSequence(idx);
} }
} }

View File

@@ -550,7 +550,9 @@ public final class AssetManager implements AutoCloseable {
outValue.changingConfigurations); outValue.changingConfigurations);
if (outValue.type == TypedValue.TYPE_STRING) { if (outValue.type == TypedValue.TYPE_STRING) {
outValue.string = getPooledStringForCookie(cookie, outValue.data); if ((outValue.string = getPooledStringForCookie(cookie, outValue.data)) == null) {
return false;
}
} }
return true; return true;
} }
@@ -731,7 +733,9 @@ public final class AssetManager implements AutoCloseable {
outValue.changingConfigurations); outValue.changingConfigurations);
if (outValue.type == TypedValue.TYPE_STRING) { if (outValue.type == TypedValue.TYPE_STRING) {
outValue.string = getPooledStringForCookie(cookie, outValue.data); if ((outValue.string = getPooledStringForCookie(cookie, outValue.data)) == null) {
return false;
}
} }
return true; return true;
} }
@@ -833,6 +837,7 @@ public final class AssetManager implements AutoCloseable {
} }
} }
@Nullable
CharSequence getPooledStringForCookie(int cookie, int id) { CharSequence getPooledStringForCookie(int cookie, int id) {
// Cookies map to ApkAssets starting at 1. // Cookies map to ApkAssets starting at 1.
return getApkAssets()[cookie - 1].getStringFromPool(id); return getApkAssets()[cookie - 1].getStringFromPool(id);

View File

@@ -16,6 +16,8 @@
package android.content.res; package android.content.res;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage; import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.Paint; import android.graphics.Paint;
@@ -86,8 +88,19 @@ public final class StringBlock implements Closeable {
+ ": " + nativeGetSize(mNative)); + ": " + nativeGetSize(mNative));
} }
/**
* @deprecated use {@link #getSequence(int)} which can return null when a string cannot be found
* due to incremental installation.
*/
@Deprecated
@UnsupportedAppUsage @UnsupportedAppUsage
public CharSequence get(int idx) { public CharSequence get(int idx) {
CharSequence seq = getSequence(idx);
return seq == null ? "" : seq;
}
@Nullable
public CharSequence getSequence(int idx) {
synchronized (this) { synchronized (this) {
if (mStrings != null) { if (mStrings != null) {
CharSequence res = mStrings[idx]; CharSequence res = mStrings[idx];
@@ -108,6 +121,9 @@ public final class StringBlock implements Closeable {
} }
} }
String str = nativeGetString(mNative, idx); String str = nativeGetString(mNative, idx);
if (str == null) {
return null;
}
CharSequence res = str; CharSequence res = str;
int[] style = nativeGetStyle(mNative, idx); int[] style = nativeGetStyle(mNative, idx);
if (localLOGV) Log.v(TAG, "Got string: " + str); if (localLOGV) Log.v(TAG, "Got string: " + str);
@@ -133,6 +149,9 @@ public final class StringBlock implements Closeable {
} }
String styleTag = nativeGetString(mNative, styleId); String styleTag = nativeGetString(mNative, styleId);
if (styleTag == null) {
return null;
}
if (styleTag.equals("b")) { if (styleTag.equals("b")) {
mStyleIDs.boldId = styleId; mStyleIDs.boldId = styleId;
@@ -161,8 +180,10 @@ public final class StringBlock implements Closeable {
res = applyStyles(str, style, mStyleIDs); res = applyStyles(str, style, mStyleIDs);
} }
if (mStrings != null) mStrings[idx] = res; if (res != null) {
else mSparseStrings.put(idx, res); if (mStrings != null) mStrings[idx] = res;
else mSparseStrings.put(idx, res);
}
return res; return res;
} }
} }
@@ -203,6 +224,7 @@ public final class StringBlock implements Closeable {
private int marqueeId = -1; private int marqueeId = -1;
} }
@Nullable
private CharSequence applyStyles(String str, int[] style, StyleIDs ids) { private CharSequence applyStyles(String str, int[] style, StyleIDs ids) {
if (style.length == 0) if (style.length == 0)
return str; return str;
@@ -260,6 +282,9 @@ public final class StringBlock implements Closeable {
Spannable.SPAN_INCLUSIVE_INCLUSIVE); Spannable.SPAN_INCLUSIVE_INCLUSIVE);
} else { } else {
String tag = nativeGetString(mNative, type); String tag = nativeGetString(mNative, type);
if (tag == null) {
return null;
}
if (tag.startsWith("font;")) { if (tag.startsWith("font;")) {
String sub; String sub;

View File

@@ -1376,6 +1376,7 @@ public class TypedArray implements AutoCloseable {
return true; return true;
} }
@Nullable
private CharSequence loadStringValueAt(int index) { private CharSequence loadStringValueAt(int index) {
final int[] data = mData; final int[] data = mData;
final int cookie = data[index + STYLE_ASSET_COOKIE]; final int cookie = data[index + STYLE_ASSET_COOKIE];

View File

@@ -19,6 +19,7 @@ package android.content.res;
import static android.content.res.Resources.ID_NULL; import static android.content.res.Resources.ID_NULL;
import android.annotation.AnyRes; import android.annotation.AnyRes;
import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage; import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build; import android.os.Build;
@@ -161,9 +162,10 @@ public final class XmlBlock implements AutoCloseable {
public int getDepth() { public int getDepth() {
return mDepth; return mDepth;
} }
@Nullable
public String getText() { public String getText() {
int id = nativeGetText(mParseState); int id = nativeGetText(mParseState);
return id >= 0 ? mStrings.get(id).toString() : null; return id >= 0 ? getSequenceString(mStrings.getSequence(id)) : null;
} }
public int getLineNumber() { public int getLineNumber() {
return nativeGetLineNumber(mParseState); return nativeGetLineNumber(mParseState);
@@ -189,25 +191,29 @@ public final class XmlBlock implements AutoCloseable {
} }
return chars; return chars;
} }
@Nullable
public String getNamespace() { public String getNamespace() {
int id = nativeGetNamespace(mParseState); int id = nativeGetNamespace(mParseState);
return id >= 0 ? mStrings.get(id).toString() : ""; return id >= 0 ? getSequenceString(mStrings.getSequence(id)) : "";
} }
@Nullable
public String getName() { public String getName() {
int id = nativeGetName(mParseState); int id = nativeGetName(mParseState);
return id >= 0 ? mStrings.get(id).toString() : null; return id >= 0 ? getSequenceString(mStrings.getSequence(id)) : null;
} }
@NonNull
public String getAttributeNamespace(int index) { public String getAttributeNamespace(int index) {
int id = nativeGetAttributeNamespace(mParseState, index); int id = nativeGetAttributeNamespace(mParseState, index);
if (DEBUG) System.out.println("getAttributeNamespace of " + index + " = " + id); if (DEBUG) System.out.println("getAttributeNamespace of " + index + " = " + id);
if (id >= 0) return mStrings.get(id).toString(); if (id >= 0) return getSequenceString(mStrings.getSequence(id));
else if (id == -1) return ""; else if (id == -1) return "";
throw new IndexOutOfBoundsException(String.valueOf(index)); throw new IndexOutOfBoundsException(String.valueOf(index));
} }
@NonNull
public String getAttributeName(int index) { public String getAttributeName(int index) {
int id = nativeGetAttributeName(mParseState, index); int id = nativeGetAttributeName(mParseState, index);
if (DEBUG) System.out.println("getAttributeName of " + index + " = " + id); if (DEBUG) System.out.println("getAttributeName of " + index + " = " + id);
if (id >= 0) return mStrings.get(id).toString(); if (id >= 0) return getSequenceString(mStrings.getSequence(id));
throw new IndexOutOfBoundsException(String.valueOf(index)); throw new IndexOutOfBoundsException(String.valueOf(index));
} }
public String getAttributePrefix(int index) { public String getAttributePrefix(int index) {
@@ -220,10 +226,11 @@ public final class XmlBlock implements AutoCloseable {
public int getAttributeCount() { public int getAttributeCount() {
return mEventType == START_TAG ? nativeGetAttributeCount(mParseState) : -1; return mEventType == START_TAG ? nativeGetAttributeCount(mParseState) : -1;
} }
@NonNull
public String getAttributeValue(int index) { public String getAttributeValue(int index) {
int id = nativeGetAttributeStringValue(mParseState, index); int id = nativeGetAttributeStringValue(mParseState, index);
if (DEBUG) System.out.println("getAttributeValue of " + index + " = " + id); if (DEBUG) System.out.println("getAttributeValue of " + index + " = " + id);
if (id >= 0) return mStrings.get(id).toString(); if (id >= 0) return getSequenceString(mStrings.getSequence(id));
// May be some other type... check and try to convert if so. // May be some other type... check and try to convert if so.
int t = nativeGetAttributeDataType(mParseState, index); int t = nativeGetAttributeDataType(mParseState, index);
@@ -390,7 +397,7 @@ public final class XmlBlock implements AutoCloseable {
int v = nativeGetAttributeData(mParseState, idx); int v = nativeGetAttributeData(mParseState, idx);
if (t == TypedValue.TYPE_STRING) { if (t == TypedValue.TYPE_STRING) {
return XmlUtils.convertValueToList( return XmlUtils.convertValueToList(
mStrings.get(v), options, defaultValue); mStrings.getSequence(v), options, defaultValue);
} }
return v; return v;
} }
@@ -444,14 +451,15 @@ public final class XmlBlock implements AutoCloseable {
} }
throw new RuntimeException("not a float!"); throw new RuntimeException("not a float!");
} }
@Nullable
public String getIdAttribute() { public String getIdAttribute() {
int id = nativeGetIdAttribute(mParseState); int id = nativeGetIdAttribute(mParseState);
return id >= 0 ? mStrings.get(id).toString() : null; return id >= 0 ? getSequenceString(mStrings.getSequence(id)) : null;
} }
@Nullable
public String getClassAttribute() { public String getClassAttribute() {
int id = nativeGetClassAttribute(mParseState); int id = nativeGetClassAttribute(mParseState);
return id >= 0 ? mStrings.get(id).toString() : null; return id >= 0 ? getSequenceString(mStrings.getSequence(id)) : null;
} }
public int getIdAttributeResourceValue(int defaultValue) { public int getIdAttributeResourceValue(int defaultValue) {
@@ -463,6 +471,17 @@ public final class XmlBlock implements AutoCloseable {
return nativeGetStyleAttribute(mParseState); return nativeGetStyleAttribute(mParseState);
} }
private String getSequenceString(@Nullable CharSequence str) {
if (str == null) {
// A value of null retrieved from a StringPool indicates that retrieval of the
// string failed due to incremental installation. The presence of all the XmlBlock
// data is verified when it is created, so this exception must not be possible.
throw new IllegalStateException("Retrieving a string from the StringPool of an"
+ " XmlBlock should never fail");
}
return str.toString();
}
public void close() { public void close() {
synchronized (mBlock) { synchronized (mBlock) {
if (mParseState != 0) { if (mParseState != 0) {
@@ -472,13 +491,14 @@ public final class XmlBlock implements AutoCloseable {
} }
} }
} }
protected void finalize() throws Throwable { protected void finalize() throws Throwable {
close(); close();
} }
@Nullable
/*package*/ final CharSequence getPooledString(int id) { /*package*/ final CharSequence getPooledString(int id) {
return mStrings.get(id); return mStrings.getSequence(id);
} }
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)

View File

@@ -212,10 +212,11 @@ static jlong NativeLoad(JNIEnv* env, jclass /*clazz*/, const format_type_t forma
std::unique_ptr<ApkAssets> apk_assets; std::unique_ptr<ApkAssets> apk_assets;
switch (format) { switch (format) {
case FORMAT_APK: { case FORMAT_APK: {
auto assets = MultiAssetsProvider::Create(std::move(loader_assets), auto assets = MultiAssetsProvider::Create(std::move(loader_assets),
ZipAssetsProvider::Create(path.c_str())); ZipAssetsProvider::Create(path.c_str(),
apk_assets = ApkAssets::Load(std::move(assets), property_flags); property_flags));
break; apk_assets = ApkAssets::Load(std::move(assets), property_flags);
break;
} }
case FORMAT_IDMAP: case FORMAT_IDMAP:
apk_assets = ApkAssets::LoadOverlay(path.c_str(), property_flags); 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<const ApkAssets> apk_assets; std::unique_ptr<const ApkAssets> apk_assets;
switch (format) { switch (format) {
case FORMAT_APK: { case FORMAT_APK: {
auto assets = MultiAssetsProvider::Create( auto assets =
std::move(loader_assets), MultiAssetsProvider::Create(std::move(loader_assets),
ZipAssetsProvider::Create(std::move(dup_fd), friendly_name_utf8.c_str())); ZipAssetsProvider::Create(std::move(dup_fd),
apk_assets = ApkAssets::Load(std::move(assets), property_flags); friendly_name_utf8.c_str(),
break; property_flags));
apk_assets = ApkAssets::Load(std::move(assets), property_flags);
break;
} }
case FORMAT_ARSC: case FORMAT_ARSC:
apk_assets = ApkAssets::LoadTable( apk_assets = ApkAssets::LoadTable(
@@ -336,12 +339,16 @@ static jlong NativeLoadFromFdOffset(JNIEnv* env, jclass /*clazz*/, const format_
std::unique_ptr<const ApkAssets> apk_assets; std::unique_ptr<const ApkAssets> apk_assets;
switch (format) { switch (format) {
case FORMAT_APK: { case FORMAT_APK: {
auto assets = MultiAssetsProvider::Create( auto assets =
std::move(loader_assets), MultiAssetsProvider::Create(std::move(loader_assets),
ZipAssetsProvider::Create(std::move(dup_fd), friendly_name_utf8.c_str(), ZipAssetsProvider::Create(std::move(dup_fd),
static_cast<off64_t>(offset), static_cast<off64_t>(length))); friendly_name_utf8.c_str(),
apk_assets = ApkAssets::Load(std::move(assets), property_flags); property_flags,
break; static_cast<off64_t>(offset),
static_cast<off64_t>(
length)));
apk_assets = ApkAssets::Load(std::move(assets), property_flags);
break;
} }
case FORMAT_ARSC: case FORMAT_ARSC:
apk_assets = ApkAssets::LoadTable( apk_assets = ApkAssets::LoadTable(

View File

@@ -72,7 +72,7 @@ static jstring android_content_StringBlock_nativeGetString(JNIEnv* env, jobject
ResStringPool* osb = reinterpret_cast<ResStringPool*>(token); ResStringPool* osb = reinterpret_cast<ResStringPool*>(token);
if (osb == NULL) { if (osb == NULL) {
jniThrowNullPointerException(env, NULL); jniThrowNullPointerException(env, NULL);
return 0; return NULL;
} }
if (auto str8 = osb->string8At(idx); str8.has_value()) { if (auto str8 = osb->string8At(idx); str8.has_value()) {
@@ -80,9 +80,11 @@ static jstring android_content_StringBlock_nativeGetString(JNIEnv* env, jobject
} }
auto str = osb->stringAt(idx); auto str = osb->stringAt(idx);
if (UNLIKELY(!str.has_value())) { if (IsIOError(str)) {
return NULL;
} else if (UNLIKELY(!str.has_value())) {
jniThrowException(env, "java/lang/IndexOutOfBoundsException", NULL); jniThrowException(env, "java/lang/IndexOutOfBoundsException", NULL);
return 0; return NULL;
} }
return env->NewString((const jchar*)str->data(), str->size()); return env->NewString((const jchar*)str->data(), str->size());

View File

@@ -40,7 +40,7 @@ ApkAssets::ApkAssets(std::unique_ptr<Asset> resources_asset,
loaded_idmap_(std::move(loaded_idmap)) {} loaded_idmap_(std::move(loaded_idmap)) {}
std::unique_ptr<ApkAssets> ApkAssets::Load(const std::string& path, package_property_t flags) { std::unique_ptr<ApkAssets> 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> ApkAssets::LoadFromFd(base::unique_fd fd, std::unique_ptr<ApkAssets> ApkAssets::LoadFromFd(base::unique_fd fd,
@@ -91,7 +91,7 @@ std::unique_ptr<ApkAssets> ApkAssets::LoadOverlay(const std::string& idmap_path,
overlay_assets = EmptyAssetsProvider::Create(overlay_path); overlay_assets = EmptyAssetsProvider::Create(overlay_path);
} else { } else {
// The overlay should be an APK. // The overlay should be an APK.
overlay_assets = ZipAssetsProvider::Create(overlay_path); overlay_assets = ZipAssetsProvider::Create(overlay_path, flags);
} }
if (overlay_assets == nullptr) { if (overlay_assets == nullptr) {
return {}; return {};

View File

@@ -85,12 +85,14 @@ const std::string& ZipAssetsProvider::PathOrDebugName::GetDebugName() const {
} }
ZipAssetsProvider::ZipAssetsProvider(ZipArchiveHandle handle, PathOrDebugName&& path, ZipAssetsProvider::ZipAssetsProvider(ZipArchiveHandle handle, PathOrDebugName&& path,
time_t last_mod_time) package_property_t flags, time_t last_mod_time)
: zip_handle_(handle, ::CloseArchive), : zip_handle_(handle, ::CloseArchive),
name_(std::forward<PathOrDebugName>(path)), name_(std::forward<PathOrDebugName>(path)),
flags_(flags),
last_mod_time_(last_mod_time) {} last_mod_time_(last_mod_time) {}
std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(std::string path) { std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(std::string path,
package_property_t flags) {
ZipArchiveHandle handle; ZipArchiveHandle handle;
if (int32_t result = OpenArchive(path.c_str(), &handle); result != 0) { if (int32_t result = OpenArchive(path.c_str(), &handle); result != 0) {
LOG(ERROR) << "Failed to open APK '" << path << "': " << ::ErrorCodeString(result); LOG(ERROR) << "Failed to open APK '" << path << "': " << ::ErrorCodeString(result);
@@ -109,11 +111,12 @@ std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(std::string path) {
return std::unique_ptr<ZipAssetsProvider>( return std::unique_ptr<ZipAssetsProvider>(
new ZipAssetsProvider(handle, PathOrDebugName{std::move(path), new ZipAssetsProvider(handle, PathOrDebugName{std::move(path),
true /* is_path */}, sb.st_mtime)); true /* is_path */}, flags, sb.st_mtime));
} }
std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(base::unique_fd fd, std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(base::unique_fd fd,
std::string friendly_name, std::string friendly_name,
package_property_t flags,
off64_t offset, off64_t offset,
off64_t len) { off64_t len) {
ZipArchiveHandle handle; ZipArchiveHandle handle;
@@ -140,7 +143,7 @@ std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(base::unique_fd fd,
return std::unique_ptr<ZipAssetsProvider>( return std::unique_ptr<ZipAssetsProvider>(
new ZipAssetsProvider(handle, PathOrDebugName{std::move(friendly_name), new ZipAssetsProvider(handle, PathOrDebugName{std::move(friendly_name),
false /* is_path */}, sb.st_mtime)); false /* is_path */}, flags, sb.st_mtime));
} }
std::unique_ptr<Asset> ZipAssetsProvider::OpenInternal(const std::string& path, std::unique_ptr<Asset> ZipAssetsProvider::OpenInternal(const std::string& path,
@@ -161,10 +164,11 @@ std::unique_ptr<Asset> ZipAssetsProvider::OpenInternal(const std::string& path,
const int fd = GetFileDescriptor(zip_handle_.get()); const int fd = GetFileDescriptor(zip_handle_.get());
const off64_t fd_offset = GetFileDescriptorOffset(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; incfs::IncFsFileMap asset_map;
if (entry.method == kCompressDeflated) { if (entry.method == kCompressDeflated) {
if (!asset_map.Create(fd, entry.offset + fd_offset, entry.compressed_length, 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() LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << name_.GetDebugName()
<< "'"; << "'";
return {}; return {};
@@ -181,7 +185,7 @@ std::unique_ptr<Asset> ZipAssetsProvider::OpenInternal(const std::string& path,
} }
if (!asset_map.Create(fd, entry.offset + fd_offset, entry.uncompressed_length, 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() << "'"; LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << name_.GetDebugName() << "'";
return {}; return {};
} }

View File

@@ -2,6 +2,9 @@
"presubmit": [ "presubmit": [
{ {
"name": "CtsResourcesLoaderTests" "name": "CtsResourcesLoaderTests"
},
{
"name": "ResourcesHardeningTest"
} }
] ]
} }

View File

@@ -80,9 +80,12 @@ struct AssetsProvider {
// Supplies assets from a zip archive. // Supplies assets from a zip archive.
struct ZipAssetsProvider : public AssetsProvider { struct ZipAssetsProvider : public AssetsProvider {
static std::unique_ptr<ZipAssetsProvider> Create(std::string path); static std::unique_ptr<ZipAssetsProvider> Create(std::string path,
package_property_t flags);
static std::unique_ptr<ZipAssetsProvider> Create(base::unique_fd fd, static std::unique_ptr<ZipAssetsProvider> Create(base::unique_fd fd,
std::string friendly_name, std::string friendly_name,
package_property_t flags,
off64_t offset = 0, off64_t offset = 0,
off64_t len = kUnknownLength); off64_t len = kUnknownLength);
@@ -101,7 +104,8 @@ struct ZipAssetsProvider : public AssetsProvider {
private: private:
struct PathOrDebugName; 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 { struct PathOrDebugName {
PathOrDebugName(std::string&& value, bool is_path); PathOrDebugName(std::string&& value, bool is_path);
@@ -119,6 +123,7 @@ struct ZipAssetsProvider : public AssetsProvider {
std::unique_ptr<ZipArchive, void (*)(ZipArchive*)> zip_handle_; std::unique_ptr<ZipArchive, void (*)(ZipArchive*)> zip_handle_;
PathOrDebugName name_; PathOrDebugName name_;
package_property_t flags_;
time_t last_mod_time_; time_t last_mod_time_;
}; };

View File

@@ -92,6 +92,10 @@ enum : package_property_t {
// The package is a RRO. // The package is a RRO.
PROPERTY_OVERLAY = 1U << 3U, 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 { struct OverlayableInfo {