Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C - why I cannot mmap a small (256UL or smaller) size of memory?

Please tell me, why my simple application cannot mmap a small size of memory?

And, why such a specific boundary - 257UL?

// #define MAP_SIZE 256UL or below - fail
// #define MAP_SIZE 257UL - ok

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <ctype.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/mman.h>

#define FATAL do { fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", \
  __LINE__, __FILE__, errno, strerror(errno)); exit(1); } while(0)

#define MAP_SIZE 4096UL
#define MAP_MASK (MAP_SIZE - 1)

int main(int argc, char **argv) {
    int fd;
    void *map_base, *virt_addr;
    unsigned long read_result, writeval;
    off_t target = strtoul("0x00002000", 0, 0);

    if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) FATAL;
    printf("/dev/mem opened.\n");
    fflush(stdout);

    map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, target & ~MAP_MASK);
    if(map_base == (void *) -1) FATAL;
    printf("Memory mapped at address %p.\n", map_base);
    fflush(stdout);
...
}
like image 582
Jake Badlands Avatar asked Oct 10 '12 08:10

Jake Badlands


2 Answers

mmap works in multiples of the page size on your system. If you're doing this on i386/amd64 or actually most modern CPUs, this will be 4096.

In the man page of mmap on my system it says: "offset must be a multiple of the page size as returned by sysconf(_SC_PAGE_SIZE).". On some systems for historical reasons the length argument may be not a multiple of page size, but mmap will round up to a full page in that case anyway.

like image 111
Art Avatar answered Sep 30 '22 00:09

Art


Probably you just don't have the rights to write to /dev/mem. This is probably not what you want, mapping all the low end physical memory into your address space.

Have a look into shm_open to open memory segments or MAP_ANONYMOUS to map anonymously.

Edit:

Do a man mem to know what the /dev/mem device node is about:

Byte addresses in mem are interpreted as physical memory addresses. References to nonexistent locations cause errors to be returned.

If you want to map to a device node to have a memory segment you should use /dev/zero, but nowadays the tools I describe above should be sufficient.

Then don't, really don't, run such a code with root privileges unless you really know what you are doing. Writing into the physical memory and thus overwriting kernel and userspace data and programs can only lead to catastrophes.

like image 26
Jens Gustedt Avatar answered Sep 30 '22 00:09

Jens Gustedt