Added decoding of truncated AAPT string lengths.
AAPT incorrectly writes a truncated string length when the string size
exceeded the maximum possible encode length value (0x7FFF). To decode a
truncated length, this change iterates through length values that end
in the encode length bits. Strings that exceed the maximum encode length
are not placed into StringPools in AAPT2.
Test: Successfully ran broken apps from the duplicates of the bugs
provided and created tests
Bug: 69320870
Change-Id: I99dd9b63e91ac250f81d5dfc26b7c0e6276ae162
(cherry picked from commit ea9e8b447a5d24d1b199507dac203c69d81736e2)
diff --git a/libs/androidfw/tests/ResTable_test.cpp b/libs/androidfw/tests/ResTable_test.cpp
index 2df4130..326474e 100644
--- a/libs/androidfw/tests/ResTable_test.cpp
+++ b/libs/androidfw/tests/ResTable_test.cpp
@@ -424,4 +424,56 @@
EXPECT_EQ(1, std::count(locales.begin(), locales.end(), String8("sv")));
}
+TEST(ResTableTest, TruncatedEncodeLength) {
+ std::string contents;
+ ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/length_decode/length_decode_valid.apk",
+ "resources.arsc", &contents));
+
+ ResTable table;
+ ASSERT_EQ(NO_ERROR, table.add(contents.data(), contents.size()));
+
+ Res_value val;
+ ssize_t block = table.getResource(0x7f010001, &val, MAY_NOT_BE_BAG);
+ ASSERT_GE(block, 0);
+ ASSERT_EQ(Res_value::TYPE_STRING, val.dataType);
+
+ const ResStringPool* pool = table.getTableStringBlock(block);
+ ASSERT_TRUE(pool != NULL);
+ ASSERT_LT(val.data, pool->size());
+
+ // Make sure a string with a truncated length is read to its correct length
+ size_t str_len;
+ const char* target_str8 = pool->string8At(val.data, &str_len);
+ ASSERT_TRUE(target_str8 != NULL);
+ ASSERT_EQ(size_t(40076), String8(target_str8, str_len).size());
+ ASSERT_EQ(target_str8[40075], ']');
+
+ const char16_t* target_str16 = pool->stringAt(val.data, &str_len);
+ ASSERT_TRUE(target_str16 != NULL);
+ ASSERT_EQ(size_t(40076), String16(target_str16, str_len).size());
+ ASSERT_EQ(target_str8[40075], (char16_t) ']');
+
+ // Load an edited apk with the null terminator removed from the end of the
+ // string
+ std::string invalid_contents;
+ ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/length_decode/length_decode_invalid.apk",
+ "resources.arsc", &invalid_contents));
+ ResTable invalid_table;
+ ASSERT_EQ(NO_ERROR, invalid_table.add(invalid_contents.data(), invalid_contents.size()));
+
+ Res_value invalid_val;
+ ssize_t invalid_block = invalid_table.getResource(0x7f010001, &invalid_val, MAY_NOT_BE_BAG);
+ ASSERT_GE(invalid_block, 0);
+ ASSERT_EQ(Res_value::TYPE_STRING, invalid_val.dataType);
+
+ const ResStringPool* invalid_pool = invalid_table.getTableStringBlock(invalid_block);
+ ASSERT_TRUE(invalid_pool != NULL);
+ ASSERT_LT(invalid_val.data, invalid_pool->size());
+
+ // Make sure a string with a truncated length that is not null terminated errors
+ // and does not return the string
+ ASSERT_TRUE(invalid_pool->string8At(invalid_val.data, &str_len) == NULL);
+ ASSERT_TRUE(invalid_pool->stringAt(invalid_val.data, &str_len) == NULL);
+}
+
} // namespace android