0
votes

Created a simple mmap program that modifies a byte file. Run it as root on a simple/small file, got error

# ./a.out tmp.txt 92
fd=3
mmap: Permission denied

Code snippet

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>

int main(int argc, char *argv[]) {
    int fd = open(argv[1], O_WRONLY);
    printf("fd=%d\n", fd);
    char *p = mmap(0, 0x1000, PROT_WRITE, MAP_SHARED, fd, 0);
    if (p == MAP_FAILED) {
        perror ("mmap");
        return 1;
    }
    p[0] = 0xde;
    close(fd);
    return 0;
}

Wonder what went wrong. Thanks.

UPDATE1 Fixed a typo in the code snippet, I meant to use PROT_WRITE there.

1
Thanks @mch for pointing out, I corrected the code snippet by using PROT_WRITE but got the same story.packetie
Is the size of the file really 0x1000 bytes? That are 4096 bytes.mch
The size is actually 92 bytes, used 0x1000 because it's a page size on my Linuxpacketie
What owner/user and permissions does tmp.txt have, and what user are you running the program as? ls -l tmp.txt; idC0deH4cker

1 Answers

3
votes

from the man page for mmap:

EACCES A file descriptor refers to a non-regular file. Or a file mapping was requested, but fd is not open for reading. Or MAP_SHARED was requested and PROT_WRITE is set, but fd is not open in read/write (O_RDWR) mode. Or PROT_WRITE is set, but the file is append-only.

So in order to map a file MAP_SHARED, you need to open it in read/write mode, not writeonly. Makes sense, as the contents of the file needs to be read to initialize parts of the memory you don't write.

In addition, IA-32 does not allow write-only mappings of pages, so mapping with PROT_WRITE on such a machine will implictly also enable PROT_READ, so will fail for a file descriptor that isn't readable.