This is the mail archive of the
libc-help@sourceware.org
mailing list for the glibc project.
Re: Creating aliases for memory ranges
- From: Florian Weimer <fweimer at redhat dot com>
- To: Ángel González <keisial at gmail dot com>, Maxim Kuvyrkov <maxim at kugelworks dot com>
- Cc: libc-help at sourceware dot org
- Date: Fri, 18 Oct 2013 15:54:07 +0200
- Subject: Re: Creating aliases for memory ranges
- Authentication-results: sourceware.org; auth=none
- References: <50FFB8E6 dot 4010808 at redhat dot com> <77E174C8-B5EB-435F-A6AF-ED7C01D85A32 at kugelworks dot com> <5104301A dot 4070801 at gmail dot com>
On 01/26/2013 08:35 PM, Ángel González wrote:
Florian, you need to open a temporary file and map it twice (once ro and
the other rw). You can then unlink the file after opening. You can't
duplicate a mapping with no associated file.
I tried to map memory from /proc/self/map, but that doesn't work,
either. I came up with the attached code instead. It has the advantage
that the memory area isn't backed by disk (if /dev/shm is on tmpfs), so
it won't cause any pointless disk I/O.
--
Florian Weimer / Red Hat Product Security Team
#define _GNU_SOURCE
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdio.h>
void
test_alias(volatile char *left, volatile char *right)
{
errno = EINVAL;
if (*left != 0) {
err(1, "check 1");
}
if (*right != 0) {
err(1, "check 2");
}
*left = 1;
if (*right != 1) {
err(1, "check 3");
}
*right = 2;
if (*left != 2) {
err(1, "check 4");
}
}
int
main(void)
{
long page_size = sysconf(_SC_PAGE_SIZE);
if (page_size < 0) {
err(1, "sysconf(_SC_PAGE_SIZE)");
}
int memfd;
{
unsigned count = 0;
char buf[64];
while (1) {
snprintf(buf, sizeof(buf), "/alias.%d.%u", getpid(), count++);
memfd = shm_open(buf, O_RDWR | O_CREAT | O_EXCL, 0700);
if (memfd < 0) {
if (errno == EEXIST) {
continue;
}
err(1, "shm_open");
}
if (shm_unlink(buf) < 0) {
err(1, "shm_unlink");
}
break;
}
}
if (ftruncate(memfd, page_size) < 0) {
err(1, "ftruncate(%ld)", page_size);
}
void *area =
mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE,
MAP_SHARED, memfd, 0);
if (area == MAP_FAILED) {
err(1, "mmap(%ld)", 2 * page_size);
}
char *page_two = area;
page_two += page_size;
if (mmap(page_two, page_size, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_FIXED, memfd, 0) != page_two) {
err(1, "mmap(MAP_FIXED)");
}
test_alias(area, page_two);
return 0;
}