据我了解,用户空间程序运行在非特权模式下,因此无法直接访问内存或 I/O。
那么当我们在用户空间程序中mmap /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);
这是嵌入式设备中非常常用的一种技巧。
现在该变量leds
可以即时使用来访问可能存在于 0x80840000 处的任何设备。
我们将不再使用任何系统调用来访问该地址。
甚至像
leds[0x20] = val;
会工作。
但是特权操作,例如直接从 I/O 地址读取/写入,只能通过系统调用将处理器置于特权模式来实现。
来源。
答案1
允许非特权进程访问/dev/mem
确实是一个安全问题,不应该被允许。
在我的系统上,ls -l /dev/mem
看起来像这样:
crw-r----- 1 root kmem 1, 1 Sep 8 10:12 /dev/mem
所以root
可以读和写它,该kmem
组的成员(恰好没有)可以读它但不能写它,其他人根本无法打开它。所以这应该是安全的。
如果您的/dev/mem
与我的类似,那么您的非特权进程根本就不应该能够打开该文件,更不用说mmap
它了。
检查您系统上的权限/dev/mem
以确保它们是安全的!
答案2
用户进程(无论是作为 root 用户还是非特权用户运行)可见的地址都是虚拟地址,它们由 MMU 通过页表映射到物理地址。设置页表是一个特权操作,只能由内核代码执行;然而,一旦设置了页表,就允许在用户模式下访问内存。
具体来说,您的代码用于mmap
请求内核设置页表以允许访问给定范围的物理内存。内核检查进程的权限(它具有读/写访问权限/dev/mem
)并设置页表以允许其访问物理内存。
答案3
的值leds
是一个虚拟地址。只要它在当前进程的用户空间中,进程就可以直接通过指令访问它,leds[0] = val
而不必处于特权模式,无论这个虚拟地址映射到 RAM 中的哪个位置