Limit media-supported values ipphelper parses media-col-ready, media-ready, and media-supported into a fixed-size array. Add a check to make sure crafted Get-Printer-Attributes responses don't run past the end. Bug: 503542266 Test: atest libwfds_ipphelper_test Flag: EXEMPT CVE_FIX Cherrypick-From: https://googleplex-android-review.googlesource.com/q/commit:852c02f88419183d0469e833f232e178cc6f53e0 Cherrypick-From: https://googleplex-android-review.googlesource.com/q/commit:d3e4806a36b4405b977e987bea7f48984a7a4b44 Merged-In: I86726f3cadbde0e08ea6ecc39ca6ad98fa6e579c Change-Id: I86726f3cadbde0e08ea6ecc39ca6ad98fa6e579c
diff --git a/jni/Android.bp b/jni/Android.bp index 971a813..d1fc7bd 100644 --- a/jni/Android.bp +++ b/jni/Android.bp
@@ -15,6 +15,7 @@ package { default_applicable_licenses: ["Android-Apache-2.0"], + default_team: "trendy_team_android_printing", } cc_library_shared { @@ -78,3 +79,40 @@ "server_configurable_flags", ], } + +cc_test { + name: "libwfds_ipphelper_test", + gtest: true, + cflags: [ + "-DINCLUDE_PDF=1", + "-Wno-unused-parameter", + "-Wno-sign-compare", + "-Wno-missing-field-initializers", + "-Wno-format", + "-Wno-missing-braces", + "-Wno-deprecated-declarations", + ], + srcs: [ + "ipphelper/ipphelper_test.cpp", + // Compile the source file directly into the test to access all JNI symbols + "ipphelper/ipphelper.c", + "ipphelper/ipp_print.c", + "ipphelper/ippstatus_capabilities.c", + ], + local_include_dirs: [ + "include", + "ipphelper", + "plugins/genPCLm/inc", + ], + static_libs: [ + "bips_aconfig_flags_cc_lib", + "libjpeg_static_ndk", + ], + shared_libs: [ + "libaconfig_storage_read_api_cc", + "libcups", + "liblog", + "libcutils", + "libz", + ], +}
diff --git a/jni/ipphelper/ipphelper.c b/jni/ipphelper/ipphelper.c index 8ad0447..0229d4f 100644 --- a/jni/ipphelper/ipphelper.c +++ b/jni/ipphelper/ipphelper.c
@@ -1021,6 +1021,9 @@ int *sizes_idx, media_supported_t *media_supported, media_size_t media_size) { + if (sizes_idx == NULL || *sizes_idx >= PAGE_STATUS_MAX) { + return; + } if (idx >= 0) { // Check if we've already added this media size to the supported list bool isDuplicate = false; @@ -1154,7 +1157,7 @@ // Append media-supported. media is de-duplicated later in java if ((attrptr = ippFindAttribute(response, "media-supported", IPP_TAG_KEYWORD)) != NULL) { LOGD("media-supported found; number of values %d", ippGetCount(attrptr)); - for (i = 0; i < ippGetCount(attrptr); i++) { + for (i = 0; i < ippGetCount(attrptr) && sizes_idx < PAGE_STATUS_MAX; i++) { idx = ipp_find_media_size(ippGetString(attrptr, i, NULL), &media_sizeTemp); // Modified since anytime the find media size returned 0 it could either mean
diff --git a/jni/ipphelper/ipphelper_test.cpp b/jni/ipphelper/ipphelper_test.cpp new file mode 100644 index 0000000..bc1c65b --- /dev/null +++ b/jni/ipphelper/ipphelper_test.cpp
@@ -0,0 +1,61 @@ +#include <gtest/gtest.h> +#include <string.h> + +extern "C" { +#include "cups.h" +#include "ipphelper.h" +} + +class IppHelperTest : public ::testing::Test { + protected: + void SetUp() override { memset(&capabilities_, 0, sizeof(capabilities_)); } + + printer_capabilities_t capabilities_; +}; + +TEST_F(IppHelperTest, ParseGetMediaSupported_AvoidsOverflow) { + // Initialize the structure as it would be in parse_printerAttributes + media_supported_t media_supported_; + for (int i = 0; i < PAGE_STATUS_MAX; i++) { + media_supported_.media_size[i] = (media_size_t)0; + media_supported_.idxKeywordTranTable[i] = -1; + } + int canary = 0xffffffff; // Overwritten if media_supported_ overflows. + + // 1. Construct a mock IPP response + ipp_t* response = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES); + ASSERT_NE(response, nullptr); + + // Create 1000 values (exceeding PAGE_STATUS_MAX = 200) + // Use a valid keyword ("na_letter_8.5x11in") so ipp_find_media_size succeeds. + const int num_values = 1000; + const char* values[num_values]; + for (int i = 0; i < num_values; i++) { + values[i] = "na_letter_8.5x11in"; + } + + // Add the "media-supported" attribute with 1000 values to the mock response + ippAddStrings(response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-supported", + num_values, nullptr, values); + + // 2. Call the function under test + // BEFORE the fix: This would trigger a stack buffer overflow / crash. + // AFTER the fix: This should return safely without crashing. + parse_getMediaSupported(response, &media_supported_, &capabilities_); + + // 3. Count updated entries. + int written_count = 0; + for (int i = 0; i < PAGE_STATUS_MAX; i++) { + if (media_supported_.media_size[i] != 0) { + written_count++; + } + } + + // Expect exactly PAGE_STATUS_MAX (200) entries to be written and the canary + // to be intact. + EXPECT_EQ(written_count, PAGE_STATUS_MAX); + EXPECT_EQ(capabilities_.numSupportedMediaReadySizes, 0); + EXPECT_EQ(canary, 0xffffffff); + + ippDelete(response); +}