root/drivers/gpu/drm/drm_auth.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. drm_getmagic
  2. drm_authmagic
  3. drm_master_create
  4. drm_set_master
  5. drm_new_set_master
  6. drm_setmaster_ioctl
  7. drm_drop_master
  8. drm_dropmaster_ioctl
  9. drm_master_open
  10. drm_master_release
  11. drm_is_current_master
  12. drm_master_get
  13. drm_master_destroy
  14. drm_master_put
  15. drm_master_internal_acquire
  16. drm_master_internal_release

   1 /*
   2  * Created: Tue Feb  2 08:37:54 1999 by faith@valinux.com
   3  *
   4  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
   5  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
   6  * All Rights Reserved.
   7  *
   8  * Author Rickard E. (Rik) Faith <faith@valinux.com>
   9  * Author Gareth Hughes <gareth@valinux.com>
  10  *
  11  * Permission is hereby granted, free of charge, to any person obtaining a
  12  * copy of this software and associated documentation files (the "Software"),
  13  * to deal in the Software without restriction, including without limitation
  14  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  15  * and/or sell copies of the Software, and to permit persons to whom the
  16  * Software is furnished to do so, subject to the following conditions:
  17  *
  18  * The above copyright notice and this permission notice (including the next
  19  * paragraph) shall be included in all copies or substantial portions of the
  20  * Software.
  21  *
  22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  23  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  24  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  25  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  26  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  27  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  28  * OTHER DEALINGS IN THE SOFTWARE.
  29  */
  30 
  31 #include <linux/slab.h>
  32 
  33 #include <drm/drm_auth.h>
  34 #include <drm/drm_drv.h>
  35 #include <drm/drm_file.h>
  36 #include <drm/drm_lease.h>
  37 #include <drm/drm_print.h>
  38 
  39 #include "drm_internal.h"
  40 #include "drm_legacy.h"
  41 
  42 /**
  43  * DOC: master and authentication
  44  *
  45  * &struct drm_master is used to track groups of clients with open
  46  * primary/legacy device nodes. For every &struct drm_file which has had at
  47  * least once successfully became the device master (either through the
  48  * SET_MASTER IOCTL, or implicitly through opening the primary device node when
  49  * no one else is the current master that time) there exists one &drm_master.
  50  * This is noted in &drm_file.is_master. All other clients have just a pointer
  51  * to the &drm_master they are associated with.
  52  *
  53  * In addition only one &drm_master can be the current master for a &drm_device.
  54  * It can be switched through the DROP_MASTER and SET_MASTER IOCTL, or
  55  * implicitly through closing/openeing the primary device node. See also
  56  * drm_is_current_master().
  57  *
  58  * Clients can authenticate against the current master (if it matches their own)
  59  * using the GETMAGIC and AUTHMAGIC IOCTLs. Together with exchanging masters,
  60  * this allows controlled access to the device for an entire group of mutually
  61  * trusted clients.
  62  */
  63 
  64 int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv)
  65 {
  66         struct drm_auth *auth = data;
  67         int ret = 0;
  68 
  69         mutex_lock(&dev->master_mutex);
  70         if (!file_priv->magic) {
  71                 ret = idr_alloc(&file_priv->master->magic_map, file_priv,
  72                                 1, 0, GFP_KERNEL);
  73                 if (ret >= 0)
  74                         file_priv->magic = ret;
  75         }
  76         auth->magic = file_priv->magic;
  77         mutex_unlock(&dev->master_mutex);
  78 
  79         DRM_DEBUG("%u\n", auth->magic);
  80 
  81         return ret < 0 ? ret : 0;
  82 }
  83 
  84 int drm_authmagic(struct drm_device *dev, void *data,
  85                   struct drm_file *file_priv)
  86 {
  87         struct drm_auth *auth = data;
  88         struct drm_file *file;
  89 
  90         DRM_DEBUG("%u\n", auth->magic);
  91 
  92         mutex_lock(&dev->master_mutex);
  93         file = idr_find(&file_priv->master->magic_map, auth->magic);
  94         if (file) {
  95                 file->authenticated = 1;
  96                 idr_replace(&file_priv->master->magic_map, NULL, auth->magic);
  97         }
  98         mutex_unlock(&dev->master_mutex);
  99 
 100         return file ? 0 : -EINVAL;
 101 }
 102 
 103 struct drm_master *drm_master_create(struct drm_device *dev)
 104 {
 105         struct drm_master *master;
 106 
 107         master = kzalloc(sizeof(*master), GFP_KERNEL);
 108         if (!master)
 109                 return NULL;
 110 
 111         kref_init(&master->refcount);
 112         drm_master_legacy_init(master);
 113         idr_init(&master->magic_map);
 114         master->dev = dev;
 115 
 116         /* initialize the tree of output resource lessees */
 117         INIT_LIST_HEAD(&master->lessees);
 118         INIT_LIST_HEAD(&master->lessee_list);
 119         idr_init(&master->leases);
 120         idr_init(&master->lessee_idr);
 121 
 122         return master;
 123 }
 124 
 125 static int drm_set_master(struct drm_device *dev, struct drm_file *fpriv,
 126                           bool new_master)
 127 {
 128         int ret = 0;
 129 
 130         dev->master = drm_master_get(fpriv->master);
 131         if (dev->driver->master_set) {
 132                 ret = dev->driver->master_set(dev, fpriv, new_master);
 133                 if (unlikely(ret != 0)) {
 134                         drm_master_put(&dev->master);
 135                 }
 136         }
 137 
 138         return ret;
 139 }
 140 
 141 static int drm_new_set_master(struct drm_device *dev, struct drm_file *fpriv)
 142 {
 143         struct drm_master *old_master;
 144         int ret;
 145 
 146         lockdep_assert_held_once(&dev->master_mutex);
 147 
 148         WARN_ON(fpriv->is_master);
 149         old_master = fpriv->master;
 150         fpriv->master = drm_master_create(dev);
 151         if (!fpriv->master) {
 152                 fpriv->master = old_master;
 153                 return -ENOMEM;
 154         }
 155 
 156         if (dev->driver->master_create) {
 157                 ret = dev->driver->master_create(dev, fpriv->master);
 158                 if (ret)
 159                         goto out_err;
 160         }
 161         fpriv->is_master = 1;
 162         fpriv->authenticated = 1;
 163 
 164         ret = drm_set_master(dev, fpriv, true);
 165         if (ret)
 166                 goto out_err;
 167 
 168         if (old_master)
 169                 drm_master_put(&old_master);
 170 
 171         return 0;
 172 
 173 out_err:
 174         /* drop references and restore old master on failure */
 175         drm_master_put(&fpriv->master);
 176         fpriv->master = old_master;
 177         fpriv->is_master = 0;
 178 
 179         return ret;
 180 }
 181 
 182 int drm_setmaster_ioctl(struct drm_device *dev, void *data,
 183                         struct drm_file *file_priv)
 184 {
 185         int ret = 0;
 186 
 187         mutex_lock(&dev->master_mutex);
 188         if (drm_is_current_master(file_priv))
 189                 goto out_unlock;
 190 
 191         if (dev->master) {
 192                 ret = -EINVAL;
 193                 goto out_unlock;
 194         }
 195 
 196         if (!file_priv->master) {
 197                 ret = -EINVAL;
 198                 goto out_unlock;
 199         }
 200 
 201         if (!file_priv->is_master) {
 202                 ret = drm_new_set_master(dev, file_priv);
 203                 goto out_unlock;
 204         }
 205 
 206         if (file_priv->master->lessor != NULL) {
 207                 DRM_DEBUG_LEASE("Attempt to set lessee %d as master\n", file_priv->master->lessee_id);
 208                 ret = -EINVAL;
 209                 goto out_unlock;
 210         }
 211 
 212         ret = drm_set_master(dev, file_priv, false);
 213 out_unlock:
 214         mutex_unlock(&dev->master_mutex);
 215         return ret;
 216 }
 217 
 218 static void drm_drop_master(struct drm_device *dev,
 219                             struct drm_file *fpriv)
 220 {
 221         if (dev->driver->master_drop)
 222                 dev->driver->master_drop(dev, fpriv);
 223         drm_master_put(&dev->master);
 224 }
 225 
 226 int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
 227                          struct drm_file *file_priv)
 228 {
 229         int ret = -EINVAL;
 230 
 231         mutex_lock(&dev->master_mutex);
 232         if (!drm_is_current_master(file_priv))
 233                 goto out_unlock;
 234 
 235         if (!dev->master)
 236                 goto out_unlock;
 237 
 238         if (file_priv->master->lessor != NULL) {
 239                 DRM_DEBUG_LEASE("Attempt to drop lessee %d as master\n", file_priv->master->lessee_id);
 240                 ret = -EINVAL;
 241                 goto out_unlock;
 242         }
 243 
 244         ret = 0;
 245         drm_drop_master(dev, file_priv);
 246 out_unlock:
 247         mutex_unlock(&dev->master_mutex);
 248         return ret;
 249 }
 250 
 251 int drm_master_open(struct drm_file *file_priv)
 252 {
 253         struct drm_device *dev = file_priv->minor->dev;
 254         int ret = 0;
 255 
 256         /* if there is no current master make this fd it, but do not create
 257          * any master object for render clients */
 258         mutex_lock(&dev->master_mutex);
 259         if (!dev->master)
 260                 ret = drm_new_set_master(dev, file_priv);
 261         else
 262                 file_priv->master = drm_master_get(dev->master);
 263         mutex_unlock(&dev->master_mutex);
 264 
 265         return ret;
 266 }
 267 
 268 void drm_master_release(struct drm_file *file_priv)
 269 {
 270         struct drm_device *dev = file_priv->minor->dev;
 271         struct drm_master *master = file_priv->master;
 272 
 273         mutex_lock(&dev->master_mutex);
 274         if (file_priv->magic)
 275                 idr_remove(&file_priv->master->magic_map, file_priv->magic);
 276 
 277         if (!drm_is_current_master(file_priv))
 278                 goto out;
 279 
 280         drm_legacy_lock_master_cleanup(dev, master);
 281 
 282         if (dev->master == file_priv->master)
 283                 drm_drop_master(dev, file_priv);
 284 out:
 285         if (drm_core_check_feature(dev, DRIVER_MODESET) && file_priv->is_master) {
 286                 /* Revoke any leases held by this or lessees, but only if
 287                  * this is the "real" master
 288                  */
 289                 drm_lease_revoke(master);
 290         }
 291 
 292         /* drop the master reference held by the file priv */
 293         if (file_priv->master)
 294                 drm_master_put(&file_priv->master);
 295         mutex_unlock(&dev->master_mutex);
 296 }
 297 
 298 /**
 299  * drm_is_current_master - checks whether @priv is the current master
 300  * @fpriv: DRM file private
 301  *
 302  * Checks whether @fpriv is current master on its device. This decides whether a
 303  * client is allowed to run DRM_MASTER IOCTLs.
 304  *
 305  * Most of the modern IOCTL which require DRM_MASTER are for kernel modesetting
 306  * - the current master is assumed to own the non-shareable display hardware.
 307  */
 308 bool drm_is_current_master(struct drm_file *fpriv)
 309 {
 310         return fpriv->is_master && drm_lease_owner(fpriv->master) == fpriv->minor->dev->master;
 311 }
 312 EXPORT_SYMBOL(drm_is_current_master);
 313 
 314 /**
 315  * drm_master_get - reference a master pointer
 316  * @master: &struct drm_master
 317  *
 318  * Increments the reference count of @master and returns a pointer to @master.
 319  */
 320 struct drm_master *drm_master_get(struct drm_master *master)
 321 {
 322         kref_get(&master->refcount);
 323         return master;
 324 }
 325 EXPORT_SYMBOL(drm_master_get);
 326 
 327 static void drm_master_destroy(struct kref *kref)
 328 {
 329         struct drm_master *master = container_of(kref, struct drm_master, refcount);
 330         struct drm_device *dev = master->dev;
 331 
 332         if (drm_core_check_feature(dev, DRIVER_MODESET))
 333                 drm_lease_destroy(master);
 334 
 335         if (dev->driver->master_destroy)
 336                 dev->driver->master_destroy(dev, master);
 337 
 338         drm_legacy_master_rmmaps(dev, master);
 339 
 340         idr_destroy(&master->magic_map);
 341         idr_destroy(&master->leases);
 342         idr_destroy(&master->lessee_idr);
 343 
 344         kfree(master->unique);
 345         kfree(master);
 346 }
 347 
 348 /**
 349  * drm_master_put - unreference and clear a master pointer
 350  * @master: pointer to a pointer of &struct drm_master
 351  *
 352  * This decrements the &drm_master behind @master and sets it to NULL.
 353  */
 354 void drm_master_put(struct drm_master **master)
 355 {
 356         kref_put(&(*master)->refcount, drm_master_destroy);
 357         *master = NULL;
 358 }
 359 EXPORT_SYMBOL(drm_master_put);
 360 
 361 /* Used by drm_client and drm_fb_helper */
 362 bool drm_master_internal_acquire(struct drm_device *dev)
 363 {
 364         mutex_lock(&dev->master_mutex);
 365         if (dev->master) {
 366                 mutex_unlock(&dev->master_mutex);
 367                 return false;
 368         }
 369 
 370         return true;
 371 }
 372 EXPORT_SYMBOL(drm_master_internal_acquire);
 373 
 374 /* Used by drm_client and drm_fb_helper */
 375 void drm_master_internal_release(struct drm_device *dev)
 376 {
 377         mutex_unlock(&dev->master_mutex);
 378 }
 379 EXPORT_SYMBOL(drm_master_internal_release);

/* [<][>][^][v][top][bottom][index][help] */