在我们的 3.X 系列内核上,专有的 PCI-Express 设备具有专有的内核驱动程序。我们在拖网 PCI 功能时发现了一些奇怪的错误。我找不到任何很棒的文档 - 有谁知道内核驱动程序是否可以根据用户 ID控制sysfs
/公开哪些数据?procfs
具体来说,此调用在供应商的实用程序中失败:
c = pci_find_cap(mdev->pdev, VENDOR_EXT_CAP_ID, PCI_CAP_EXTENDED);
经过大量挖掘后,我可以使用 setpci 查找VENDOR_EXT_CAP_ID
.
我看到的是:
- FS 权限授予用户和 root 读取权限。
- 打开文件“config”
sysfs
并读取$data
. $data
对于用户和$data
root 来说是不同的。
我看不到很多关于如何做到这一点的文档,我们也没有与供应商建立良好的升级路径。有没有人见过这个?
答案1
是的,内核驱动程序可以根据用户 ID 和/或内核有权访问的基本上任何信息来控制它在 sysfs/procfs 中公开的数据。
当您从 procfs 或 sysfs 读取某些内容时,用于读取信息的系统调用基本上会结束调用相应驱动程序中的函数。该函数可以查看调用读取操作的用户空间进程的所有信息,并且当然可以基于该信息或基于内核可以访问的任何其他内容来修改其输出。
在 的特定情况下/sys/bus/pci/devices/<PCI device ID>/config
,任何读取它的尝试都会以pci_read_config()
文件中的函数drivers/pci/pci-sysfs.c
它将检查调用的用户空间进程是否具有 CAP_SYS_ADMIN 功能(在大多数情况下意味着用户具有 CAP_SYS_ADMIN 功能root
)。如果用户不具备该能力,该函数会将可读的 PCI 配置数据限制为前(dev->cfg_size)
字节(CardBus 上为 128 字节)。
在内核版本 2.6.5 及更低版本中,限制曾经是 256 字节,但在 2.6.6 中它被收紧到(dev->cfg_size)
。在现代系统中,(dev->cfg_size)
根据相关设备,该字节往往是 64 或 256 字节。
您可以用一个简单的lspci -v
.如果以 root 身份运行它,您将看到每个设备的 PCI/PCIe 功能。但如果您以普通用户身份运行它,您将得到:
Capabilities: <access denied>
答案2
使用带有内核的 AlmaLinux 8.84.18.0-477.27.2.el8_8.x86_64
旨在创建一个用户空间应用程序,以作为普通用户解码 PCIe 功能。对于此应用程序,希望将端点的 PCIe 链路宽度和速度能力与端点所连接的 PCIe 根端口相关联。
不同机制中:
在没有为可执行文件提供任何 Linux 功能的情况下,以普通用户身份尝试读取 PCIe 功能时,函数
pci_device_cfg_read*
会libpciaccess
失败返回。ENXIO
使用后即
sudo setcap cap_sys_admin=ep <executable>
可以普通用户身份读取 PCIe 功能。使用
pciutils
:- 、
pci_read_byte
和函数在尝试以普通用户身份读取 PCI 功能时返回全 1 值,而无需为可执行文件提供任何 Linux 功能pci_read_word
。不是在失败时设置的。pci_read_long
errno
- 该
pci_read_block
函数返回零表示在尝试以普通用户身份读取 PCIe 功能时失败,而没有为可执行文件提供任何 Linux 功能。
使用后即
sudo setcap cap_sys_admin=ep <executable>
可以普通用户身份读取 PCIe 功能。- 、
使用VFIO,获得的文件描述符
VFIO_GROUP_GET_DEVICE_FD
可以作为普通用户读取PCIe能力没有需要为可执行文件提供任何 Linux 功能的可执行文件。然而,这种方法的缺点是 VFIO 不能用于 PCIe 根端口,因为
vfio-pci
驱动程序仅绑定到具有标头类型的 PCI 设备NORMAL
。vfio_pci_probe包含以下代码,解释了尝试将 VFIO 绑定到具有BRIDGE
标头类型的 PCIe 根端口时出现的错误:if (pdev->hdr_type != PCI_HEADER_TYPE_NORMAL) return -EINVAL;