1/* ----------------------------------------------------------------------- 2 closures.c - Copyright (c) 2007, 2009, 2010 Red Hat, Inc. 3 Copyright (C) 2007, 2009, 2010 Free Software Foundation, Inc 4 Copyright (c) 2011 Plausible Labs Cooperative, Inc. 5 6 Code to allocate and deallocate memory for closures. 7 8 Permission is hereby granted, free of charge, to any person obtaining 9 a copy of this software and associated documentation files (the 10 ``Software''), to deal in the Software without restriction, including 11 without limitation the rights to use, copy, modify, merge, publish, 12 distribute, sublicense, and/or sell copies of the Software, and to 13 permit persons to whom the Software is furnished to do so, subject to 14 the following conditions: 15 16 The above copyright notice and this permission notice shall be included 17 in all copies or substantial portions of the Software. 18 19 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, 20 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 23 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 24 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 DEALINGS IN THE SOFTWARE. 27 ----------------------------------------------------------------------- */ 28 29#if defined __linux__ && !defined _GNU_SOURCE 30#define _GNU_SOURCE 1 31#endif 32 33#include <ffi.h> 34#include <ffi_common.h> 35 36#if !FFI_MMAP_EXEC_WRIT && !FFI_EXEC_TRAMPOLINE_TABLE 37# if __gnu_linux__ && !defined(__ANDROID__) 38/* This macro indicates it may be forbidden to map anonymous memory 39 with both write and execute permission. Code compiled when this 40 option is defined will attempt to map such pages once, but if it 41 fails, it falls back to creating a temporary file in a writable and 42 executable filesystem and mapping pages from it into separate 43 locations in the virtual memory space, one location writable and 44 another executable. */ 45# define FFI_MMAP_EXEC_WRIT 1 46# define HAVE_MNTENT 1 47# endif 48# if defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__) 49/* Windows systems may have Data Execution Protection (DEP) enabled, 50 which requires the use of VirtualMalloc/VirtualFree to alloc/free 51 executable memory. */ 52# define FFI_MMAP_EXEC_WRIT 1 53# endif 54#endif 55 56#if FFI_MMAP_EXEC_WRIT && !defined FFI_MMAP_EXEC_SELINUX 57# ifdef __linux__ 58/* When defined to 1 check for SELinux and if SELinux is active, 59 don't attempt PROT_EXEC|PROT_WRITE mapping at all, as that 60 might cause audit messages. */ 61# define FFI_MMAP_EXEC_SELINUX 1 62# endif 63#endif 64 65#if FFI_CLOSURES 66 67# if FFI_EXEC_TRAMPOLINE_TABLE 68 69// Per-target implementation; It's unclear what can reasonable be shared between two OS/architecture implementations. 70 71# elif FFI_MMAP_EXEC_WRIT /* !FFI_EXEC_TRAMPOLINE_TABLE */ 72 73#define USE_LOCKS 1 74#define USE_DL_PREFIX 1 75#ifdef __GNUC__ 76#ifndef USE_BUILTIN_FFS 77#define USE_BUILTIN_FFS 1 78#endif 79#endif 80 81/* We need to use mmap, not sbrk. */ 82#define HAVE_MORECORE 0 83 84/* We could, in theory, support mremap, but it wouldn't buy us anything. */ 85#define HAVE_MREMAP 0 86 87/* We have no use for this, so save some code and data. */ 88#define NO_MALLINFO 1 89 90/* We need all allocations to be in regular segments, otherwise we 91 lose track of the corresponding code address. */ 92#define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T 93 94/* Don't allocate more than a page unless needed. */ 95#define DEFAULT_GRANULARITY ((size_t)malloc_getpagesize) 96 97#if FFI_CLOSURE_TEST 98/* Don't release single pages, to avoid a worst-case scenario of 99 continuously allocating and releasing single pages, but release 100 pairs of pages, which should do just as well given that allocations 101 are likely to be small. */ 102#define DEFAULT_TRIM_THRESHOLD ((size_t)malloc_getpagesize) 103#endif 104 105#include <sys/types.h> 106#include <sys/stat.h> 107#include <fcntl.h> 108#include <errno.h> 109#ifndef _MSC_VER 110#include <unistd.h> 111#endif 112#include <string.h> 113#include <stdio.h> 114#if !defined(X86_WIN32) && !defined(X86_WIN64) 115#ifdef HAVE_MNTENT 116#include <mntent.h> 117#endif /* HAVE_MNTENT */ 118#include <sys/param.h> 119#include <pthread.h> 120 121/* We don't want sys/mman.h to be included after we redefine mmap and 122 dlmunmap. */ 123#include <sys/mman.h> 124#define LACKS_SYS_MMAN_H 1 125 126#if FFI_MMAP_EXEC_SELINUX 127#include <sys/statfs.h> 128#include <stdlib.h> 129 130static int selinux_enabled = -1; 131 132static int 133selinux_enabled_check (void) 134{ 135 struct statfs sfs; 136 FILE *f; 137 char *buf = NULL; 138 size_t len = 0; 139 140 if (statfs ("/selinux", &sfs) >= 0 141 && (unsigned int) sfs.f_type == 0xf97cff8cU) 142 return 1; 143 f = fopen ("/proc/mounts", "r"); 144 if (f == NULL) 145 return 0; 146 while (getline (&buf, &len, f) >= 0) 147 { 148 char *p = strchr (buf, ' '); 149 if (p == NULL) 150 break; 151 p = strchr (p + 1, ' '); 152 if (p == NULL) 153 break; 154 if (strncmp (p + 1, "selinuxfs ", 10) == 0) 155 { 156 free (buf); 157 fclose (f); 158 return 1; 159 } 160 } 161 free (buf); 162 fclose (f); 163 return 0; 164} 165 166#define is_selinux_enabled() (selinux_enabled >= 0 ? selinux_enabled \ 167 : (selinux_enabled = selinux_enabled_check ())) 168 169#else 170 171#define is_selinux_enabled() 0 172 173#endif /* !FFI_MMAP_EXEC_SELINUX */ 174 175/* On PaX enable kernels that have MPROTECT enable we can't use PROT_EXEC. */ 176#ifdef FFI_MMAP_EXEC_EMUTRAMP_PAX 177#include <stdlib.h> 178 179static int emutramp_enabled = -1; 180 181static int 182emutramp_enabled_check (void) 183{ 184 char *buf = NULL; 185 size_t len = 0; 186 FILE *f; 187 int ret; 188 f = fopen ("/proc/self/status", "r"); 189 if (f == NULL) 190 return 0; 191 ret = 0; 192 193 while (getline (&buf, &len, f) != -1) 194 if (!strncmp (buf, "PaX:", 4)) 195 { 196 char emutramp; 197 if (sscanf (buf, "%*s %*c%c", &emutramp) == 1) 198 ret = (emutramp == 'E'); 199 break; 200 } 201 free (buf); 202 fclose (f); 203 return ret; 204} 205 206#define is_emutramp_enabled() (emutramp_enabled >= 0 ? emutramp_enabled \ 207 : (emutramp_enabled = emutramp_enabled_check ())) 208#endif /* FFI_MMAP_EXEC_EMUTRAMP_PAX */ 209 210#elif defined (__CYGWIN__) || defined(__INTERIX) 211 212#include <sys/mman.h> 213 214/* Cygwin is Linux-like, but not quite that Linux-like. */ 215#define is_selinux_enabled() 0 216 217#endif /* !defined(X86_WIN32) && !defined(X86_WIN64) */ 218 219#ifndef FFI_MMAP_EXEC_EMUTRAMP_PAX 220#define is_emutramp_enabled() 0 221#endif /* FFI_MMAP_EXEC_EMUTRAMP_PAX */ 222 223/* Declare all functions defined in dlmalloc.c as static. */ 224static void *dlmalloc(size_t); 225static void dlfree(void*); 226static void *dlcalloc(size_t, size_t) MAYBE_UNUSED; 227static void *dlrealloc(void *, size_t) MAYBE_UNUSED; 228static void *dlmemalign(size_t, size_t) MAYBE_UNUSED; 229static void *dlvalloc(size_t) MAYBE_UNUSED; 230static int dlmallopt(int, int) MAYBE_UNUSED; 231static size_t dlmalloc_footprint(void) MAYBE_UNUSED; 232static size_t dlmalloc_max_footprint(void) MAYBE_UNUSED; 233static void** dlindependent_calloc(size_t, size_t, void**) MAYBE_UNUSED; 234static void** dlindependent_comalloc(size_t, size_t*, void**) MAYBE_UNUSED; 235static void *dlpvalloc(size_t) MAYBE_UNUSED; 236static int dlmalloc_trim(size_t) MAYBE_UNUSED; 237static size_t dlmalloc_usable_size(void*) MAYBE_UNUSED; 238static void dlmalloc_stats(void) MAYBE_UNUSED; 239 240#if !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX) 241/* Use these for mmap and munmap within dlmalloc.c. */ 242static void *dlmmap(void *, size_t, int, int, int, off_t); 243static int dlmunmap(void *, size_t); 244#endif /* !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX) */ 245 246#define mmap dlmmap 247#define munmap dlmunmap 248 249#include "dlmalloc.c" 250 251#undef mmap 252#undef munmap 253 254#if !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX) 255 256/* A mutex used to synchronize access to *exec* variables in this file. */ 257static pthread_mutex_t open_temp_exec_file_mutex = PTHREAD_MUTEX_INITIALIZER; 258 259/* A file descriptor of a temporary file from which we'll map 260 executable pages. */ 261static int execfd = -1; 262 263/* The amount of space already allocated from the temporary file. */ 264static size_t execsize = 0; 265 266/* Open a temporary file name, and immediately unlink it. */ 267static int 268open_temp_exec_file_name (char *name) 269{ 270 int fd = mkstemp (name); 271 272 if (fd != -1) 273 unlink (name); 274 275 return fd; 276} 277 278/* Open a temporary file in the named directory. */ 279static int 280open_temp_exec_file_dir (const char *dir) 281{ 282 static const char suffix[] = "/ffiXXXXXX"; 283 size_t lendir = strlen (dir); 284 char *tempname = __builtin_alloca (lendir + sizeof (suffix)); 285 286 if (!tempname) 287 return -1; 288 289 memcpy (tempname, dir, lendir); 290 memcpy (tempname + lendir, suffix, sizeof (suffix)); 291 292 return open_temp_exec_file_name (tempname); 293} 294 295/* Open a temporary file in the directory in the named environment 296 variable. */ 297static int 298open_temp_exec_file_env (const char *envvar) 299{ 300 const char *value = getenv (envvar); 301 302 if (!value) 303 return -1; 304 305 return open_temp_exec_file_dir (value); 306} 307 308#ifdef HAVE_MNTENT 309/* Open a temporary file in an executable and writable mount point 310 listed in the mounts file. Subsequent calls with the same mounts 311 keep searching for mount points in the same file. Providing NULL 312 as the mounts file closes the file. */ 313static int 314open_temp_exec_file_mnt (const char *mounts) 315{ 316 static const char *last_mounts; 317 static FILE *last_mntent; 318 319 if (mounts != last_mounts) 320 { 321 if (last_mntent) 322 endmntent (last_mntent); 323 324 last_mounts = mounts; 325 326 if (mounts) 327 last_mntent = setmntent (mounts, "r"); 328 else 329 last_mntent = NULL; 330 } 331 332 if (!last_mntent) 333 return -1; 334 335 for (;;) 336 { 337 int fd; 338 struct mntent mnt; 339 char buf[MAXPATHLEN * 3]; 340 341 if (getmntent_r (last_mntent, &mnt, buf, sizeof (buf)) == NULL) 342 return -1; 343 344 if (hasmntopt (&mnt, "ro") 345 || hasmntopt (&mnt, "noexec") 346 || access (mnt.mnt_dir, W_OK)) 347 continue; 348 349 fd = open_temp_exec_file_dir (mnt.mnt_dir); 350 351 if (fd != -1) 352 return fd; 353 } 354} 355#endif /* HAVE_MNTENT */ 356 357/* Instructions to look for a location to hold a temporary file that 358 can be mapped in for execution. */ 359static struct 360{ 361 int (*func)(const char *); 362 const char *arg; 363 int repeat; 364} open_temp_exec_file_opts[] = { 365 { open_temp_exec_file_env, "TMPDIR", 0 }, 366 { open_temp_exec_file_dir, "/tmp", 0 }, 367 { open_temp_exec_file_dir, "/var/tmp", 0 }, 368 { open_temp_exec_file_dir, "/dev/shm", 0 }, 369 { open_temp_exec_file_env, "HOME", 0 }, 370#ifdef HAVE_MNTENT 371 { open_temp_exec_file_mnt, "/etc/mtab", 1 }, 372 { open_temp_exec_file_mnt, "/proc/mounts", 1 }, 373#endif /* HAVE_MNTENT */ 374}; 375 376/* Current index into open_temp_exec_file_opts. */ 377static int open_temp_exec_file_opts_idx = 0; 378 379/* Reset a current multi-call func, then advances to the next entry. 380 If we're at the last, go back to the first and return nonzero, 381 otherwise return zero. */ 382static int 383open_temp_exec_file_opts_next (void) 384{ 385 if (open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat) 386 open_temp_exec_file_opts[open_temp_exec_file_opts_idx].func (NULL); 387 388 open_temp_exec_file_opts_idx++; 389 if (open_temp_exec_file_opts_idx 390 == (sizeof (open_temp_exec_file_opts) 391 / sizeof (*open_temp_exec_file_opts))) 392 { 393 open_temp_exec_file_opts_idx = 0; 394 return 1; 395 } 396 397 return 0; 398} 399 400/* Return a file descriptor of a temporary zero-sized file in a 401 writable and executable filesystem. */ 402static int 403open_temp_exec_file (void) 404{ 405 int fd; 406 407 do 408 { 409 fd = open_temp_exec_file_opts[open_temp_exec_file_opts_idx].func 410 (open_temp_exec_file_opts[open_temp_exec_file_opts_idx].arg); 411 412 if (!open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat 413 || fd == -1) 414 { 415 if (open_temp_exec_file_opts_next ()) 416 break; 417 } 418 } 419 while (fd == -1); 420 421 return fd; 422} 423 424/* Map in a chunk of memory from the temporary exec file into separate 425 locations in the virtual memory address space, one writable and one 426 executable. Returns the address of the writable portion, after 427 storing an offset to the corresponding executable portion at the 428 last word of the requested chunk. */ 429static void * 430dlmmap_locked (void *start, size_t length, int prot, int flags, off_t offset) 431{ 432 void *ptr; 433 434 if (execfd == -1) 435 { 436 open_temp_exec_file_opts_idx = 0; 437 retry_open: 438 execfd = open_temp_exec_file (); 439 if (execfd == -1) 440 return MFAIL; 441 } 442 443 offset = execsize; 444 445 if (ftruncate (execfd, offset + length)) 446 return MFAIL; 447 448 flags &= ~(MAP_PRIVATE | MAP_ANONYMOUS); 449 flags |= MAP_SHARED; 450 451 ptr = mmap (NULL, length, (prot & ~PROT_WRITE) | PROT_EXEC, 452 flags, execfd, offset); 453 if (ptr == MFAIL) 454 { 455 if (!offset) 456 { 457 close (execfd); 458 goto retry_open; 459 } 460 ftruncate (execfd, offset); 461 return MFAIL; 462 } 463 else if (!offset 464 && open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat) 465 open_temp_exec_file_opts_next (); 466 467 start = mmap (start, length, prot, flags, execfd, offset); 468 469 if (start == MFAIL) 470 { 471 munmap (ptr, length); 472 ftruncate (execfd, offset); 473 return start; 474 } 475 476 mmap_exec_offset ((char *)start, length) = (char*)ptr - (char*)start; 477 478 execsize += length; 479 480 return start; 481} 482 483/* Map in a writable and executable chunk of memory if possible. 484 Failing that, fall back to dlmmap_locked. */ 485static void * 486dlmmap (void *start, size_t length, int prot, 487 int flags, int fd, off_t offset) 488{ 489 void *ptr; 490 491 assert (start == NULL && length % malloc_getpagesize == 0 492 && prot == (PROT_READ | PROT_WRITE) 493 && flags == (MAP_PRIVATE | MAP_ANONYMOUS) 494 && fd == -1 && offset == 0); 495 496#if FFI_CLOSURE_TEST 497 printf ("mapping in %zi\n", length); 498#endif 499 500 if (execfd == -1 && is_emutramp_enabled ()) 501 { 502 ptr = mmap (start, length, prot & ~PROT_EXEC, flags, fd, offset); 503 return ptr; 504 } 505 506 if (execfd == -1 && !is_selinux_enabled ()) 507 { 508 ptr = mmap (start, length, prot | PROT_EXEC, flags, fd, offset); 509 510 if (ptr != MFAIL || (errno != EPERM && errno != EACCES)) 511 /* Cool, no need to mess with separate segments. */ 512 return ptr; 513 514 /* If MREMAP_DUP is ever introduced and implemented, try mmap 515 with ((prot & ~PROT_WRITE) | PROT_EXEC) and mremap with 516 MREMAP_DUP and prot at this point. */ 517 } 518 519 if (execsize == 0 || execfd == -1) 520 { 521 pthread_mutex_lock (&open_temp_exec_file_mutex); 522 ptr = dlmmap_locked (start, length, prot, flags, offset); 523 pthread_mutex_unlock (&open_temp_exec_file_mutex); 524 525 return ptr; 526 } 527 528 return dlmmap_locked (start, length, prot, flags, offset); 529} 530 531/* Release memory at the given address, as well as the corresponding 532 executable page if it's separate. */ 533static int 534dlmunmap (void *start, size_t length) 535{ 536 /* We don't bother decreasing execsize or truncating the file, since 537 we can't quite tell whether we're unmapping the end of the file. 538 We don't expect frequent deallocation anyway. If we did, we 539 could locate pages in the file by writing to the pages being 540 deallocated and checking that the file contents change. 541 Yuck. */ 542 msegmentptr seg = segment_holding (gm, start); 543 void *code; 544 545#if FFI_CLOSURE_TEST 546 printf ("unmapping %zi\n", length); 547#endif 548 549 if (seg && (code = add_segment_exec_offset (start, seg)) != start) 550 { 551 int ret = munmap (code, length); 552 if (ret) 553 return ret; 554 } 555 556 return munmap (start, length); 557} 558 559#if FFI_CLOSURE_FREE_CODE 560/* Return segment holding given code address. */ 561static msegmentptr 562segment_holding_code (mstate m, char* addr) 563{ 564 msegmentptr sp = &m->seg; 565 for (;;) { 566 if (addr >= add_segment_exec_offset (sp->base, sp) 567 && addr < add_segment_exec_offset (sp->base, sp) + sp->size) 568 return sp; 569 if ((sp = sp->next) == 0) 570 return 0; 571 } 572} 573#endif 574 575#endif /* !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX) */ 576 577/* Allocate a chunk of memory with the given size. Returns a pointer 578 to the writable address, and sets *CODE to the executable 579 corresponding virtual address. */ 580void * 581ffi_closure_alloc (size_t size, void **code) 582{ 583 void *ptr; 584 585 if (!code) 586 return NULL; 587 588 ptr = dlmalloc (size); 589 590 if (ptr) 591 { 592 msegmentptr seg = segment_holding (gm, ptr); 593 594 *code = add_segment_exec_offset (ptr, seg); 595 } 596 597 return ptr; 598} 599 600/* Release a chunk of memory allocated with ffi_closure_alloc. If 601 FFI_CLOSURE_FREE_CODE is nonzero, the given address can be the 602 writable or the executable address given. Otherwise, only the 603 writable address can be provided here. */ 604void 605ffi_closure_free (void *ptr) 606{ 607#if FFI_CLOSURE_FREE_CODE 608 msegmentptr seg = segment_holding_code (gm, ptr); 609 610 if (seg) 611 ptr = sub_segment_exec_offset (ptr, seg); 612#endif 613 614 dlfree (ptr); 615} 616 617 618#if FFI_CLOSURE_TEST 619/* Do some internal sanity testing to make sure allocation and 620 deallocation of pages are working as intended. */ 621int main () 622{ 623 void *p[3]; 624#define GET(idx, len) do { p[idx] = dlmalloc (len); printf ("allocated %zi for p[%i]\n", (len), (idx)); } while (0) 625#define PUT(idx) do { printf ("freeing p[%i]\n", (idx)); dlfree (p[idx]); } while (0) 626 GET (0, malloc_getpagesize / 2); 627 GET (1, 2 * malloc_getpagesize - 64 * sizeof (void*)); 628 PUT (1); 629 GET (1, 2 * malloc_getpagesize); 630 GET (2, malloc_getpagesize / 2); 631 PUT (1); 632 PUT (0); 633 PUT (2); 634 return 0; 635} 636#endif /* FFI_CLOSURE_TEST */ 637# else /* ! FFI_MMAP_EXEC_WRIT */ 638 639/* On many systems, memory returned by malloc is writable and 640 executable, so just use it. */ 641 642#include <stdlib.h> 643 644void * 645ffi_closure_alloc (size_t size, void **code) 646{ 647 if (!code) 648 return NULL; 649 650 return *code = malloc (size); 651} 652 653void 654ffi_closure_free (void *ptr) 655{ 656 free (ptr); 657} 658 659# endif /* ! FFI_MMAP_EXEC_WRIT */ 660#endif /* FFI_CLOSURES */ 661