diff options
| author | 2017-03-03 13:50:21 -0800 | |
|---|---|---|
| committer | 2017-03-03 14:01:09 -0800 | |
| commit | 136fd0764faf7a588b4a1b479d7a8cc6fe18fcc6 (patch) | |
| tree | 91f7316861e5d879a627bd00578170791889c528 | |
| parent | 485c0feea53199b1d43db8782073044c846424c4 (diff) | |
AAPT2: Fix parsing ResTable_type
ResTable_type's size changes due to it containing
ResTable_config. Make sure we check for the minimum size
required to read it.
Bug: 35861796
Test: Manual (don't have an integration test harness setup yet)
Change-Id: Ifb0cd1d732625f59835c8ed0449adb78129636de
| -rw-r--r-- | libs/androidfw/LoadedArsc.cpp | 4 | ||||
| -rw-r--r-- | libs/androidfw/include/androidfw/Chunk.h | 4 | ||||
| -rw-r--r-- | libs/androidfw/include/androidfw/ResourceTypes.h | 13 | ||||
| -rw-r--r-- | tools/aapt2/unflatten/BinaryResourceParser.cpp | 4 | ||||
| -rw-r--r-- | tools/aapt2/unflatten/ResChunkPullParser.h | 4 |
5 files changed, 20 insertions, 9 deletions
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp index db72f487d52b..621d8c0e96f0 100644 --- a/libs/androidfw/LoadedArsc.cpp +++ b/libs/androidfw/LoadedArsc.cpp @@ -212,7 +212,7 @@ const LoadedPackage* LoadedArsc::GetPackageForId(uint32_t resid) const { static bool VerifyType(const Chunk& chunk) { ATRACE_CALL(); - const ResTable_type* header = chunk.header<ResTable_type>(); + const ResTable_type* header = chunk.header<ResTable_type, kResTableTypeMinSize>(); const size_t entry_count = dtohl(header->entryCount); if (entry_count > std::numeric_limits<uint16_t>::max()) { @@ -533,7 +533,7 @@ std::unique_ptr<LoadedPackage> LoadedPackage::Load(const Chunk& chunk) { } break; case RES_TABLE_TYPE_TYPE: { - const ResTable_type* type = child_chunk.header<ResTable_type>(); + const ResTable_type* type = child_chunk.header<ResTable_type, kResTableTypeMinSize>(); if (type == nullptr) { LOG(ERROR) << "Chunk RES_TABLE_TYPE_TYPE is too small."; return {}; diff --git a/libs/androidfw/include/androidfw/Chunk.h b/libs/androidfw/include/androidfw/Chunk.h index e87b94087450..89b588e2b2e9 100644 --- a/libs/androidfw/include/androidfw/Chunk.h +++ b/libs/androidfw/include/androidfw/Chunk.h @@ -48,9 +48,9 @@ class Chunk { // Returns the size of the header. Caller need not worry about endianness. inline size_t header_size() const { return dtohs(device_chunk_->headerSize); } - template <typename T> + template <typename T, size_t MinSize = sizeof(T)> inline const T* header() const { - if (header_size() >= sizeof(T)) { + if (header_size() >= MinSize) { return reinterpret_cast<const T*>(device_chunk_); } return nullptr; diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h index d982a353b013..306ff9a7c42c 100644 --- a/libs/androidfw/include/androidfw/ResourceTypes.h +++ b/libs/androidfw/include/androidfw/ResourceTypes.h @@ -1391,11 +1391,20 @@ struct ResTable_type // Offset from header where ResTable_entry data starts. uint32_t entriesStart; - - // Configuration this collection of entries is designed for. + + // Configuration this collection of entries is designed for. This must always be last. ResTable_config config; }; +// The minimum size required to read any version of ResTable_type. +constexpr size_t kResTableTypeMinSize = + sizeof(ResTable_type) - sizeof(ResTable_config) + sizeof(ResTable_config::size); + +// Assert that the ResTable_config is always the last field. This poses a problem for extending +// ResTable_type in the future, as ResTable_config is variable (over different releases). +static_assert(sizeof(ResTable_type) == offsetof(ResTable_type, config) + sizeof(ResTable_config), + "ResTable_config must be last field in ResTable_type"); + /** * An entry in a ResTable_type with the flag `FLAG_SPARSE` set. */ diff --git a/tools/aapt2/unflatten/BinaryResourceParser.cpp b/tools/aapt2/unflatten/BinaryResourceParser.cpp index 9158bddfb193..66bcfa034dfb 100644 --- a/tools/aapt2/unflatten/BinaryResourceParser.cpp +++ b/tools/aapt2/unflatten/BinaryResourceParser.cpp @@ -313,7 +313,9 @@ bool BinaryResourceParser::ParseType(const ResourceTablePackage* package, return false; } - const ResTable_type* type = ConvertTo<ResTable_type>(chunk); + // Specify a manual size, because ResTable_type contains ResTable_config, which changes + // a lot and has its own code to handle variable size. + const ResTable_type* type = ConvertTo<ResTable_type, kResTableTypeMinSize>(chunk); if (!type) { context_->GetDiagnostics()->Error(DiagMessage(source_) << "corrupt ResTable_type chunk"); diff --git a/tools/aapt2/unflatten/ResChunkPullParser.h b/tools/aapt2/unflatten/ResChunkPullParser.h index 437fc5c8a9b6..58277531034c 100644 --- a/tools/aapt2/unflatten/ResChunkPullParser.h +++ b/tools/aapt2/unflatten/ResChunkPullParser.h @@ -78,9 +78,9 @@ class ResChunkPullParser { std::string error_; }; -template <typename T> +template <typename T, size_t MinSize = sizeof(T)> inline static const T* ConvertTo(const android::ResChunk_header* chunk) { - if (util::DeviceToHost16(chunk->headerSize) < sizeof(T)) { + if (util::DeviceToHost16(chunk->headerSize) < MinSize) { return nullptr; } return reinterpret_cast<const T*>(chunk); |