Home > Software engineering >  mmap right after a variable address
mmap right after a variable address

Time:06-05

Is there ANY way to mmap memory right after a string literal? I want to make a simple implemtation of redzoning so that my program writes a character right after the null terminator of a string literal, and then check if it was overwritten in case of buffer overflow, my approach was to mmap memory right above the address of the string's null terminator.

My concern is that there might be some important data after that string literal and I might overwrite it with MAP_FIXED, however, MAP_FIXED doesn't work - invalid argument.

void *addr; /* the address of the memory after the end of buf */
char *mmap_addr; /* This is where we put the redzone characters */
struct redzone zone; /* our zone, to be modified */
char buf[MAX_BUF_SIZE] = "ABCDEFGHIG";

addr = (void *)&buf[MAX_BUF_SIZE]   1; /* exactly after NULL terminator */

mmap_addr = mmap(addr, sizeof(zone), PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, 0, 0);
if (mmap_addr == MAP_FAILED) /* ((void *) - 1) */
    FOO("mmap: ");
    // ....

Without MAP_FIXED the offset between buf and mmap_addr is huge. If I understand correctly, MAP_FIXED mmap exactly where addr is without optimizations.

CodePudding user response:

Is there ANY way to mmap memory right after a string literal?

No,

... unless you coded something in assembler (at least on Linux/x86-64) to align suitably that string literal (so that its next after last byte is page aligned).

Try for example in C:

 const char*literal = "literal in " __FILE__;
 printf("here is '%s' at %p (line %d)\n", 
        literal, (void*)literal, __LINE__);

Since a string literal is likely to have a random address (subject to ASLR), and its end is very probably not aligned to the page (4Kbytes).

I made a tiny C program e.c (containing the three lines above) compiled it as gcc -O -g e.c -o e then ran it twice:

 % ./e
 here is 'literal in e.c' at 0x55fb00466022 (line 5)
 % ./e
 here is 'literal in e.c' at 0x558237e51022 (line 5)

See mmap(2) and proc(5).

The failure reasons for mmap are well documented. MAP_FIXED requires the first addr argument to be exactly page aligned (e.g. multiple of 4Kbytes) and a valid address. See also getpagesize(2).

For debugging purposes only, consider adding:

char cmd[64];
snprintf(cmd, sizeof(cmd), "/bin/cat /proc/%d/maps", (int)getpid())
fflush(NULL);
system(cmd);

to understand the layout of your virtual address space.

For some intuition, run /bin/cat /proc/self/maps in a terminal.

CodePudding user response:

Is there ANY way to mmap memory right after a string literal?

NO, there is no safe and reliable way to mmap a region relative to an object, whether string literal, ordinary array, or anything else. In addition to the severe risk, noted in the question, that

  • that memory may already be in use for something else (the stack, for example)

there are also the issues that

  • the base address of the mapping must be suitably aligned (details are architecture dependent), and

  • if the mapped region overlaps another memory mapping (not necessarily created explicitly by your code) then the overlapped part of the existing mapping will be discarded.

As far as ...

MAP_FIXED doesn't work - invalid argument.

... the issue is likely that the specified address is not properly aligned. Supposing that the required alignment is on a page boundary (typical), this is a very likely outcome for trying to mmap an arbitrarily chosen address.

According to the notes on the Linux manual page for mmap():

The only safe use for MAP_FIXED is where the address range specified by addr and length was previously reserved using another mapping

  • Related