Merge "Fail installation in case zip file is malformed." into main

This commit is contained in:
Treehugger Robot
2023-07-06 22:24:11 +00:00
committed by Android (Google) Code Review
3 changed files with 104 additions and 44 deletions

View File

@@ -292,21 +292,31 @@ private:
}
public:
static NativeLibrariesIterator* create(ZipFileRO* zipFile, bool debuggable) {
void* cookie = nullptr;
static base::expected<std::unique_ptr<NativeLibrariesIterator>, int32_t> create(
ZipFileRO* zipFile, bool debuggable) {
// Do not specify a suffix to find both .so files and gdbserver.
if (!zipFile->startIteration(&cookie, APK_LIB.data(), nullptr /* suffix */)) {
return nullptr;
auto result = zipFile->startIterationOrError(APK_LIB.data(), nullptr /* suffix */);
if (!result.ok()) {
return base::unexpected(result.error());
}
return new NativeLibrariesIterator(zipFile, debuggable, cookie);
return std::unique_ptr<NativeLibrariesIterator>(
new NativeLibrariesIterator(zipFile, debuggable, result.value()));
}
ZipEntryRO next() {
ZipEntryRO next = nullptr;
while ((next = mZipFile->nextEntry(mCookie)) != nullptr) {
base::expected<ZipEntryRO, int32_t> next() {
ZipEntryRO nextEntry;
while (true) {
auto next = mZipFile->nextEntryOrError(mCookie);
if (!next.ok()) {
return base::unexpected(next.error());
}
nextEntry = next.value();
if (nextEntry == nullptr) {
break;
}
// Make sure this entry has a filename.
if (mZipFile->getEntryFileName(next, fileName, sizeof(fileName))) {
if (mZipFile->getEntryFileName(nextEntry, fileName, sizeof(fileName))) {
continue;
}
@@ -317,7 +327,7 @@ public:
}
}
return next;
return nextEntry;
}
inline const char* currentEntry() const {
@@ -348,19 +358,28 @@ iterateOverNativeFiles(JNIEnv *env, jlong apkHandle, jstring javaCpuAbi,
return INSTALL_FAILED_INVALID_APK;
}
std::unique_ptr<NativeLibrariesIterator> it(
NativeLibrariesIterator::create(zipFile, debuggable));
if (it.get() == nullptr) {
auto result = NativeLibrariesIterator::create(zipFile, debuggable);
if (!result.ok()) {
return INSTALL_FAILED_INVALID_APK;
}
std::unique_ptr<NativeLibrariesIterator> it(std::move(result.value()));
const ScopedUtfChars cpuAbi(env, javaCpuAbi);
if (cpuAbi.c_str() == nullptr) {
// This would've thrown, so this return code isn't observable by Java.
return INSTALL_FAILED_INVALID_APK;
}
ZipEntryRO entry = nullptr;
while ((entry = it->next()) != nullptr) {
while (true) {
auto next = it->next();
if (!next.ok()) {
return INSTALL_FAILED_INVALID_APK;
}
auto entry = next.value();
if (entry == nullptr) {
break;
}
const char* fileName = it->currentEntry();
const char* lastSlash = it->lastSlash();
@@ -388,11 +407,11 @@ static int findSupportedAbi(JNIEnv* env, jlong apkHandle, jobjectArray supported
return INSTALL_FAILED_INVALID_APK;
}
std::unique_ptr<NativeLibrariesIterator> it(
NativeLibrariesIterator::create(zipFile, debuggable));
if (it.get() == nullptr) {
auto result = NativeLibrariesIterator::create(zipFile, debuggable);
if (!result.ok()) {
return INSTALL_FAILED_INVALID_APK;
}
std::unique_ptr<NativeLibrariesIterator> it(std::move(result.value()));
const int numAbis = env->GetArrayLength(supportedAbisArray);
@@ -402,9 +421,17 @@ static int findSupportedAbi(JNIEnv* env, jlong apkHandle, jobjectArray supported
supportedAbis.emplace_back(env, (jstring)env->GetObjectArrayElement(supportedAbisArray, i));
}
ZipEntryRO entry = nullptr;
int status = NO_NATIVE_LIBRARIES;
while ((entry = it->next()) != nullptr) {
while (true) {
auto next = it->next();
if (!next.ok()) {
return INSTALL_FAILED_INVALID_APK;
}
auto entry = next.value();
if (entry == nullptr) {
break;
}
// We're currently in the lib/ directory of the APK, so it does have some native
// code. We should return INSTALL_FAILED_NO_MATCHING_ABIS if none of the
// libraries match.

View File

@@ -40,17 +40,24 @@ class _ZipEntryRO {
public:
ZipEntry entry;
std::string_view name;
void *cookie;
void *cookie = nullptr;
_ZipEntryRO() : cookie(NULL) {}
_ZipEntryRO() = default;
~_ZipEntryRO() {
EndIteration(cookie);
EndIteration(cookie);
}
android::ZipEntryRO convertToPtr() {
_ZipEntryRO* result = new _ZipEntryRO;
result->entry = std::move(this->entry);
result->name = std::move(this->name);
result->cookie = std::exchange(this->cookie, nullptr);
return result;
}
private:
_ZipEntryRO(const _ZipEntryRO& other);
_ZipEntryRO& operator=(const _ZipEntryRO& other);
DISALLOW_COPY_AND_ASSIGN(_ZipEntryRO);
};
ZipFileRO::~ZipFileRO() {
@@ -94,17 +101,15 @@ ZipFileRO::~ZipFileRO() {
ZipEntryRO ZipFileRO::findEntryByName(const char* entryName) const
{
_ZipEntryRO* data = new _ZipEntryRO;
_ZipEntryRO data;
data.name = entryName;
data->name = entryName;
const int32_t error = FindEntry(mHandle, entryName, &(data->entry));
const int32_t error = FindEntry(mHandle, entryName, &(data.entry));
if (error) {
delete data;
return NULL;
return nullptr;
}
return (ZipEntryRO) data;
return data.convertToPtr();
}
/*
@@ -143,35 +148,50 @@ bool ZipFileRO::getEntryInfo(ZipEntryRO entry, uint16_t* pMethod,
}
bool ZipFileRO::startIteration(void** cookie) {
return startIteration(cookie, NULL, NULL);
return startIteration(cookie, nullptr, nullptr);
}
bool ZipFileRO::startIteration(void** cookie, const char* prefix, const char* suffix)
{
_ZipEntryRO* ze = new _ZipEntryRO;
int32_t error = StartIteration(mHandle, &(ze->cookie),
bool ZipFileRO::startIteration(void** cookie, const char* prefix, const char* suffix) {
auto result = startIterationOrError(prefix, suffix);
if (!result.ok()) {
return false;
}
*cookie = result.value();
return true;
}
base::expected<void*, int32_t>
ZipFileRO::startIterationOrError(const char* prefix, const char* suffix) {
_ZipEntryRO ze;
int32_t error = StartIteration(mHandle, &(ze.cookie),
prefix ? prefix : "", suffix ? suffix : "");
if (error) {
ALOGW("Could not start iteration over %s: %s", mFileName != NULL ? mFileName : "<null>",
ErrorCodeString(error));
delete ze;
return false;
return base::unexpected(error);
}
*cookie = ze;
return true;
return ze.convertToPtr();
}
ZipEntryRO ZipFileRO::nextEntry(void* cookie)
{
ZipEntryRO ZipFileRO::nextEntry(void* cookie) {
auto result = nextEntryOrError(cookie);
if (!result.ok()) {
return nullptr;
}
return result.value();
}
base::expected<ZipEntryRO, int32_t> ZipFileRO::nextEntryOrError(void* cookie) {
_ZipEntryRO* ze = reinterpret_cast<_ZipEntryRO*>(cookie);
int32_t error = Next(ze->cookie, &(ze->entry), &(ze->name));
if (error) {
if (error != -1) {
ALOGW("Error iteration over %s: %s", mFileName != NULL ? mFileName : "<null>",
ErrorCodeString(error));
return base::unexpected(error);
}
return NULL;
return nullptr;
}
return &(ze->entry);

View File

@@ -37,6 +37,8 @@
#include <unistd.h>
#include <time.h>
#include <android-base/expected.h>
#include <util/map_ptr.h>
#include <utils/Compat.h>
@@ -102,6 +104,11 @@ public:
*/
bool startIteration(void** cookie);
bool startIteration(void** cookie, const char* prefix, const char* suffix);
/*
* Same as above, but returns the error code in case of failure.
* #see libziparchive/zip_error.h.
*/
base::expected<void*, int32_t> startIterationOrError(const char* prefix, const char* suffix);
/**
* Return the next entry in iteration order, or NULL if there are no more
@@ -109,6 +116,12 @@ public:
*/
ZipEntryRO nextEntry(void* cookie);
/**
* Same as above, but returns the error code in case of failure.
* #see libziparchive/zip_error.h.
*/
base::expected<ZipEntryRO, int32_t> nextEntryOrError(void* cookie);
void endIteration(void* cookie);
void releaseEntry(ZipEntryRO entry) const;