draw: Allocate extra padding for extra shader outputs.

This prevents read buffer overflows in dup_vertex(), when draw stages
allocate extra shader outputs after the vertex buffers are allocated.

The original issue can be exercised with upcoming
piglit/tests/general/vertex-fallbacks.c test.

Reviewed-by: Roland Scheidegger <sroland@vmware.com>
Cc: 21.0 21.1 <mesa-stable@lists.freedesktop.org>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/10836>
This commit is contained in:
Jose Fonseca
2021-05-14 16:25:32 +01:00
committed by Marge Bot
parent 0df249f542
commit 250605c57d
7 changed files with 49 additions and 12 deletions

View File

@@ -589,7 +589,8 @@ int draw_geometry_shader_run(struct draw_geometry_shader *shader,
output_verts[i].stride = output_verts[i].vertex_size;
output_verts[i].verts =
(struct vertex_header *)MALLOC(output_verts[i].vertex_size *
total_verts_per_buffer * shader->num_invocations);
total_verts_per_buffer * shader->num_invocations +
DRAW_EXTRA_VERTICES_PADDING);
debug_assert(output_verts[i].verts);
}

View File

@@ -76,8 +76,8 @@ boolean draw_alloc_temp_verts( struct draw_stage *stage, unsigned nr )
if (nr != 0)
{
unsigned i;
ubyte *store = (ubyte *) MALLOC( MAX_VERTEX_SIZE * nr );
ubyte *store = (ubyte *) MALLOC( MAX_VERTEX_SIZE * nr +
DRAW_EXTRA_VERTICES_PADDING );
if (!store)
return FALSE;

View File

@@ -268,7 +268,7 @@ draw_prim_assembler_run(struct draw_context *draw,
output_verts->vertex_size = input_verts->vertex_size;
output_verts->stride = input_verts->stride;
output_verts->verts = (struct vertex_header*)MALLOC(
input_verts->vertex_size * max_verts);
input_verts->vertex_size * max_verts + DRAW_EXTRA_VERTICES_PADDING);
output_verts->count = 0;

View File

@@ -59,6 +59,37 @@ struct gallivm_state;
*/
#define DRAW_MAX_FETCH_IDX 0xffffffff
/**
* Maximum number of extra shader outputs. These are allocated by:
* - draw_pipe_aaline.c (1)
* - draw_pipe_aapoint.c (1)
* - draw_pipe_unfilled.c (1)
* - draw_pipe_wide_point.c (up to 32)
* - draw_prim_assembler.c (1)
*/
#define DRAW_MAX_EXTRA_SHADER_OUTPUTS 32
/**
* Despite some efforts to determine the number of extra shader outputs ahead
* of time, the matter of fact is that this number will vary as primitives
* flow through the draw pipeline. In particular, aaline/aapoint stages
* only allocate their extra shader outputs on the first line/point.
*
* Consequently dup_vert() ends up copying vertices larger than those
* allocated.
*
* Ideally we'd keep track of incoming/outgoing vertex sizes (and strides)
* throughout the draw pipeline, but unfortunately we recompute these all over
* the place, so preemptively expanding the vertex stride/size does not work
* as mismatches ensue.
*
* As stopgap to prevent buffer read overflows, we allocate an extra bit of
* padding at the end of temporary vertex buffers, allowing dup_vert() to copy
* more vertex attributes than allocated.
*/
#define DRAW_EXTRA_VERTICES_PADDING \
(DRAW_MAX_EXTRA_SHADER_OUTPUTS * sizeof(float[4]))
struct pipe_context;
struct draw_vertex_shader;
struct draw_context;
@@ -361,9 +392,9 @@ struct draw_context
*/
struct {
uint num;
uint semantic_name[10];
uint semantic_index[10];
uint slot[10];
uint semantic_name[DRAW_MAX_EXTRA_SHADER_OUTPUTS];
uint semantic_index[DRAW_MAX_EXTRA_SHADER_OUTPUTS];
uint slot[DRAW_MAX_EXTRA_SHADER_OUTPUTS];
} extra_shader_outputs;
unsigned instance_id;

View File

@@ -214,7 +214,8 @@ draw_vertex_shader_run(struct draw_vertex_shader *vshader,
output_verts->count = input_verts->count;
output_verts->verts =
(struct vertex_header *)MALLOC(output_verts->vertex_size *
align(output_verts->count, 4));
align(output_verts->count, 4) +
DRAW_EXTRA_VERTICES_PADDING);
vshader->run_linear(vshader,
(const float (*)[4])input_verts->verts->data,
@@ -254,7 +255,8 @@ fetch_pipeline_generic(struct draw_pt_middle_end *middle,
fetched_vert_info.stride = fpme->vertex_size;
fetched_vert_info.verts =
(struct vertex_header *)MALLOC(fpme->vertex_size *
align(fetch_info->count, 4));
align(fetch_info->count, 4) +
DRAW_EXTRA_VERTICES_PADDING);
if (!fetched_vert_info.verts) {
assert(0);
return;

View File

@@ -595,7 +595,8 @@ llvm_pipeline_generic(struct draw_pt_middle_end *middle,
llvm_vert_info.stride = fpme->vertex_size;
llvm_vert_info.verts = (struct vertex_header *)
MALLOC(fpme->vertex_size *
align(fetch_info->count, lp_native_vector_width / 32));
align(fetch_info->count, lp_native_vector_width / 32) +
DRAW_EXTRA_VERTICES_PADDING);
if (!llvm_vert_info.verts) {
assert(0);
return;

View File

@@ -158,7 +158,8 @@ static void PIPE_CDECL vsvg_run_elts( struct draw_vs_variant *variant,
{
struct draw_vs_variant_generic *vsvg = (struct draw_vs_variant_generic *)variant;
unsigned temp_vertex_stride = vsvg->temp_vertex_stride;
void *temp_buffer = MALLOC( align(count,4) * temp_vertex_stride );
void *temp_buffer = MALLOC( align(count,4) * temp_vertex_stride +
DRAW_EXTRA_VERTICES_PADDING );
if (0) debug_printf("%s %d \n", __FUNCTION__, count);
@@ -227,7 +228,8 @@ static void PIPE_CDECL vsvg_run_linear( struct draw_vs_variant *variant,
{
struct draw_vs_variant_generic *vsvg = (struct draw_vs_variant_generic *)variant;
unsigned temp_vertex_stride = vsvg->temp_vertex_stride;
void *temp_buffer = MALLOC( align(count,4) * temp_vertex_stride );
void *temp_buffer = MALLOC( align(count,4) * temp_vertex_stride +
DRAW_EXTRA_VERTICES_PADDING );
if (0) debug_printf("%s %d %d (sz %d, %d)\n", __FUNCTION__, start, count,
vsvg->base.key.output_stride,