| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /** | 
| Dave Airlie | b5e89ed | 2005-09-25 14:28:13 +1000 | [diff] [blame] | 2 |  * \file drm_auth.c | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3 |  * IOCTLs for authentication | 
 | 4 |  * | 
 | 5 |  * \author Rickard E. (Rik) Faith <faith@valinux.com> | 
 | 6 |  * \author Gareth Hughes <gareth@valinux.com> | 
 | 7 |  */ | 
 | 8 |  | 
 | 9 | /* | 
 | 10 |  * Created: Tue Feb  2 08:37:54 1999 by faith@valinux.com | 
 | 11 |  * | 
 | 12 |  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. | 
 | 13 |  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. | 
 | 14 |  * All Rights Reserved. | 
 | 15 |  * | 
 | 16 |  * Permission is hereby granted, free of charge, to any person obtaining a | 
 | 17 |  * copy of this software and associated documentation files (the "Software"), | 
 | 18 |  * to deal in the Software without restriction, including without limitation | 
 | 19 |  * the rights to use, copy, modify, merge, publish, distribute, sublicense, | 
 | 20 |  * and/or sell copies of the Software, and to permit persons to whom the | 
 | 21 |  * Software is furnished to do so, subject to the following conditions: | 
 | 22 |  * | 
 | 23 |  * The above copyright notice and this permission notice (including the next | 
 | 24 |  * paragraph) shall be included in all copies or substantial portions of the | 
 | 25 |  * Software. | 
 | 26 |  * | 
 | 27 |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 
 | 28 |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | 
 | 29 |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL | 
 | 30 |  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR | 
 | 31 |  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | 
 | 32 |  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | 
 | 33 |  * OTHER DEALINGS IN THE SOFTWARE. | 
 | 34 |  */ | 
 | 35 |  | 
| David Howells | 760285e | 2012-10-02 18:01:07 +0100 | [diff] [blame] | 36 | #include <drm/drmP.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 37 |  | 
 | 38 | /** | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 39 |  * Find the file with the given magic number. | 
 | 40 |  * | 
 | 41 |  * \param dev DRM device. | 
 | 42 |  * \param magic magic number. | 
 | 43 |  * | 
 | 44 |  * Searches in drm_device::magiclist within all files with the same hash key | 
| Dave Airlie | 30e2fb1 | 2006-02-02 19:37:46 +1100 | [diff] [blame] | 45 |  * the one with matching magic number, while holding the drm_device::struct_mutex | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 46 |  * lock. | 
 | 47 |  */ | 
| Dave Airlie | 7c1c287 | 2008-11-28 14:22:24 +1000 | [diff] [blame] | 48 | static struct drm_file *drm_find_file(struct drm_master *master, drm_magic_t magic) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 49 | { | 
| Dave Airlie | 84b1fd1 | 2007-07-11 15:53:27 +1000 | [diff] [blame] | 50 | 	struct drm_file *retval = NULL; | 
| Dave Airlie | 8fc2fdf | 2007-07-11 16:21:47 +1000 | [diff] [blame] | 51 | 	struct drm_magic_entry *pt; | 
| Dave Airlie | e0be428 | 2007-07-12 10:26:44 +1000 | [diff] [blame] | 52 | 	struct drm_hash_item *hash; | 
| Dave Airlie | 7c1c287 | 2008-11-28 14:22:24 +1000 | [diff] [blame] | 53 | 	struct drm_device *dev = master->minor->dev; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 54 |  | 
| Dave Airlie | 30e2fb1 | 2006-02-02 19:37:46 +1100 | [diff] [blame] | 55 | 	mutex_lock(&dev->struct_mutex); | 
| Dave Airlie | 7c1c287 | 2008-11-28 14:22:24 +1000 | [diff] [blame] | 56 | 	if (!drm_ht_find_item(&master->magiclist, (unsigned long)magic, &hash)) { | 
| Dave Airlie | 8fc2fdf | 2007-07-11 16:21:47 +1000 | [diff] [blame] | 57 | 		pt = drm_hash_entry(hash, struct drm_magic_entry, hash_item); | 
| Thomas Hellstrom | 8669cbc | 2006-08-07 22:22:10 +1000 | [diff] [blame] | 58 | 		retval = pt->priv; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 59 | 	} | 
| Dave Airlie | 30e2fb1 | 2006-02-02 19:37:46 +1100 | [diff] [blame] | 60 | 	mutex_unlock(&dev->struct_mutex); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 61 | 	return retval; | 
 | 62 | } | 
 | 63 |  | 
 | 64 | /** | 
 | 65 |  * Adds a magic number. | 
| Dave Airlie | b5e89ed | 2005-09-25 14:28:13 +1000 | [diff] [blame] | 66 |  * | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 67 |  * \param dev DRM device. | 
 | 68 |  * \param priv file private data. | 
 | 69 |  * \param magic magic number. | 
 | 70 |  * | 
 | 71 |  * Creates a drm_magic_entry structure and appends to the linked list | 
 | 72 |  * associated the magic number hash key in drm_device::magiclist, while holding | 
| Dave Airlie | 30e2fb1 | 2006-02-02 19:37:46 +1100 | [diff] [blame] | 73 |  * the drm_device::struct_mutex lock. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 74 |  */ | 
| Dave Airlie | 7c1c287 | 2008-11-28 14:22:24 +1000 | [diff] [blame] | 75 | static int drm_add_magic(struct drm_master *master, struct drm_file *priv, | 
| Dave Airlie | b5e89ed | 2005-09-25 14:28:13 +1000 | [diff] [blame] | 76 | 			 drm_magic_t magic) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 77 | { | 
| Dave Airlie | 8fc2fdf | 2007-07-11 16:21:47 +1000 | [diff] [blame] | 78 | 	struct drm_magic_entry *entry; | 
| Dave Airlie | 7c1c287 | 2008-11-28 14:22:24 +1000 | [diff] [blame] | 79 | 	struct drm_device *dev = master->minor->dev; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 80 | 	DRM_DEBUG("%d\n", magic); | 
 | 81 |  | 
| Julia Lawall | 6ebc22e | 2010-05-13 21:58:56 +0200 | [diff] [blame] | 82 | 	entry = kzalloc(sizeof(*entry), GFP_KERNEL); | 
| Dave Airlie | b5e89ed | 2005-09-25 14:28:13 +1000 | [diff] [blame] | 83 | 	if (!entry) | 
 | 84 | 		return -ENOMEM; | 
| Dave Airlie | b5e89ed | 2005-09-25 14:28:13 +1000 | [diff] [blame] | 85 | 	entry->priv = priv; | 
| Thomas Hellstrom | 8669cbc | 2006-08-07 22:22:10 +1000 | [diff] [blame] | 86 | 	entry->hash_item.key = (unsigned long)magic; | 
| Dave Airlie | 30e2fb1 | 2006-02-02 19:37:46 +1100 | [diff] [blame] | 87 | 	mutex_lock(&dev->struct_mutex); | 
| Dave Airlie | 7c1c287 | 2008-11-28 14:22:24 +1000 | [diff] [blame] | 88 | 	drm_ht_insert_item(&master->magiclist, &entry->hash_item); | 
 | 89 | 	list_add_tail(&entry->head, &master->magicfree); | 
| Dave Airlie | 30e2fb1 | 2006-02-02 19:37:46 +1100 | [diff] [blame] | 90 | 	mutex_unlock(&dev->struct_mutex); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 91 |  | 
 | 92 | 	return 0; | 
 | 93 | } | 
 | 94 |  | 
 | 95 | /** | 
 | 96 |  * Remove a magic number. | 
| Dave Airlie | b5e89ed | 2005-09-25 14:28:13 +1000 | [diff] [blame] | 97 |  * | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 98 |  * \param dev DRM device. | 
 | 99 |  * \param magic magic number. | 
 | 100 |  * | 
 | 101 |  * Searches and unlinks the entry in drm_device::magiclist with the magic | 
| Dave Airlie | 30e2fb1 | 2006-02-02 19:37:46 +1100 | [diff] [blame] | 102 |  * number hash key, while holding the drm_device::struct_mutex lock. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 103 |  */ | 
| Thomas Hellstrom | 598781d | 2012-01-24 18:54:21 +0100 | [diff] [blame] | 104 | int drm_remove_magic(struct drm_master *master, drm_magic_t magic) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 105 | { | 
| Dave Airlie | 8fc2fdf | 2007-07-11 16:21:47 +1000 | [diff] [blame] | 106 | 	struct drm_magic_entry *pt; | 
| Dave Airlie | e0be428 | 2007-07-12 10:26:44 +1000 | [diff] [blame] | 107 | 	struct drm_hash_item *hash; | 
| Dave Airlie | 7c1c287 | 2008-11-28 14:22:24 +1000 | [diff] [blame] | 108 | 	struct drm_device *dev = master->minor->dev; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 109 |  | 
 | 110 | 	DRM_DEBUG("%d\n", magic); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 111 |  | 
| Dave Airlie | 30e2fb1 | 2006-02-02 19:37:46 +1100 | [diff] [blame] | 112 | 	mutex_lock(&dev->struct_mutex); | 
| Dave Airlie | 7c1c287 | 2008-11-28 14:22:24 +1000 | [diff] [blame] | 113 | 	if (drm_ht_find_item(&master->magiclist, (unsigned long)magic, &hash)) { | 
| Thomas Hellstrom | 8669cbc | 2006-08-07 22:22:10 +1000 | [diff] [blame] | 114 | 		mutex_unlock(&dev->struct_mutex); | 
 | 115 | 		return -EINVAL; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 116 | 	} | 
| Dave Airlie | 8fc2fdf | 2007-07-11 16:21:47 +1000 | [diff] [blame] | 117 | 	pt = drm_hash_entry(hash, struct drm_magic_entry, hash_item); | 
| Dave Airlie | 7c1c287 | 2008-11-28 14:22:24 +1000 | [diff] [blame] | 118 | 	drm_ht_remove_item(&master->magiclist, hash); | 
| Thomas Hellstrom | 8669cbc | 2006-08-07 22:22:10 +1000 | [diff] [blame] | 119 | 	list_del(&pt->head); | 
| Dave Airlie | 30e2fb1 | 2006-02-02 19:37:46 +1100 | [diff] [blame] | 120 | 	mutex_unlock(&dev->struct_mutex); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 121 |  | 
| Eric Anholt | 9a298b2 | 2009-03-24 12:23:04 -0700 | [diff] [blame] | 122 | 	kfree(pt); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 123 |  | 
| Dave Airlie | 572225b | 2006-08-08 22:17:02 +1000 | [diff] [blame] | 124 | 	return 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 125 | } | 
 | 126 |  | 
 | 127 | /** | 
 | 128 |  * Get a unique magic number (ioctl). | 
 | 129 |  * | 
 | 130 |  * \param inode device inode. | 
| Eric Anholt | 6c340ea | 2007-08-25 20:23:09 +1000 | [diff] [blame] | 131 |  * \param file_priv DRM file private. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 132 |  * \param cmd command. | 
 | 133 |  * \param arg pointer to a resulting drm_auth structure. | 
 | 134 |  * \return zero on success, or a negative number on failure. | 
 | 135 |  * | 
 | 136 |  * If there is a magic number in drm_file::magic then use it, otherwise | 
 | 137 |  * searches an unique non-zero magic number and add it associating it with \p | 
| Eric Anholt | 6c340ea | 2007-08-25 20:23:09 +1000 | [diff] [blame] | 138 |  * file_priv. | 
| Thomas Hellstrom | 598781d | 2012-01-24 18:54:21 +0100 | [diff] [blame] | 139 |  * This ioctl needs protection by the drm_global_mutex, which protects | 
 | 140 |  * struct drm_file::magic and struct drm_magic_entry::priv. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 141 |  */ | 
| Eric Anholt | c153f45 | 2007-09-03 12:06:45 +1000 | [diff] [blame] | 142 | int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 143 | { | 
 | 144 | 	static drm_magic_t sequence = 0; | 
 | 145 | 	static DEFINE_SPINLOCK(lock); | 
| Eric Anholt | c153f45 | 2007-09-03 12:06:45 +1000 | [diff] [blame] | 146 | 	struct drm_auth *auth = data; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 147 |  | 
| Dave Airlie | b5e89ed | 2005-09-25 14:28:13 +1000 | [diff] [blame] | 148 | 	/* Find unique magic */ | 
| Eric Anholt | 6c340ea | 2007-08-25 20:23:09 +1000 | [diff] [blame] | 149 | 	if (file_priv->magic) { | 
| Eric Anholt | c153f45 | 2007-09-03 12:06:45 +1000 | [diff] [blame] | 150 | 		auth->magic = file_priv->magic; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 151 | 	} else { | 
 | 152 | 		do { | 
 | 153 | 			spin_lock(&lock); | 
| Dave Airlie | b5e89ed | 2005-09-25 14:28:13 +1000 | [diff] [blame] | 154 | 			if (!sequence) | 
 | 155 | 				++sequence;	/* reserve 0 */ | 
| Eric Anholt | c153f45 | 2007-09-03 12:06:45 +1000 | [diff] [blame] | 156 | 			auth->magic = sequence++; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 157 | 			spin_unlock(&lock); | 
| Dave Airlie | 7c1c287 | 2008-11-28 14:22:24 +1000 | [diff] [blame] | 158 | 		} while (drm_find_file(file_priv->master, auth->magic)); | 
| Eric Anholt | c153f45 | 2007-09-03 12:06:45 +1000 | [diff] [blame] | 159 | 		file_priv->magic = auth->magic; | 
| Dave Airlie | 7c1c287 | 2008-11-28 14:22:24 +1000 | [diff] [blame] | 160 | 		drm_add_magic(file_priv->master, file_priv, auth->magic); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 161 | 	} | 
 | 162 |  | 
| Eric Anholt | c153f45 | 2007-09-03 12:06:45 +1000 | [diff] [blame] | 163 | 	DRM_DEBUG("%u\n", auth->magic); | 
 | 164 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 165 | 	return 0; | 
 | 166 | } | 
 | 167 |  | 
 | 168 | /** | 
 | 169 |  * Authenticate with a magic. | 
 | 170 |  * | 
 | 171 |  * \param inode device inode. | 
| Eric Anholt | 6c340ea | 2007-08-25 20:23:09 +1000 | [diff] [blame] | 172 |  * \param file_priv DRM file private. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 173 |  * \param cmd command. | 
 | 174 |  * \param arg pointer to a drm_auth structure. | 
 | 175 |  * \return zero if authentication successed, or a negative number otherwise. | 
 | 176 |  * | 
| Eric Anholt | 6c340ea | 2007-08-25 20:23:09 +1000 | [diff] [blame] | 177 |  * Checks if \p file_priv is associated with the magic number passed in \arg. | 
| Thomas Hellstrom | 598781d | 2012-01-24 18:54:21 +0100 | [diff] [blame] | 178 |  * This ioctl needs protection by the drm_global_mutex, which protects | 
 | 179 |  * struct drm_file::magic and struct drm_magic_entry::priv. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 180 |  */ | 
| Eric Anholt | c153f45 | 2007-09-03 12:06:45 +1000 | [diff] [blame] | 181 | int drm_authmagic(struct drm_device *dev, void *data, | 
 | 182 | 		  struct drm_file *file_priv) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 183 | { | 
| Eric Anholt | c153f45 | 2007-09-03 12:06:45 +1000 | [diff] [blame] | 184 | 	struct drm_auth *auth = data; | 
| Dave Airlie | 84b1fd1 | 2007-07-11 15:53:27 +1000 | [diff] [blame] | 185 | 	struct drm_file *file; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 186 |  | 
| Eric Anholt | c153f45 | 2007-09-03 12:06:45 +1000 | [diff] [blame] | 187 | 	DRM_DEBUG("%u\n", auth->magic); | 
| Dave Airlie | 7c1c287 | 2008-11-28 14:22:24 +1000 | [diff] [blame] | 188 | 	if ((file = drm_find_file(file_priv->master, auth->magic))) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 189 | 		file->authenticated = 1; | 
| Dave Airlie | 7c1c287 | 2008-11-28 14:22:24 +1000 | [diff] [blame] | 190 | 		drm_remove_magic(file_priv->master, auth->magic); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 191 | 		return 0; | 
 | 192 | 	} | 
 | 193 | 	return -EINVAL; | 
 | 194 | } |