From 2291f9f43f528d8f18893ab4669bae482239f719 Mon Sep 17 00:00:00 2001 From: Nicolas Boichat Date: Fri, 17 Jan 2014 11:29:25 +0800 Subject: [PATCH 2/8] CHROMIUM: drm: Add drm_master_relax debugfs file (non-root set/drop master ioctls) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Writing 'Y' to /sys/kernel/debug/dri/drm_master_relax allows non-CAP_SYS_ADMIN user to call the 2 ioctls DRM_IOCTL_SET_MASTER and DRM_IOCTL_DROP_MASTER. This makes it possible to run 2 X11 servers at the same time, where at least one of them runs under a non-root user (e.g. Chromium OS X server as xorg user, and a crouton X server as root). The behavior is not modified if /sys/kernel/debug/dri/drm_master_relax is kept to its default value ('N'). Modifying drm_master_relax is only possible by root user, so it cannot possibly lead to exploits. Also, even when the flag is set to 'Y', DROP_MASTER permissions are changed to DRM_MASTER which means that only a process that has DRM master can drop it (which is actually quite logical), and the SET_MASTER IOCTL is changed to DRM_AUTH which allows all authenticated DRM users to get master. R=seanpaul@chromium.org, dbehr@chromium.org BUG=chromium:328115 TEST=With or without the debugfs flag, WebGL examples work, and we can switch between VT1 and VT2. TEST=On a peppy in developer mode: With the debugfs flag to 'Y', Ubuntu saucy chroot generated by crouton (xfce target) is able to start a second X11 display. Switching back and forth between the two displays works, and 3D acceleration is working in the chroot. Signed-off-by: Nicolas Boichat Reviewed-on: https://chromium-review.googlesource.com/183190 Reviewed-by: Kees Cook Reviewed-by: Dominik Behr Commit-Queue: David Schneider Tested-by: David Schneider (cherry picked from commit d53b6142c2b5c742d2c547568c9814597c41ede6) Signed-off-by: Dominik Behr Reviewed-on: https://chromium-review.googlesource.com/189390 Reviewed-by: Haixia Shi [benzh: 3.14 rebase. Resolved trivial conflicts] Signed-off-by: Ben Zhang [bfreed: 3.18 rebase. Resolved conflicts] Signed-off-by: Bryan Freed [briannorris: 4.4 rebase. Resolved conflicts; change drm_master_relax to 'bool' to match usage and debugfs_create_bool() API change] Signed-off-by: Brian Norris Change-Id: I7b8a00ca8e21321019875012a24cb88fea3c1317 Reviewed-on: https://chromium-review.googlesource.com/267810 Trybot-Ready: Bryan Freed Tested-by: Bryan Freed Reviewed-by: Stéphane Marchesin Commit-Queue: Bryan Freed Reviewed-on: https://chromium-review.googlesource.com/339283 Commit-Queue: Brian Norris Tested-by: Brian Norris Conflicts: drivers/gpu/drm/drm_ioctl.c include/drm/drmP.h (variable moved to include/drm/drm_drv.h) [rebase412(groeck): Context conflicts] Signed-off-by: Guenter Roeck Conflicts: drivers/gpu/drm/drm_ioctl.c [rebase414(groeck): drm_ioctl() reorganized] Signed-off-by: Guenter Roeck [tfiga: Rebase onto Linux 4.20] Signed-off-by: Tomasz Figa --- drivers/gpu/drm/drm_drv.c | 11 ++++++++++- drivers/gpu/drm/drm_ioctl.c | 13 ++++++++++++- include/drm/drm_drv.h | 1 + 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 7e7d7e0efff083..9cf4ae4d678a9a 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -948,6 +948,9 @@ static int drm_stub_open(struct inode *inode, struct file *filp) return err; } +/* When set to true, allow set/drop master ioctls as normal user */ +bool drm_master_relax; + static const struct file_operations drm_stub_fops = { .owner = THIS_MODULE, .open = drm_stub_open, @@ -957,7 +960,7 @@ static const struct file_operations drm_stub_fops = { static void drm_core_exit(void) { unregister_chrdev(DRM_MAJOR, "drm"); - debugfs_remove(drm_debugfs_root); + debugfs_remove_recursive(drm_debugfs_root); drm_sysfs_destroy(); idr_destroy(&drm_minors_idr); drm_connector_ida_destroy(); @@ -983,6 +986,12 @@ static int __init drm_core_init(void) goto error; } + if (!debugfs_create_bool("drm_master_relax", S_IRUSR | S_IWUSR, + drm_debugfs_root, &drm_master_relax)) { + DRM_ERROR( + "Cannot create /sys/kernel/debug/dri/drm_master_relax\n"); + } + ret = register_chrdev(DRM_MAJOR, "drm", &drm_stub_fops); if (ret < 0) goto error; diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 94bd872d56c48b..22a6c32e4039a8 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -790,6 +790,7 @@ long drm_ioctl(struct file *filp, char *kdata = NULL; unsigned int in_size, out_size, drv_size, ksize; bool is_driver_ioctl; + int flags; dev = file_priv->minor->dev; @@ -823,6 +824,15 @@ long drm_ioctl(struct file *filp, (long)old_encode_dev(file_priv->minor->kdev->devt), file_priv->authenticated, ioctl->name); + flags = ioctl->flags; + if (drm_master_relax) { + if (nr == DRM_IOCTL_NR(DRM_IOCTL_SET_MASTER)) + flags = DRM_AUTH; + else if (nr == DRM_IOCTL_NR(DRM_IOCTL_DROP_MASTER)) + flags = DRM_MASTER; + } + + /* Do not trust userspace, use our own definition */ func = ioctl->func; @@ -850,7 +860,8 @@ long drm_ioctl(struct file *filp, if (ksize > in_size) memset(kdata + in_size, 0, ksize - in_size); - retcode = drm_ioctl_kernel(filp, func, kdata, ioctl->flags); + retcode = drm_ioctl_kernel(filp, func, kdata, flags); + if (copy_to_user((void __user *)arg, kdata, out_size) != 0) retcode = -EFAULT; diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h index 252dd216cc607e..ebde29c1fc2c83 100644 --- a/include/drm/drm_drv.h +++ b/include/drm/drm_drv.h @@ -612,6 +612,7 @@ struct drm_driver { }; extern unsigned int drm_debug; +extern bool drm_master_relax; int drm_dev_init(struct drm_device *dev, struct drm_driver *driver, -- 2.20.0.rc2.403.gdbc3b29805-goog