# How do I read from /proc/$pid/mem under Linux? The Linux proc(5) man page tells me that /proc/$pid/mem “can be used to access the pages of a process's memory”. But a straightforward attempt to use it only gives me

$cat /proc/$$/mem /proc/self/mem cat: /proc/3065/mem: No such process cat: /proc/self/mem: Input/output error  Why isn't cat able to print its own memory (/proc/self/mem)? And what is this strange “no such process” error when I try to print the shell's memory (/proc/$$/mem, obviously the process exists)? How can I read from /proc/$pid/mem, then?

-
instant favorite. –  ixtmixilix Mar 21 '12 at 21:18
There are several other methods that show how to do this on SF in this Q&A titled: Dump a linux process's memory to file –  slm Jan 15 '14 at 5:16

The way to find out what parts of the process memory are mapped is to read /proc/$pid/maps. This file contains one line per mapped region, looking like this: 08048000-08054000 r-xp 00000000 08:01 828061 /bin/cat 08c9b000-08cbc000 rw-p 00000000 00:00 0 [heap]  The first two numbers are the boundaries of the region (addresses of the first byte and the byte after last, in hexa). The next column contain the permissions, then there's some information about the file (offset, device, inode and name) if this is a file mapping. See the proc(5) man page or Understanding Linux /proc/id/maps for more information. Here's a proof-of-concept script that dumps the contents of its own memory. #! /usr/bin/env python import re maps_file = open("/proc/self/maps", 'r') mem_file = open("/proc/self/mem", 'r', 0) for line in maps_file.readlines(): # for each mapped region m = re.match(r'([0-9A-Fa-f]+)-([0-9A-Fa-f]+) ([-r])', line) if m.group(3) == 'r': # if this is a readable region start = int(m.group(1), 16) end = int(m.group(2), 16) mem_file.seek(start) # seek to region start chunk = mem_file.read(end - start) # read region contents print chunk, # dump contents to standard output maps_file.close() mem_file.close()  ### /proc/$pid/mem

If you try to read from the mem pseudo-file of another process, it doesn't work: you get an ESRCH (No such process) error.

The permissions on /proc/$pid/mem (r--------) are more liberal than what should be the case. For example, you shouldn't be able to read a setuid process's memory. Furthermore, trying to read a process's memory while the process is modifying it could give the reader an inconsistent view of the memory, and worse, there were race conditions that could trace older versions of the Linux kernel (according to this lkml thread, though I don't know the details). So additional checks are needed: • The process that wants to read from /proc/$pid/mem must attach to the process using ptrace with the PTRACE_ATTACH flag. This is what debuggers do when they start debugging a process; it's also what strace does to a process's system calls. Once the reader has finished reading from /proc/$pid/mem, it should detach by calling ptrace with the PTRACE_DETACH flag. • The observed process must not be running. Normally calling ptrace(PTRACE_ATTACH, …) will stop the target process (it sends a STOP signal), but there is a race condition (signal delivery is asynchronous), so the tracer should call wait (as documented in ptrace(2)). A process running as root can read any process's memory, without needing to call ptrace, but the observed process must be stopped, or the read will still return ESRCH. In the Linux kernel source, the code providing per-process entries in /proc is in fs/proc/base.c, and the function to read from /proc/$pid/mem is mem_read. The additional check is performed by check_mem_permission.

Here's some sample C code to attach to a process and read a chunk its of mem file (error checking omitted):

sprintf(mem_file_name, "/proc/%d/mem", pid);
mem_fd = open(mem_file_name, O_RDONLY);
ptrace(PTRACE_ATTACH, pid, NULL, NULL);
waitpid(pid, NULL, 0);
lseek(mem_fd, offset, SEEK_SET);
ptrace(PTRACE_DETACH, pid, NULL, NULL);

-
Or you can just use dd to read from /proc/pid/mem –  abc Mar 4 '12 at 6:12
@abc No, reading from /proc/$pid/mem directly (whether with cat or dd or anything else) doesn't work. Read my answer. – Gilles Mar 4 '12 at 17:55 You are right. Please check this article. trilithium.com/johan/2005/08/linux-gate Here the author is using dd to read from /proc/self/mem. I have asked him how was he able to accomplish that? – abc Mar 4 '12 at 20:32 @abc He's reading from /proc/self/mem. A process can read its own memory space just fine, it's reading another process's memory space that requires PTRACE_ATTACH. – Gilles Mar 4 '12 at 20:49 Somehow this hits the 2GB fseek limit, I didn't get it to work in Python 3 to see if that uses fseeko. Also it needs a SIGCONT somewhere in the crash case. I know it's quick and dirty, sorry. – Tobu Mar 19 '13 at 11:30 This command (from gdb) dumps memory reliably: gcore pid  Dumps can be large, use -o outfile if your current directory doesn't have enough room. - When you execute cat /proc/$$/mem the variable $$ is evaluated by by bash which inserts its own pid. It then executes cat which has a different pid. You end up with cat trying to read the memory of bash, its parent process. Since non-privileged processes can only read their own memory space this gets denied by the kernel. Here's an example: $ echo $$17823  Note that $$ evaluates to 17823. Let's see which process that is.

$ps -ef | awk '{if ($2 == "17823") print}'
bahamat  17823 17822  0 13:51 pts/0    00:00:00 -bash


It's my current shell.

$cat /proc/$$/mem cat: /proc/17823/mem: No such process  Here again $$ evaluates to 17823, which is my shell. cat can't read my shell's memory space. - You end up trying to read the memory of whatever $pid is. As I explain in my answer, reading the memory of a different process requires you to ptrace it. –  Gilles Jan 24 '11 at 19:35
Which is going to be bash. I wasn't saying your answer was wrong. I was just answering in more layman's terms "why doesn't this work". –  bahamat Jan 24 '11 at 21:07
@bahamat: Are you thinking of $$ when you write (and read) pid? – Gilles Jan 31 '11 at 22:22 Yes...he started out asking referring to $$ and put $pid at the end. I transposed it in my head without realizing it. My entire answer should refer to $$, not $pid. –  bahamat Jan 31 '11 at 22:44
@bahamat: Is the question clearer now? (BTW I don't see your comments unless you use “@Gilles”, I just happened to see your edit and came to see.) –  Gilles Jan 31 '11 at 23:23