I want to access an encrypted core storage volume in my program. My plan is to mmap the decrypting block device to be able to jump around in the file system structures with ease and without having to deal with the crypto myself.
While mapping a big file works like a charm, I am getting an EINVAL error on the mmap syscall in the following code:
#include <stddef.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
int main(int argc, char *argv[])
{
int fd = open("/dev/disk2", O_RDONLY); // this works fine
if (fd < 0)
{
perror("Could not open file"); return(-1);
}
int pagesize = getpagesize(); // page size is 4096 on my system
void* address = mmap(NULL, pagesize, PROT_READ, MAP_SHARED | MAP_FILE, fd, 0); // try to map first page
if (address == MAP_FAILED)
{
perror("Could not mmap"); // Error complaining about an invalid argument
}
}
The device has a size of 112 GB and I am compiling with clang mmap.c -O0 -o mmap
on Mavericks 10.9.3 for x86_64. My system has 4 GB of RAM and > 10 GB of free hard disk space.
The man-Page mmap(2) only lists the following explanations for an EINVAL error, but these do not seem to apply:
- MAP_FIXED was specified and the addr argument was not page aligned, or part of the desired address space resides out of the valid address space for a user process.
- flags does not include either MAP_PRIVATE or MAP_SHARED.
- The len argument was negative.
- The offset argument was not page-aligned based on the page size as returned by getpagesize(3).
[...]
- The flags parameter must specify either MAP_PRIVATE or MAP_SHARED.
- The size parameter must not be 0.
- The off parameter must be a multiple of pagesize, as returned by sysconf().
While I have not figured out all the nitty gritty details of the implementation, the comments on this XNU kernel source file explicitly mention being able to map a block device (as long as it's shared): https://www.opensource.apple.com/source/xnu/xnu-2422.1.72/bsd/kern/kern_mman.c
What am I missing?
MAP_FAILED
anderrno
is set to the appropriate error constant. So checking for either should be fine. In this case I am always gettingEINVAL
(= Invalid argument). – struct54MAP_FAILED
is returned, thenerrno
contains information about the error. Typicallyerrno
is not touched if there is no error. – Kerrek SBMAP_FAILED
as return value all along. I updated source code to reflect that. Sorry about the omission. – struct54pagesize
? – Kerrek SB