Skip to content

Commit a0af2e5

Browse files
thomashvmwairlied
authored andcommitted
drm: Fix an unwanted master inheritance v2
A client calling drmSetMaster() using a file descriptor that was opened when another client was master would inherit the latter client's master object and all its authenticated clients. This is unwanted behaviour, and when this happens, instead allocate a brand new master object for the client calling drmSetMaster(). Fixes a BUG() throw in vmw_master_set(). Cc: <stable@vger.kernel.org> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
1 parent f46e699 commit a0af2e5

File tree

3 files changed

+67
-28
lines changed

3 files changed

+67
-28
lines changed

drivers/gpu/drm/drm_drv.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,11 @@ int drm_setmaster_ioctl(struct drm_device *dev, void *data,
160160
goto out_unlock;
161161
}
162162

163+
if (!file_priv->allowed_master) {
164+
ret = drm_new_set_master(dev, file_priv);
165+
goto out_unlock;
166+
}
167+
163168
file_priv->minor->master = drm_master_get(file_priv->master);
164169
file_priv->is_master = 1;
165170
if (dev->driver->master_set) {

drivers/gpu/drm/drm_fops.c

Lines changed: 56 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,60 @@ static int drm_cpu_valid(void)
125125
return 1;
126126
}
127127

128+
/**
129+
* drm_new_set_master - Allocate a new master object and become master for the
130+
* associated master realm.
131+
*
132+
* @dev: The associated device.
133+
* @fpriv: File private identifying the client.
134+
*
135+
* This function must be called with dev::struct_mutex held.
136+
* Returns negative error code on failure. Zero on success.
137+
*/
138+
int drm_new_set_master(struct drm_device *dev, struct drm_file *fpriv)
139+
{
140+
struct drm_master *old_master;
141+
int ret;
142+
143+
lockdep_assert_held_once(&dev->master_mutex);
144+
145+
/* create a new master */
146+
fpriv->minor->master = drm_master_create(fpriv->minor);
147+
if (!fpriv->minor->master)
148+
return -ENOMEM;
149+
150+
/* take another reference for the copy in the local file priv */
151+
old_master = fpriv->master;
152+
fpriv->master = drm_master_get(fpriv->minor->master);
153+
154+
if (dev->driver->master_create) {
155+
ret = dev->driver->master_create(dev, fpriv->master);
156+
if (ret)
157+
goto out_err;
158+
}
159+
if (dev->driver->master_set) {
160+
ret = dev->driver->master_set(dev, fpriv, true);
161+
if (ret)
162+
goto out_err;
163+
}
164+
165+
fpriv->is_master = 1;
166+
fpriv->allowed_master = 1;
167+
fpriv->authenticated = 1;
168+
if (old_master)
169+
drm_master_put(&old_master);
170+
171+
return 0;
172+
173+
out_err:
174+
/* drop both references and restore old master on failure */
175+
drm_master_put(&fpriv->minor->master);
176+
drm_master_put(&fpriv->master);
177+
fpriv->master = old_master;
178+
179+
return ret;
180+
}
181+
128182
/**
129183
* Called whenever a process opens /dev/drm.
130184
*
@@ -189,35 +243,9 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor)
189243
mutex_lock(&dev->master_mutex);
190244
if (drm_is_primary_client(priv) && !priv->minor->master) {
191245
/* create a new master */
192-
priv->minor->master = drm_master_create(priv->minor);
193-
if (!priv->minor->master) {
194-
ret = -ENOMEM;
246+
ret = drm_new_set_master(dev, priv);
247+
if (ret)
195248
goto out_close;
196-
}
197-
198-
priv->is_master = 1;
199-
/* take another reference for the copy in the local file priv */
200-
priv->master = drm_master_get(priv->minor->master);
201-
priv->authenticated = 1;
202-
203-
if (dev->driver->master_create) {
204-
ret = dev->driver->master_create(dev, priv->master);
205-
if (ret) {
206-
/* drop both references if this fails */
207-
drm_master_put(&priv->minor->master);
208-
drm_master_put(&priv->master);
209-
goto out_close;
210-
}
211-
}
212-
if (dev->driver->master_set) {
213-
ret = dev->driver->master_set(dev, priv, true);
214-
if (ret) {
215-
/* drop both references if this fails */
216-
drm_master_put(&priv->minor->master);
217-
drm_master_put(&priv->master);
218-
goto out_close;
219-
}
220-
}
221249
} else if (drm_is_primary_client(priv)) {
222250
/* get a reference to the master */
223251
priv->master = drm_master_get(priv->minor->master);

include/drm/drmP.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,11 @@ struct drm_file {
309309
unsigned universal_planes:1;
310310
/* true if client understands atomic properties */
311311
unsigned atomic:1;
312+
/*
313+
* This client is allowed to gain master privileges for @master.
314+
* Protected by struct drm_device::master_mutex.
315+
*/
316+
unsigned allowed_master:1;
312317

313318
struct pid *pid;
314319
kuid_t uid;
@@ -910,6 +915,7 @@ extern int drm_open(struct inode *inode, struct file *filp);
910915
extern ssize_t drm_read(struct file *filp, char __user *buffer,
911916
size_t count, loff_t *offset);
912917
extern int drm_release(struct inode *inode, struct file *filp);
918+
extern int drm_new_set_master(struct drm_device *dev, struct drm_file *fpriv);
913919

914920
/* Mapping support (drm_vm.h) */
915921
extern unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait);

0 commit comments

Comments
 (0)