Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

brk

Let’s write a code like this and investigate the memory footprint of our program:

#![no_std]
#![no_main]

#[macro_use]
extern crate linux;

use linux::syscall::*;

#[no_mangle]
fn main() -> u8 { 
    println!("pid: {}", getpid().unwrap());
    let _ = pause();
    0
}

This small program gets the process id of our program and pauses the execution so we can checkout the memory

> ./cargo.sh run
pid: 1320734

Let’s checkout the mappings in the proc file system by using the pid like this:

> cat /proc/1320734/maps
00400000-00401000                  r--p  00000000  fd:00  950935  /target/bin
00401000-00404000                  r-xp  00001000  fd:00  950935  /target/bin
00404000-00405000                  r--p  00004000  fd:00  950935  /target/bin
00406000-00407000                  rw-p  00005000  fd:00  950935  /target/bin
00407000-00408000                  rw-p  00000000  00:00  0       
7ffe1a300000-7ffe1a321000          rw-p  00000000  00:00  0       [stack]
7ffe1a3f2000-7ffe1a3f6000          r--p  00000000  00:00  0       [vvar]
7ffe1a3f6000-7ffe1a3f8000          r-xp  00000000  00:00  0       [vdso]
ffffffffff600000-ffffffffff601000  --xp  00000000  00:00  0       [vsyscall]

Let’s break it down what this file tells us:

  • Our binary is mapped into the low address rage with different permissions:
    • read-only
    • read-exec
    • read-only
    • read-write
  • There is a middle section
  • In the high address range we have
    • stack
    • vvar
    • vdso
    • vsyscall

Allocating memory

Let’s modify our main function like this and run our program:

#[no_mangle]
fn main() -> u8 { 
    println!("pid: {}", getpid().unwrap());
    brk(brk(0) + 4096);
    let _ = pause();
    0
}

The mappings have been changed like this:

> cat /proc/1321009/maps
00400000-00401000                  r--p  00000000  fd:00  950935  /target/bin
00401000-00404000                  r-xp  00001000  fd:00  950935  /target/bin
00404000-00405000                  r--p  00004000  fd:00  950935  /target/bin
00406000-00407000                  rw-p  00005000  fd:00  950935  /target/bin
00407000-00408000                  rw-p  00000000  00:00  0       
004cd000-004ce000                  rw-p  00000000  00:00  0       [heap]
7ffc131b5000-7ffc131d6000          rw-p  00000000  00:00  0       [stack]
7ffc131ed000-7ffc131f1000          r--p  00000000  00:00  0       [vvar]
7ffc131f1000-7ffc131f3000          r-xp  00000000  00:00  0       [vdso]
ffffffffff600000-ffffffffff601000  --xp  00000000  00:00  0       [vsyscall]

There is a new section called [heap] mapped as a private region with read and write permissions (rw-p) So let’s use that space to to read the mappings from in the proc filesystem

#![no_std]
#![no_main]

extern crate linux;

use linux::syscall::*;
use linux::constants::*;

#[no_mangle]
fn main() -> u8 { 
    let len = 4096;
    let old = brk(0);
    let _ = brk(old + len) as *mut u8;
    let mut buf = unsafe { 
        core::slice::from_raw_parts_mut(old as *mut u8, len as usize) 
    };

    let fd = open("/proc/self/maps", O_RDONLY, 0).unwrap();
    loop {
        let len = read(fd, &mut buf).unwrap();
        let _ = write(1, &buf[..len]).unwrap();
        if len < buf.len() {
            break;
        }
    }
    0
}

It works like this:

> ./cargo.sh run
00400000-00401000                  r--p  00000000  fd:00  950935  /target/bin
00401000-00404000                  r-xp  00001000  fd:00  950935  /target/bin
00404000-00406000                  r--p  00004000  fd:00  950935  /target/bin
00406000-00407000                  rw-p  00005000  fd:00  950935  /target/bin
00407000-00408000                  rw-p  00000000  00:00  0       
017c8000-017c9000                  rw-p  00000000  00:00  0       [heap]
7ffc3c050000-7ffc3c071000          rw-p  00000000  00:00  0       [stack]
7ffc3c079000-7ffc3c07d000          r--p  00000000  00:00  0       [vvar]
7ffc3c07d000-7ffc3c07f000          r-xp  00000000  00:00  0       [vdso]
ffffffffff600000-ffffffffff601000  --xp  00000000  00:00  0       [vsyscall]