Skip to content

Instantly share code, notes, and snippets.

@tkhai
Created May 15, 2019 14:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tkhai/198d32fdc001ec7812a5e1ccf091f275 to your computer and use it in GitHub Desktop.
Save tkhai/198d32fdc001ec7812a5e1ccf091f275 to your computer and use it in GitHub Desktop.
#define _GNU_SOURCE
#include <linux/mman.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <signal.h>
#include <sched.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <errno.h>
#include <err.h>
#include <wait.h>
/* Check process_vm_mmap() saves sharing and flags */
#define __NR_process_vm_mmap 428
#define PVMMAP_FIXED 0x01
#define PAGE_SIZE 4096
#define MAX_SIZE (PAGE_SIZE * 32768 * 16UL / 4)
typedef _Bool bool;
static void *process_vm_mmap(pid_t pid, unsigned long src_addr,
unsigned long len,
unsigned long dst_addr,
unsigned long flags)
{
unsigned long ret;
ret = syscall(__NR_process_vm_mmap, pid, src_addr, len, dst_addr, flags);
if (ret < PAGE_SIZE) {
errno = (int)ret;
return MAP_FAILED;
}
return (void *)ret;
}
static int child()
{
while (1)
sleep(1);
}
static int test(bool file, bool shared, bool huge, int map_prot, bool populate,
unsigned long size, unsigned long offset, bool unaligned)
{
int status, mmap_flags = 0, pvm_mmap_flags = 0, fd = -1;
void *addr, *faddr, *addr2 = NULL;
long i, ret, retval = -1;
unsigned long size2;
pid_t pid;
if (file) {
fd = open("/tmp/proc_vm_mmap.test", O_RDWR|O_CREAT);
if (fd < 0) {
perror("open");
return -1;
}
if (ftruncate(fd, size)) {
perror("ftruncate");
return -1;
}
} else {
mmap_flags |= MAP_ANONYMOUS;
}
if (shared)
mmap_flags |= MAP_SHARED;
else
mmap_flags |= MAP_PRIVATE;
if (huge)
mmap_flags |= MAP_HUGE_2MB;
pid = fork();
if (pid < 0) {
perror("fork");
return -1;
}
if (pid == 0)
return child();
addr = mmap(0, size, map_prot, mmap_flags, fd, 0);
if (addr == MAP_FAILED) {
perror("mmap\n");
goto kill;
}
if (huge) {
ret = madvise(addr, size, MADV_HUGEPAGE);
if (ret) {
perror("madvise");
goto kill;
}
}
if (populate) {
for (i = 0; i < size; i += PAGE_SIZE)
*(unsigned long *)(addr + i) = (unsigned long)addr + i;
}
faddr = process_vm_mmap(-pid, (unsigned long)addr, size, 0, 0);
if (faddr == MAP_FAILED) {
warn("process_vm_mmap: %d", __LINE__);
goto kill;
}
if (unaligned) {
pvm_mmap_flags |= PVMMAP_FIXED;
/* Find a place for addr2 */
addr2 = mmap(0, size + PAGE_SIZE, PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
if (addr2 == MAP_FAILED) {
perror("mmap addr2");
goto kill;
}
munmap(addr2, size + PAGE_SIZE);
if (((unsigned long)addr2 & PAGE_SIZE) == 0)
addr2 += PAGE_SIZE;
} else {
addr2 = NULL;
}
size2 = size - offset;
addr2 = process_vm_mmap(pid, (unsigned long)faddr + offset, size2,
(unsigned long)addr2, pvm_mmap_flags);
if (addr2 == MAP_FAILED) {
warn("process_vm_mmap: %d", __LINE__);
goto kill;
}
if (memcmp(addr + offset, addr2, size2)) {
printf("not equal: %d\n", __LINE__);
goto kill;
}
for (i = 0; i < size2; i += PAGE_SIZE) {
bool is_shared;
*(unsigned long *)(addr2 + i) = (unsigned long)addr2 + i;
is_shared = (*(unsigned long *)(addr + offset + i) == *(unsigned long *)(addr2 + i));
if (shared != is_shared) {
printf("sharing changed\n");
goto kill;
}
}
retval = 0;
kill:
printf("file=%d shared=%d huge=%d map_prot=%d populate=%d size=%lu offset=%lu unaligned=%d: %s\n",
file, shared, huge, map_prot, populate, size, offset, unaligned,
retval ? "FAIL" : "OK");
kill(pid, SIGKILL);
if (fd >= 0)
close(fd);
munmap(addr2, size2);
munmap(addr, size);
wait(&status);
return retval;
}
int main()
{
int file, shared, huge, map_prot, populate, unaligned, ret;
unsigned long size, offset;
/* test(bool file, bool shared, bool huge, int map_prot, bool populate, unsigned long size, unsigned long offset, bool unaligned) */
for (file = 0; file <= 1; file++)
for (shared = 0; shared <= 1; shared++)
for (huge = 0; huge <= 1; huge++)
for (populate = 0; populate <= 1; populate++)
for (unaligned = 0; unaligned <= 1; unaligned++)
for (size = PAGE_SIZE; size <= MAX_SIZE; size <<= 1)
for (offset = 0; offset < size; offset = (offset << 1) ? : PAGE_SIZE) {
map_prot = PROT_WRITE|PROT_READ;
while (1) {
ret = test(file, shared, huge, map_prot, populate, size, offset, unaligned);
if (ret < 0)
exit(1);
if (map_prot == PROT_READ|PROT_WRITE|PROT_EXEC)
break;
map_prot |= PROT_EXEC;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment