#include "orconfig.h"
#include "lib/malloc/map_anon.h"
#include "lib/malloc/malloc.h"
#include "lib/err/torerr.h"
#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_MACH_VM_INHERIT_H
#include <mach/vm_inherit.h>
#endif
#ifdef _WIN32
#include <windows.h>
#endif
#include <string.h>
#include <errno.h>
#if SIZEOF_SIZE_T > 4
#define HIGH_SIZE_T_BYTES(sz) ((sz) >> 32)
#else
#define HIGH_SIZE_T_BYTES(sz) (0)
#endif
#if defined(HAVE_MINHERIT)
#define MINHERIT minherit
#ifdef INHERIT_ZERO
#define FLAG_ZERO INHERIT_ZERO
#elif defined(MAP_INHERIT_ZERO)
#define FLAG_ZERO MAP_INHERIT_ZERO
#endif
#ifdef INHERIT_NONE
#define FLAG_NOINHERIT INHERIT_NONE
#elif defined(VM_INHERIT_NONE)
#define FLAG_NOINHERIT VM_INHERIT_NONE
#elif defined(MAP_INHERIT_NONE)
#define FLAG_NOINHERIT MAP_INHERIT_NONE
#endif
#elif defined(HAVE_MADVISE)
#define MINHERIT madvise
#ifdef MADV_WIPEONFORK
#define FLAG_ZERO MADV_WIPEONFORK
#endif
#ifdef MADV_DONTFORK
#define FLAG_NOINHERIT MADV_DONTFORK
#endif
#endif
#if defined(HAVE_MINHERIT) && !defined(FLAG_ZERO) && !defined(FLAG_NOINHERIT)
#warning "minherit() is defined, but FLAG_ZERO/NOINHERIT are not."
#warning "This is probably a bug in Tor's support for this platform."
#endif
static int
lock_mem(void *mem, size_t sz)
{
#ifdef _WIN32
return VirtualLock(mem, sz) ? 0 : -1;
#elif defined(HAVE_MLOCK)
return mlock(mem, sz);
#else
(void) mem;
(void) sz;
return 0;
#endif
}
static int
nodump_mem(void *mem, size_t sz)
{
#if defined(MADV_DONTDUMP)
int rv = madvise(mem, sz, MADV_DONTDUMP);
if (rv == 0) {
return 0;
} else if (errno == ENOSYS || errno == EINVAL) {
return 0; } else {
tor_log_err_sigsafe("Unexpected error from madvise: ",
strerror(errno),
NULL);
return -1;
}
#else
(void) mem;
(void) sz;
return 0;
#endif
}
static int
noinherit_mem(void *mem, size_t sz, inherit_res_t *inherit_result_out)
{
#ifdef FLAG_ZERO
int r = MINHERIT(mem, sz, FLAG_ZERO);
if (r == 0) {
*inherit_result_out = INHERIT_RES_ZERO;
return 0;
}
#endif
#ifdef FLAG_NOINHERIT
int r2 = MINHERIT(mem, sz, FLAG_NOINHERIT);
if (r2 == 0) {
*inherit_result_out = INHERIT_RES_DROP;
return 0;
}
#endif
#if defined(FLAG_ZERO) || defined(FLAG_NOINHERIT)
if (errno == ENOSYS || errno == EINVAL) {
return 0;
} else {
tor_log_err_sigsafe("Unexpected error from minherit: ",
strerror(errno),
NULL);
return -1;
}
#else
(void)inherit_result_out;
(void)mem;
(void)sz;
return 0;
#endif
}
void *
tor_mmap_anonymous(size_t sz, unsigned flags,
inherit_res_t *inherit_result_out)
{
void *ptr;
inherit_res_t itmp=0;
if (inherit_result_out == NULL) {
inherit_result_out = &itmp;
}
*inherit_result_out = INHERIT_RES_KEEP;
#if defined(_WIN32)
HANDLE mapping = CreateFileMapping(INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
HIGH_SIZE_T_BYTES(sz),
sz & 0xffffffff,
NULL );
raw_assert(mapping != NULL);
ptr = MapViewOfFile(mapping, FILE_MAP_WRITE,
0, 0,
0 );
raw_assert(ptr);
CloseHandle(mapping);
#elif defined(HAVE_SYS_MMAN_H)
ptr = mmap(NULL, sz,
PROT_READ|PROT_WRITE,
MAP_ANON|MAP_PRIVATE,
-1, 0);
raw_assert(ptr != MAP_FAILED);
raw_assert(ptr != NULL);
#else
ptr = tor_malloc_zero(sz);
#endif
if (flags & ANONMAP_PRIVATE) {
int lock_result = lock_mem(ptr, sz);
raw_assert(lock_result == 0);
int nodump_result = nodump_mem(ptr, sz);
raw_assert(nodump_result == 0);
}
if (flags & ANONMAP_NOINHERIT) {
int noinherit_result = noinherit_mem(ptr, sz, inherit_result_out);
raw_assert(noinherit_result == 0);
}
return ptr;
}
void
tor_munmap_anonymous(void *mapping, size_t sz)
{
if (!mapping)
return;
#if defined(_WIN32)
(void)sz;
UnmapViewOfFile(mapping);
#elif defined(HAVE_SYS_MMAN_H)
munmap(mapping, sz);
#else
(void)sz;
tor_free(mapping);
#endif
}