OSDN Git Service

drm/vmwgfx: Fix kernel NULL pointer dereference on older hardware
[uclinux-h8/linux.git] / drivers / gpu / drm / vmwgfx / vmwgfx_surface.c
index 12ade0c..03f63c7 100644 (file)
@@ -1,6 +1,6 @@
 /**************************************************************************
  *
- * Copyright © 2009-2014 VMware, Inc., Palo Alto, CA., USA
+ * Copyright © 2009-2015 VMware, Inc., Palo Alto, CA., USA
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -46,6 +46,7 @@ struct vmw_user_surface {
        struct vmw_surface srf;
        uint32_t size;
        struct drm_master *master;
+       struct ttm_base_object *backup_base;
 };
 
 /**
@@ -656,6 +657,8 @@ static void vmw_user_surface_base_release(struct ttm_base_object **p_base)
        struct vmw_resource *res = &user_srf->srf.res;
 
        *p_base = NULL;
+       if (user_srf->backup_base)
+               ttm_base_object_unref(&user_srf->backup_base);
        vmw_resource_unreference(&res);
 }
 
@@ -851,7 +854,8 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
                                            res->backup_size,
                                            true,
                                            &backup_handle,
-                                           &res->backup);
+                                           &res->backup,
+                                           &user_srf->backup_base);
                if (unlikely(ret != 0)) {
                        vmw_resource_unreference(&res);
                        goto out_unlock;
@@ -911,6 +915,12 @@ vmw_surface_handle_reference(struct vmw_private *dev_priv,
                                  "surface reference.\n");
                        return -EACCES;
                }
+               if (ACCESS_ONCE(vmw_fpriv(file_priv)->locked_master)) {
+                       DRM_ERROR("Locked master refused legacy "
+                                 "surface reference.\n");
+                       return -EACCES;
+               }
+
                handle = u_handle;
        }
 
@@ -1315,7 +1325,8 @@ int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data,
 
        if (req->buffer_handle != SVGA3D_INVALID_ID) {
                ret = vmw_user_dmabuf_lookup(tfile, req->buffer_handle,
-                                            &res->backup);
+                                            &res->backup,
+                                            &user_srf->backup_base);
                if (ret == 0 && res->backup->base.num_pages * PAGE_SIZE <
                    res->backup_size) {
                        DRM_ERROR("Surface backup buffer is too small.\n");
@@ -1329,7 +1340,8 @@ int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data,
                                            req->drm_surface_flags &
                                            drm_vmw_surface_flag_shareable,
                                            &backup_handle,
-                                           &res->backup);
+                                           &res->backup,
+                                           &user_srf->backup_base);
 
        if (unlikely(ret != 0)) {
                vmw_resource_unreference(&res);
@@ -1533,6 +1545,7 @@ int vmw_surface_gb_priv_define(struct drm_device *dev,
        srf->offsets           = NULL;
        srf->base_size         = size;
        srf->autogen_filter    = SVGA3D_TEX_FILTER_NONE;
+       srf->array_size        = array_size;
        srf->multisample_count = multisample_count;
 
        if (array_size)