Truncate WindowInfo.name during parcelling. This is a mitigation for an exploit of one-way binder call overflow. Bug: 433251166 Test: presubmit Flag: EXEMPT BUGFIX Cherrypick-From: https://googleplex-android-review.googlesource.com/q/commit:03b9ecf49d11630d5992da30265fb03621846ce1 Cherrypick-From: https://googleplex-android-review.googlesource.com/q/commit:1d4bb5d8bef543769e3fef7d4f4bc720696cd7cd Merged-In: I7ed75c7a11e9ca30b2dd1287953b2f0e426c3415 Change-Id: I7ed75c7a11e9ca30b2dd1287953b2f0e426c3415
diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp index 3fb66d1..817ca5e 100644 --- a/libs/gui/WindowInfo.cpp +++ b/libs/gui/WindowInfo.cpp
@@ -28,6 +28,26 @@ namespace { +constexpr size_t kMaxBytesName = 1024; + +// Avoiding pulling in ICU here. +status_t writeUtf8AsUtf16WithTruncation(Parcel* parcel, const std::string& str, size_t max_bytes) { + if (str.size() <= max_bytes) { + return parcel->writeUtf8AsUtf16(str); + } + std::string truncated; + truncated.reserve(max_bytes); + static constexpr std::string_view kTail = "[TRUNC]"; + size_t truncated_length = max_bytes - kTail.size(); + while (truncated_length > 0 && + (static_cast<unsigned char>(str[truncated_length]) & 0xC0) == 0x80) { + truncated_length--; + } + truncated.append(str.substr(0, truncated_length)); + truncated.append(kTail); + return parcel->writeUtf8AsUtf16(truncated); +} + std::ostream& operator<<(std::ostream& out, const sp<IBinder>& binder) { if (binder == nullptr) { out << "<null>"; @@ -147,7 +167,7 @@ status_t status = parcel->writeStrongBinder(token) ?: parcel->writeInt64(dispatchingTimeout.count()) ?: parcel->writeInt32(id) ?: - parcel->writeUtf8AsUtf16(name) ?: + writeUtf8AsUtf16WithTruncation(parcel, name, kMaxBytesName) ?: parcel->writeInt32(layoutParamsFlags.get()) ?: parcel->writeInt32( static_cast<std::underlying_type_t<WindowInfo::Type>>(layoutParamsType)) ?:
diff --git a/libs/gui/tests/WindowInfo_test.cpp b/libs/gui/tests/WindowInfo_test.cpp index e3f9a07..4da653f 100644 --- a/libs/gui/tests/WindowInfo_test.cpp +++ b/libs/gui/tests/WindowInfo_test.cpp
@@ -14,6 +14,7 @@ * limitations under the License. */ +#include <gmock/gmock-matchers.h> #include <gtest/gtest.h> #include <binder/Binder.h> @@ -116,6 +117,34 @@ ASSERT_EQ(i.cloneLayerStackTransform, i2.cloneLayerStackTransform); } +TEST(WindowInfo, ParcelNameTruncation) { + WindowInfo writeInfo; + // Construct a long string with a 3-byte UTF-8 character ('あ') to test truncation. + // 342 characters * 3 bytes/char = 1026 bytes, which is > 1024. + std::string_view c = "あ"; + ASSERT_EQ(3u, c.size()); + std::string longName; + longName.reserve(342 * 3); + for (int i = 0; i < 342; i++) { + longName.append(c); + } + + ASSERT_GT(longName.length(), 1024u); + writeInfo.name = longName; + + Parcel p; + ASSERT_EQ(OK, writeInfo.writeToParcel(&p)); + p.setDataPosition(0); + + WindowInfo readInfo; + ASSERT_EQ(OK, readInfo.readFromParcel(&p)); + + // The name should be truncated to the last valid character boundary at or before 1024 bytes. + // 1024 / 3 = 341.33. So, 341 characters should remain. 341 * 3 = 1023 bytes. + EXPECT_EQ(readInfo.name.length(), 1024u); + EXPECT_THAT(readInfo.name, testing::EndsWith("[TRUNC]")); +} + TEST(InputApplicationInfo, Parcelling) { InputApplicationInfo i; i.token = new BBinder();