aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
authorThomas Hellstrom <thellstrom@vmware.com>2014-02-27 06:56:08 -0500
committerThomas Hellstrom <thellstrom@vmware.com>2014-03-28 09:19:03 -0400
commit64190bded3c84ed988ff620ec2f4cd858b53426c (patch)
treef7e0d5b213e700ab0697e306a8e9bcb8ceb71406 /drivers/gpu/drm
parent294adf7d86226c0e6abeb4475159b03aa315d56f (diff)
drm/vmwgfx: Reinstate and tighten security around legacy master model
The following restrictions affect clients connecting using legacy nodes: *) Masters that have dropped master privilieges are not considered authenticated until they regain master privileges. *) Clients whose master have dropped master privileges block interruptibly on ioctls requiring authentication until their master regains master privileges. If their master exits, they are killed. This is primarily designed to prevent clients authenticated with one master to access data from clients authenticated with another master. (Think fast user-switching or data sniffers enabled while X is vt-switched). Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Reviewed-by: Brian Paul <brianp@vmware.com>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.c94
1 files changed, 89 insertions, 5 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index 54cfeb6fc3b1..8fdbe26a98d2 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -982,12 +982,70 @@ out_no_tfile:
982 return ret; 982 return ret;
983} 983}
984 984
985static long vmw_unlocked_ioctl(struct file *filp, unsigned int cmd, 985static struct vmw_master *vmw_master_check(struct drm_device *dev,
986 unsigned long arg) 986 struct drm_file *file_priv,
987 unsigned int flags)
988{
989 int ret;
990 struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv);
991 struct vmw_master *vmaster;
992
993 if (file_priv->minor->type != DRM_MINOR_LEGACY ||
994 !(flags & DRM_AUTH))
995 return NULL;
996
997 ret = mutex_lock_interruptible(&dev->master_mutex);
998 if (unlikely(ret != 0))
999 return ERR_PTR(-ERESTARTSYS);
1000
1001 if (file_priv->is_master) {
1002 mutex_unlock(&dev->master_mutex);
1003 return NULL;
1004 }
1005
1006 /*
1007 * Check if we were previously master, but now dropped.
1008 */
1009 if (vmw_fp->locked_master) {
1010 mutex_unlock(&dev->master_mutex);
1011 DRM_ERROR("Dropped master trying to access ioctl that "
1012 "requires authentication.\n");
1013 return ERR_PTR(-EACCES);
1014 }
1015 mutex_unlock(&dev->master_mutex);
1016
1017 /*
1018 * Taking the drm_global_mutex after the TTM lock might deadlock
1019 */
1020 if (!(flags & DRM_UNLOCKED)) {
1021 DRM_ERROR("Refusing locked ioctl access.\n");
1022 return ERR_PTR(-EDEADLK);
1023 }
1024
1025 /*
1026 * Take the TTM lock. Possibly sleep waiting for the authenticating
1027 * master to become master again, or for a SIGTERM if the
1028 * authenticating master exits.
1029 */
1030 vmaster = vmw_master(file_priv->master);
1031 ret = ttm_read_lock(&vmaster->lock, true);
1032 if (unlikely(ret != 0))
1033 vmaster = ERR_PTR(ret);
1034
1035 return vmaster;
1036}
1037
1038static long vmw_generic_ioctl(struct file *filp, unsigned int cmd,
1039 unsigned long arg,
1040 long (*ioctl_func)(struct file *, unsigned int,
1041 unsigned long))
987{ 1042{
988 struct drm_file *file_priv = filp->private_data; 1043 struct drm_file *file_priv = filp->private_data;
989 struct drm_device *dev = file_priv->minor->dev; 1044 struct drm_device *dev = file_priv->minor->dev;
990 unsigned int nr = DRM_IOCTL_NR(cmd); 1045 unsigned int nr = DRM_IOCTL_NR(cmd);
1046 struct vmw_master *vmaster;
1047 unsigned int flags;
1048 long ret;
991 1049
992 /* 1050 /*
993 * Do extra checking on driver private ioctls. 1051 * Do extra checking on driver private ioctls.
@@ -996,18 +1054,44 @@ static long vmw_unlocked_ioctl(struct file *filp, unsigned int cmd,
996 if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END) 1054 if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END)
997 && (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) { 1055 && (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) {
998 const struct drm_ioctl_desc *ioctl = 1056 const struct drm_ioctl_desc *ioctl =
999 &vmw_ioctls[nr - DRM_COMMAND_BASE]; 1057 &vmw_ioctls[nr - DRM_COMMAND_BASE];
1000 1058
1001 if (unlikely(ioctl->cmd_drv != cmd)) { 1059 if (unlikely(ioctl->cmd_drv != cmd)) {
1002 DRM_ERROR("Invalid command format, ioctl %d\n", 1060 DRM_ERROR("Invalid command format, ioctl %d\n",
1003 nr - DRM_COMMAND_BASE); 1061 nr - DRM_COMMAND_BASE);
1004 return -EINVAL; 1062 return -EINVAL;
1005 } 1063 }
1064 flags = ioctl->flags;
1065 } else if (!drm_ioctl_flags(nr, &flags))
1066 return -EINVAL;
1067
1068 vmaster = vmw_master_check(dev, file_priv, flags);
1069 if (unlikely(IS_ERR(vmaster))) {
1070 DRM_INFO("IOCTL ERROR %d\n", nr);
1071 return PTR_ERR(vmaster);
1006 } 1072 }
1007 1073
1008 return drm_ioctl(filp, cmd, arg); 1074 ret = ioctl_func(filp, cmd, arg);
1075 if (vmaster)
1076 ttm_read_unlock(&vmaster->lock);
1077
1078 return ret;
1079}
1080
1081static long vmw_unlocked_ioctl(struct file *filp, unsigned int cmd,
1082 unsigned long arg)
1083{
1084 return vmw_generic_ioctl(filp, cmd, arg, &drm_ioctl);
1009} 1085}
1010 1086
1087#ifdef CONFIG_COMPAT
1088static long vmw_compat_ioctl(struct file *filp, unsigned int cmd,
1089 unsigned long arg)
1090{
1091 return vmw_generic_ioctl(filp, cmd, arg, &drm_compat_ioctl);
1092}
1093#endif
1094
1011static void vmw_lastclose(struct drm_device *dev) 1095static void vmw_lastclose(struct drm_device *dev)
1012{ 1096{
1013 struct drm_crtc *crtc; 1097 struct drm_crtc *crtc;
@@ -1315,7 +1399,7 @@ static const struct file_operations vmwgfx_driver_fops = {
1315 .poll = vmw_fops_poll, 1399 .poll = vmw_fops_poll,
1316 .read = vmw_fops_read, 1400 .read = vmw_fops_read,
1317#if defined(CONFIG_COMPAT) 1401#if defined(CONFIG_COMPAT)
1318 .compat_ioctl = drm_compat_ioctl, 1402 .compat_ioctl = vmw_compat_ioctl,
1319#endif 1403#endif
1320 .llseek = noop_llseek, 1404 .llseek = noop_llseek,
1321}; 1405};