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)
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 byaddr
andlength
was previously reserved using another mapping