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