在深入研究它为什么不起作用之前,我必须了解它是如何工作的。
因此,实际上调用drmModeSetCRTC
和drmSetMaster
在 libdrm 中只是调用ioctl
:
包括/xf86drm.c
int drmSetMaster(int fd)
{
return ioctl(fd, DRM_IOCTL_SET_MASTER, 0);
}
这是由内核处理的。在我的程序中,控制显示的最重要功能是drmModeSetCRTC
and drmModeAddFB
,其余的实际上只是诊断。那么让我们看看它们是如何被内核处理的。原来有一个大表将ioctl
事件映射到它们的处理程序:
驱动程序/gpu/drm/drm_ioctl.c
static const struct drm_ioctl_desc drm_ioctls[] = {
...
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
...,
DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB2, drm_mode_addfb2, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
...,
},
这是使用的drm_ioctl
,其中最有趣的部分是drm_ioctl_permit
。
驱动程序/gpu/drm/drm_ioctl.c
long drm_ioctl(struct file *filp,
unsigned int cmd, unsigned long arg)
{
...
retcode = drm_ioctl_permit(ioctl->flags, file_priv);
if (unlikely(retcode))
goto err_i1;
...
}
static int drm_ioctl_permit(u32 flags, struct drm_file *file_priv)
{
/* ROOT_ONLY is only for CAP_SYS_ADMIN */
if (unlikely((flags & DRM_ROOT_ONLY) && !capable(CAP_SYS_ADMIN)))
return -EACCES;
/* AUTH is only for authenticated or render client */
if (unlikely((flags & DRM_AUTH) && !drm_is_render_client(file_priv) &&
!file_priv->authenticated))
return -EACCES;
/* MASTER is only for master or control clients */
if (unlikely((flags & DRM_MASTER) && !file_priv->is_master &&
!drm_is_control_client(file_priv)))
return -EACCES;
/* Control clients must be explicitly allowed */
if (unlikely(!(flags & DRM_CONTROL_ALLOW) &&
drm_is_control_client(file_priv)))
return -EACCES;
/* Render clients must be explicitly allowed */
if (unlikely(!(flags & DRM_RENDER_ALLOW) &&
drm_is_render_client(file_priv)))
return -EACCES;
return 0;
}
到目前为止,一切都说得通。我确实可以打电话drmModeSetCrtc
,因为我是当前的 DRM 大师。(我不知道为什么。这可能与我切换到另一个 VT 后 X11 正确放弃其权利有关。也许仅此一项就可以让我在开始搞乱时自动成为新的 DRM 大师ioctl
?)
无论如何,让我们看一下drmDropMaster
and的drmSetMaster
定义:
驱动程序/gpu/drm/drm_ioctl.c
static const struct drm_ioctl_desc drm_ioctls[] = {
...
DRM_IOCTL_DEF(DRM_IOCTL_SET_MASTER, drm_setmaster_ioctl, DRM_ROOT_ONLY),
DRM_IOCTL_DEF(DRM_IOCTL_DROP_MASTER, drm_dropmaster_ioctl, DRM_ROOT_ONLY),
...
};
什么。
所以我的困惑是正确的。我没有做错任何事,事情真的是这样的。
我的印象是这是一个严重的内核错误。要么我根本不能设置 CRTC,要么我应该能够删除/设置 master。在任何情况下,撤销每个非 root 程序在屏幕上绘制的权利,因为
任何随机应用程序都可以在您的屏幕上显示它想要的任何内容
太激进了。作为用户,我应该可以自由地控制它,而无需授予对整个程序的 root 访问权限,也不依赖于 systemd,例如通过制作chmod 0777 /dev/dri/card0
(或组管理)。就像现在一样,在我看来,这就像懒人对适当权限管理的回答。