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>
(cherry picked from commit
b06f6e00fba6e33c28a198a1bb14b89e9dfbb4ae)
"description": "zink: fix heap-use-after-free on batch_state with sub-allocated pipe_resources",
"nominated": true,
"nomination_type": 0,
- "resolution": 0,
+ "resolution": 1,
"main_sha": null,
"because_sha": null,
"notes": null
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) ||
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);
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))
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);
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;