Answers:
实际上,在大多数平台上,它只会因错误而失败,但这取决于硬件体系结构。除非您以非特权用户身份运行该命令,否则绝对不能保证这是无害的。对于没有特权的用户,该命令是完全无害的,因为您无法打开/dev/mem
。
当您以root用户身份运行命令时,您应该知道自己在做什么。内核有时会阻止您执行危险的操作,但并非总是如此。/dev/mem
是您真正应该知道自己在做什么的那些潜在危险的事情之一。
我将逐步介绍如何/dev/mem
在Linux上进行写操作。其他Unices的一般原理相同,但是内核选项之类的东西完全不同。
当进程读取或写入设备文件时,将由内核决定。对设备文件的访问会在处理该设备文件的驱动程序中运行一些代码。例如,写/dev/mem
调用函数write_mem
在drivers/char/mem.c
。该函数有4个参数:表示打开文件的数据结构,指向要写入的数据的指针,要写入的字节数以及文件中的当前位置。
请注意,只有在调用者首先有权打开文件的情况下,您才能做到这一点。设备文件通常服从文件权限。正常的权限/dev/mem
是crw-r-----
由国有root:kmem
,因此,如果您尝试打开它写入而不根,你将只能收到拒绝“权限”(EACCESS)。但是,如果您是root用户(或root用户更改了该文件的权限),则打开过程将进行,然后您可以尝试写入。
write_mem
函数中的代码进行了一些健全性检查,但是这些检查不足以防止所有不良情况。它要做的第一件事是将当前文件位置*ppos
转换为物理地址。如果失败(实际上,因为您使用的平台具有32位物理地址,但文件偏移量为64位并且文件偏移量大于2 ^ 32),则EFBIG(文件太大)将导致写入失败。下一个检查是要写入的物理地址范围在此特定处理器体系结构上是否有效,并且将导致EFAULT(错误地址)失败。
接下来,在Sparc和m68k上,静默跳过第一物理页面中写入的任何部分。
现在,我们到达了主循环,该循环以适合一个MMU页的块为单位循环访问数据。
/dev/mem
访问物理内存而不是虚拟内存,但是处理器指令使用虚拟地址加载和存储数据到内存中,因此代码需要安排将物理内存映射到某个虚拟地址。在Linux上,根据处理器体系结构和内核配置,此映射要么永久存在,要么必须实时生成。这就是xlate_dev_mem_ptr
(并且unxlate_dev_mem_ptr
撤消任何xlate_dev_mem_ptr
操作)的工作。然后,该函数copy_from_user
从传递给write
系统调用,并仅写入物理内存当前映射的虚拟地址。该代码发出正常的内存存储指令,这取决于硬件。
在讨论写入物理地址之前,我将讨论在该写入之前发生的检查。在循环中,函数page_is_allowed
如果内核配置选项阻止访问某些地址CONFIG_STRICT_DEVMEM
启用(这是默认的情况下):只有允许的地址devmem_is_allowed
可以通过达成/dev/mem
,为别人写失败EPERM(操作不允许)。此选项的说明指出:
如果打开此选项,并且IO_STRICT_DEVMEM = n,则/ dev / mem文件仅允许用户空间访问PCI空间以及BIOS代码和数据区域。这对于dosemu和X以及/ dev / mem的所有普通用户来说已经足够。
这是非常以x86为中心的描述。实际上,更一般而言,CONFIG_STRICT_DEVMEM
阻止访问映射到RAM的物理内存地址,但允许访问未映射到RAM的地址。允许的物理地址范围的详细信息取决于处理器体系结构,但是所有这些都排除了RAM,内核和用户登陆进程的数据存储在RAM中。附加选项CONFIG_IO_STRICT_DEVMEM
(自Ubuntu 18.04起已禁用)可阻止访问驱动程序声明的物理地址。
映射到RAM的物理内存地址。因此,有没有映射到RAM的物理内存地址?是。这就是我在上面承诺的关于写地址的含义的讨论。
存储器存储指令不一定要写入RAM。处理器分解地址,并决定将商店分派到哪个外围设备。(当我说“处理器”时,我包含的外围控制器可能不是同一家制造商生产的。)RAM只是这些外围设备之一。调度的完成方式在很大程度上取决于处理器体系结构,但是基本原理在所有体系结构上基本相同。处理器基本上将地址的高位分解,并根据硬编码信息,通过探测某些总线获得的信息以及由软件配置的信息在填充的某些表中查找它们。可能涉及很多缓存和缓冲,但是总的来说,在分解之后,总线,然后由外围设备来处理。(或者,表查找的结果可能是此地址没有外围设备,在这种情况下,处理器进入陷阱状态,在该状态下处理器在内核中执行一些代码,该代码通常会导致SIGBUS用于调用过程。)
存储到映射到RAM的地址不会“做任何事情”,只会覆盖先前存储在该地址的值,并保证以后在同一地址进行的加载将返回最后存储的值。但是,即使RAM也有一些地址不是这样工作的:它有一些寄存器可以控制刷新率和电压。
通常,对硬件寄存器的读取或写入会完成对硬件进行编程后所能做的任何事情。对硬件的大多数访问都是以这种方式工作的:软件(通常是内核代码)访问某个物理地址,该地址到达将处理器连接至外围设备的总线,外围设备则开始工作。一些处理器(尤其是x86)还具有单独的CPU指令,这些指令导致对外设的读/写操作与内存的加载和存储不同,但是即使在x86上,也可以通过加载/存储访问许多外设。
该命令dd if=/dev/urandom of=/dev/mem
将随机数据写入映射到地址0(以及后续地址,只要写入成功)的任何外设。在实践中,我希望在许多体系结构上,物理地址0都没有映射到任何外围设备,也没有RAM,因此第一次写入尝试失败。但是,如果有一个外设映射到地址0,或者如果您更改命令以写入另一个地址,则会在该外设中触发某些不可预测的事件。随着地址上随机数据的增加,不太可能做一些有趣的事情,但是原则上它可以关闭计算机(实际上可能有一个地址可以这样做),覆盖某些BIOS设置使其无法启动,甚至无法正常运行。越野车的损坏方式。
alias Russian_roulette='dd if=/dev/urandom of=/dev/mem seek=$((4096*RANDOM+4096*32768*RANDOM))'
CONFIG_STRICT_DEVMEM
启用,您将无法破坏内核。
每手册页mem(4):
/ dev / mem是字符设备文件,它是计算机主内存的映像。例如,它可以用于检查(甚至修补)系统。
因此,从理论上讲,dd if=/dev/urandom of=/dev/mem
应该覆盖已安装的物理内存的整个地址空间,并且由于内核和其他程序是从内存运行的,因此应该有效地使系统崩溃。实际上,有限制。在同一手册页中:
从Linux 2.6.26开始,并根据体系结构,CONFIG_STRICT_DEVMEM内核配置选项限制了可通过此文件访问的区域。
在虚拟机Ubuntu 18.04上尝试此操作,dd: writing to '/dev/mem': Operation not permitted
即使具有sudo
root权限,即使有权限也返回错误crw-r-----
。从Ubuntu Wiki:
/ dev / mem保护
某些应用程序(Xorg)需要从用户空间直接访问物理内存。存在特殊文件/ dev / mem来提供此访问。过去,如果攻击者具有root用户访问权限,则可以从该文件查看和更改内核内存。引入了CONFIG_STRICT_DEVMEM内核选项以阻止对非设备内存的访问(最初名为CONFIG_NONPROMISC_DEVMEM)。
因此,从技术上讲,没有它是不安全的(因为它会使系统崩溃),并且如果CONFIG_STRICT_DEVMEM
禁用了内核选项,这是一个安全漏洞,但是据我所知,如果启用了该选项,该命令将无法运行。根据跨站点重复项的说明,重新启动将解决所有问题,但是那时RAM中的数据当然会丢失并且不会刷新到磁盘(如果必须的话)。
在先前链接的重复项上有一个建议的方法,busybox devmem
因此,如果您确定要搞乱RAM,毕竟可能有办法。
CONFIG_STRICT_DEVMEM
,您也可以访问外围设备映射到的存储区域,这是具有的全部要点/dev/mem
。如果您向外围设备随机写入内容,则可能会发生任何事情。如果尝试访问未映射的地址,则会得到“不允许操作”,并且该命令从地址0开始。地址0是否映射到不良地址取决于硬件体系结构。就我所知,它可能永远不会映射到PC上的任何内容,但通常来说并不安全。
head -c 1024 </dev/mem | od -tx1
),但是我不知道当处理器不在实模式(8088模式)时是否使用了这些东西。我认为它们不能在64位模式下使用:毕竟,8088中断向量的地址只有32位。而且通过CONFIG_STRICT_DEVMEM
set 可以访问它,所以我想Linux不会使用它。