[PATCH 2/2] ddraw: Relax "dwSize" validation in ddraw_surface*_Lock().

Józef Kucia jkucia at codeweavers.com
Tue Jan 17 05:26:37 CST 2017


Signed-off-by: Józef Kucia <jkucia at codeweavers.com>
---

Fixes bug 14897
https://bugs.winehq.org/show_bug.cgi?id=14897

---
 dlls/ddraw/ddraw_private.h |  6 +--
 dlls/ddraw/surface.c       | 91 ++++++++++++++++++++++++++--------------------
 dlls/ddraw/tests/ddraw7.c  |  4 --
 3 files changed, 54 insertions(+), 47 deletions(-)

diff --git a/dlls/ddraw/ddraw_private.h b/dlls/ddraw/ddraw_private.h
index 1133bbd..f229215 100644
--- a/dlls/ddraw/ddraw_private.h
+++ b/dlls/ddraw/ddraw_private.h
@@ -626,10 +626,10 @@ struct member_info
 /* Structure copy */
 #define ME(x,f,e) { x, #x, (void (*)(const void *))(f), offsetof(STRUCT, e) }
 
-#define DD_STRUCT_COPY_BYSIZE_(to,from,from_size)                 \
+#define DD_STRUCT_COPY_BYSIZE_(to,from,to_size,from_size)         \
     do {                                                          \
         DWORD __size = (to)->dwSize;                              \
-        DWORD __resetsize = min(__size, sizeof(*to));             \
+        DWORD __resetsize = min(to_size, sizeof(*to));            \
         DWORD __copysize = min(__resetsize, from_size);           \
         assert(to != from);                                       \
         memcpy(to, from, __copysize);                             \
@@ -637,7 +637,7 @@ struct member_info
         (to)->dwSize = __size; /* restore size */                 \
     } while (0)
 
-#define DD_STRUCT_COPY_BYSIZE(to,from) DD_STRUCT_COPY_BYSIZE_(to,from,(from)->dwSize)
+#define DD_STRUCT_COPY_BYSIZE(to,from) DD_STRUCT_COPY_BYSIZE_(to,from,(to)->dwSize,(from)->dwSize)
 
 HRESULT hr_ddraw_from_wined3d(HRESULT hr) DECLSPEC_HIDDEN;
 
diff --git a/dlls/ddraw/surface.c b/dlls/ddraw/surface.c
index 4b53ac3..94f850b 100644
--- a/dlls/ddraw/surface.c
+++ b/dlls/ddraw/surface.c
@@ -954,14 +954,15 @@ static HRESULT WINAPI ddraw_surface1_GetAttachedSurface(IDirectDrawSurface *ifac
  *
  *****************************************************************************/
 static HRESULT surface_lock(struct ddraw_surface *surface,
-        RECT *rect, DDSURFACEDESC2 *surface_desc, DWORD flags, HANDLE h)
+        RECT *rect, DDSURFACEDESC2 *surface_desc, unsigned int surface_desc_size,
+        DWORD flags, HANDLE h)
 {
-    struct wined3d_box box;
     struct wined3d_map_desc map_desc;
+    struct wined3d_box box;
     HRESULT hr = DD_OK;
 
-    TRACE("surface %p, rect %s, surface_desc %p, flags %#x, h %p.\n",
-            surface, wine_dbgstr_rect(rect), surface_desc, flags, h);
+    TRACE("surface %p, rect %s, surface_desc %p, surface_desc_size %u, flags %#x, h %p.\n",
+            surface, wine_dbgstr_rect(rect), surface_desc, surface_desc_size, flags, h);
 
     /* surface->surface_desc.dwWidth and dwHeight are changeable, thus lock */
     wined3d_mutex_lock();
@@ -1025,7 +1026,7 @@ static HRESULT surface_lock(struct ddraw_surface *surface,
     }
 
     /* Windows does not set DDSD_LPSURFACE on locked surfaces. */
-    DD_STRUCT_COPY_BYSIZE(surface_desc, &surface->surface_desc);
+    DD_STRUCT_COPY_BYSIZE_(surface_desc, &surface->surface_desc, surface_desc_size, surface->surface_desc.dwSize);
     surface_desc->lpSurface = map_desc.data;
 
     TRACE("locked surface returning description :\n");
@@ -1037,63 +1038,80 @@ static HRESULT surface_lock(struct ddraw_surface *surface,
     return DD_OK;
 }
 
+static BOOL surface_validate_lock_desc(struct ddraw_surface *surface,
+        const DDSURFACEDESC *desc, unsigned int *size)
+{
+    if (!desc)
+        return FALSE;
+
+    if (desc->dwSize == sizeof(DDSURFACEDESC) || desc->dwSize == sizeof(DDSURFACEDESC2))
+    {
+        *size = desc->dwSize;
+        return TRUE;
+    }
+
+    if (surface->version == 7
+            && surface->surface_desc.ddsCaps.dwCaps & DDSCAPS_TEXTURE
+            && !(surface->surface_desc.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY))
+    {
+        if (desc->dwSize >= sizeof(DDSURFACEDESC2))
+            *size = sizeof(DDSURFACEDESC2);
+        else
+            *size = sizeof(DDSURFACEDESC);
+        return TRUE;
+    }
+
+    WARN("Invalid structure size %u.\n", desc->dwSize);
+    return FALSE;
+}
+
 static HRESULT WINAPI ddraw_surface7_Lock(IDirectDrawSurface7 *iface,
         RECT *rect, DDSURFACEDESC2 *surface_desc, DWORD flags, HANDLE h)
 {
     struct ddraw_surface *surface = impl_from_IDirectDrawSurface7(iface);
+    unsigned int surface_desc_size;
 
     TRACE("iface %p, rect %s, surface_desc %p, flags %#x, h %p.\n",
             iface, wine_dbgstr_rect(rect), surface_desc, flags, h);
 
-    if (!surface_desc) return DDERR_INVALIDPARAMS;
-    if (surface_desc->dwSize != sizeof(DDSURFACEDESC) &&
-            surface_desc->dwSize != sizeof(DDSURFACEDESC2))
-    {
-        WARN("Invalid structure size %d, returning DDERR_INVALIDPARAMS\n", surface_desc->dwSize);
+    if (!surface_validate_lock_desc(surface, (DDSURFACEDESC *)surface_desc, &surface_desc_size))
         return DDERR_INVALIDPARAMS;
-    }
-    return surface_lock(surface, rect, surface_desc, flags, h);
+
+    return surface_lock(surface, rect, surface_desc, surface_desc_size, flags, h);
 }
 
 static HRESULT WINAPI ddraw_surface4_Lock(IDirectDrawSurface4 *iface, RECT *rect,
         DDSURFACEDESC2 *surface_desc, DWORD flags, HANDLE h)
 {
     struct ddraw_surface *surface = impl_from_IDirectDrawSurface4(iface);
+    unsigned int surface_desc_size;
 
     TRACE("iface %p, rect %s, surface_desc %p, flags %#x, h %p.\n",
             iface, wine_dbgstr_rect(rect), surface_desc, flags, h);
 
-    if (!surface_desc) return DDERR_INVALIDPARAMS;
-    if (surface_desc->dwSize != sizeof(DDSURFACEDESC) &&
-            surface_desc->dwSize != sizeof(DDSURFACEDESC2))
-    {
-        WARN("Invalid structure size %d, returning DDERR_INVALIDPARAMS\n", surface_desc->dwSize);
+    if (!surface_validate_lock_desc(surface, (DDSURFACEDESC *)surface_desc, &surface_desc_size))
         return DDERR_INVALIDPARAMS;
-    }
-    return surface_lock(surface, rect, surface_desc, flags, h);
+
+    return surface_lock(surface, rect, surface_desc, surface_desc_size, flags, h);
 }
 
 static HRESULT WINAPI ddraw_surface3_Lock(IDirectDrawSurface3 *iface, RECT *rect,
         DDSURFACEDESC *surface_desc, DWORD flags, HANDLE h)
 {
     struct ddraw_surface *surface = impl_from_IDirectDrawSurface3(iface);
+    unsigned int surface_desc_size;
     DDSURFACEDESC2 surface_desc2;
     HRESULT hr;
 
     TRACE("iface %p, rect %s, surface_desc %p, flags %#x, h %p.\n",
             iface, wine_dbgstr_rect(rect), surface_desc, flags, h);
 
-    if (!surface_desc) return DDERR_INVALIDPARAMS;
-    if (surface_desc->dwSize != sizeof(DDSURFACEDESC) &&
-            surface_desc->dwSize != sizeof(DDSURFACEDESC2))
-    {
-        WARN("Invalid structure size %d, returning DDERR_INVALIDPARAMS\n", surface_desc->dwSize);
+    if (!surface_validate_lock_desc(surface, surface_desc, &surface_desc_size))
         return DDERR_INVALIDPARAMS;
-    }
 
     surface_desc2.dwSize = surface_desc->dwSize;
     surface_desc2.dwFlags = 0;
-    hr = surface_lock(surface, rect, &surface_desc2, flags, h);
+    hr = surface_lock(surface, rect, &surface_desc2, surface_desc_size, flags, h);
     DDSD2_to_DDSD(&surface_desc2, surface_desc);
     surface_desc->dwSize = surface_desc2.dwSize;
     return hr;
@@ -1103,23 +1121,19 @@ static HRESULT WINAPI ddraw_surface2_Lock(IDirectDrawSurface2 *iface, RECT *rect
         DDSURFACEDESC *surface_desc, DWORD flags, HANDLE h)
 {
     struct ddraw_surface *surface = impl_from_IDirectDrawSurface2(iface);
+    unsigned int surface_desc_size;
     DDSURFACEDESC2 surface_desc2;
     HRESULT hr;
 
     TRACE("iface %p, rect %s, surface_desc %p, flags %#x, h %p.\n",
             iface, wine_dbgstr_rect(rect), surface_desc, flags, h);
 
-    if (!surface_desc) return DDERR_INVALIDPARAMS;
-    if (surface_desc->dwSize != sizeof(DDSURFACEDESC) &&
-            surface_desc->dwSize != sizeof(DDSURFACEDESC2))
-    {
-        WARN("Invalid structure size %d, returning DDERR_INVALIDPARAMS\n", surface_desc->dwSize);
+    if (!surface_validate_lock_desc(surface, surface_desc, &surface_desc_size))
         return DDERR_INVALIDPARAMS;
-    }
 
     surface_desc2.dwSize = surface_desc->dwSize;
     surface_desc2.dwFlags = 0;
-    hr = surface_lock(surface, rect, &surface_desc2, flags, h);
+    hr = surface_lock(surface, rect, &surface_desc2, surface_desc_size, flags, h);
     DDSD2_to_DDSD(&surface_desc2, surface_desc);
     surface_desc->dwSize = surface_desc2.dwSize;
     return hr;
@@ -1129,22 +1143,19 @@ static HRESULT WINAPI ddraw_surface1_Lock(IDirectDrawSurface *iface, RECT *rect,
         DDSURFACEDESC *surface_desc, DWORD flags, HANDLE h)
 {
     struct ddraw_surface *surface = impl_from_IDirectDrawSurface(iface);
+    unsigned int surface_desc_size;
     DDSURFACEDESC2 surface_desc2;
     HRESULT hr;
+
     TRACE("iface %p, rect %s, surface_desc %p, flags %#x, h %p.\n",
             iface, wine_dbgstr_rect(rect), surface_desc, flags, h);
 
-    if (!surface_desc) return DDERR_INVALIDPARAMS;
-    if (surface_desc->dwSize != sizeof(DDSURFACEDESC) &&
-            surface_desc->dwSize != sizeof(DDSURFACEDESC2))
-    {
-        WARN("Invalid structure size %d, returning DDERR_INVALIDPARAMS\n", surface_desc->dwSize);
+    if (!surface_validate_lock_desc(surface, surface_desc, &surface_desc_size))
         return DDERR_INVALIDPARAMS;
-    }
 
     surface_desc2.dwSize = surface_desc->dwSize;
     surface_desc2.dwFlags = 0;
-    hr = surface_lock(surface, rect, &surface_desc2, flags, h);
+    hr = surface_lock(surface, rect, &surface_desc2, surface_desc_size, flags, h);
     DDSD2_to_DDSD(&surface_desc2, surface_desc);
     surface_desc->dwSize = surface_desc2.dwSize;
     return hr;
diff --git a/dlls/ddraw/tests/ddraw7.c b/dlls/ddraw/tests/ddraw7.c
index 633ea9f..88b22b2 100644
--- a/dlls/ddraw/tests/ddraw7.c
+++ b/dlls/ddraw/tests/ddraw7.c
@@ -5891,7 +5891,6 @@ static void test_surface_lock(void)
         expected_hr = tests[i].caps & DDSCAPS_TEXTURE && !(tests[i].caps & DDSCAPS_VIDEOMEMORY)
                 ? DD_OK : DDERR_INVALIDPARAMS;
         hr = IDirectDrawSurface7_Lock(surface, NULL, &ddsd, DDLOCK_WAIT, NULL);
-        todo_wine_if(expected_hr == D3D_OK)
         ok(hr == expected_hr, "Got hr %#x, expected %#x, type %s.\n", hr, expected_hr, tests[i].name);
         if (SUCCEEDED(hr))
         {
@@ -12322,7 +12321,6 @@ static void test_surface_desc_size(void)
             desc.blob[sizeof(DDSURFACEDESC2)] = 0xef;
             hr = IDirectDrawSurface_Lock(surface, NULL, &desc.desc1, 0, 0);
             expected_hr = ignore_size || valid_size ? DD_OK : DDERR_INVALIDPARAMS;
-            todo_wine_if(ignore_size && !valid_size)
             ok(hr == expected_hr, "Got hr %#x, expected %#x, dwSize %u, type %s.\n",
                     hr, expected_hr, desc_sizes[j], surface_caps[i].name);
             ok(desc.dwSize == desc_sizes[j], "dwSize was changed from %u to %u, type %s.\n",
@@ -12349,7 +12347,6 @@ static void test_surface_desc_size(void)
             desc.blob[sizeof(DDSURFACEDESC2)] = 0xef;
             hr = IDirectDrawSurface3_Lock(surface3, NULL, &desc.desc1, 0, 0);
             expected_hr = ignore_size || valid_size ? DD_OK : DDERR_INVALIDPARAMS;
-            todo_wine_if(ignore_size && !valid_size)
             ok(hr == expected_hr, "Got hr %#x, expected %#x, dwSize %u, type %s.\n",
                     hr, expected_hr, desc_sizes[j], surface_caps[i].name);
             ok(desc.dwSize == desc_sizes[j], "dwSize was changed from %u to %u, type %s.\n",
@@ -12376,7 +12373,6 @@ static void test_surface_desc_size(void)
             desc.blob[sizeof(DDSURFACEDESC2)] = 0xef;
             hr = IDirectDrawSurface7_Lock(surface7, NULL, &desc.desc2, 0, 0);
             expected_hr = ignore_size || valid_size ? DD_OK : DDERR_INVALIDPARAMS;
-            todo_wine_if(ignore_size && !valid_size)
             ok(hr == expected_hr, "Got hr %#x, expected %#x, dwSize %u, type %s.\n",
                     hr, expected_hr, desc_sizes[j], surface_caps[i].name);
             ok(desc.dwSize == desc_sizes[j], "dwSize was changed from %u to %u, type %s.\n",
-- 
2.7.3




More information about the wine-patches mailing list