Mesa (master): radeonsi: Check pitch and offset for validity.

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Fri Nov 13 03:44:46 UTC 2020


Module: Mesa
Branch: master
Commit: f7a4051b836294ab8f55c71d239e99c5cbf63170
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=f7a4051b836294ab8f55c71d239e99c5cbf63170

Author: Bas Nieuwenhuizen <bas at basnieuwenhuizen.nl>
Date:   Sat May 30 03:42:39 2020 +0200

radeonsi: Check pitch and offset for validity.

And lack of overflows, which should help for security.

Reviewed-by: Marek Olšák <marek.olsak at amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6176>

---

 src/amd/common/ac_surface.c               | 65 +++++++++++++++++++++++++++++--
 src/amd/common/ac_surface.h               |  2 +-
 src/gallium/drivers/radeonsi/si_texture.c | 12 +++++-
 3 files changed, 72 insertions(+), 7 deletions(-)

diff --git a/src/amd/common/ac_surface.c b/src/amd/common/ac_surface.c
index ccd5c20f98b..ee20fbebc26 100644
--- a/src/amd/common/ac_surface.c
+++ b/src/amd/common/ac_surface.c
@@ -2446,6 +2446,10 @@ void ac_surface_zero_dcc_fields(struct radeon_surf *surf)
 {
    surf->dcc_offset = 0;
    surf->display_dcc_offset = 0;
+   if (!surf->htile_offset && !surf->fmask_offset && !surf->cmask_offset) {
+      surf->total_size = surf->surf_size;
+      surf->alignment = surf->surf_alignment;
+   }
 }
 
 static unsigned eg_tile_split(unsigned tile_split)
@@ -2744,21 +2748,69 @@ void ac_surface_get_umd_metadata(const struct radeon_info *info, struct radeon_s
    }
 }
 
-void ac_surface_override_offset_stride(const struct radeon_info *info, struct radeon_surf *surf,
+static uint32_t ac_surface_get_gfx9_pitch_align(struct radeon_surf *surf)
+{
+   if (surf->u.gfx9.surf.swizzle_mode == ADDR_SW_LINEAR)
+      return 256 / surf->bpe;
+
+   if (surf->u.gfx9.resource_type == RADEON_RESOURCE_3D)
+      return 1; /* TODO */
+
+   unsigned bpe_shift = util_logbase2(surf->bpe) / 2;
+   switch(surf->u.gfx9.surf.swizzle_mode & ~3) {
+   case ADDR_SW_LINEAR: /* 256B block. */
+      return 16 >> bpe_shift;
+   case ADDR_SW_4KB_Z:
+   case ADDR_SW_4KB_Z_X:
+      return 64 >> bpe_shift;
+   case ADDR_SW_64KB_Z:
+   case ADDR_SW_64KB_Z_T:
+   case ADDR_SW_64KB_Z_X:
+      return 256 >> bpe_shift;
+   case ADDR_SW_VAR_Z_X:
+   default:
+      return 1; /* TODO */
+   }
+}
+
+bool ac_surface_override_offset_stride(const struct radeon_info *info, struct radeon_surf *surf,
                                        unsigned num_mipmap_levels, uint64_t offset, unsigned pitch)
 {
+   /*
+    * GFX10 and newer don't support custom strides. Furthermore, for
+    * multiple miplevels or compression data we'd really need to rerun
+    * addrlib to update all the fields in the surface. That, however, is a
+    * software limitation and could be relaxed later.
+    */
+   bool require_equal_pitch = surf->surf_size != surf->total_size ||
+                              num_mipmap_levels != 1 ||
+                              info->chip_class >= GFX10;
+
    if (info->chip_class >= GFX9) {
       if (pitch) {
-         surf->u.gfx9.surf_pitch = pitch;
-         if (num_mipmap_levels == 1)
+         if (surf->u.gfx9.surf_pitch != pitch && require_equal_pitch)
+            return false;
+
+         if ((ac_surface_get_gfx9_pitch_align(surf) - 1) & pitch)
+            return false;
+
+         if (pitch != surf->u.gfx9.surf_pitch) {
+            unsigned slices = surf->surf_size / surf->u.gfx9.surf_slice_size;
+
+            surf->u.gfx9.surf_pitch = pitch;
             surf->u.gfx9.surf.epitch = pitch - 1;
-         surf->u.gfx9.surf_slice_size = (uint64_t)pitch * surf->u.gfx9.surf_height * surf->bpe;
+            surf->u.gfx9.surf_slice_size = (uint64_t)pitch * surf->u.gfx9.surf_height * surf->bpe;
+            surf->total_size = surf->surf_size = surf->u.gfx9.surf_slice_size * slices;
+         }
       }
       surf->u.gfx9.surf_offset = offset;
       if (surf->u.gfx9.stencil_offset)
          surf->u.gfx9.stencil_offset += offset;
    } else {
       if (pitch) {
+         if (surf->u.legacy.level[0].nblk_x != pitch && require_equal_pitch)
+            return false;
+
          surf->u.legacy.level[0].nblk_x = pitch;
          surf->u.legacy.level[0].slice_size_dw =
             ((uint64_t)pitch * surf->u.legacy.level[0].nblk_y * surf->bpe) / 4;
@@ -2770,6 +2822,10 @@ void ac_surface_override_offset_stride(const struct radeon_info *info, struct ra
       }
    }
 
+   if (offset & (surf->alignment - 1) ||
+       offset >= UINT64_MAX - surf->total_size)
+      return false;
+
    if (surf->htile_offset)
       surf->htile_offset += offset;
    if (surf->fmask_offset)
@@ -2780,6 +2836,7 @@ void ac_surface_override_offset_stride(const struct radeon_info *info, struct ra
       surf->dcc_offset += offset;
    if (surf->display_dcc_offset)
       surf->display_dcc_offset += offset;
+   return true;
 }
 
 unsigned ac_surface_get_nplanes(const struct radeon_surf *surf)
diff --git a/src/amd/common/ac_surface.h b/src/amd/common/ac_surface.h
index 04aa5f0b5f7..878226d3e9a 100644
--- a/src/amd/common/ac_surface.h
+++ b/src/amd/common/ac_surface.h
@@ -318,7 +318,7 @@ void ac_surface_get_umd_metadata(const struct radeon_info *info, struct radeon_s
                                  unsigned num_mipmap_levels, uint32_t desc[8],
                                  unsigned *size_metadata, uint32_t metadata[64]);
 
-void ac_surface_override_offset_stride(const struct radeon_info *info, struct radeon_surf *surf,
+bool ac_surface_override_offset_stride(const struct radeon_info *info, struct radeon_surf *surf,
                                        unsigned num_mipmap_levels, uint64_t offset, unsigned pitch);
 
 
diff --git a/src/gallium/drivers/radeonsi/si_texture.c b/src/gallium/drivers/radeonsi/si_texture.c
index 794ba1ae0f6..2904a76309c 100644
--- a/src/gallium/drivers/radeonsi/si_texture.c
+++ b/src/gallium/drivers/radeonsi/si_texture.c
@@ -1035,9 +1035,10 @@ static struct si_texture *si_texture_create_object(struct pipe_screen *screen,
     */
    tex->ps_draw_ratio = 0;
 
-   ac_surface_override_offset_stride(&sscreen->info, &tex->surface,
+   if (!ac_surface_override_offset_stride(&sscreen->info, &tex->surface,
                                      tex->buffer.b.b.last_level + 1,
-                                     offset, pitch_in_bytes / tex->surface.bpe);
+                                          offset, pitch_in_bytes / tex->surface.bpe))
+      goto error;
 
    if (tex->is_depth) {
       if (sscreen->info.chip_class >= GFX9) {
@@ -1463,6 +1464,13 @@ static struct pipe_resource *si_texture_from_winsys_buffer(struct si_screen *ssc
       return NULL;
    }
 
+   if (ac_surface_get_plane_offset(sscreen->info.chip_class, &tex->surface, 0, 0) +
+        tex->surface.total_size > buf->size ||
+       buf->alignment < tex->surface.alignment) {
+      si_texture_reference(&tex, NULL);
+      return NULL;
+   }
+
    /* Displayable DCC requires an explicit flush. */
    if (dedicated && offset == 0 && !(usage & PIPE_HANDLE_USAGE_EXPLICIT_FLUSH) &&
        si_has_displayable_dcc(tex)) {



More information about the mesa-commit mailing list