uid-range: fix out-of-bounds write in uid_range_partition()
uid_range_partition() filled the grown entries[] buffer backwards in
place. The backward-fill invariant (the write cursor stays above the
read index) only holds when every source entry contributes at least
one partition; an entry with nr < size contributes zero, so the cursor
stalls while the read index keeps descending. A later multi-part
entry's writes then overwrite the still-live zero-part slot, the
corrupted slot is re-read as a one-part entry, and the next
range->entries[--t] underflows.
Add a forward compaction first pass that drops the zero-part entries
before the backward fill.
Follow-up for 025439faaa
Co-Authored-by: Paul Meyer <katexochen0@gmail.com>
This commit is contained in:
co-authored by
Paul Meyer
parent
f66144cf2a
commit
d30e87ea49
+11
-2
@@ -395,9 +395,18 @@ int uid_range_partition(UIDRange *range, uid_t size) {
|
||||
if (n_new_entries > range->n_entries && !GREEDY_REALLOC(range->entries, n_new_entries))
|
||||
return -ENOMEM;
|
||||
|
||||
/* Work backwards to avoid overwriting entries we still need to read */
|
||||
/* Compact in place: drop entries that contribute zero partitions (nr < size). This forward pass
|
||||
* reads each entry once and only writes to lower-or-equal indices, so it cannot alias an unread
|
||||
* source entry. */
|
||||
size_t n_src = 0;
|
||||
for (size_t i = 0; i < range->n_entries; i++)
|
||||
if (range->entries[i].nr >= size)
|
||||
range->entries[n_src++] = range->entries[i];
|
||||
|
||||
/* Pre-compaction guarantees every surviving entry contributes at least one partition slot, so the
|
||||
* write cursor t stays ahead of the read index. */
|
||||
size_t t = n_new_entries;
|
||||
for (size_t i = range->n_entries; i > 0; i--) {
|
||||
for (size_t i = n_src; i > 0; i--) {
|
||||
UIDRangeEntry *e = range->entries + i - 1;
|
||||
unsigned n_parts = e->nr / size;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user