Calling mmap from specific address - c

How to read mmap function from specific address, if knew it (0x6A6F7444)?
I tried:
mmap(0x6A6F7444, 100, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)
But it doen't works. Compile says:
warning: passing argument 1 of ‘munmap’ makes pointer from integer without a cast [-Wint-conversion]

#include <stdint.h> // for uintptr_t
uintptr_t addr = 0x6A6F7444;
mmap((void *)addr, 100, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
will disable the warning.

For mmap to use your address it needs MAP_FIXED flag, see man mmap for full details.

Related

How to allocate buffer within 32-bit address space?

I would like to allocate a buffer within 32-bit address space on 64-bit ARM. In other words, I would like to ensure that my buffer is bound to the lower 32-bit address space. Do you know a nice C function which does that?
There is no C standard function to do so. However, since you tagged the question as Linux, take a look at mmap(2) and the MAP_ANONYMOUS and MAP_32BIT flags, e.g.:
mmap(
0, 1,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT,
-1, 0
);
Another option is passing an explicit address in the lower 32-bit address space using the MAP_FIXED flag:
mmap(
(void *)0x10000, 1,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
-1, 0
);

Basic mmap(2) call fails

I've been pulling my hairs out for hours on this very basic piece of code and I haven't managed to understand why mmap(2) was failing.
#include <sys/mman.h>
#include <sys/user.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#define NPAGES 50
#define SLABSIZE (PAGE_SIZE * NPAGES) // 200 kB
int
main(int argc, char *argv[])
{
char *slab;
printf("DEBUG: mmap(%#x, %u, %#x, %#x, %d, %u)\n",
NULL, SLABSIZE, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0);
slab = mmap(NULL, SLABSIZE, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0);
if (slab == MAP_FAILED)
err(1, "mmap");
}
But when I run it:
$ make mmap
cc mmap.c -o mmap
$ ./mmap
DEBUG: mmap(0, 204800, 0x3, 0x20, -1, 0)
mmap: mmap: Invalid argument
I checked and re-checked mmap(2)'s manpage [1], and it seems that all requirements are OK but I must be missing something.
I'm running Linux kernel 4.8.13.
Thanks.
-- Jeremie
[1] http://man7.org/linux/man-pages/man2/mmap.2.html
When strace ing your program, I see:
mmap(NULL, 204800, PROT_READ|PROT_WRITE, MAP_FILE|MAP_ANONYMOUS, -1, 0) = -1 EINVAL (Invalid argument)
You forgot a MAP_SHARED flag (or a MAP_PRIVATE one). With it (either MAP_SHARED or MAP_PRIVATE, but you need one of them) your program works:
slab = mmap(NULL, SLABSIZE, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
Quoting the mmap(2) man page:
This behavior is determined by including exactly one of the following values in flags:
(emphasis is mine)
MAP_SHARED
Share this mapping. Updates to the mapping are visible to
other processes mapping the same region, and (in the case of
file-backed mappings) are carried through to the underlying
file. (To precisely control when updates are carried through
to the underlying file requires the use of msync(2).)
MAP_PRIVATE
Create a private copy-on-write mapping. Updates to the
mapping are not visible to other processes mapping the same
file, and are not carried through to the underlying file. It
is unspecified whether changes made to the file after the
mmap() call are visible in the mapped region.
So the general advice before pulling your hairs: read once again the documentation; take a nap; read another time the documentation and think about what did you miss.
Another hint would be to use strace(1) on some (or several) existing executable(s). You'll learn a lot.

mmapping /dev/zero on Mac OSX gives invalid argument

So I am trying to port some code from Linux to Mac OSX. During porting I came across this code.
static void allocZeroMap(unsigned long size, int prot, const char *name)
{
struct map *newnode;
int fd;
char buf[11];
fd = open("/dev/zero", O_RDWR);
if (fd == -1) {
printf("couldn't open /dev/zero\n");
exit(EXIT_FAILURE);
}
newnode = zmalloc(sizeof(struct map));
newnode->name = strdup(name);
newnode->size = size;
newnode->prot = prot;
newnode->type = INITIAL_MAP;
newnode->ptr = mmap(NULL, size, prot, MAP_ANONYMOUS | MAP_SHARED, fd, 0);
if (newnode->ptr == MAP_FAILED) {
perror("mmap");
exit(EXIT_FAILURE);
}
newnode->name = zmalloc(80);
sprintf(newnode->name, "anon(%s)", name);
num_initial_mappings++;
list_add_tail(&newnode->list, &initial_mappings->list);
sizeUnit(size, buf);
printf("mapping[%d]: (zeropage %s) %p (%s)\n",
num_initial_mappings - 1, name, newnode->ptr, buf);
close(fd);
}
So I figured that I would need to just switch newnode->ptr = mmap(NULL, size, prot, MAP_ANONYMOUS | MAP_SHARED, fd, 0); to newnode->ptr = mmap(NULL, size, prot, MAP_ANON | MAP_SHARED, fd, 0); because Mac OSX does not have the MAP_ANONYMOUS flag and uses MAP_ANON instead.
But when I run the program, that mmap call fails with Invalid argument. So my next thought was check the man page for what causes Invalid arguments errors. The first cause is that MAP_FIXED is set and the addr argument is not page aligned, but I'm not calling MAP_FIXED. Second it's says it will return Invalid argument if you don't specify either MAP_PRIVATE or MAP_SHARED but I'm using MAP_SHARED so that shouldn't be it. Next it says the len argument must not be negative, so I printed the size variable and ran it and it's a positive value. The final reason is that the offset argument is not page aligned, but I am passing zero so that shouldn't be the problem either.
So next I checked stack overflow and saw this question mmap with /dev/zero . I tried using MAP_FILE instead of MAP_ANON but now I get Operation not supported by device, which the man page says means I am missing MAP_ANON. So I tried adding MAP_ANON so that I have mmap(NULL, size, prot, MAP_FILE | MAP_ANON| MAP_SHARED, fd, 0); but that returns Invalid argument as well.
So how do I mmap /dev/zero on Mac OSX or at least create a zero-filled memory map on Mac OSX?
You should pass -1 instead of fd as the value of the file descriptor as per mmap() man page. Also as you said MAP_ANON is the correct option for MacOS (at least older versions) and there is not need for MAP_FILE.

Why is mmap not working here

I get segmentation fault when I run the following piece of code...
int * x = mmap( 0, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE, 0, 0 );
x[0] = 42; // <--- Segmentation fault happens due to this
What is wrong here?
You've specified the incorrect flags and file descriptor. It looks like what you want is an anonymous (not backed by a file) mapping. If that's the case, the correct call would be:
x = mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
You need to use the MAP_ANONYMOUS flag to tell Linux there is no file. And you should pass -1 for the file descriptor, not 0.
OK, I got it. I forgot to place MAP_ANONYMOUS, so it should had been like this...
int * x = mmap( 0, 4096, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE,
0, 0 );
Its working this way.
man mmap says:
On success, mmap() returns a pointer to the mapped area. On error, the value MAP_FAILED (that is, (void *) -1) is returned, and errno is set appropriately
Check, whether x == MAP_FAILED or not. May be this is the case.
And you should always check that the result of mmap is not MAP_FAILED (that is, (void *) -1) and use errno to get the error code in that case.
Your mmap could fail (e.g. because of resource limits set with setrlimit, or because the swap space is full).

Create/initialize objects in shared memory (opened by mmap())

I created my shared memory and mapped my object with following code:
shmfd = shm_open(SHMOBJ_PATH, O_CREAT | O_EXCL | O_RDWR, S_IRWXU | S_IRWXG);
ftruncate(shmfd, shared_seg_size);
bbuffer = (boundedBuffer *)mmap(NULL, shared_seg_size, PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0);
Now I need to initialize and add/remove items to/from bbuffer. When I try to add/remove, I get Segmentation Fault: 11, which indicates the program accessed a memory location that was not assigned. What can I do to solve this problem?
A wild guess:
perhaps you don't have the header file for mmap included
and you are on an architecture with 64 bit void* and 32 bit int
What could happen there is that the compiler takes mmap as returning int by default, casts this into a pointer and by that clashes the higher order bits.
Never cast return values from functions such as malloc or mmap, and always take the warnings of your compiler seriously.

Resources