diff options
author | Aidan MacDonald <amachronic@protonmail.com> | 2022-03-28 21:59:43 +0100 |
---|---|---|
committer | Aidan MacDonald <amachronic@protonmail.com> | 2022-09-19 15:09:51 -0400 |
commit | c8365b2bddbdb85a983efcab0485cb8587b90bb2 (patch) | |
tree | 03f91a29a0491a60e24914d4f6561b195d910311 /firmware | |
parent | 4d3bf1c446a7d1d2f85d368dfff70fcedfb5e045 (diff) | |
download | rockbox-c8365b2bddbdb85a983efcab0485cb8587b90bb2.tar.gz rockbox-c8365b2bddbdb85a983efcab0485cb8587b90bb2.zip |
buflib: fix bug in handle_table_shrink
The way it iterated over the handle table is unsafe if *every*
handle is free, leading to an out of bounds access.
This is a contrived example, but the bug can be triggered by
making several allocations, freeing them out of order so that
the handle table remains uncompacted, and then triggering a
compaction using buflib_alloc_maximum().
Change-Id: I879e2f0b223e6ca596769610ac46f4edf1107f5c
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/buflib.c | 16 |
1 files changed, 9 insertions, 7 deletions
diff --git a/firmware/buflib.c b/firmware/buflib.c index eccf8b057e..5b837aa439 100644 --- a/firmware/buflib.c +++ b/firmware/buflib.c | |||
@@ -247,18 +247,20 @@ union buflib_data* handle_to_block(struct buflib_context* ctx, int handle) | |||
247 | /* Shrink the handle table, returning true if its size was reduced, false if | 247 | /* Shrink the handle table, returning true if its size was reduced, false if |
248 | * not | 248 | * not |
249 | */ | 249 | */ |
250 | static inline | 250 | static inline bool handle_table_shrink(struct buflib_context *ctx) |
251 | bool | ||
252 | handle_table_shrink(struct buflib_context *ctx) | ||
253 | { | 251 | { |
254 | bool rv; | ||
255 | union buflib_data *handle; | 252 | union buflib_data *handle; |
256 | for (handle = ctx->last_handle; !(handle->alloc); handle++); | 253 | union buflib_data *old_last = ctx->last_handle; |
254 | |||
255 | for (handle = ctx->last_handle; handle != ctx->handle_table; ++handle) | ||
256 | if (handle->alloc) | ||
257 | break; | ||
258 | |||
257 | if (handle > ctx->first_free_handle) | 259 | if (handle > ctx->first_free_handle) |
258 | ctx->first_free_handle = handle - 1; | 260 | ctx->first_free_handle = handle - 1; |
259 | rv = handle != ctx->last_handle; | 261 | |
260 | ctx->last_handle = handle; | 262 | ctx->last_handle = handle; |
261 | return rv; | 263 | return handle != old_last; |
262 | } | 264 | } |
263 | 265 | ||
264 | 266 | ||