drm/radeon: add more UVD CS checking

Improve error handling in case userspace sends us
an invalid command buffer.

Signed-off-by: Christian König <christian.koenig@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Christian König 2013-08-05 14:10:57 +02:00 committed by Alex Deucher
parent 641a00593f
commit 56cc2c1538

View File

@ -357,8 +357,10 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo,
} }
r = radeon_bo_kmap(bo, &ptr); r = radeon_bo_kmap(bo, &ptr);
if (r) if (r) {
DRM_ERROR("Failed mapping the UVD message (%d)!\n", r);
return r; return r;
}
msg = ptr + offset; msg = ptr + offset;
@ -384,8 +386,14 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo,
radeon_bo_kunmap(bo); radeon_bo_kunmap(bo);
return 0; return 0;
} else { } else {
/* it's a create msg, no special handling needed */
radeon_bo_kunmap(bo); radeon_bo_kunmap(bo);
if (msg_type != 0) {
DRM_ERROR("Illegal UVD message type (%d)!\n", msg_type);
return -EINVAL;
}
/* it's a create msg, no special handling needed */
} }
/* create or decode, validate the handle */ /* create or decode, validate the handle */
@ -408,7 +416,7 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo,
static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p, static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p,
int data0, int data1, int data0, int data1,
unsigned buf_sizes[]) unsigned buf_sizes[], bool *has_msg_cmd)
{ {
struct radeon_cs_chunk *relocs_chunk; struct radeon_cs_chunk *relocs_chunk;
struct radeon_cs_reloc *reloc; struct radeon_cs_reloc *reloc;
@ -437,7 +445,7 @@ static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p,
if (cmd < 0x4) { if (cmd < 0x4) {
if ((end - start) < buf_sizes[cmd]) { if ((end - start) < buf_sizes[cmd]) {
DRM_ERROR("buffer to small (%d / %d)!\n", DRM_ERROR("buffer (%d) to small (%d / %d)!\n", cmd,
(unsigned)(end - start), buf_sizes[cmd]); (unsigned)(end - start), buf_sizes[cmd]);
return -EINVAL; return -EINVAL;
} }
@ -462,9 +470,17 @@ static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p,
} }
if (cmd == 0) { if (cmd == 0) {
if (*has_msg_cmd) {
DRM_ERROR("More than one message in a UVD-IB!\n");
return -EINVAL;
}
*has_msg_cmd = true;
r = radeon_uvd_cs_msg(p, reloc->robj, offset, buf_sizes); r = radeon_uvd_cs_msg(p, reloc->robj, offset, buf_sizes);
if (r) if (r)
return r; return r;
} else if (!*has_msg_cmd) {
DRM_ERROR("Message needed before other commands are send!\n");
return -EINVAL;
} }
return 0; return 0;
@ -473,7 +489,8 @@ static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p,
static int radeon_uvd_cs_reg(struct radeon_cs_parser *p, static int radeon_uvd_cs_reg(struct radeon_cs_parser *p,
struct radeon_cs_packet *pkt, struct radeon_cs_packet *pkt,
int *data0, int *data1, int *data0, int *data1,
unsigned buf_sizes[]) unsigned buf_sizes[],
bool *has_msg_cmd)
{ {
int i, r; int i, r;
@ -487,7 +504,8 @@ static int radeon_uvd_cs_reg(struct radeon_cs_parser *p,
*data1 = p->idx; *data1 = p->idx;
break; break;
case UVD_GPCOM_VCPU_CMD: case UVD_GPCOM_VCPU_CMD:
r = radeon_uvd_cs_reloc(p, *data0, *data1, buf_sizes); r = radeon_uvd_cs_reloc(p, *data0, *data1,
buf_sizes, has_msg_cmd);
if (r) if (r)
return r; return r;
break; break;
@ -508,6 +526,9 @@ int radeon_uvd_cs_parse(struct radeon_cs_parser *p)
struct radeon_cs_packet pkt; struct radeon_cs_packet pkt;
int r, data0 = 0, data1 = 0; int r, data0 = 0, data1 = 0;
/* does the IB has a msg command */
bool has_msg_cmd = false;
/* minimum buffer sizes */ /* minimum buffer sizes */
unsigned buf_sizes[] = { unsigned buf_sizes[] = {
[0x00000000] = 2048, [0x00000000] = 2048,
@ -534,8 +555,8 @@ int radeon_uvd_cs_parse(struct radeon_cs_parser *p)
return r; return r;
switch (pkt.type) { switch (pkt.type) {
case RADEON_PACKET_TYPE0: case RADEON_PACKET_TYPE0:
r = radeon_uvd_cs_reg(p, &pkt, &data0, r = radeon_uvd_cs_reg(p, &pkt, &data0, &data1,
&data1, buf_sizes); buf_sizes, &has_msg_cmd);
if (r) if (r)
return r; return r;
break; break;
@ -547,6 +568,12 @@ int radeon_uvd_cs_parse(struct radeon_cs_parser *p)
return -EINVAL; return -EINVAL;
} }
} while (p->idx < p->chunks[p->chunk_ib_idx].length_dw); } while (p->idx < p->chunks[p->chunk_ib_idx].length_dw);
if (!has_msg_cmd) {
DRM_ERROR("UVD-IBs need a msg command!\n");
return -EINVAL;
}
return 0; return 0;
} }