测试场景 NVIDIA-Driver 418.67
nvidia-docker 版本
1 | [root~]# rpm -qa|grep nvidia |
Linux 设备的major 和minor number
Linux 系统的/dev 目录下面的设备文件是用来描述外设的,如/dev/sda1表示第一块硬盘的第一个分区,但是这个/dev/sda1紧紧是方便用户观察,Linux内核中表示不同的设备是通过major和minor number 实现,对多major和minor number 来加载相应的驱动程序。其中
major number:表示不同的设备类型
minor number :表示同一个设备的不同分区
主设备号标识设备对应的驱动程序(或者多个相关的驱动程序共用相同的一个主设备号),次设备号表示驱动程序驱动的一个设备。
例如Linux系统中的sda磁盘和sdb 磁盘major number 都是8,但是sda的minor number 是从0 开始,sdb的minor number 是16开始
使用以下命令查看major number 和minor number
1 | [root@node devices]# ls -l /dev/sda1 |
上述命令中,brw的b表示块设备(block),主设备号是8,次设备号是1。也就是8,1表示major,minor。也可以stat –format=%t:%T显示
查看GPU的信息major和minor 信息
1 | [root@node ~]# ls -l /dev/nvidia0 |
也可以通过代码获取major number 和minor numer ,这里找到一段代码用于获取
1 | func getDiskMajorMinor(path string) (major, minor int, err error) { |
Linux mknod 命令
linux操作系统跟外部设备(如磁盘、光盘等)的通信都是通过设备文件进行的,应用程序可以打开、关闭、读写这些设备文件,从而对设备进行读写,这种操作就像读写普通的文件一样easy。linux为不同种类的设备文件提供了相同的接口,比如read(),write(),open(),close()。
在系统与设备通信之前,系统首先要建立一个设备文件,这个设备文件存放在/dev目录下。其实系统默认情况下就已经生成了很多设备文件,有时候需要自己手动新建一些设备文件,这个时候就会用到像mkdir, mknod这样的命令。
我们也可以自己mknod /dev/sda1_myref b 8 1来创建设备文件。设备文件可以看成是对linux内核设备对象的一个索引。所以主设备号和次设备号均相同的两个设备文件,对其中一个设备的修改,在另一个设备文件访问时也会看到修改的结果。
mknod 的标准形式为: mknod DEVNAME {b | c} MAJOR MINOR
1,DEVNAME是要创建的设备文件名,如果想将设备文件放在一个特定的文件夹下,就需要先用mkdir在dev目录下新建一个目录;
2, b和c 分别表示块设备和字符设备:
b表示系统从块设备中读取数据的时候,直接从内存的buffer中读取数据,而不经过磁盘;
c表示字符设备文件与设备传送数据的时候是以字符的形式传送,一次传送一个字符,比如打印机、终端都是以字符的形式传送数据;
3,MAJOR和MINOR分别表示主设备号和次设备号:为了管理设备,系统为每个设备分配一个编号,一个设备号由主设备号和次设备号组成。主设备号标示某一种类的设备,次设备号用来区分同一类型的设备。linux操作系统中为设备文件编号分配了32位无符号整数,其中前12位是主设备号,后20位为次设备号,所以在向系统申请设备文件时主设备号不好超过4095,次设备号不好超过2^20 -1。
cgroup device子系统
使用devices 子系统可以允许或者拒绝cgroup中的进程访问设备。devices子系统有三个控制文件:devices.allow,devices.deny,devices.list。devices.allow用于指定cgroup中的进程可以访问的设备,devices.deny用于指定cgroup中的进程不能访问的设备,devices.list用于报告cgroup中的进程访问的设备。devices.allow文件中包含若干条目,每个条目有四个字段:type、major、minor 和 access。type、major 和 minor 字段中使用的值对应 Linux 分配的设备。
type指定设备类型:
a - 应用所有设备,可以是字符设备,也可以是块设备
b- 指定块设备
c - 指定字符设备
major和minor指定设备的主次设备号。
access 则指定相应的权限:
r - 允许任务从指定设备中读取
w - 允许任务写入指定设备
m - 允许任务生成还不存在的设备文件
具体可以参考这里
pokerfaceSad/CVE-2021-1056 项目
这个项目主要是一个main.sh, 脚本里主要是查询GPU的major number,然后使用mknod 命令新增容器,如下所示
1 | root@container1:/ttt# nvidia-smi |
GPUmounter 项目
该项目主要设计了一个项目,用于Kubernetes 内的集群,用于增加删除容器内的GPU卡数,主要功能是在容器外部进行操作,将容器内的GPU卡数增加或者减少
容器外部控制容器内GPU卡 数量的方法如下所示:
获取Pod对应的容器的cgroup文件信息,例如容器ID为d80172f6ba5f9d4e82ce6f95c592f89dfa5f3ad637c9c38f7739c04b1f9c5d62
则该容器对应的cgroup 的device 目录如下所示:
执行命令
1 | cd /sys/fs/cgroup/devices/system.slice/docker-d80172f6ba5f9d4e82ce6f95c592f89dfa5f3ad637c9c38f7739c04b1f9c5d62.scope |
从该目录的cgroup.procs 文件中获取容器对应的PID,该文件可能存在多个PId,获取该文件中第一个PID,如下所示为157136
1 | [root@node1 docker-d80172f6ba5f9d4e82ce6f95c592f89dfa5f3ad637c9c38f7739c04b1f9c5d62.scope]# cat cgroup.procs |
进入容器命名空间执行命令
nsenter –target 157136 –mount
/bin/mknod -m 666 /dev/nvidia1 c 195 0
再次登录容器查看GPU信息
1 | root@28cam0e1oddj1-0:/ttt# nvidia-smi |
核心代码如下所示
1 |
|