[PATCH] drm/radeon: copy userspace cmd to local copy before processing it v3

Alex Deucher alexdeucher at gmail.com
Fri Feb 8 15:15:10 PST 2013


On Fri, Feb 8, 2013 at 6:13 PM,  <j.glisse at gmail.com> wrote:
> From: Jerome Glisse <jglisse at redhat.com>
>
> 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.
>
> v2: Make sure we do copy all the page and don't forget some when
>     the packet count dw is bigger than 1 page
> v3: Rebase patch against Linus master
>
> Signed-off-by: Jerome Glisse <jglisse at redhat.com>

Reviewed-by: Alex Deucher <alexander.deucher at amd.com>

> ---
>  drivers/gpu/drm/radeon/evergreen_cs.c | 35 ++++++++++++++++++++++++++++++++++-
>  drivers/gpu/drm/radeon/r600_cs.c      | 19 ++++++++++++++++++-
>  2 files changed, 52 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c
> index 7a44566..51ad74a 100644
> --- a/drivers/gpu/drm/radeon/evergreen_cs.c
> +++ b/drivers/gpu/drm/radeon/evergreen_cs.c
> @@ -1021,7 +1021,7 @@ static int evergreen_cs_packet_parse(struct radeon_cs_parser *p,
>                               unsigned idx)
>  {
>         struct radeon_cs_chunk *ib_chunk = &p->chunks[p->chunk_ib_idx];
> -       uint32_t header;
> +       uint32_t header, i, npages;
>
>         if (idx >= ib_chunk->length_dw) {
>                 DRM_ERROR("Can not parse packet at %d after CS end %d !\n",
> @@ -1052,6 +1052,11 @@ 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 */
> +       npages = ((idx + pkt->count + 1) >> 10) - (idx >> 10);
> +       for (i = 1; i <= npages; i++) {
> +               radeon_get_ib_value(p, (idx & 0xfffffc00) + i * 0x400);
> +       }
>         return 0;
>  }
>
> @@ -2909,12 +2914,16 @@ int evergreen_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);
>                                 dst_offset = ib[idx+1];
>                                 dst_offset <<= 8;
>
>                                 ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8);
>                                 p->idx += count + 7;
>                         } 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;
>
> @@ -2945,6 +2954,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
>                                         switch (misc) {
>                                         case 0:
>                                                 /* L2T, frame to fields */
> +                                               /* make sure we copied packet fully from userspace */
> +                                               radeon_get_ib_value(p, idx + 9);
>                                                 if (idx_value & (1 << 31)) {
>                                                         DRM_ERROR("bad L2T, frame to fields DMA_PACKET_COPY\n");
>                                                         return -EINVAL;
> @@ -2983,6 +2994,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
>                                                 break;
>                                         case 1:
>                                                 /* L2T, T2L partial */
> +                                               /* make sure we copied packet fully from userspace */
> +                                               radeon_get_ib_value(p, idx + 11);
>                                                 if (p->family < CHIP_CAYMAN) {
>                                                         DRM_ERROR("L2T, T2L Partial is cayman only !\n");
>                                                         return -EINVAL;
> @@ -3005,6 +3018,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
>                                                 break;
>                                         case 3:
>                                                 /* L2T, broadcast */
> +                                               /* make sure we copied packet fully from userspace */
> +                                               radeon_get_ib_value(p, idx + 9);
>                                                 if (idx_value & (1 << 31)) {
>                                                         DRM_ERROR("bad L2T, broadcast DMA_PACKET_COPY\n");
>                                                         return -EINVAL;
> @@ -3043,6 +3058,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
>                                                 break;
>                                         case 4:
>                                                 /* L2T, T2L */
> +                                               /* make sure we copied packet fully from userspace */
> +                                               radeon_get_ib_value(p, idx + 8);
>                                                 /* detile bit */
>                                                 if (idx_value & (1 << 31)) {
>                                                         /* tiled src, linear dst */
> @@ -3079,6 +3096,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
>                                                 break;
>                                         case 5:
>                                                 /* T2T partial */
> +                                               /* make sure we copied packet fully from userspace */
> +                                               radeon_get_ib_value(p, idx + 12);
>                                                 if (p->family < CHIP_CAYMAN) {
>                                                         DRM_ERROR("L2T, T2L Partial is cayman only !\n");
>                                                         return -EINVAL;
> @@ -3089,6 +3108,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
>                                                 break;
>                                         case 7:
>                                                 /* L2T, broadcast */
> +                                               /* make sure we copied packet fully from userspace */
> +                                               radeon_get_ib_value(p, idx + 9);
>                                                 if (idx_value & (1 << 31)) {
>                                                         DRM_ERROR("bad L2T, broadcast DMA_PACKET_COPY\n");
>                                                         return -EINVAL;
> @@ -3132,6 +3153,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
>                                 } else {
>                                         switch (misc) {
>                                         case 0:
> +                                               /* make sure we copied packet fully from userspace */
> +                                               radeon_get_ib_value(p, idx + 8);
>                                                 /* detile bit */
>                                                 if (idx_value & (1 << 31)) {
>                                                         /* tiled src, linear dst */
> @@ -3176,6 +3199,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
>                                         switch (misc) {
>                                         case 0:
>                                                 /* L2L, byte */
> +                                               /* 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];
> @@ -3198,6 +3223,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
>                                                 break;
>                                         case 1:
>                                                 /* L2L, partial */
> +                                               /* make sure we copied packet fully from userspace */
> +                                               radeon_get_ib_value(p, idx + 8);
>                                                 if (p->family < CHIP_CAYMAN) {
>                                                         DRM_ERROR("L2L Partial is cayman only !\n");
>                                                         return -EINVAL;
> @@ -3211,6 +3238,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
>                                                 break;
>                                         case 4:
>                                                 /* L2L, dw, broadcast */
> +                                               /* make sure we copied packet fully from userspace */
> +                                               radeon_get_ib_value(p, idx + 6);
>                                                 r = r600_dma_cs_next_reloc(p, &dst2_reloc);
>                                                 if (r) {
>                                                         DRM_ERROR("bad L2L, dw, broadcast DMA_PACKET_COPY\n");
> @@ -3251,6 +3280,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
>                                         }
>                                 } else {
>                                         /* L2L, dw */
> +                                       /* 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];
> @@ -3274,6 +3305,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 69ec24a..d36f9e6 100644
> --- a/drivers/gpu/drm/radeon/r600_cs.c
> +++ b/drivers/gpu/drm/radeon/r600_cs.c
> @@ -796,7 +796,7 @@ static int r600_cs_packet_parse(struct radeon_cs_parser *p,
>                         unsigned idx)
>  {
>         struct radeon_cs_chunk *ib_chunk = &p->chunks[p->chunk_ib_idx];
> -       uint32_t header;
> +       uint32_t header, i, npages;
>
>         if (idx >= ib_chunk->length_dw) {
>                 DRM_ERROR("Can not parse packet at %d after CS end %d !\n",
> @@ -827,6 +827,11 @@ 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 */
> +       npages = ((idx + pkt->count + 1) >> 10) - (idx >> 10);
> +       for (i = 1; i <= npages; i++) {
> +               radeon_get_ib_value(p, (idx & 0xfffffc00) + i * 0x400);
> +       }
>         return 0;
>  }
>
> @@ -2623,12 +2628,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;
>
> @@ -2654,6 +2663,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)) {
> @@ -2680,6 +2691,8 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p)
>                                 p->idx += 7;
>                         } else {
>                                 if (p->family >= CHIP_RV770) {
> +                                       /* 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];
> @@ -2691,6 +2704,8 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p)
>                                         ib[idx+4] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
>                                         p->idx += 5;
>                                 } else {
> +                                       /* make sure we copied packet fully from userspace */
> +                                       radeon_get_ib_value(p, idx + 3);
>                                         src_offset = ib[idx+2];
>                                         src_offset |= ((u64)(ib[idx+3] & 0xff)) << 32;
>                                         dst_offset = ib[idx+1];
> @@ -2715,6 +2730,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
>
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel


More information about the dri-devel mailing list