9

What exactly does this do? I don't understand how you could access base memory with this...seems kinda weird. Is it safe?

dd if=/dev/urandom of=/dev/mem
  • 9
    Considering this user has about 40 reputation points across 4 different communities, I don't think they even know what HNQ means or expect views, and rather it's general curiosity about what does a command do. And do questions have to have some sort of ulterior motive or purpose all the time ? Besides we got another in-depth and detailed answer from Gilles thanks to this question. – Sergiy Kolodyazhnyy Jul 27 at 8:50
  • I am a stack noob – Coder14 Jul 27 at 16:44
  • What is this "safe" of which you speak? Safe with respect to what? – waltinator Jul 27 at 20:35
  • What do you want to achieve with this command? – jochen Jul 28 at 11:08
22

Don't try this at home! It can crash your system, and if you're really unlucky it could damage a peripheral or make your computer unbootable.

Actually, on most platforms, it just fails with an error, but that depends on the hardware architecture. There is most definitely no guarantee that this is harmless unless you run the command as an unprivileged user. With an unprivileged user, the command is perfectly harmless because you can't open /dev/mem.

When you run a command as root, you're supposed to know what you're doing. The kernel will sometimes prevent you from doing something dangerous, but not always. /dev/mem is one of those potentially dangerous things where you're really supposed to know what you're doing.

I'm going to walk through how a write to /dev/mem works on Linux. The general principle would be the same on other Unices, but things like kernel options are completely different.

What happens when a process reads or writes to a device file is up to the kernel. An access to a device file runs some code in the driver that handles this device file. For example, writing to /dev/mem invokes the function write_mem in drivers/char/mem.c. This function takes 4 arguments: a data structure that represents the open file, a pointer to the data to write, the number of bytes to write, and the current position in the file.

Note that you only get that far if the caller had permission to open the file in the first place. Device files obey file permissions normally. The normal permissions of /dev/mem are crw-r----- owned by root:kmem, so if you try to open it for writing without being root, you'll just get “permission denied” (EACCESS). But if you're root (or if root has changed the permissions of this file), the opening goes through and then you can attempt a write.

The code in the write_mem function makes some sanity checks, but these checks aren't enough to protect against everything bad. The first thing it does is convert the current file position *ppos to a physical address. If that fails (in practice, because you're on a platform with 32-bit physical addresses but 64-bit file offsets and the file offset is larger than 2^32), the write fails with EFBIG (file too large). The next check is whether the range of physical addresses to write is valid on this particular processor architecture, and there a failure results in EFAULT (bad address).

Next, on Sparc and m68k, any part of the write in the very first physical page is silently skipped.

We've now reached the main loop which iterates over the data in blocks that can fit within one MMU page. /dev/mem accesses physical memory, not virtual memory, but the processor instructions to load and store data in memory use virtual addresses, so the code needs to arrange to map the physical memory at some virtual address. On Linux, depending on the processor architecture and the kernel configuration, this mapping either exists permantently or has to be made on the fly; that's the job of xlate_dev_mem_ptr (and unxlate_dev_mem_ptr undoes whatever xlate_dev_mem_ptr does). Then the function copy_from_user reads from the buffer that was passed to the write system call and just writes to the virtual address where the physical memory is currently mapped. The code emits normal memory store instructions, and what this means is up to the hardware.

Before I discuss that a write to a physical address does, I'll discuss a check that happens before this write. Inside the loop, the function page_is_allowed blocks accesses to certain addresses if the kernel configuration option CONFIG_STRICT_DEVMEM is enabled (which is the case by default): only addresses allowed by devmem_is_allowed can be reached through /dev/mem, for others the write fails with EPERM (operation not permitted). The description of this option states:

If this option is switched on, and IO_STRICT_DEVMEM=n, the /dev/mem file only allows userspace access to PCI space and the BIOS code and data regions. This is sufficient for dosemu and X and all common users of /dev/mem.

This is very x86-centric description. In fact, more generically, CONFIG_STRICT_DEVMEM blocks access to physical memory addresses that map to RAM, but allows access to addresses that don't map to RAM. The details of what ranges of physical address are allowed depend on the processor architecture, but all of them exclude the RAM where data of the kernel and of user land processes is stored. The additional option CONFIG_IO_STRICT_DEVMEM (disabled as of Ubuntu 18.04) blocks accesses to physical addresses that are claimed by a driver.

Physical memory addresses that map to RAM. So there are physical memory addresses that don't map to RAM? Yes. That's the discussion I promised above about what it means to write to an address.

A memory store instruction does not necessarily write to RAM. The processor decomposes the address and decides which peripheral to dispatch the store to. (When I say “the processor”, I encompass peripheral controllers which may not come from the same manufacturer.) RAM is only one of those peripherals. How the dispatch is done is very dependent on the processor architecture, but the fundamentals are more or less the same on all architectures. The processor basically decomposes the higher bits of the address and looks them up in some tables that are populated based on hard-coded information, information obtained by probing some buses, and information configured by the software. A lot of caching and buffering may be involved, but in a nutshell, after this decomposition, the processor writes something (encoding both the target address and the data that's being stored) on some bus and then it's up to the peripheral to deal with it. (Or the outcome of the table lookup might be that there is no peripheral at this address, in which case the processor enters a trap state where it executes some code in the kernel that normally results in a SIGBUS for the calling process.)

A store to an address that maps to RAM doesn't “do” anything other than overwrite the value that was previously stored at this address, with the promise that a later load at the same address will give back the last stored value. But even RAM has a few addresses that don't behave this way: it has a few registers that can control things like refresh rate and voltage.

In general, a read or write to a hardware register does whatever the hardware is programmed to do. Most accesses to hardware work this way: the software (normally kernel code) accesses a certain physical address, this reaches the bus that connects the processor to the peripheral, and the peripheral does its thing. Some processors (in particular x86) also have separate CPU instructions that cause reads/writes to peripherals which are distinct from memory load and store, but even on x86, many peripherals are reached through load/store.

The command dd if=/dev/urandom of=/dev/mem writes random data to whatever peripheral is mapped at address 0 (and subsequent addresses, as long as the writes succeed). In practice, I expect that on many architectures, physical address 0 doesn't have any peripheral mapped to it, or has RAM, and therefore the very first write attempt fails. But if there is a peripheral mapped at address 0, or if you change the command to write to a different address, you'll trigger something unpredictable in the peripheral. With random data at increasing addresses, it's unlikely to do something interesting, but in principle it could turn off the computer (there's probably an address that does this in fact), overwrite some BIOS setting that makes it impossible to boot, or even hit some buggy peripheral in a way that damages it.

alias Russian_roulette='dd if=/dev/urandom of=/dev/mem seek=$((4096*RANDOM+4096*32768*RANDOM))'
  • Thank you! This is what I was looking for! I was just confused whether /dev/mem allows memory access to things like peripherals and hardware-related things! – Coder14 Jul 27 at 16:46
  • A peripheral can't be mapped at physical address 0 on x86 pc; that configuration would never boot. – Joshua Jul 27 at 20:50
  • This is not true – Yvain Jul 27 at 21:02
  • Of course you can damage the kernel but not the bios – Yvain Jul 27 at 21:04
  • 1
    @Yvain What is not true? And actually you can't damage the kernel if CONFIG_STRICT_DEVMEM is enabled. – Gilles Jul 28 at 12:05
13

It is safe, if you have properly configured kernel ( safe because it won't work )

Per manual page mem(4):

/dev/mem is a character device file that is an image of the main memory of the computer. It may be used, for example, to examine (and even patch) the system.

So in theory, dd if=/dev/urandom of=/dev/mem should overwrite whole address space of the physical memory you have installed, and since kernel and other programs run from memory this should effectively crash the system. In practice, there's limit. From the same man page:

Since Linux 2.6.26, and depending on the architecture, the CONFIG_STRICT_DEVMEM kernel configuration option limits the areas which can be accessed through this file.

Trying this on virtual machine Ubuntu 18.04 , it returns an error dd: writing to '/dev/mem': Operation not permitted even with sudo and despite permissions for root crw-r-----. From Ubuntu Wiki:

/dev/mem protection

Some applications (Xorg) need direct access to the physical memory from user-space. The special file /dev/mem exists to provide this access. In the past, it was possible to view and change kernel memory from this file if an attacker had root access. The CONFIG_STRICT_DEVMEM kernel option was introduced to block non-device memory access (originally named CONFIG_NONPROMISC_DEVMEM).

So technically, no it is not safe (since it would crash the system) and if kernel option CONFIG_STRICT_DEVMEM is disabled that's a security hole, but from what I see so far the command wouldn't run if that option is enabled. According to cross-site duplicate, a reboot will fix any issues with it, but of course data in RAM at that time would be lost and not flushed to disk (if any had to be).

There is a suggested method on the duplicate linked earlier using busybox devmem so if you're determined to mess around with RAM, there may be a way after all.

  • 6
    “It is safe” No, it most certainly is not. Even with CONFIG_STRICT_DEVMEM, you can access memory regions where a peripheral is mapped, which is the whole point of having /dev/mem. If you write random stuff to peripherals, anything might happen. You get “operation not permitted” if you try to access an address that isn't mapped, and the command starts at address 0. Whether address 0 maps to something bad depends on the hardware architecture. For all I know it might never map to anything on a PC, but it isn't safe in general. – Gilles Jul 27 at 6:27
  • 1
    @Gilles On x86 (not sure about x86-64), the first 1 KiB of RAM (addresses 0x0 through 0x3ff) holds the interrupt vectors; four bytes' worth of address per vector. If you succeed in overwriting those with random garbage, all kinds of interesting things are likely to happen very soon. Most likely, you'll end up with a double or triple fault and the system will crash, but there are no guarantees... – a CVn Jul 27 at 17:05
  • @aCVn There certainly is something mapped (head -c 1024 </dev/mem | od -tx1), but I don't know if these are used when the processor is not in real mode (8088 mode). I don't think they can be used in 64-bit mode: after all, the 8088 interrupt vectors only have 32 bits for the address. And by the way this is accessible with CONFIG_STRICT_DEVMEM set, so I guess Linux doesn't use it. – Gilles Jul 27 at 20:16
  • @Gilles: The 0 page on x86 is reserved for v86, bootloader, etc; that's the real mode interrupt vector table there. In protected mode, the IVT is somewhere else (a machine register says where). – Joshua Jul 27 at 20:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.