mirror of
https://github.com/RsyncProject/rsync.git
synced 2026-09-12 21:28:25 -04:00
Add t_hashtable_overflow (links the real hashtable.o, sets a realistic --max-alloc, requests an absurd size) and a test asserting hashtable_create now rejects it with RERR_MALLOC instead of under-allocating and crashing on the OOB node access a regressed build would hit. The helper defines its own info_levels/debug_levels (as the other t_* helpers do) for the DEBUG_GTE macro in the linked hashtable.o.
51 lines
2.1 KiB
C
51 lines
2.1 KiB
C
/*
|
|
* Regression harness for the hashtable size*node_size integer overflow
|
|
* (Leonid Bugaev May-2026 re-audit, KI-11/12).
|
|
*
|
|
* hashtable_create() once computed the slot-array byte count as
|
|
* new_array0(char, size * node_size) in 32-bit int arithmetic; for a large
|
|
* peer/data-driven size the product wrapped to a tiny value, under-allocating
|
|
* the table while tbl->size recorded the huge size -- a later node access then
|
|
* ran out of bounds (heap overflow / SEGV). The fix passes size and node_size
|
|
* as separate factors so my_alloc's --max-alloc guard rejects the oversized
|
|
* request, exiting RERR_MALLOC instead of under-allocating.
|
|
*
|
|
* This harness sets a realistic max_alloc (t_stub leaves it at SIZE_MAX) and
|
|
* asks for an absurd size: the fixed code exits RERR_MALLOC; a regressed build
|
|
* under-allocates and crashes on the node access below. Not linked into rsync.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it under
|
|
* the terms of the GNU General Public License version 3 as published by the
|
|
* Free Software Foundation.
|
|
*/
|
|
|
|
#include "rsync.h"
|
|
|
|
extern size_t max_alloc; /* defined in util2.o/t_stub.o */
|
|
short info_levels[COUNT_INFO], debug_levels[COUNT_DEBUG]; /* for DEBUG_GTE in hashtable.o */
|
|
|
|
int main(UNUSED(int argc), UNUSED(char *argv[]))
|
|
{
|
|
struct hashtable *tbl;
|
|
int i;
|
|
|
|
/* A realistic --max-alloc cap (the default is 1 GiB) so my_alloc's guard
|
|
* can engage; t_stub.o leaves max_alloc == SIZE_MAX. */
|
|
max_alloc = (size_t)1024 * 1024 * 1024;
|
|
|
|
/* 2^28 buckets * 16-byte node = 2^32 bytes: the product wraps int to ~0 in
|
|
* the unfixed code. The fix must reject this (exit RERR_MALLOC) rather than
|
|
* under-allocate. */
|
|
tbl = hashtable_create(1 << 28, 0);
|
|
|
|
/* Unreachable with the fix (hashtable_create exits above). If a regression
|
|
* lets it return, touch a node near the claimed end -- an under-allocated
|
|
* table faults here -- and report the unexpected survival as a failure. */
|
|
for (i = 0; i < tbl->size; i += tbl->size / 64 + 1) {
|
|
struct ht_int32_node *node = HT_NODE(tbl, tbl->nodes, i);
|
|
node->key = i;
|
|
}
|
|
fprintf(stderr, "FAIL: hashtable_create(1<<28) was not rejected\n");
|
|
return 1;
|
|
}
|