This is the mail archive of the libc-help@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Creating aliases for memory ranges


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;
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]