drm: Fix authentication kernel crash
Thomas Hellstrom [Tue, 24 Jan 2012 17:54:21 +0000 (18:54 +0100)]
commit 598781d71119827b454fd75d46f84755bca6f0c6 upstream.

If the master tries to authenticate a client using drm_authmagic and
that client has already closed its drm file descriptor,
either wilfully or because it was terminated, the
call to drm_authmagic will dereference a stale pointer into kmalloc'ed memory
and corrupt it.

Typically this results in a hard system hang.

This patch fixes that problem by removing any authentication tokens
(struct drm_magic_entry) open for a file descriptor when that file
descriptor is closed.

Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Varun Wadekar <vwadekar@nvidia.com>
Change-Id: Icbba107e666306a34a621955458091410da3956a
Reviewed-on: http://git-master/r/79654
Reviewed-by: Automatic_Commit_Validation_User

drivers/gpu/drm/drm_auth.c
drivers/gpu/drm/drm_fops.c
include/drm/drmP.h

index 3f46772..ba23790 100644 (file)
@@ -101,7 +101,7 @@ static int drm_add_magic(struct drm_master *master, struct drm_file *priv,
  * Searches and unlinks the entry in drm_device::magiclist with the magic
  * number hash key, while holding the drm_device::struct_mutex lock.
  */
-static int drm_remove_magic(struct drm_master *master, drm_magic_t magic)
+int drm_remove_magic(struct drm_master *master, drm_magic_t magic)
 {
        struct drm_magic_entry *pt;
        struct drm_hash_item *hash;
@@ -136,6 +136,8 @@ static int drm_remove_magic(struct drm_master *master, drm_magic_t magic)
  * If there is a magic number in drm_file::magic then use it, otherwise
  * searches an unique non-zero magic number and add it associating it with \p
  * file_priv.
+ * This ioctl needs protection by the drm_global_mutex, which protects
+ * struct drm_file::magic and struct drm_magic_entry::priv.
  */
 int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
@@ -173,6 +175,8 @@ int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv)
  * \return zero if authentication successed, or a negative number otherwise.
  *
  * Checks if \p file_priv is associated with the magic number passed in \arg.
+ * This ioctl needs protection by the drm_global_mutex, which protects
+ * struct drm_file::magic and struct drm_magic_entry::priv.
  */
 int drm_authmagic(struct drm_device *dev, void *data,
                  struct drm_file *file_priv)
index 2ec7d48..c42e12c 100644 (file)
@@ -486,6 +486,11 @@ int drm_release(struct inode *inode, struct file *filp)
                  (long)old_encode_dev(file_priv->minor->device),
                  dev->open_count);
 
+       /* Release any auth tokens that might point to this file_priv,
+          (do that under the drm_global_mutex) */
+       if (file_priv->magic)
+               (void) drm_remove_magic(file_priv->master, file_priv->magic);
+
        /* if the master has gone away we can't do anything with the lock */
        if (file_priv->minor->master)
                drm_master_release(dev, filp);
index 9b7c2bb..4397cb0 100644 (file)
@@ -1325,6 +1325,7 @@ extern int drm_getmagic(struct drm_device *dev, void *data,
                        struct drm_file *file_priv);
 extern int drm_authmagic(struct drm_device *dev, void *data,
                         struct drm_file *file_priv);
+extern int drm_remove_magic(struct drm_master *master, drm_magic_t magic);
 
 /* Cache management (drm_cache.c) */
 void drm_clflush_pages(struct page *pages[], unsigned long num_pages);