Skip to content

Commit c32fc9c

Browse files
committed
Merge tag 'vmwgfx-next-2014-03-28' of git://people.freedesktop.org/~thomash/linux into drm-next
vmwgfx render-node support and drm + ttm changes it depends upon. Pull request of 2014-03-28 * tag 'vmwgfx-next-2014-03-28' of git://people.freedesktop.org/~thomash/linux: drm/vmwgfx: Bump driver minor and date drm/vmwgfx: Enable render nodes drm/vmwgfx: Tighten the security around buffer maps drm/ttm: Add a ttm_ref_object_exists function drm/vmwgfx: Tighten security around surface sharing v2 drm/vmwgfx: Allow prime fds in the surface reference ioctls drm/vmwgfx: Drop authentication requirement on UNREF ioctls drm/vmwgfx: Reinstate and tighten security around legacy master model drm/vmwgfx: Use a per-device semaphore for reservation protection drm: Add a function to get the ioctl flags drm: Protect the master management with a drm_device::master_mutex v3 drm: Remove the minor master list drm: Improve on minor type helpers v3 drm: Make control nodes master-less v3 drm: Break out ioctl permission check to a separate function v2 drm: Have the crtc code only reference master from legacy nodes v2
2 parents 60f2b4a + 03c5b8f commit c32fc9c

19 files changed

+500
-226
lines changed

drivers/gpu/drm/drm_crtc.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1492,9 +1492,9 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
14921492
mutex_unlock(&file_priv->fbs_lock);
14931493

14941494
drm_modeset_lock_all(dev);
1495-
mode_group = &file_priv->master->minor->mode_group;
1496-
if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
1495+
if (!drm_is_primary_client(file_priv)) {
14971496

1497+
mode_group = NULL;
14981498
list_for_each(lh, &dev->mode_config.crtc_list)
14991499
crtc_count++;
15001500

@@ -1505,6 +1505,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
15051505
encoder_count++;
15061506
} else {
15071507

1508+
mode_group = &file_priv->master->minor->mode_group;
15081509
crtc_count = mode_group->num_crtcs;
15091510
connector_count = mode_group->num_connectors;
15101511
encoder_count = mode_group->num_encoders;
@@ -1519,7 +1520,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
15191520
if (card_res->count_crtcs >= crtc_count) {
15201521
copied = 0;
15211522
crtc_id = (uint32_t __user *)(unsigned long)card_res->crtc_id_ptr;
1522-
if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
1523+
if (!mode_group) {
15231524
list_for_each_entry(crtc, &dev->mode_config.crtc_list,
15241525
head) {
15251526
DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
@@ -1546,7 +1547,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
15461547
if (card_res->count_encoders >= encoder_count) {
15471548
copied = 0;
15481549
encoder_id = (uint32_t __user *)(unsigned long)card_res->encoder_id_ptr;
1549-
if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
1550+
if (!mode_group) {
15501551
list_for_each_entry(encoder,
15511552
&dev->mode_config.encoder_list,
15521553
head) {
@@ -1577,7 +1578,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
15771578
if (card_res->count_connectors >= connector_count) {
15781579
copied = 0;
15791580
connector_id = (uint32_t __user *)(unsigned long)card_res->connector_id_ptr;
1580-
if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
1581+
if (!mode_group) {
15811582
list_for_each_entry(connector,
15821583
&dev->mode_config.connector_list,
15831584
head) {
@@ -2846,7 +2847,8 @@ int drm_mode_getfb(struct drm_device *dev,
28462847
r->bpp = fb->bits_per_pixel;
28472848
r->pitch = fb->pitches[0];
28482849
if (fb->funcs->create_handle) {
2849-
if (file_priv->is_master || capable(CAP_SYS_ADMIN)) {
2850+
if (file_priv->is_master || capable(CAP_SYS_ADMIN) ||
2851+
drm_is_control_client(file_priv)) {
28502852
ret = fb->funcs->create_handle(fb, file_priv,
28512853
&r->handle);
28522854
} else {

drivers/gpu/drm/drm_drv.c

Lines changed: 94 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,45 @@ static int drm_version(struct drm_device *dev, void *data,
285285
return err;
286286
}
287287

288+
/**
289+
* drm_ioctl_permit - Check ioctl permissions against caller
290+
*
291+
* @flags: ioctl permission flags.
292+
* @file_priv: Pointer to struct drm_file identifying the caller.
293+
*
294+
* Checks whether the caller is allowed to run an ioctl with the
295+
* indicated permissions. If so, returns zero. Otherwise returns an
296+
* error code suitable for ioctl return.
297+
*/
298+
static int drm_ioctl_permit(u32 flags, struct drm_file *file_priv)
299+
{
300+
/* ROOT_ONLY is only for CAP_SYS_ADMIN */
301+
if (unlikely((flags & DRM_ROOT_ONLY) && !capable(CAP_SYS_ADMIN)))
302+
return -EACCES;
303+
304+
/* AUTH is only for authenticated or render client */
305+
if (unlikely((flags & DRM_AUTH) && !drm_is_render_client(file_priv) &&
306+
!file_priv->authenticated))
307+
return -EACCES;
308+
309+
/* MASTER is only for master or control clients */
310+
if (unlikely((flags & DRM_MASTER) && !file_priv->is_master &&
311+
!drm_is_control_client(file_priv)))
312+
return -EACCES;
313+
314+
/* Control clients must be explicitly allowed */
315+
if (unlikely(!(flags & DRM_CONTROL_ALLOW) &&
316+
drm_is_control_client(file_priv)))
317+
return -EACCES;
318+
319+
/* Render clients must be explicitly allowed */
320+
if (unlikely(!(flags & DRM_RENDER_ALLOW) &&
321+
drm_is_render_client(file_priv)))
322+
return -EACCES;
323+
324+
return 0;
325+
}
326+
288327
/**
289328
* Called whenever a process performs an ioctl on /dev/drm.
290329
*
@@ -350,52 +389,51 @@ long drm_ioctl(struct file *filp,
350389
/* Do not trust userspace, use our own definition */
351390
func = ioctl->func;
352391

353-
if (!func) {
392+
if (unlikely(!func)) {
354393
DRM_DEBUG("no function\n");
355394
retcode = -EINVAL;
356-
} else if (((ioctl->flags & DRM_ROOT_ONLY) && !capable(CAP_SYS_ADMIN)) ||
357-
((ioctl->flags & DRM_AUTH) && !drm_is_render_client(file_priv) && !file_priv->authenticated) ||
358-
((ioctl->flags & DRM_MASTER) && !file_priv->is_master) ||
359-
(!(ioctl->flags & DRM_CONTROL_ALLOW) && (file_priv->minor->type == DRM_MINOR_CONTROL)) ||
360-
(!(ioctl->flags & DRM_RENDER_ALLOW) && drm_is_render_client(file_priv))) {
361-
retcode = -EACCES;
362-
} else {
363-
if (cmd & (IOC_IN | IOC_OUT)) {
364-
if (asize <= sizeof(stack_kdata)) {
365-
kdata = stack_kdata;
366-
} else {
367-
kdata = kmalloc(asize, GFP_KERNEL);
368-
if (!kdata) {
369-
retcode = -ENOMEM;
370-
goto err_i1;
371-
}
372-
}
373-
if (asize > usize)
374-
memset(kdata + usize, 0, asize - usize);
375-
}
395+
goto err_i1;
396+
}
376397

377-
if (cmd & IOC_IN) {
378-
if (copy_from_user(kdata, (void __user *)arg,
379-
usize) != 0) {
380-
retcode = -EFAULT;
398+
retcode = drm_ioctl_permit(ioctl->flags, file_priv);
399+
if (unlikely(retcode))
400+
goto err_i1;
401+
402+
if (cmd & (IOC_IN | IOC_OUT)) {
403+
if (asize <= sizeof(stack_kdata)) {
404+
kdata = stack_kdata;
405+
} else {
406+
kdata = kmalloc(asize, GFP_KERNEL);
407+
if (!kdata) {
408+
retcode = -ENOMEM;
381409
goto err_i1;
382410
}
383-
} else
384-
memset(kdata, 0, usize);
385-
386-
if (ioctl->flags & DRM_UNLOCKED)
387-
retcode = func(dev, kdata, file_priv);
388-
else {
389-
mutex_lock(&drm_global_mutex);
390-
retcode = func(dev, kdata, file_priv);
391-
mutex_unlock(&drm_global_mutex);
392411
}
412+
if (asize > usize)
413+
memset(kdata + usize, 0, asize - usize);
414+
}
393415

394-
if (cmd & IOC_OUT) {
395-
if (copy_to_user((void __user *)arg, kdata,
396-
usize) != 0)
397-
retcode = -EFAULT;
416+
if (cmd & IOC_IN) {
417+
if (copy_from_user(kdata, (void __user *)arg,
418+
usize) != 0) {
419+
retcode = -EFAULT;
420+
goto err_i1;
398421
}
422+
} else
423+
memset(kdata, 0, usize);
424+
425+
if (ioctl->flags & DRM_UNLOCKED)
426+
retcode = func(dev, kdata, file_priv);
427+
else {
428+
mutex_lock(&drm_global_mutex);
429+
retcode = func(dev, kdata, file_priv);
430+
mutex_unlock(&drm_global_mutex);
431+
}
432+
433+
if (cmd & IOC_OUT) {
434+
if (copy_to_user((void __user *)arg, kdata,
435+
usize) != 0)
436+
retcode = -EFAULT;
399437
}
400438

401439
err_i1:
@@ -412,3 +450,21 @@ long drm_ioctl(struct file *filp,
412450
return retcode;
413451
}
414452
EXPORT_SYMBOL(drm_ioctl);
453+
454+
/**
455+
* drm_ioctl_flags - Check for core ioctl and return ioctl permission flags
456+
*
457+
* @nr: Ioctl number.
458+
* @flags: Where to return the ioctl permission flags
459+
*/
460+
bool drm_ioctl_flags(unsigned int nr, unsigned int *flags)
461+
{
462+
if ((nr >= DRM_COMMAND_END && nr < DRM_CORE_IOCTL_COUNT) ||
463+
(nr < DRM_COMMAND_BASE)) {
464+
*flags = drm_ioctls[nr].flags;
465+
return true;
466+
}
467+
468+
return false;
469+
}
470+
EXPORT_SYMBOL(drm_ioctl_flags);

drivers/gpu/drm/drm_fops.c

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -231,50 +231,43 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
231231

232232
/* if there is no current master make this fd it, but do not create
233233
* any master object for render clients */
234-
mutex_lock(&dev->struct_mutex);
235-
if (!priv->minor->master && !drm_is_render_client(priv)) {
234+
mutex_lock(&dev->master_mutex);
235+
if (drm_is_primary_client(priv) && !priv->minor->master) {
236236
/* create a new master */
237237
priv->minor->master = drm_master_create(priv->minor);
238238
if (!priv->minor->master) {
239-
mutex_unlock(&dev->struct_mutex);
240239
ret = -ENOMEM;
241240
goto out_close;
242241
}
243242

244243
priv->is_master = 1;
245244
/* take another reference for the copy in the local file priv */
246245
priv->master = drm_master_get(priv->minor->master);
247-
248246
priv->authenticated = 1;
249247

250-
mutex_unlock(&dev->struct_mutex);
251248
if (dev->driver->master_create) {
252249
ret = dev->driver->master_create(dev, priv->master);
253250
if (ret) {
254-
mutex_lock(&dev->struct_mutex);
255251
/* drop both references if this fails */
256252
drm_master_put(&priv->minor->master);
257253
drm_master_put(&priv->master);
258-
mutex_unlock(&dev->struct_mutex);
259254
goto out_close;
260255
}
261256
}
262-
mutex_lock(&dev->struct_mutex);
263257
if (dev->driver->master_set) {
264258
ret = dev->driver->master_set(dev, priv, true);
265259
if (ret) {
266260
/* drop both references if this fails */
267261
drm_master_put(&priv->minor->master);
268262
drm_master_put(&priv->master);
269-
mutex_unlock(&dev->struct_mutex);
270263
goto out_close;
271264
}
272265
}
273-
} else if (!drm_is_render_client(priv)) {
266+
} else if (drm_is_primary_client(priv)) {
274267
/* get a reference to the master */
275268
priv->master = drm_master_get(priv->minor->master);
276269
}
277-
mutex_unlock(&dev->struct_mutex);
270+
mutex_unlock(&dev->master_mutex);
278271

279272
mutex_lock(&dev->struct_mutex);
280273
list_add(&priv->lhead, &dev->filelist);
@@ -302,6 +295,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
302295
return 0;
303296

304297
out_close:
298+
mutex_unlock(&dev->master_mutex);
305299
if (dev->driver->postclose)
306300
dev->driver->postclose(dev, priv);
307301
out_prime_destroy:
@@ -489,11 +483,13 @@ int drm_release(struct inode *inode, struct file *filp)
489483
}
490484
mutex_unlock(&dev->ctxlist_mutex);
491485

492-
mutex_lock(&dev->struct_mutex);
486+
mutex_lock(&dev->master_mutex);
493487

494488
if (file_priv->is_master) {
495489
struct drm_master *master = file_priv->master;
496490
struct drm_file *temp;
491+
492+
mutex_lock(&dev->struct_mutex);
497493
list_for_each_entry(temp, &dev->filelist, lhead) {
498494
if ((temp->master == file_priv->master) &&
499495
(temp != file_priv))
@@ -512,6 +508,7 @@ int drm_release(struct inode *inode, struct file *filp)
512508
master->lock.file_priv = NULL;
513509
wake_up_interruptible_all(&master->lock.lock_queue);
514510
}
511+
mutex_unlock(&dev->struct_mutex);
515512

516513
if (file_priv->minor->master == file_priv->master) {
517514
/* drop the reference held my the minor */
@@ -521,10 +518,13 @@ int drm_release(struct inode *inode, struct file *filp)
521518
}
522519
}
523520

524-
/* drop the reference held my the file priv */
521+
/* drop the master reference held by the file priv */
525522
if (file_priv->master)
526523
drm_master_put(&file_priv->master);
527524
file_priv->is_master = 0;
525+
mutex_unlock(&dev->master_mutex);
526+
527+
mutex_lock(&dev->struct_mutex);
528528
list_del(&file_priv->lhead);
529529
mutex_unlock(&dev->struct_mutex);
530530

0 commit comments

Comments
 (0)