Mesa (mesa_7_7_branch): svga: Prevent buffer overflow in buffer ranges.

Jose Fonseca jrfonseca at kemper.freedesktop.org
Wed Jan 27 16:42:18 UTC 2010


Module: Mesa
Branch: mesa_7_7_branch
Commit: 15fe4918223f04fa89d523220609abea0cac34e2
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=15fe4918223f04fa89d523220609abea0cac34e2

Author: José Fonseca <jfonseca at vmware.com>
Date:   Wed Jan 27 15:41:25 2010 +0000

svga: Prevent buffer overflow in buffer ranges.

Do this by extending the nearest range to cover the new range.

This fixes an access fault in Call of Duty which was doing many disjoint
glBufferSubData calls.

---

 src/gallium/drivers/svga/svga_screen_buffer.c |   62 +++++++++++++++++++++---
 1 files changed, 54 insertions(+), 8 deletions(-)

diff --git a/src/gallium/drivers/svga/svga_screen_buffer.c b/src/gallium/drivers/svga/svga_screen_buffer.c
index 719adde..6a58ff2 100644
--- a/src/gallium/drivers/svga/svga_screen_buffer.c
+++ b/src/gallium/drivers/svga/svga_screen_buffer.c
@@ -310,10 +310,20 @@ svga_buffer_upload_queue(struct svga_buffer *sbuf,
                          unsigned end)
 {
    unsigned i;
+   unsigned nearest_range;
+   unsigned nearest_dist;
 
    assert(sbuf->hw.buf);
    assert(end > start);
    
+   if (sbuf->hw.num_ranges < SVGA_BUFFER_MAX_RANGES) {
+      nearest_range = sbuf->hw.num_ranges;
+      nearest_dist = ~0;
+   } else {
+      nearest_range = SVGA_BUFFER_MAX_RANGES - 1;
+      nearest_dist = 0;
+   }
+
    /*
     * Try to grow one of the ranges.
     *
@@ -325,11 +335,33 @@ svga_buffer_upload_queue(struct svga_buffer *sbuf,
     */
 
    for(i = 0; i < sbuf->hw.num_ranges; ++i) {
-      if(start <= sbuf->hw.ranges[i].end && sbuf->hw.ranges[i].start <= end) {
+      int left_dist;
+      int right_dist;
+      int dist;
+
+      left_dist = start - sbuf->hw.ranges[i].end;
+      right_dist = sbuf->hw.ranges[i].start - end;
+      dist = MAX2(left_dist, right_dist);
+
+      if (dist <= 0) {
+         /*
+          * Ranges are contiguous or overlapping -- extend this one and return.
+          */
+
          sbuf->hw.ranges[i].start = MIN2(sbuf->hw.ranges[i].start, start);
-         sbuf->hw.ranges[i].end   = MAX2(sbuf->hw.ranges[i].end,    end);
+         sbuf->hw.ranges[i].end   = MAX2(sbuf->hw.ranges[i].end,   end);
          return;
       }
+      else {
+         /*
+          * Discontiguous ranges -- keep track of the nearest range.
+          */
+
+         if (dist < nearest_dist) {
+            nearest_range = i;
+            nearest_dist = dist;
+         }
+      }
    }
 
    /*
@@ -344,13 +376,27 @@ svga_buffer_upload_queue(struct svga_buffer *sbuf,
    assert(!sbuf->hw.svga);
    assert(!sbuf->hw.boxes);
 
-   /*
-    * Add a new range.
-    */
+   if (sbuf->hw.num_ranges < SVGA_BUFFER_MAX_RANGES) {
+      /*
+       * Add a new range.
+       */
 
-   sbuf->hw.ranges[sbuf->hw.num_ranges].start = start;
-   sbuf->hw.ranges[sbuf->hw.num_ranges].end = end;
-   ++sbuf->hw.num_ranges;
+      sbuf->hw.ranges[sbuf->hw.num_ranges].start = start;
+      sbuf->hw.ranges[sbuf->hw.num_ranges].end = end;
+      ++sbuf->hw.num_ranges;
+   } else {
+      /*
+       * Everything else failed, so just extend the nearest range.
+       *
+       * It is OK to do this because we always keep a local copy of the
+       * host buffer data, for SW TNL, and the host never modifies the buffer.
+       */
+
+      assert(nearest_range < SVGA_BUFFER_MAX_RANGES);
+      assert(nearest_range < sbuf->hw.num_ranges);
+      sbuf->hw.ranges[nearest_range].start = MIN2(sbuf->hw.ranges[nearest_range].start, start);
+      sbuf->hw.ranges[nearest_range].end   = MAX2(sbuf->hw.ranges[nearest_range].end,   end);
+   }
 }
 
 




More information about the mesa-commit mailing list