summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Anholt <[email protected]>2014-08-02 21:06:50 -0700
committerEric Anholt <[email protected]>2014-08-11 14:45:32 -0700
commit3aba1b124ffcd4b9a62cbf68744b5d9fe9424ea8 (patch)
treef1485dfc6637719137d47dc78d7ab209a8c90939
parent5692122147ef19591e16f708d158ae014d2f6bfe (diff)
vc4: Add validation that vertex indices don't overflow VBO bounds.
-rw-r--r--src/gallium/drivers/vc4/vc4_simulator_validate.c85
-rw-r--r--src/gallium/drivers/vc4/vc4_simulator_validate.h4
2 files changed, 71 insertions, 18 deletions
diff --git a/src/gallium/drivers/vc4/vc4_simulator_validate.c b/src/gallium/drivers/vc4/vc4_simulator_validate.c
index ff97963cf88..234160d470b 100644
--- a/src/gallium/drivers/vc4/vc4_simulator_validate.c
+++ b/src/gallium/drivers/vc4/vc4_simulator_validate.c
@@ -90,7 +90,6 @@ gl_shader_rec_size(uint32_t pointer_bits)
{
uint32_t attribute_count = pointer_bits & 7;
bool extended = pointer_bits & 8;
- uint32_t size;
if (attribute_count == 0)
attribute_count = 8;
@@ -265,32 +264,60 @@ static int
validate_indexed_prim_list(VALIDATE_ARGS)
{
struct drm_gem_cma_object *ib;
+ uint32_t length = *(uint32_t *)(untrusted + 1);
+ uint32_t offset = *(uint32_t *)(untrusted + 5);
uint32_t max_index = *(uint32_t *)(untrusted + 9);
uint32_t index_size = (*(uint8_t *)(untrusted + 0) >> 4) ? 2 : 1;
- uint32_t ib_access_end = (max_index + 1) * index_size;
+ struct vc4_shader_state *shader_state;
/* Check overflow condition */
- if (max_index == ~0) {
- DRM_ERROR("unlimited max index\n");
+ if (exec->shader_state_count == 0) {
+ DRM_ERROR("shader state must precede primitives\n");
return -EINVAL;
}
+ shader_state = &exec->shader_state[exec->shader_state_count - 1];
- if (ib_access_end < max_index) {
- DRM_ERROR("IB access overflow\n");
+ if (max_index > shader_state->max_index)
+ shader_state->max_index = max_index;
+
+ if (!vc4_use_handle(exec, 0, VC4_MODE_RENDER, &ib))
+ return -EINVAL;
+
+ if (offset > ib->base.size ||
+ (ib->base.size - offset) / index_size < length) {
+ DRM_ERROR("IB access overflow (%d + %d*%d > %d)\n",
+ offset, length, index_size, ib->base.size);
return -EINVAL;
}
+ *(uint32_t *)(validated + 5) = ib->paddr + offset;
- if (!vc4_use_handle(exec, 0, VC4_MODE_RENDER, &ib))
+ return 0;
+}
+
+static int
+validate_gl_array_primitive(VALIDATE_ARGS)
+{
+ uint32_t length = *(uint32_t *)(untrusted + 1);
+ uint32_t base_index = *(uint32_t *)(untrusted + 5);
+ uint32_t max_index;
+ struct vc4_shader_state *shader_state;
+
+ /* Check overflow condition */
+ if (exec->shader_state_count == 0) {
+ DRM_ERROR("shader state must precede primitives\n");
return -EINVAL;
- if (ib_access_end > ib->base.size) {
- DRM_ERROR("IB access out of bounds (%d/%d)\n",
- ib_access_end, ib->base.size);
+ }
+ shader_state = &exec->shader_state[exec->shader_state_count - 1];
+
+ if (length + base_index < length) {
+ DRM_ERROR("primitive vertex count overflow\n");
return -EINVAL;
}
+ max_index = length + base_index - 1;
- *(uint32_t *)(validated + 5) =
- *(uint32_t *)(untrusted + 5) + ib->paddr;
+ if (max_index > shader_state->max_index)
+ shader_state->max_index = max_index;
return 0;
}
@@ -300,13 +327,14 @@ validate_gl_shader_state(VALIDATE_ARGS)
{
uint32_t i = exec->shader_state_count++;
- if (i >= exec->shader_state_size) { /* XXX? */
+ if (i >= exec->shader_state_size) {
DRM_ERROR("More requests for shader states than declared\n");
return -EINVAL;
}
exec->shader_state[i].packet = VC4_PACKET_GL_SHADER_STATE;
exec->shader_state[i].addr = *(uint32_t *)untrusted;
+ exec->shader_state[i].max_index = 0;
if (exec->shader_state[i].addr & ~0xf) {
DRM_ERROR("high bits set in GL shader rec reference\n");
@@ -537,8 +565,7 @@ static const struct cmd_info {
[VC4_PACKET_GL_INDEXED_PRIMITIVE] = { 1, 1, 14, "Indexed Primitive List", validate_indexed_prim_list },
- /* XXX: bounds check verts? */
- [VC4_PACKET_GL_ARRAY_PRIMITIVE] = { 1, 1, 10, "Vertex Array Primitives", NULL },
+ [VC4_PACKET_GL_ARRAY_PRIMITIVE] = { 1, 1, 10, "Vertex Array Primitives", validate_gl_array_primitive },
[VC4_PACKET_PRIMITIVE_LIST_FORMAT] = { 1, 1, 2, "primitive list format", NULL }, /* XXX: bin valid? */
@@ -824,10 +851,32 @@ validate_shader_rec(struct drm_device *dev,
}
for (i = 0; i < nr_attributes; i++) {
- /* XXX: validation */
+ struct drm_gem_cma_object *vbo = bo[nr_fixed_relocs + i];
uint32_t o = 36 + i * 8;
- *(uint32_t *)(pkt_v + o) = (bo[nr_fixed_relocs + i]->paddr +
- *(uint32_t *)(pkt_u + o));
+ uint32_t offset = *(uint32_t *)(pkt_u + o + 0);
+ uint32_t attr_size = *(uint8_t *)(pkt_u + o + 4) + 1;
+ uint32_t stride = *(uint8_t *)(pkt_u + o + 5);
+ uint32_t max_index;
+
+ if (state->addr & 0x8)
+ stride |= (*(uint32_t *)(pkt_u + 100 + i * 4)) & ~0xff;
+
+ if (vbo->base.size < offset ||
+ vbo->base.size - offset < attr_size ||
+ stride == 0) {
+ DRM_ERROR("BO offset overflow (%d + %d > %d)\n",
+ offset, attr_size, vbo->base.size);
+ return -EINVAL;
+ }
+
+ max_index = (vbo->base.size - offset - attr_size) / stride;
+ if (state->max_index > max_index) {
+ DRM_ERROR("primitives use index %d out of supplied %d\n",
+ state->max_index, max_index);
+ return -EINVAL;
+ }
+
+ *(uint32_t *)(pkt_v + o) = vbo->paddr + offset;
}
kfree(validated_shader);
diff --git a/src/gallium/drivers/vc4/vc4_simulator_validate.h b/src/gallium/drivers/vc4/vc4_simulator_validate.h
index 42701244b13..8b74df2bdad 100644
--- a/src/gallium/drivers/vc4/vc4_simulator_validate.h
+++ b/src/gallium/drivers/vc4/vc4_simulator_validate.h
@@ -111,6 +111,10 @@ struct exec_info {
struct vc4_shader_state {
uint8_t packet;
uint32_t addr;
+ /* Maximum vertex index referenced by any primitive using this
+ * shader state.
+ */
+ uint32_t max_index;
} *shader_state;
/** How many shader states the user declared they were using. */