From b3454e8d7ca8101823b24e2ff7b60a738ff321fd Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Thu, 7 Feb 2013 11:51:52 -0500 Subject: [PATCH] drm/radeon: copy userspace cmd to local copy before processing it In some rare case were packet is big enough to go over page boundary we might not have copied yet the userspace data into the local copy resulting in kernel reading garbage data. Without this patch kernel might submit unprocessed/unrelocated cmd to the GPU which might lead to GPU lockup. Signed-off-by: Jerome Glisse --- drivers/gpu/drm/radeon/evergreen_cs.c | 28 ++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/r600_cs.c | 12 ++++++++++++ 2 files changed, 40 insertions(+) diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c index 32c07bb..695aa42 100644 --- a/drivers/gpu/drm/radeon/evergreen_cs.c +++ b/drivers/gpu/drm/radeon/evergreen_cs.c @@ -1052,6 +1052,8 @@ static int evergreen_cs_packet_parse(struct radeon_cs_parser *p, pkt->idx, pkt->type, pkt->count, ib_chunk->length_dw); return -EINVAL; } + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + pkt->count + 1); return 0; } @@ -2891,6 +2893,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) switch (cmd) { case DMA_PACKET_WRITE: + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 2); r = r600_dma_cs_next_reloc(p, &dst_reloc); if (r) { DRM_ERROR("bad DMA_PACKET_WRITE\n"); @@ -2938,6 +2942,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) switch (sub_cmd) { /* Copy L2L, DW aligned */ case 0x00: + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 4); /* L2L, dw */ src_offset = ib[idx+2]; src_offset |= ((u64)(ib[idx+4] & 0xff)) << 32; @@ -2961,6 +2967,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) break; /* Copy L2T/T2L */ case 0x08: + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 8); /* detile bit */ if (ib[idx + 2] & (1 << 31)) { /* tiled src, linear dst */ @@ -2997,6 +3005,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) break; /* Copy L2L, byte aligned */ case 0x40: + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 4); /* L2L, byte */ src_offset = ib[idx+2]; src_offset |= ((u64)(ib[idx+4] & 0xff)) << 32; @@ -3020,6 +3030,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) break; /* Copy L2L, partial */ case 0x41: + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 8); /* L2L, partial */ if (p->family < CHIP_CAYMAN) { DRM_ERROR("L2L Partial is cayman only !\n"); @@ -3034,6 +3046,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) break; /* Copy L2L, DW aligned, broadcast */ case 0x44: + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 6); /* L2L, dw, broadcast */ r = r600_dma_cs_next_reloc(p, &dst2_reloc); if (r) { @@ -3071,6 +3085,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) break; /* Copy L2T Frame to Field */ case 0x48: + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 9); if (ib[idx + 2] & (1 << 31)) { DRM_ERROR("bad L2T, frame to fields DMA_PACKET_COPY\n"); return -EINVAL; @@ -3109,6 +3125,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) break; /* Copy L2T/T2L, partial */ case 0x49: + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 11); /* L2T, T2L partial */ if (p->family < CHIP_CAYMAN) { DRM_ERROR("L2T, T2L Partial is cayman only !\n"); @@ -3132,6 +3150,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) break; /* Copy L2T broadcast */ case 0x4b: + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 9); /* L2T, broadcast */ if (ib[idx + 2] & (1 << 31)) { DRM_ERROR("bad L2T, broadcast DMA_PACKET_COPY\n"); @@ -3171,6 +3191,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) break; /* Copy L2T/T2L (tile units) */ case 0x4c: + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 8); /* L2T, T2L */ /* detile bit */ if (ib[idx + 2] & (1 << 31)) { @@ -3208,6 +3230,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) break; /* Copy T2T, partial (tile units) */ case 0x4d: + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 12); /* T2T partial */ if (p->family < CHIP_CAYMAN) { DRM_ERROR("L2T, T2L Partial is cayman only !\n"); @@ -3219,6 +3243,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) break; /* Copy L2T broadcast (tile units) */ case 0x4f: + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 9); /* L2T, broadcast */ if (ib[idx + 2] & (1 << 31)) { DRM_ERROR("bad L2T, broadcast DMA_PACKET_COPY\n"); @@ -3262,6 +3288,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) } break; case DMA_PACKET_CONSTANT_FILL: + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 3); r = r600_dma_cs_next_reloc(p, &dst_reloc); if (r) { DRM_ERROR("bad DMA_PACKET_CONSTANT_FILL\n"); diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index f91919e..1e0aa64 100644 --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c @@ -827,6 +827,8 @@ static int r600_cs_packet_parse(struct radeon_cs_parser *p, pkt->idx, pkt->type, pkt->count, ib_chunk->length_dw); return -EINVAL; } + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + pkt->count + 1); return 0; } @@ -2621,12 +2623,16 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p) return -EINVAL; } if (tiled) { + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 4); dst_offset = ib[idx+1]; dst_offset <<= 8; ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8); p->idx += count + 5; } else { + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 2); dst_offset = ib[idx+1]; dst_offset |= ((u64)(ib[idx+2] & 0xff)) << 32; @@ -2652,6 +2658,8 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p) return -EINVAL; } if (tiled) { + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 6); idx_value = radeon_get_ib_value(p, idx + 2); /* detile bit */ if (idx_value & (1 << 31)) { @@ -2677,6 +2685,8 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p) } p->idx += 7; } else { + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 4); src_offset = ib[idx+2]; src_offset |= ((u64)(ib[idx+4] & 0xff)) << 32; dst_offset = ib[idx+1]; @@ -2700,6 +2710,8 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p) } break; case DMA_PACKET_CONSTANT_FILL: + /* make sure we copied packet fully from userspace */ + radeon_get_ib_value(p, idx + 3); if (p->family < CHIP_RV770) { DRM_ERROR("Constant Fill is 7xx only !\n"); return -EINVAL; -- 1.7.11.7