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