zink: fix heap-use-after-free on batch_state with sub-allocated pipe_resources

zink_bo_create can run into a heap-use-after-free when the bo is still
referencing an batch_state from an older destroyed context. In order to
fix this, every context gives back their batch_states to the zink, where
they can be reused from for new contexts.

Cc: mesa-stable
Suggested-by: Mike Blumenkrantz <michael.blumenkrantz@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/26889>
This commit is contained in:
Karol Herbst
2024-01-04 02:42:16 +01:00
committed by Marge Bot
parent e2a7c877ad
commit b06f6e00fb
4 changed files with 50 additions and 2 deletions

View File

@@ -446,6 +446,18 @@ get_batch_state(struct zink_context *ctx, struct zink_batch *batch)
if (bs == ctx->last_free_batch_state)
ctx->last_free_batch_state = NULL;
}
/* try from the ones that are given back to the screen next */
if (!bs) {
simple_mtx_lock(&screen->free_batch_states_lock);
if (screen->free_batch_states) {
bs = screen->free_batch_states;
bs->ctx = ctx;
screen->free_batch_states = bs->next;
if (bs == screen->last_free_batch_state)
screen->last_free_batch_state = NULL;
}
simple_mtx_unlock(&screen->free_batch_states_lock);
}
if (!bs && ctx->batch_states) {
/* states are stored sequentially, so if the first one doesn't work, none of them will */
if (zink_screen_check_last_finished(screen, ctx->batch_states->fence.batch_id) ||

View File

@@ -162,16 +162,41 @@ zink_context_destroy(struct pipe_context *pctx)
while (bs) {
struct zink_batch_state *bs_next = bs->next;
zink_clear_batch_state(ctx, bs);
zink_batch_state_destroy(screen, bs);
/* restore link as we insert them into the screens free_batch_states
* list below
*/
bs->next = bs_next;
bs = bs_next;
}
bs = ctx->free_batch_states;
while (bs) {
struct zink_batch_state *bs_next = bs->next;
zink_clear_batch_state(ctx, bs);
zink_batch_state_destroy(screen, bs);
/* restore link as we insert them into the screens free_batch_states
* list below
*/
bs->next = bs_next;
bs = bs_next;
}
simple_mtx_lock(&screen->free_batch_states_lock);
if (ctx->batch_states) {
if (screen->free_batch_states)
screen->last_free_batch_state->next = ctx->batch_states;
else {
screen->free_batch_states = ctx->batch_states;
screen->last_free_batch_state = screen->free_batch_states;
}
while (screen->last_free_batch_state->next)
screen->last_free_batch_state = screen->last_free_batch_state->next;
}
if (ctx->free_batch_states) {
if (screen->free_batch_states)
screen->last_free_batch_state->next = ctx->free_batch_states;
else
screen->free_batch_states = ctx->free_batch_states;
screen->last_free_batch_state = ctx->last_free_batch_state;
}
simple_mtx_unlock(&screen->free_batch_states_lock);
if (ctx->batch.state) {
zink_clear_batch_state(ctx, ctx->batch.state);
zink_batch_state_destroy(screen, ctx->batch.state);

View File

@@ -1463,6 +1463,12 @@ static void
zink_destroy_screen(struct pipe_screen *pscreen)
{
struct zink_screen *screen = zink_screen(pscreen);
struct zink_batch_state *bs = screen->free_batch_states;
while (bs) {
struct zink_batch_state *bs_next = bs->next;
zink_batch_state_destroy(screen, bs);
bs = bs_next;
}
#ifdef HAVE_RENDERDOC_APP_H
if (screen->renderdoc_capture_all && p_atomic_dec_zero(&num_screens))
@@ -3498,6 +3504,7 @@ zink_internal_create_screen(const struct pipe_screen_config *config, int64_t dev
screen->base_descriptor_size = MAX4(screen->db_size[0], screen->db_size[1], screen->db_size[2], screen->db_size[3]);
}
simple_mtx_init(&screen->free_batch_states_lock, mtx_plain);
simple_mtx_init(&screen->dt_lock, mtx_plain);
util_idalloc_mt_init_tc(&screen->buffer_ids);

View File

@@ -1416,6 +1416,10 @@ struct zink_screen {
simple_mtx_t copy_context_lock;
struct zink_context *copy_context;
struct zink_batch_state *free_batch_states; //unused batch states
struct zink_batch_state *last_free_batch_state; //for appending
simple_mtx_t free_batch_states_lock;
simple_mtx_t semaphores_lock;
struct util_dynarray semaphores;
struct util_dynarray fd_semaphores;