From: Joseph Marrero Corchado Date: Wed, 15 Jul 2026 17:22:45 +0000 (-0400) Subject: tests/bsdiff: add content_size guard boundary test X-Git-Tag: archive/raspbian/2026.4-1+rpi1^2~9^2~1^2~15^2 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=4c9a6675e4cc91d6f3541e3db982e049a6113b85;p=ostree.git tests/bsdiff: add content_size guard boundary test Add test_bspatch_content_size_guard to verify the integer truncation guard added for RHEL-189207. The test exercises the exact boundary condition used in dispatch_bspatch(): content_size > G_MAXSIZE || content_size > (guint64)G_MAXINT64 It validates that: - Values with bit 63 set and G_MAXUINT64 are always rejected - On 32-bit systems, values above G_MAXUINT32 (4 GiB) are rejected including the PoC value 0x100001000 (4 GiB + 4 KiB) - Normal values (0, 1, 4096, 1 GiB) are accepted and the casts to gsize and int64_t produce correct values --- diff --git a/tests/test-bsdiff.c b/tests/test-bsdiff.c index 2d6b4722..405ab20e 100644 --- a/tests/test-bsdiff.c +++ b/tests/test-bsdiff.c @@ -92,10 +92,81 @@ test_bsdiff (void) g_assert_cmpint (memcmp (new, new_generated, NEW_SIZE), ==, 0); } +/* Verify the guard condition used in dispatch_bspatch() to prevent integer + * truncation on 32-bit systems (RHEL-189207). The actual guard is: + * if (content_size > G_MAXSIZE || content_size > (guint64)G_MAXINT64) + * + * On 32-bit: G_MAXSIZE == 0xFFFFFFFF, so any content_size >= 4 GiB triggers. + * On 64-bit: G_MAXSIZE == G_MAXUINT64, so only content_size > G_MAXINT64 + * (i.e. bit 63 set) triggers. + * + * This test validates the boundary conditions portably. + */ +static void +test_bspatch_content_size_guard (void) +{ + /* Values that must be rejected by the guard */ + const guint64 reject_values[] = { + (guint64)G_MAXINT64 + 1ULL, /* bit 63 set — always rejected */ + G_MAXUINT64, /* maximum uint64 — always rejected */ + }; + + for (gsize i = 0; i < G_N_ELEMENTS (reject_values); i++) + { + guint64 content_size = reject_values[i]; + gboolean would_reject + = (content_size > G_MAXSIZE || content_size > (guint64)G_MAXINT64); + g_assert_true (would_reject); + } + + /* On 32-bit systems, values above 4 GiB must also be rejected. + * This check is meaningful on 32-bit; on 64-bit it's a tautology + * (the cast fits) but still valid to run. + */ + if (sizeof (gsize) == 4) + { + const guint64 reject_32bit[] = { + (guint64)G_MAXUINT32 + 1ULL, /* 4 GiB — overflows gsize on 32-bit */ + 0x100001000ULL, /* 4 GiB + 4 KiB — the PoC value */ + }; + for (gsize i = 0; i < G_N_ELEMENTS (reject_32bit); i++) + { + guint64 content_size = reject_32bit[i]; + gboolean would_reject + = (content_size > G_MAXSIZE || content_size > (guint64)G_MAXINT64); + g_assert_true (would_reject); + } + } + + /* Values that must be accepted by the guard */ + const guint64 accept_values[] = { + 0, + 1, + 4096, + (guint64)1024 * 1024 * 1024, /* 1 GiB */ + }; + + for (gsize i = 0; i < G_N_ELEMENTS (accept_values); i++) + { + guint64 content_size = accept_values[i]; + gboolean would_reject + = (content_size > G_MAXSIZE || content_size > (guint64)G_MAXINT64); + g_assert_false (would_reject); + + /* Also verify that the casts produce correct values when accepted */ + gsize alloc_size = (gsize)content_size; + int64_t newsize = (int64_t)content_size; + g_assert_cmpuint (alloc_size, ==, content_size); + g_assert_cmpint (newsize, >=, 0); + g_assert_cmpuint ((guint64)newsize, ==, content_size); + } +} + int main (int argc, char **argv) { g_test_init (&argc, &argv, NULL); g_test_add_func ("/bsdiff", test_bsdiff); + g_test_add_func ("/bsdiff/content-size-guard", test_bspatch_content_size_guard); return g_test_run (); }