就我的理解而言,用户空间程序以非特权模式运行,因此无法直接访问内存或 I/O。
那么当我们在用户空间程序中映射 /dev/mem 时,我们究竟如何直接访问内存或 I/O 位置呢?
例如:
int fd = 0;
u8 leds = 0;
fd = open("/dev/mem", O_RDWR|O_SYNC);
leds = (u8 *)mmap(0, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0x80840000);
Run Code Online (Sandbox Code Playgroud)
这是一种在嵌入式设备中非常常用的 hack。
现在leds
可以动态使用该变量来访问可能存在于 0x80840000 处的任何设备。
我们将不再使用任何系统调用来访问该地址。
甚至像
leds[0x20] = val;
Run Code Online (Sandbox Code Playgroud)
会工作。
但是特权操作,例如直接从 I/O 地址读/写,应该只有通过系统调用将处理器置于特权模式才能实现。
来源。
允许/dev/mem
非特权进程访问确实是一个安全问题,不应被允许。
在我的系统上,ls -l /dev/mem
看起来像这样:
crw-r----- 1 root kmem 1, 1 Sep 8 10:12 /dev/mem
Run Code Online (Sandbox Code Playgroud)
所以root
可以读和写,kmem
组的成员(碰巧没有)可以读但不能写,其他人根本无法打开它。所以这应该是安全的。
如果你/dev/mem
和我一样,你的非特权进程甚至根本无法打开文件,更不用说mmap
它了。
检查/dev/mem
系统上的权限以确保它们是安全的!
小智 6
用户进程(无论是作为 root 还是非特权用户运行)可见的地址是虚拟地址,它由 MMU 通过页表映射到物理地址。设置页表是一项特权操作,只能由内核代码执行;但是,一旦设置了页表,就允许在用户模式下访问内存。
具体来说,您的代码用于mmap
请求内核设置页表以允许访问给定范围的物理内存。内核检查进程的权限(它具有读/写访问权限/dev/mem
)并设置页表以允许它访问物理内存。