1161651Skan/* Linux host-specific hook definitions. 2161651Skan Copyright (C) 2004, 2005 Free Software Foundation, Inc. 3161651Skan 4161651Skan This file is part of GCC. 5161651Skan 6161651Skan GCC is free software; you can redistribute it and/or modify it 7161651Skan under the terms of the GNU General Public License as published 8161651Skan by the Free Software Foundation; either version 2, or (at your 9161651Skan option) any later version. 10161651Skan 11161651Skan GCC is distributed in the hope that it will be useful, but WITHOUT 12161651Skan ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 13161651Skan or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 14161651Skan License for more details. 15161651Skan 16161651Skan You should have received a copy of the GNU General Public License 17161651Skan along with GCC; see the file COPYING. If not, write to the 18169689Skan Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, 19169689Skan MA 02110-1301, USA. */ 20161651Skan 21161651Skan#include "config.h" 22161651Skan#include "system.h" 23161651Skan#include "coretypes.h" 24161651Skan#include <sys/mman.h> 25161651Skan#include <limits.h> 26161651Skan#include "hosthooks.h" 27161651Skan#include "hosthooks-def.h" 28161651Skan 29161651Skan 30161651Skan/* Linux has a feature called exec-shield-randomize that perturbs the 31161651Skan address of non-fixed mapped segments by a (relatively) small amount. 32161651Skan The feature is intended to make it harder to attack the system with 33161651Skan buffer overflow attacks, since every invocation of a program will 34161651Skan have its libraries and data segments at slightly different addresses. 35161651Skan 36161651Skan This feature causes us problems with PCH because it makes it that 37161651Skan much harder to acquire a stable location at which to map our PCH 38161651Skan data file. 39161651Skan 40161651Skan [ The feature causes other points of non-determinism within the 41161651Skan compiler as well, so we'd *really* like to be able to have the 42161651Skan driver disable exec-shield-randomize for the process group, but 43161651Skan that isn't possible at present. ] 44161651Skan 45161651Skan We're going to try several things: 46161651Skan 47161651Skan * Select an architecture specific address as "likely" and see 48161651Skan if that's free. For our 64-bit hosts, we can easily choose 49161651Skan an address in Never Never Land. 50161651Skan 51161651Skan * If exec-shield-randomize is disabled, then just use the 52161651Skan address chosen by mmap in step one. 53161651Skan 54161651Skan * If exec-shield-randomize is enabled, then temporarily allocate 55161651Skan 32M of memory as a buffer, then allocate PCH memory, then 56161651Skan free the buffer. The theory here is that the perturbation is 57161651Skan no more than 16M, and so by allocating our buffer larger than 58161651Skan that we make it considerably more likely that the address will 59161651Skan be free when we want to load the data back. 60161651Skan*/ 61161651Skan 62161651Skan#undef HOST_HOOKS_GT_PCH_GET_ADDRESS 63161651Skan#define HOST_HOOKS_GT_PCH_GET_ADDRESS linux_gt_pch_get_address 64161651Skan 65161651Skan#undef HOST_HOOKS_GT_PCH_USE_ADDRESS 66161651Skan#define HOST_HOOKS_GT_PCH_USE_ADDRESS linux_gt_pch_use_address 67161651Skan 68161651Skan/* For various ports, try to guess a fixed spot in the vm space 69161651Skan that's probably free. */ 70161651Skan#if defined(__alpha) 71161651Skan# define TRY_EMPTY_VM_SPACE 0x10000000000 72161651Skan#elif defined(__ia64) 73161651Skan# define TRY_EMPTY_VM_SPACE 0x2000000100000000 74161651Skan#elif defined(__x86_64) 75161651Skan# define TRY_EMPTY_VM_SPACE 0x1000000000 76161651Skan#elif defined(__i386) 77161651Skan# define TRY_EMPTY_VM_SPACE 0x60000000 78161651Skan#elif defined(__powerpc__) 79161651Skan# define TRY_EMPTY_VM_SPACE 0x60000000 80161651Skan#elif defined(__s390x__) 81161651Skan# define TRY_EMPTY_VM_SPACE 0x8000000000 82161651Skan#elif defined(__s390__) 83161651Skan# define TRY_EMPTY_VM_SPACE 0x60000000 84161651Skan#elif defined(__sparc__) && defined(__LP64__) 85161651Skan# define TRY_EMPTY_VM_SPACE 0x8000000000 86161651Skan#elif defined(__sparc__) 87161651Skan# define TRY_EMPTY_VM_SPACE 0x60000000 88161651Skan#else 89161651Skan# define TRY_EMPTY_VM_SPACE 0 90161651Skan#endif 91161651Skan 92161651Skan/* Determine a location where we might be able to reliably allocate SIZE 93161651Skan bytes. FD is the PCH file, though we should return with the file 94161651Skan unmapped. */ 95161651Skan 96161651Skanstatic void * 97161651Skanlinux_gt_pch_get_address (size_t size, int fd) 98161651Skan{ 99161651Skan size_t buffer_size = 32 * 1024 * 1024; 100161651Skan void *addr, *buffer; 101161651Skan FILE *f; 102161651Skan bool randomize_on; 103161651Skan 104161651Skan addr = mmap ((void *)TRY_EMPTY_VM_SPACE, size, PROT_READ | PROT_WRITE, 105161651Skan MAP_PRIVATE, fd, 0); 106161651Skan 107161651Skan /* If we failed the map, that means there's *no* free space. */ 108161651Skan if (addr == (void *) MAP_FAILED) 109161651Skan return NULL; 110161651Skan /* Unmap the area before returning. */ 111161651Skan munmap (addr, size); 112161651Skan 113161651Skan /* If we got the exact area we requested, then that's great. */ 114161651Skan if (TRY_EMPTY_VM_SPACE && addr == (void *) TRY_EMPTY_VM_SPACE) 115161651Skan return addr; 116161651Skan 117161651Skan /* If we didn't, then we need to look to see if virtual address 118161651Skan randomization is on. That is recorded in 119161651Skan kernel.randomize_va_space. An older implementation used 120161651Skan kernel.exec-shield-randomize. */ 121161651Skan f = fopen ("/proc/sys/kernel/randomize_va_space", "r"); 122161651Skan if (f == NULL) 123161651Skan f = fopen ("/proc/sys/kernel/exec-shield-randomize", "r"); 124161651Skan randomize_on = false; 125161651Skan if (f != NULL) 126161651Skan { 127161651Skan char buf[100]; 128161651Skan size_t c; 129161651Skan 130161651Skan c = fread (buf, 1, sizeof buf - 1, f); 131161651Skan if (c > 0) 132161651Skan { 133161651Skan buf[c] = '\0'; 134161651Skan randomize_on = (atoi (buf) > 0); 135161651Skan } 136161651Skan fclose (f); 137161651Skan } 138161651Skan 139161651Skan /* If it isn't, then accept the address that mmap selected as fine. */ 140161651Skan if (!randomize_on) 141161651Skan return addr; 142161651Skan 143161651Skan /* Otherwise, we need to try again with buffer space. */ 144161651Skan buffer = mmap (0, buffer_size, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0); 145161651Skan addr = mmap (0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); 146161651Skan if (buffer != (void *) MAP_FAILED) 147161651Skan munmap (buffer, buffer_size); 148161651Skan if (addr == (void *) MAP_FAILED) 149161651Skan return NULL; 150161651Skan munmap (addr, size); 151161651Skan 152161651Skan return addr; 153161651Skan} 154161651Skan 155161651Skan/* Map SIZE bytes of FD+OFFSET at BASE. Return 1 if we succeeded at 156161651Skan mapping the data at BASE, -1 if we couldn't. 157161651Skan 158161651Skan It's not possibly to reliably mmap a file using MAP_PRIVATE to 159161651Skan a specific START address on either hpux or linux. First we see 160161651Skan if mmap with MAP_PRIVATE works. If it does, we are off to the 161161651Skan races. If it doesn't, we try an anonymous private mmap since the 162161651Skan kernel is more likely to honor the BASE address in anonymous maps. 163161651Skan We then copy the data to the anonymous private map. This assumes 164161651Skan of course that we don't need to change the data in the PCH file 165161651Skan after it is created. 166161651Skan 167161651Skan This approach obviously causes a performance penalty but there is 168161651Skan little else we can do given the current PCH implementation. */ 169161651Skan 170161651Skanstatic int 171161651Skanlinux_gt_pch_use_address (void *base, size_t size, int fd, size_t offset) 172161651Skan{ 173161651Skan void *addr; 174161651Skan 175161651Skan /* We're called with size == 0 if we're not planning to load a PCH 176161651Skan file at all. This allows the hook to free any static space that 177161651Skan we might have allocated at link time. */ 178161651Skan if (size == 0) 179161651Skan return -1; 180161651Skan 181161651Skan /* Try to map the file with MAP_PRIVATE. */ 182161651Skan addr = mmap (base, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, offset); 183161651Skan 184161651Skan if (addr == base) 185161651Skan return 1; 186161651Skan 187161651Skan if (addr != (void *) MAP_FAILED) 188161651Skan munmap (addr, size); 189161651Skan 190161651Skan /* Try to make an anonymous private mmap at the desired location. */ 191161651Skan addr = mmap (base, size, PROT_READ | PROT_WRITE, 192161651Skan MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 193161651Skan 194161651Skan if (addr != base) 195161651Skan { 196161651Skan if (addr != (void *) MAP_FAILED) 197161651Skan munmap (addr, size); 198161651Skan return -1; 199161651Skan } 200161651Skan 201161651Skan if (lseek (fd, offset, SEEK_SET) == (off_t)-1) 202161651Skan return -1; 203161651Skan 204161651Skan while (size) 205161651Skan { 206161651Skan ssize_t nbytes; 207161651Skan 208161651Skan nbytes = read (fd, base, MIN (size, SSIZE_MAX)); 209161651Skan if (nbytes <= 0) 210161651Skan return -1; 211161651Skan base = (char *) base + nbytes; 212161651Skan size -= nbytes; 213161651Skan } 214161651Skan 215161651Skan return 1; 216161651Skan} 217161651Skan 218161651Skan 219161651Skanconst struct host_hooks host_hooks = HOST_HOOKS_INITIALIZER; 220