2014-05-10 02:12:08 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2010 The Android Open Source Project
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
2018-10-25 18:00:00 +00:00
|
|
|
#pragma once
|
2014-05-10 02:12:08 +00:00
|
|
|
|
Align-up and randomize shared libraries.
This change implements the following property:
Any 2**N aligned memory region on size 2**N contains no more than one DSO.
The value N can be configured, with 16 or 18 looking like a good choice.
Additionally, DSOs are loaded at random page-aligned address inside these large
regions.
This change has dual purpose:
1. Larger values of N allow a lot more compact CFI shadow implementation.
See change I14dfea630de468eb5620e7f55f92b1397ba06217.
For example, CFI shadow for the system_server process has the following size (RSS, KB):
152 for N = 12, 32 for N = 16, 16 for N = 18.
2. Extra randomization is good for security.
This change does not result in extra RAM usage, because everything is still page-aligned.
It does result in a bit more VM fragmentation because of the gaps between shared libraries.
As it turns out, this fragmentation is barely noticeable because the kernel creates new mapping
at the highest possible address, and we do enough small mappings to almost completely fill the
gaps (ex. in the Zygote the gaps are filled with .ttf file mappings and thread stacks).
I've measured VM fragmentation as the sum of all VM gaps (unmapped regions) that are larger
than 1MB according to /proc/$PID/maps. On aosp_angler-userdebug, the numbers are (in GB):
| N = 12 | N = 18
system_server | 521.9 | 521.1
zygote64 | 522.1 | 521.3
zygote32 | 2.55 | 2.55
mediaserver | 4.00 | 4.00
Change-Id: Ia6df840dd409c82837efd1f263be420d9723c84a
2016-07-15 23:31:42 +00:00
|
|
|
#include <stdint.h>
|
|
|
|
|
2018-10-25 18:00:00 +00:00
|
|
|
#define BIONIC_DISALLOW_COPY_AND_ASSIGN(TypeName) \
|
|
|
|
TypeName(const TypeName&) = delete; \
|
2014-09-08 23:22:22 +00:00
|
|
|
void operator=(const TypeName&) = delete
|
2014-05-10 02:12:08 +00:00
|
|
|
|
2018-10-25 18:00:00 +00:00
|
|
|
#define BIONIC_DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
|
|
|
|
TypeName() = delete; \
|
|
|
|
BIONIC_DISALLOW_COPY_AND_ASSIGN(TypeName)
|
2014-05-10 02:12:08 +00:00
|
|
|
|
2014-06-13 20:57:51 +00:00
|
|
|
#define BIONIC_ROUND_UP_POWER_OF_2(value) \
|
2015-12-17 00:11:04 +00:00
|
|
|
((sizeof(value) == 8) \
|
2014-07-15 01:47:23 +00:00
|
|
|
? (1UL << (64 - __builtin_clzl(static_cast<unsigned long>(value)))) \
|
2015-12-17 00:11:04 +00:00
|
|
|
: (1UL << (32 - __builtin_clz(static_cast<unsigned int>(value)))))
|
2014-06-13 20:57:51 +00:00
|
|
|
|
2016-07-06 20:20:59 +00:00
|
|
|
static constexpr uintptr_t align_down(uintptr_t p, size_t align) {
|
Align-up and randomize shared libraries.
This change implements the following property:
Any 2**N aligned memory region on size 2**N contains no more than one DSO.
The value N can be configured, with 16 or 18 looking like a good choice.
Additionally, DSOs are loaded at random page-aligned address inside these large
regions.
This change has dual purpose:
1. Larger values of N allow a lot more compact CFI shadow implementation.
See change I14dfea630de468eb5620e7f55f92b1397ba06217.
For example, CFI shadow for the system_server process has the following size (RSS, KB):
152 for N = 12, 32 for N = 16, 16 for N = 18.
2. Extra randomization is good for security.
This change does not result in extra RAM usage, because everything is still page-aligned.
It does result in a bit more VM fragmentation because of the gaps between shared libraries.
As it turns out, this fragmentation is barely noticeable because the kernel creates new mapping
at the highest possible address, and we do enough small mappings to almost completely fill the
gaps (ex. in the Zygote the gaps are filled with .ttf file mappings and thread stacks).
I've measured VM fragmentation as the sum of all VM gaps (unmapped regions) that are larger
than 1MB according to /proc/$PID/maps. On aosp_angler-userdebug, the numbers are (in GB):
| N = 12 | N = 18
system_server | 521.9 | 521.1
zygote64 | 522.1 | 521.3
zygote32 | 2.55 | 2.55
mediaserver | 4.00 | 4.00
Change-Id: Ia6df840dd409c82837efd1f263be420d9723c84a
2016-07-15 23:31:42 +00:00
|
|
|
return p & ~(align - 1);
|
|
|
|
}
|
|
|
|
|
2016-07-06 20:20:59 +00:00
|
|
|
static constexpr uintptr_t align_up(uintptr_t p, size_t align) {
|
Align-up and randomize shared libraries.
This change implements the following property:
Any 2**N aligned memory region on size 2**N contains no more than one DSO.
The value N can be configured, with 16 or 18 looking like a good choice.
Additionally, DSOs are loaded at random page-aligned address inside these large
regions.
This change has dual purpose:
1. Larger values of N allow a lot more compact CFI shadow implementation.
See change I14dfea630de468eb5620e7f55f92b1397ba06217.
For example, CFI shadow for the system_server process has the following size (RSS, KB):
152 for N = 12, 32 for N = 16, 16 for N = 18.
2. Extra randomization is good for security.
This change does not result in extra RAM usage, because everything is still page-aligned.
It does result in a bit more VM fragmentation because of the gaps between shared libraries.
As it turns out, this fragmentation is barely noticeable because the kernel creates new mapping
at the highest possible address, and we do enough small mappings to almost completely fill the
gaps (ex. in the Zygote the gaps are filled with .ttf file mappings and thread stacks).
I've measured VM fragmentation as the sum of all VM gaps (unmapped regions) that are larger
than 1MB according to /proc/$PID/maps. On aosp_angler-userdebug, the numbers are (in GB):
| N = 12 | N = 18
system_server | 521.9 | 521.1
zygote64 | 522.1 | 521.3
zygote32 | 2.55 | 2.55
mediaserver | 4.00 | 4.00
Change-Id: Ia6df840dd409c82837efd1f263be420d9723c84a
2016-07-15 23:31:42 +00:00
|
|
|
return (p + align - 1) & ~(align - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
static inline T* align_down(T* p, size_t align) {
|
|
|
|
return reinterpret_cast<T*>(align_down(reinterpret_cast<uintptr_t>(p), align));
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
static inline T* align_up(T* p, size_t align) {
|
|
|
|
return reinterpret_cast<T*>(align_up(reinterpret_cast<uintptr_t>(p), align));
|
|
|
|
}
|
|
|
|
|
2017-10-05 22:18:47 +00:00
|
|
|
#if defined(__arm__)
|
2019-08-27 20:54:18 +00:00
|
|
|
#define BIONIC_STOP_UNWIND asm volatile(".cfi_undefined r14")
|
2017-10-05 22:18:47 +00:00
|
|
|
#elif defined(__aarch64__)
|
|
|
|
#define BIONIC_STOP_UNWIND asm volatile(".cfi_undefined x30")
|
|
|
|
#elif defined(__i386__)
|
|
|
|
#define BIONIC_STOP_UNWIND asm volatile(".cfi_undefined \%eip")
|
|
|
|
#elif defined(__x86_64__)
|
|
|
|
#define BIONIC_STOP_UNWIND asm volatile(".cfi_undefined \%rip")
|
|
|
|
#endif
|
|
|
|
|
2017-11-14 16:50:43 +00:00
|
|
|
// The arraysize(arr) macro returns the # of elements in an array arr.
|
|
|
|
// The expression is a compile-time constant, and therefore can be
|
|
|
|
// used in defining new arrays, for example. If you use arraysize on
|
|
|
|
// a pointer by mistake, you will get a compile-time error.
|
|
|
|
//
|
|
|
|
// One caveat is that arraysize() doesn't accept any array of an
|
|
|
|
// anonymous type or a type defined inside a function.
|
|
|
|
//
|
|
|
|
// This template function declaration is used in defining arraysize.
|
|
|
|
// Note that the function doesn't need an implementation, as we only
|
|
|
|
// use its type.
|
|
|
|
template <typename T, size_t N>
|
|
|
|
char (&ArraySizeHelper(T (&array)[N]))[N]; // NOLINT(readability/casting)
|
|
|
|
|
|
|
|
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
|
|
|
|
|
2018-08-14 00:44:06 +00:00
|
|
|
// Used to inform clang's -Wimplicit-fallthrough that a fallthrough is intended. There's no way to
|
|
|
|
// silence (or enable, apparently) -Wimplicit-fallthrough in C yet.
|
|
|
|
#ifdef __cplusplus
|
|
|
|
#define __BIONIC_FALLTHROUGH [[clang::fallthrough]]
|
|
|
|
#else
|
|
|
|
#define __BIONIC_FALLTHROUGH
|
|
|
|
#endif
|
2019-08-08 02:06:00 +00:00
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
static inline T* untag_address(T* p) {
|
|
|
|
#if defined(__aarch64__)
|
|
|
|
return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(p) & ((1ULL << 56) - 1));
|
|
|
|
#else
|
|
|
|
return p;
|
|
|
|
#endif
|
|
|
|
}
|