Note that there are some explanatory texts on larger screens.

plurals
  1. POReading a child process's /proc/pid/mem file from the parent
    primarykey
    data
    text
    <p>In the program below, I am trying to cause the following to happen:</p> <ol> <li>Process <em>A</em> assigns a value to a stack variable <em>a</em>.</li> <li>Process <em>A</em> (parent) creates process <em>B</em> (child) with PID <i>child_pid</i>.</li> <li>Process <em>B</em> calls function <em>func1</em>, passing a pointer to <em>a</em>.</li> <li>Process <em>B</em> changes the value of variable <em>a</em> through the pointer.</li> <li>Process <em>B</em> opens its <strong>/proc/self/mem</strong> file, seeks to the page containing <em>a</em>, and prints the new value of <em>a</em>.</li> <li>Process <em>A</em> (at the same time) opens <strong>/proc/</strong><i>child_pid</i><strong>/mem</strong>, seeks to the right page, and prints the new value of <em>a</em>.</li> </ol> <p>The problem is that, in step 6, the parent only sees the <em>old</em> value of <em>a</em> in <strong>/proc/</strong><i>child_pid</i><strong>/mem</strong>, while the child can indeed see the new value in its <strong>/proc/self/mem</strong>. Why is this the case? Is there any way that I can get the parent to to see the child's changes to its address space through the <strong>/proc</strong> filesystem?</p> <pre><code>#include &lt;fcntl.h&gt; #include &lt;stdbool.h&gt; #include &lt;stdio.h&gt; #include &lt;stdlib.h&gt; #include &lt;string.h&gt; #include &lt;sys/types.h&gt; #include &lt;sys/stat.h&gt; #include &lt;sys/wait.h&gt; #include &lt;unistd.h&gt; #define PAGE_SIZE 0x1000 #define LOG_PAGE_SIZE 0xc #define PAGE_ROUND_DOWN(v) ((v) &amp; (~(PAGE_SIZE - 1))) #define PAGE_ROUND_UP(v) (((v) + PAGE_SIZE - 1) &amp; (~(PAGE_SIZE - 1))) #define OFFSET_IN_PAGE(v) ((v) &amp; (PAGE_SIZE - 1)) # if defined ARCH &amp;&amp; ARCH == 32 #define BP "ebp" #define SP "esp" #else #define BP "rbp" #define SP "rsp" #endif typedef struct arg_t { int a; } arg_t; void func1(void * data) { arg_t * arg_ptr = (arg_t *)data; printf("func1: old value: %d\n", arg_ptr-&gt;a); arg_ptr-&gt;a = 53; printf("func1: address: %p\n", &amp;arg_ptr-&gt;a); printf("func1: new value: %d\n", arg_ptr-&gt;a); } void expore_proc_mem(void (*fn)(void *), void * data) { off_t frame_pointer, stack_start; char buffer[PAGE_SIZE]; const char * path = "/proc/self/mem"; int child_pid, status; int parent_to_child[2]; int child_to_parent[2]; arg_t * arg_ptr; off_t child_offset; asm volatile ("mov %%"BP", %0" : "=m" (frame_pointer)); stack_start = PAGE_ROUND_DOWN(frame_pointer); printf("Stack_start: %lx\n", (unsigned long)stack_start); arg_ptr = (arg_t *)data; child_offset = OFFSET_IN_PAGE((off_t)&amp;arg_ptr-&gt;a); printf("Address of arg_ptr-&gt;a: %p\n", &amp;arg_ptr-&gt;a); pipe(parent_to_child); pipe(child_to_parent); bool msg; int child_mem_fd; char child_path[0x20]; child_pid = fork(); if (child_pid == -1) { perror("fork"); exit(EXIT_FAILURE); } if (!child_pid) { close(child_to_parent[0]); close(parent_to_child[1]); printf("CHILD (pid %d, parent pid %d).\n", getpid(), getppid()); fn(data); msg = true; write(child_to_parent[1], &amp;msg, 1); child_mem_fd = open("/proc/self/mem", O_RDONLY); if (child_mem_fd == -1) { perror("open (child)"); exit(EXIT_FAILURE); } printf("CHILD: child_mem_fd: %d\n", child_mem_fd); if (lseek(child_mem_fd, stack_start, SEEK_SET) == (off_t)-1) { perror("lseek"); exit(EXIT_FAILURE); } if (read(child_mem_fd, buffer, sizeof(buffer)) != sizeof(buffer)) { perror("read"); exit(EXIT_FAILURE); } printf("CHILD: new value %d\n", *(int *)(buffer + child_offset)); read(parent_to_child[0], &amp;msg, 1); exit(EXIT_SUCCESS); } else { printf("PARENT (pid %d, child pid %d)\n", getpid(), child_pid); printf("PARENT: child_offset: %lx\n", child_offset); read(child_to_parent[0], &amp;msg, 1); printf("PARENT: message from child: %d\n", msg); snprintf(child_path, 0x20, "/proc/%d/mem", child_pid); printf("PARENT: child_path: %s\n", child_path); child_mem_fd = open(path, O_RDONLY); if (child_mem_fd == -1) { perror("open (child)"); exit(EXIT_FAILURE); } printf("PARENT: child_mem_fd: %d\n", child_mem_fd); if (lseek(child_mem_fd, stack_start, SEEK_SET) == (off_t)-1) { perror("lseek"); exit(EXIT_FAILURE); } if (read(child_mem_fd, buffer, sizeof(buffer)) != sizeof(buffer)) { perror("read"); exit(EXIT_FAILURE); } printf("PARENT: new value %d\n", *(int *)(buffer + child_offset)); close(child_mem_fd); printf("ENDING CHILD PROCESS.\n"); write(parent_to_child[1], &amp;msg, 1); if (waitpid(child_pid, &amp;status, 0) == -1) { perror("waitpid"); exit(EXIT_FAILURE); } } } int main(void) { arg_t arg; arg.a = 42; printf("In main: address of arg.a: %p\n", &amp;arg.a); explore_proc_mem(&amp;func1, &amp;arg.a); return EXIT_SUCCESS; } </code></pre> <p>This program produces the output below. Notice that the value of <em>a</em> (boldfaced) differs between parent's and child's reading of the <strong>/proc/</strong><i>child_pid</i><strong>/mem</strong> file.</p> <p>In main: address of arg.a: 0x7ffffe1964f0<br> Stack_start: 7ffffe196000<br> Address of arg_ptr->a: 0x7ffffe1964f0<br> PARENT (pid 20376, child pid 20377)<br> PARENT: child_offset: 4f0<br> CHILD (pid 20377, parent pid 20376).<br> func1: old value: 42<br> func1: address: 0x7ffffe1964f0<br> func1: new value: 53<br> PARENT: message from child: 1<br> CHILD: child_mem_fd: 4<br> PARENT: child_path: /proc/20377/mem<br> CHILD: new value <strong>53</strong><br> PARENT: child_mem_fd: 7<br> PARENT: new value <strong>42</strong><br> ENDING CHILD PROCESS. </p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload