summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Adam Lesinski <adamlesinski@google.com> 2017-03-03 13:50:21 -0800
committer Adam Lesinski <adamlesinski@google.com> 2017-03-03 14:01:09 -0800
commit136fd0764faf7a588b4a1b479d7a8cc6fe18fcc6 (patch)
tree91f7316861e5d879a627bd00578170791889c528
parent485c0feea53199b1d43db8782073044c846424c4 (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.cpp4
-rw-r--r--libs/androidfw/include/androidfw/Chunk.h4
-rw-r--r--libs/androidfw/include/androidfw/ResourceTypes.h13
-rw-r--r--tools/aapt2/unflatten/BinaryResourceParser.cpp4
-rw-r--r--tools/aapt2/unflatten/ResChunkPullParser.h4
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);