Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
michael@0 | 4 | * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | #include <pthread.h> |
michael@0 | 7 | #include <string.h> |
michael@0 | 8 | #include <stdlib.h> |
michael@0 | 9 | #include <time.h> |
michael@0 | 10 | #include <unistd.h> |
michael@0 | 11 | #include <android/log.h> |
michael@0 | 12 | #include <sys/syscall.h> |
michael@0 | 13 | |
michael@0 | 14 | #include "mozilla/Alignment.h" |
michael@0 | 15 | |
michael@0 | 16 | #include <vector> |
michael@0 | 17 | |
michael@0 | 18 | #define NS_EXPORT __attribute__ ((visibility("default"))) |
michael@0 | 19 | |
michael@0 | 20 | #if ANDROID_VERSION < 17 || defined(MOZ_WIDGET_ANDROID) |
michael@0 | 21 | /* Android doesn't have pthread_atfork(), so we need to use our own. */ |
michael@0 | 22 | struct AtForkFuncs { |
michael@0 | 23 | void (*prepare)(void); |
michael@0 | 24 | void (*parent)(void); |
michael@0 | 25 | void (*child)(void); |
michael@0 | 26 | }; |
michael@0 | 27 | |
michael@0 | 28 | /* jemalloc's initialization calls pthread_atfork. When pthread_atfork (see |
michael@0 | 29 | * further below) stores the corresponding data, it's going to allocate memory, |
michael@0 | 30 | * which will loop back to jemalloc's initialization, leading to a dead-lock. |
michael@0 | 31 | * So, for that specific vector, we use a special allocator that returns a |
michael@0 | 32 | * static buffer for small sizes, and force the initial vector capacity to |
michael@0 | 33 | * a size enough to store one atfork function table. */ |
michael@0 | 34 | template <typename T> |
michael@0 | 35 | struct SpecialAllocator: public std::allocator<T> |
michael@0 | 36 | { |
michael@0 | 37 | SpecialAllocator(): bufUsed(false) {} |
michael@0 | 38 | |
michael@0 | 39 | inline typename std::allocator<T>::pointer allocate(typename std::allocator<T>::size_type n, const void * = 0) { |
michael@0 | 40 | if (!bufUsed && n == 1) { |
michael@0 | 41 | bufUsed = true; |
michael@0 | 42 | return buf.addr(); |
michael@0 | 43 | } |
michael@0 | 44 | return reinterpret_cast<T *>(::operator new(sizeof(T) * n)); |
michael@0 | 45 | } |
michael@0 | 46 | |
michael@0 | 47 | inline void deallocate(typename std::allocator<T>::pointer p, typename std::allocator<T>::size_type n) { |
michael@0 | 48 | if (p == buf.addr()) |
michael@0 | 49 | bufUsed = false; |
michael@0 | 50 | else |
michael@0 | 51 | ::operator delete(p); |
michael@0 | 52 | } |
michael@0 | 53 | |
michael@0 | 54 | template<typename U> |
michael@0 | 55 | struct rebind { |
michael@0 | 56 | typedef SpecialAllocator<U> other; |
michael@0 | 57 | }; |
michael@0 | 58 | |
michael@0 | 59 | private: |
michael@0 | 60 | mozilla::AlignedStorage2<T> buf; |
michael@0 | 61 | bool bufUsed; |
michael@0 | 62 | }; |
michael@0 | 63 | |
michael@0 | 64 | static std::vector<AtForkFuncs, SpecialAllocator<AtForkFuncs> > atfork; |
michael@0 | 65 | #endif |
michael@0 | 66 | |
michael@0 | 67 | #ifdef MOZ_WIDGET_GONK |
michael@0 | 68 | #include "cpuacct.h" |
michael@0 | 69 | #define WRAP(x) x |
michael@0 | 70 | |
michael@0 | 71 | #if ANDROID_VERSION < 17 || defined(MOZ_WIDGET_ANDROID) |
michael@0 | 72 | extern "C" NS_EXPORT int |
michael@0 | 73 | timer_create(clockid_t, struct sigevent*, timer_t*) |
michael@0 | 74 | { |
michael@0 | 75 | __android_log_print(ANDROID_LOG_ERROR, "BionicGlue", "timer_create not supported!"); |
michael@0 | 76 | abort(); |
michael@0 | 77 | return -1; |
michael@0 | 78 | } |
michael@0 | 79 | #endif |
michael@0 | 80 | |
michael@0 | 81 | #else |
michael@0 | 82 | #define cpuacct_add(x) |
michael@0 | 83 | #define WRAP(x) __wrap_##x |
michael@0 | 84 | #endif |
michael@0 | 85 | |
michael@0 | 86 | #if ANDROID_VERSION < 17 || defined(MOZ_WIDGET_ANDROID) |
michael@0 | 87 | extern "C" NS_EXPORT int |
michael@0 | 88 | WRAP(pthread_atfork)(void (*prepare)(void), void (*parent)(void), void (*child)(void)) |
michael@0 | 89 | { |
michael@0 | 90 | AtForkFuncs funcs; |
michael@0 | 91 | funcs.prepare = prepare; |
michael@0 | 92 | funcs.parent = parent; |
michael@0 | 93 | funcs.child = child; |
michael@0 | 94 | if (!atfork.capacity()) |
michael@0 | 95 | atfork.reserve(1); |
michael@0 | 96 | atfork.push_back(funcs); |
michael@0 | 97 | return 0; |
michael@0 | 98 | } |
michael@0 | 99 | |
michael@0 | 100 | extern "C" NS_EXPORT pid_t |
michael@0 | 101 | WRAP(fork)(void) |
michael@0 | 102 | { |
michael@0 | 103 | pid_t pid; |
michael@0 | 104 | for (auto it = atfork.rbegin(); |
michael@0 | 105 | it < atfork.rend(); ++it) |
michael@0 | 106 | if (it->prepare) |
michael@0 | 107 | it->prepare(); |
michael@0 | 108 | |
michael@0 | 109 | switch ((pid = syscall(__NR_clone, SIGCHLD, NULL, NULL, NULL, NULL))) { |
michael@0 | 110 | case 0: |
michael@0 | 111 | cpuacct_add(getuid()); |
michael@0 | 112 | for (auto it = atfork.begin(); |
michael@0 | 113 | it < atfork.end(); ++it) |
michael@0 | 114 | if (it->child) |
michael@0 | 115 | it->child(); |
michael@0 | 116 | break; |
michael@0 | 117 | default: |
michael@0 | 118 | for (auto it = atfork.begin(); |
michael@0 | 119 | it < atfork.end(); ++it) |
michael@0 | 120 | if (it->parent) |
michael@0 | 121 | it->parent(); |
michael@0 | 122 | } |
michael@0 | 123 | return pid; |
michael@0 | 124 | } |
michael@0 | 125 | #endif |
michael@0 | 126 | |
michael@0 | 127 | extern "C" NS_EXPORT int |
michael@0 | 128 | WRAP(raise)(int sig) |
michael@0 | 129 | { |
michael@0 | 130 | // Bug 741272: Bionic incorrectly uses kill(), which signals the |
michael@0 | 131 | // process, and thus could signal another thread (and let this one |
michael@0 | 132 | // return "successfully" from raising a fatal signal). |
michael@0 | 133 | // |
michael@0 | 134 | // Bug 943170: POSIX specifies pthread_kill(pthread_self(), sig) as |
michael@0 | 135 | // equivalent to raise(sig), but Bionic also has a bug with these |
michael@0 | 136 | // functions, where a forked child will kill its parent instead. |
michael@0 | 137 | |
michael@0 | 138 | extern pid_t gettid(void); |
michael@0 | 139 | return syscall(__NR_tgkill, getpid(), gettid(), sig); |
michael@0 | 140 | } |
michael@0 | 141 | |
michael@0 | 142 | /* |
michael@0 | 143 | * The following wrappers for PR_Xxx are needed until we can get |
michael@0 | 144 | * PR_DuplicateEnvironment landed in NSPR. |
michael@0 | 145 | * See see bug 772734 and bug 773414. |
michael@0 | 146 | * |
michael@0 | 147 | * We can't #include the pr headers here, and we can't call any of the |
michael@0 | 148 | * PR/PL functions either, so we just reimplemnt using native code. |
michael@0 | 149 | */ |
michael@0 | 150 | |
michael@0 | 151 | static pthread_mutex_t _pr_envLock = PTHREAD_MUTEX_INITIALIZER; |
michael@0 | 152 | |
michael@0 | 153 | extern "C" NS_EXPORT char* |
michael@0 | 154 | __wrap_PR_GetEnv(const char *var) |
michael@0 | 155 | { |
michael@0 | 156 | char *ev; |
michael@0 | 157 | |
michael@0 | 158 | pthread_mutex_lock(&_pr_envLock); |
michael@0 | 159 | ev = getenv(var); |
michael@0 | 160 | pthread_mutex_unlock(&_pr_envLock); |
michael@0 | 161 | return ev; |
michael@0 | 162 | } |
michael@0 | 163 | |
michael@0 | 164 | extern "C" NS_EXPORT int |
michael@0 | 165 | __wrap_PR_SetEnv(const char *string) |
michael@0 | 166 | { |
michael@0 | 167 | int result; |
michael@0 | 168 | |
michael@0 | 169 | if ( !strchr(string, '=')) return(-1); |
michael@0 | 170 | |
michael@0 | 171 | pthread_mutex_lock(&_pr_envLock); |
michael@0 | 172 | result = putenv(string); |
michael@0 | 173 | pthread_mutex_unlock(&_pr_envLock); |
michael@0 | 174 | return (result)? -1 : 0; |
michael@0 | 175 | } |
michael@0 | 176 | |
michael@0 | 177 | extern "C" NS_EXPORT pthread_mutex_t * |
michael@0 | 178 | PR_GetEnvLock(void) |
michael@0 | 179 | { |
michael@0 | 180 | return &_pr_envLock; |
michael@0 | 181 | } |
michael@0 | 182 | |
michael@0 | 183 | /* Amazon Kindle Fire HD's libc provides most of the |
michael@0 | 184 | * functions in string.h as weak symbols, which dlsym |
michael@0 | 185 | * cannot resolve. Thus, we must wrap these functions. |
michael@0 | 186 | * See bug 791419. |
michael@0 | 187 | */ |
michael@0 | 188 | |
michael@0 | 189 | #ifndef MOZ_WIDGET_GONK |
michael@0 | 190 | #include <string.h> |
michael@0 | 191 | extern "C" NS_EXPORT void* __real_memccpy(void * a0, const void * a1, int a2, size_t a3); |
michael@0 | 192 | extern "C" NS_EXPORT void* __real_memchr(const void * a0, int a1, size_t a2); |
michael@0 | 193 | extern "C" NS_EXPORT void* __real_memrchr(const void * a0, int a1, size_t a2); |
michael@0 | 194 | extern "C" NS_EXPORT int __real_memcmp(const void * a0, const void * a1, size_t a2); |
michael@0 | 195 | extern "C" NS_EXPORT void* __real_memcpy(void * a0, const void * a1, size_t a2); |
michael@0 | 196 | extern "C" NS_EXPORT void* __real_memmove(void * a0, const void * a1, size_t a2); |
michael@0 | 197 | extern "C" NS_EXPORT void* __real_memset(void * a0, int a1, size_t a2); |
michael@0 | 198 | extern "C" NS_EXPORT void* __real_memmem(const void * a0, size_t a1, const void * a2, size_t a3); |
michael@0 | 199 | extern "C" NS_EXPORT void __real_memswap(void * a0, void * a1, size_t a2); |
michael@0 | 200 | extern "C" NS_EXPORT char* __real_index(const char * a0, int a1); |
michael@0 | 201 | extern "C" NS_EXPORT char* __real_strchr(const char * a0, int a1); |
michael@0 | 202 | extern "C" NS_EXPORT char* __real_strrchr(const char * a0, int a1); |
michael@0 | 203 | extern "C" NS_EXPORT size_t __real_strlen(const char * a0); |
michael@0 | 204 | extern "C" NS_EXPORT int __real_strcmp(const char * a0, const char * a1); |
michael@0 | 205 | extern "C" NS_EXPORT char* __real_strcpy(char * a0, const char * a1); |
michael@0 | 206 | extern "C" NS_EXPORT char* __real_strcat(char * a0, const char * a1); |
michael@0 | 207 | extern "C" NS_EXPORT int __real_strcasecmp(const char * a0, const char * a1); |
michael@0 | 208 | extern "C" NS_EXPORT int __real_strncasecmp(const char * a0, const char * a1, size_t a2); |
michael@0 | 209 | extern "C" NS_EXPORT char* __real_strstr(const char * a0, const char * a1); |
michael@0 | 210 | extern "C" NS_EXPORT char* __real_strcasestr(const char * a0, const char * a1); |
michael@0 | 211 | extern "C" NS_EXPORT char* __real_strtok(char * a0, const char * a1); |
michael@0 | 212 | extern "C" NS_EXPORT char* __real_strtok_r(char * a0, const char * a1, char** a2); |
michael@0 | 213 | extern "C" NS_EXPORT char* __real_strerror(int a0); |
michael@0 | 214 | extern "C" NS_EXPORT int __real_strerror_r(int a0, char * a1, size_t a2); |
michael@0 | 215 | extern "C" NS_EXPORT size_t __real_strnlen(const char * a0, size_t a1); |
michael@0 | 216 | extern "C" NS_EXPORT char* __real_strncat(char * a0, const char * a1, size_t a2); |
michael@0 | 217 | extern "C" NS_EXPORT int __real_strncmp(const char * a0, const char * a1, size_t a2); |
michael@0 | 218 | extern "C" NS_EXPORT char* __real_strncpy(char * a0, const char * a1, size_t a2); |
michael@0 | 219 | extern "C" NS_EXPORT size_t __real_strlcat(char * a0, const char * a1, size_t a2); |
michael@0 | 220 | extern "C" NS_EXPORT size_t __real_strlcpy(char * a0, const char * a1, size_t a2); |
michael@0 | 221 | extern "C" NS_EXPORT size_t __real_strcspn(const char * a0, const char * a1); |
michael@0 | 222 | extern "C" NS_EXPORT char* __real_strpbrk(const char * a0, const char * a1); |
michael@0 | 223 | extern "C" NS_EXPORT char* __real_strsep(char ** a0, const char * a1); |
michael@0 | 224 | extern "C" NS_EXPORT size_t __real_strspn(const char * a0, const char * a1); |
michael@0 | 225 | extern "C" NS_EXPORT int __real_strcoll(const char * a0, const char * a1); |
michael@0 | 226 | extern "C" NS_EXPORT size_t __real_strxfrm(char * a0, const char * a1, size_t a2); |
michael@0 | 227 | |
michael@0 | 228 | extern "C" NS_EXPORT void* __wrap_memccpy(void * a0, const void * a1, int a2, size_t a3) { return __real_memccpy(a0, a1, a2, a3); } |
michael@0 | 229 | extern "C" NS_EXPORT void* __wrap_memchr(const void * a0, int a1, size_t a2) { return __real_memchr(a0, a1, a2); } |
michael@0 | 230 | extern "C" NS_EXPORT void* __wrap_memrchr(const void * a0, int a1, size_t a2) { return __real_memrchr(a0, a1, a2); } |
michael@0 | 231 | extern "C" NS_EXPORT int __wrap_memcmp(const void * a0, const void * a1, size_t a2) { return __real_memcmp(a0, a1, a2); } |
michael@0 | 232 | extern "C" NS_EXPORT void* __wrap_memcpy(void * a0, const void * a1, size_t a2) { return __real_memcpy(a0, a1, a2); } |
michael@0 | 233 | extern "C" NS_EXPORT void* __wrap_memmove(void * a0, const void * a1, size_t a2) { return __real_memmove(a0, a1, a2); } |
michael@0 | 234 | extern "C" NS_EXPORT void* __wrap_memset(void * a0, int a1, size_t a2) { return __real_memset(a0, a1, a2); } |
michael@0 | 235 | extern "C" NS_EXPORT void* __wrap_memmem(const void * a0, size_t a1, const void * a2, size_t a3) { return __real_memmem(a0, a1, a2, a3); } |
michael@0 | 236 | extern "C" NS_EXPORT void __wrap_memswap(void * a0, void * a1, size_t a2) { __real_memswap(a0, a1, a2); } |
michael@0 | 237 | extern "C" NS_EXPORT char* __wrap_index(const char * a0, int a1) { return __real_index(a0, a1); } |
michael@0 | 238 | extern "C" NS_EXPORT char* __wrap_strchr(const char * a0, int a1) { return __real_strchr(a0, a1); } |
michael@0 | 239 | extern "C" NS_EXPORT char* __wrap_strrchr(const char * a0, int a1) { return __real_strrchr(a0, a1); } |
michael@0 | 240 | extern "C" NS_EXPORT size_t __wrap_strlen(const char * a0) { return __real_strlen(a0); } |
michael@0 | 241 | extern "C" NS_EXPORT int __wrap_strcmp(const char * a0, const char * a1) { return __real_strcmp(a0, a1); } |
michael@0 | 242 | extern "C" NS_EXPORT char* __wrap_strcpy(char * a0, const char * a1) { return __real_strcpy(a0, a1); } |
michael@0 | 243 | extern "C" NS_EXPORT char* __wrap_strcat(char * a0, const char * a1) { return __real_strcat(a0, a1); } |
michael@0 | 244 | extern "C" NS_EXPORT int __wrap_strcasecmp(const char * a0, const char * a1) { return __real_strcasecmp(a0, a1); } |
michael@0 | 245 | extern "C" NS_EXPORT int __wrap_strncasecmp(const char * a0, const char * a1, size_t a2) { return __real_strncasecmp(a0, a1, a2); } |
michael@0 | 246 | extern "C" NS_EXPORT char* __wrap_strstr(const char * a0, const char * a1) { return __real_strstr(a0, a1); } |
michael@0 | 247 | extern "C" NS_EXPORT char* __wrap_strcasestr(const char * a0, const char * a1) { return __real_strcasestr(a0, a1); } |
michael@0 | 248 | extern "C" NS_EXPORT char* __wrap_strtok(char * a0, const char * a1) { return __real_strtok(a0, a1); } |
michael@0 | 249 | extern "C" NS_EXPORT char* __wrap_strtok_r(char * a0, const char * a1, char** a2) { return __real_strtok_r(a0, a1, a2); } |
michael@0 | 250 | extern "C" NS_EXPORT char* __wrap_strerror(int a0) { return __real_strerror(a0); } |
michael@0 | 251 | extern "C" NS_EXPORT int __wrap_strerror_r(int a0, char * a1, size_t a2) { return __real_strerror_r(a0, a1, a2); } |
michael@0 | 252 | extern "C" NS_EXPORT size_t __wrap_strnlen(const char * a0, size_t a1) { return __real_strnlen(a0, a1); } |
michael@0 | 253 | extern "C" NS_EXPORT char* __wrap_strncat(char * a0, const char * a1, size_t a2) { return __real_strncat(a0, a1, a2); } |
michael@0 | 254 | extern "C" NS_EXPORT int __wrap_strncmp(const char * a0, const char * a1, size_t a2) { return __real_strncmp(a0, a1, a2); } |
michael@0 | 255 | extern "C" NS_EXPORT char* __wrap_strncpy(char * a0, const char * a1, size_t a2) { return __real_strncpy(a0, a1, a2); } |
michael@0 | 256 | extern "C" NS_EXPORT size_t __wrap_strlcat(char * a0, const char * a1, size_t a2) { return __real_strlcat(a0, a1, a2); } |
michael@0 | 257 | extern "C" NS_EXPORT size_t __wrap_strlcpy(char * a0, const char * a1, size_t a2) { return __real_strlcpy(a0, a1, a2); } |
michael@0 | 258 | extern "C" NS_EXPORT size_t __wrap_strcspn(const char * a0, const char * a1) { return __real_strcspn(a0, a1); } |
michael@0 | 259 | extern "C" NS_EXPORT char* __wrap_strpbrk(const char * a0, const char * a1) { return __real_strpbrk(a0, a1); } |
michael@0 | 260 | extern "C" NS_EXPORT char* __wrap_strsep(char ** a0, const char * a1) { return __real_strsep(a0, a1); } |
michael@0 | 261 | extern "C" NS_EXPORT size_t __wrap_strspn(const char * a0, const char * a1) { return __real_strspn(a0, a1); } |
michael@0 | 262 | extern "C" NS_EXPORT int __wrap_strcoll(const char * a0, const char * a1) { return __real_strcoll(a0, a1); } |
michael@0 | 263 | extern "C" NS_EXPORT size_t __wrap_strxfrm(char * a0, const char * a1, size_t a2) { return __real_strxfrm(a0, a1, a2); } |
michael@0 | 264 | #endif |