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