Add bionic hardening patchsets from GrapheneOS

11 b3a0c2c5db
11 5412c37195 #explicit zero
11 31456ac632 #brk
11 58ebc243ea #random
11 5323b39f7e #undefined
11 6a91d9dddb #merge
11 a042b5a0ba #vla formatting
11 9ec639de1b #pthread
11 49571a0a49 #read only
11 149cc5ccb8 #zero
11 2e613ccbe7 #fork mmap
11 e239c7dff8 #memprot pthread
11 0b03d92b7f #xor
11 de08419b82 #junk
11 897d4903e2 #guard
11 648cd68ca3 #ptrhread guard
11 0bc4dbcbd2 #stack rand
10 aa9cc05d07
10 a8cdbb6352 #explicit zero
10 b28302c668 #brk
10 9f8be7d07c #random
10 cb91a7ee3a #undefined
10 08279e2fdd #merge
10 6a18bd565d #vla formatting
10 2f392c2d08 #pthread
10 8bbce1bc50 #read only
10 725f61db82 #zero
10 4cd257135f #fork mmap
10 9220cf622b #memprot pthread
10 8ef71d1ffd #memprot exit
10 0eaef1abbd #xor
10 64f1cc2148 #junk
10 5c42a527cf #guard
10 5cc8c34e60 #pthread guard
10 7f61cc8a1c #stack rand
9  abdf523d26
9  e4b9b31e6f #explicit zero
9  a3a22a63d2 #brk
9  7444dbc3cf #random
9  dcd3b72ac9 #undefined
9  543e1df342 #merge
9  611e5691f7 #vla formatting
9  8de97ce864 #pthread
9  a475717042 #read only
9  7f0947cc0e #zero
9  e9751d3370 #fork mmap
9  83cd86d0d5 #memprot pthread
9  1ebb165455 #memprot exit
9  488ba483cf #xor
9  f9351d884b #junk
9  85e5bca0a5 #move

Signed-off-by: Tad <tad@spotco.us>
This commit is contained in:
Tad 2022-03-15 16:34:57 -04:00
parent 1878cd19ab
commit 181519cf38
55 changed files with 3121 additions and 2 deletions

View file

@ -0,0 +1,163 @@
From e4b9b31e6f9ff7eb9d168db6a99a775bf4f669c1 Mon Sep 17 00:00:00 2001
From: Daniel Micay <danielmicay@gmail.com>
Date: Thu, 5 Feb 2015 21:53:16 -0500
Subject: [PATCH] add a real explicit_bzero implementation
Clang, GCC and other compilers special-case standard C functions like
memset. Calls to memset will be optimized out.
OpenBSD provides explicit_bzero to work around this but Android simply
defines it as memset so nothing prevents it from being optimized away.
This implementation uses a memory read constraint via empty inline
assembly rather than something that may be broken via link-time
optimization in the future.
---
libc/Android.bp | 1 +
libc/bionic/explicit_bzero.cpp | 7 +++++++
libc/include/string.h | 1 +
libc/libc.arm.map | 1 +
libc/libc.arm64.map | 1 +
libc/libc.map.txt | 1 +
libc/libc.mips.map | 1 +
libc/libc.mips64.map | 1 +
libc/libc.x86.map | 1 +
libc/libc.x86_64.map | 1 +
libc/upstream-openbsd/android/include/openbsd-compat.h | 2 --
11 files changed, 16 insertions(+), 2 deletions(-)
create mode 100644 libc/bionic/explicit_bzero.cpp
diff --git a/libc/Android.bp b/libc/Android.bp
index 26ffc73b66..85a739e4e9 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -1329,6 +1329,7 @@ cc_library_static {
"bionic/eventfd_read.cpp",
"bionic/eventfd_write.cpp",
"bionic/exec.cpp",
+ "bionic/explicit_bzero.cpp",
"bionic/faccessat.cpp",
"bionic/fchmod.cpp",
"bionic/fchmodat.cpp",
diff --git a/libc/bionic/explicit_bzero.cpp b/libc/bionic/explicit_bzero.cpp
new file mode 100644
index 0000000000..b06daa1386
--- /dev/null
+++ b/libc/bionic/explicit_bzero.cpp
@@ -0,0 +1,7 @@
+#include <string.h>
+
+void* explicit_bzero(void* s, size_t n) {
+ void *ptr = memset(s, 0, n);
+ __asm__ __volatile__("" : : "r"(ptr) : "memory");
+ return ptr;
+}
diff --git a/libc/include/string.h b/libc/include/string.h
index 54d5e1c800..5336777773 100644
--- a/libc/include/string.h
+++ b/libc/include/string.h
@@ -56,6 +56,7 @@ void* mempcpy(void* __dst, const void* __src, size_t __n) __INTRODUCED_IN(23);
#endif
void* memmove(void* __dst, const void* __src, size_t __n);
void* memset(void* __dst, int __ch, size_t __n);
+void* explicit_bzero(void *s, size_t n);
void* memmem(const void* __haystack, size_t __haystack_size, const void* __needle, size_t __needle_size) __attribute_pure__;
char* strchr(const char* __s, int __ch) __attribute_pure__;
diff --git a/libc/libc.arm.map b/libc/libc.arm.map
index b0f96a9ffc..28ad4913f6 100644
--- a/libc/libc.arm.map
+++ b/libc/libc.arm.map
@@ -330,6 +330,7 @@ LIBC {
execvp;
execvpe; # introduced=21
exit;
+ explicit_bzero;
faccessat; # introduced-arm=16 introduced-arm64=21 introduced-mips=16 introduced-mips64=21 introduced-x86=16 introduced-x86_64=21
fallocate; # introduced=21
fallocate64; # introduced=21
diff --git a/libc/libc.arm64.map b/libc/libc.arm64.map
index 6b0e415494..ee20108901 100644
--- a/libc/libc.arm64.map
+++ b/libc/libc.arm64.map
@@ -260,6 +260,7 @@ LIBC {
execvp;
execvpe; # introduced=21
exit;
+ explicit_bzero;
faccessat; # introduced-arm=16 introduced-arm64=21 introduced-mips=16 introduced-mips64=21 introduced-x86=16 introduced-x86_64=21
fallocate; # introduced=21
fallocate64; # introduced=21
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index 85c9a581cb..6c7e3eb368 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -332,6 +332,7 @@ LIBC {
execvp;
execvpe; # introduced=21
exit;
+ explicit_bzero;
faccessat; # introduced-arm=16 introduced-arm64=21 introduced-mips=16 introduced-mips64=21 introduced-x86=16 introduced-x86_64=21
fallocate; # introduced=21
fallocate64; # introduced=21
diff --git a/libc/libc.mips.map b/libc/libc.mips.map
index 9e760c2422..12faa5d86b 100644
--- a/libc/libc.mips.map
+++ b/libc/libc.mips.map
@@ -328,6 +328,7 @@ LIBC {
execvp;
execvpe; # introduced=21
exit;
+ explicit_bzero;
faccessat; # introduced-arm=16 introduced-arm64=21 introduced-mips=16 introduced-mips64=21 introduced-x86=16 introduced-x86_64=21
fallocate; # introduced=21
fallocate64; # introduced=21
diff --git a/libc/libc.mips64.map b/libc/libc.mips64.map
index 6b0e415494..ee20108901 100644
--- a/libc/libc.mips64.map
+++ b/libc/libc.mips64.map
@@ -260,6 +260,7 @@ LIBC {
execvp;
execvpe; # introduced=21
exit;
+ explicit_bzero;
faccessat; # introduced-arm=16 introduced-arm64=21 introduced-mips=16 introduced-mips64=21 introduced-x86=16 introduced-x86_64=21
fallocate; # introduced=21
fallocate64; # introduced=21
diff --git a/libc/libc.x86.map b/libc/libc.x86.map
index 2855f9e22d..8be30d8424 100644
--- a/libc/libc.x86.map
+++ b/libc/libc.x86.map
@@ -326,6 +326,7 @@ LIBC {
execvp;
execvpe; # introduced=21
exit;
+ explicit_bzero;
faccessat; # introduced-arm=16 introduced-arm64=21 introduced-mips=16 introduced-mips64=21 introduced-x86=16 introduced-x86_64=21
fallocate; # introduced=21
fallocate64; # introduced=21
diff --git a/libc/libc.x86_64.map b/libc/libc.x86_64.map
index 6b0e415494..ee20108901 100644
--- a/libc/libc.x86_64.map
+++ b/libc/libc.x86_64.map
@@ -260,6 +260,7 @@ LIBC {
execvp;
execvpe; # introduced=21
exit;
+ explicit_bzero;
faccessat; # introduced-arm=16 introduced-arm64=21 introduced-mips=16 introduced-mips64=21 introduced-x86=16 introduced-x86_64=21
fallocate; # introduced=21
fallocate64; # introduced=21
diff --git a/libc/upstream-openbsd/android/include/openbsd-compat.h b/libc/upstream-openbsd/android/include/openbsd-compat.h
index f178149311..929e61eeda 100644
--- a/libc/upstream-openbsd/android/include/openbsd-compat.h
+++ b/libc/upstream-openbsd/android/include/openbsd-compat.h
@@ -65,8 +65,6 @@ extern const char* __progname;
/* OpenBSD has this, but we can't really implement it correctly on Linux. */
#define issetugid() 0
-#define explicit_bzero(p, s) memset(p, 0, s)
-
/* OpenBSD has these in <sys/param.h>, but "ALIGN" isn't something we want to reserve. */
#define ALIGNBYTES (sizeof(uintptr_t) - 1)
#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES)

View file

@ -0,0 +1,85 @@
From e9751d3370aa44e6ca77843f7c7a7aac67e5bcc0 Mon Sep 17 00:00:00 2001
From: Daniel Micay <danielmicay@gmail.com>
Date: Wed, 2 Dec 2015 23:37:28 -0500
Subject: [PATCH] switch pthread_atfork handler allocation to mmap
---
libc/bionic/pthread_atfork.cpp | 35 ++++++++++++++++++++++++++++------
1 file changed, 29 insertions(+), 6 deletions(-)
diff --git a/libc/bionic/pthread_atfork.cpp b/libc/bionic/pthread_atfork.cpp
index 84e511c2e8..651c026df5 100644
--- a/libc/bionic/pthread_atfork.cpp
+++ b/libc/bionic/pthread_atfork.cpp
@@ -29,8 +29,11 @@
#include <errno.h>
#include <pthread.h>
#include <stdlib.h>
+#include <sys/mman.h>
+#include <unistd.h>
#include "private/bionic_macros.h"
+#include "private/bionic_prctl.h"
struct atfork_t {
atfork_t* next;
@@ -43,6 +46,8 @@ struct atfork_t {
void* dso_handle;
};
+static atfork_t* pool;
+
class atfork_list_t {
public:
constexpr atfork_list_t() : first_(nullptr), last_(nullptr) {}
@@ -101,7 +106,8 @@ class atfork_list_t {
last_ = entry->prev;
}
- free(entry);
+ entry->next = pool;
+ pool = entry;
}
atfork_t* first_;
@@ -154,18 +160,35 @@ void __bionic_atfork_run_parent() {
// __register_atfork is the name used by glibc
extern "C" int __register_atfork(void (*prepare)(void), void (*parent)(void),
void(*child)(void), void* dso) {
- atfork_t* entry = reinterpret_cast<atfork_t*>(malloc(sizeof(atfork_t)));
- if (entry == nullptr) {
- return ENOMEM;
+ pthread_mutex_lock(&g_atfork_list_mutex);
+
+ if (!pool) {
+ size_t page_size = getpagesize();
+ char* page = static_cast<char*>(mmap(NULL, page_size, PROT_READ|PROT_WRITE,
+ MAP_ANONYMOUS|MAP_PRIVATE, -1, 0));
+ if (page == MAP_FAILED) {
+ pthread_mutex_unlock(&g_atfork_list_mutex);
+ return ENOMEM;
+ }
+
+ prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, page, page_size,
+ "atfork handlers");
+
+ for (char* it = page; it < page + page_size - sizeof(atfork_t); it += sizeof(atfork_t)) {
+ atfork_t* node = reinterpret_cast<atfork_t*>(it);
+ node->next = pool;
+ pool = node;
+ }
}
+ atfork_t* entry = pool;
+ pool = entry->next;
+
entry->prepare = prepare;
entry->parent = parent;
entry->child = child;
entry->dso_handle = dso;
- pthread_mutex_lock(&g_atfork_list_mutex);
-
g_atfork_list.push_back(entry);
pthread_mutex_unlock(&g_atfork_list_mutex);

View file

@ -0,0 +1,95 @@
From 83cd86d0d522c64726dac41614c00f2534044f73 Mon Sep 17 00:00:00 2001
From: Daniel Micay <danielmicay@gmail.com>
Date: Thu, 3 Dec 2015 12:58:31 -0500
Subject: [PATCH] add memory protection for pthread_atfork handlers
---
libc/bionic/pthread_atfork.cpp | 34 ++++++++++++++++++++++++++++++++--
1 file changed, 32 insertions(+), 2 deletions(-)
diff --git a/libc/bionic/pthread_atfork.cpp b/libc/bionic/pthread_atfork.cpp
index 651c026df5..91c5233f73 100644
--- a/libc/bionic/pthread_atfork.cpp
+++ b/libc/bionic/pthread_atfork.cpp
@@ -47,6 +47,7 @@ struct atfork_t {
};
static atfork_t* pool;
+static atfork_t* page_list;
class atfork_list_t {
public:
@@ -160,13 +161,22 @@ void __bionic_atfork_run_parent() {
// __register_atfork is the name used by glibc
extern "C" int __register_atfork(void (*prepare)(void), void (*parent)(void),
void(*child)(void), void* dso) {
+ size_t page_size = getpagesize();
+
pthread_mutex_lock(&g_atfork_list_mutex);
+ for (atfork_t* page_it = page_list; page_it; page_it = page_it->next) {
+ mprotect(page_it, page_size, PROT_READ|PROT_WRITE);
+ }
+
if (!pool) {
- size_t page_size = getpagesize();
char* page = static_cast<char*>(mmap(NULL, page_size, PROT_READ|PROT_WRITE,
MAP_ANONYMOUS|MAP_PRIVATE, -1, 0));
if (page == MAP_FAILED) {
+ for (atfork_t* page_it = page_list; page_it; page_it = page_it->next) {
+ mprotect(page_it, page_size, PROT_READ);
+ }
+
pthread_mutex_unlock(&g_atfork_list_mutex);
return ENOMEM;
}
@@ -174,11 +184,15 @@ extern "C" int __register_atfork(void (*prepare)(void), void (*parent)(void),
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, page, page_size,
"atfork handlers");
- for (char* it = page; it < page + page_size - sizeof(atfork_t); it += sizeof(atfork_t)) {
+ for (char* it = page + sizeof(atfork_t); it < page + page_size - sizeof(atfork_t); it += sizeof(atfork_t)) {
atfork_t* node = reinterpret_cast<atfork_t*>(it);
node->next = pool;
pool = node;
}
+
+ atfork_t* page_node = reinterpret_cast<atfork_t*>(page);
+ page_node->next = page_list;
+ page_list = page_node;
}
atfork_t* entry = pool;
@@ -191,6 +205,10 @@ extern "C" int __register_atfork(void (*prepare)(void), void (*parent)(void),
g_atfork_list.push_back(entry);
+ for (atfork_t* page_it = page_list; page_it; page_it = page_it->next) {
+ mprotect(page_it, page_size, PROT_READ);
+ }
+
pthread_mutex_unlock(&g_atfork_list_mutex);
return 0;
@@ -198,9 +216,21 @@ extern "C" int __register_atfork(void (*prepare)(void), void (*parent)(void),
extern "C" __LIBC_HIDDEN__ void __unregister_atfork(void* dso) {
pthread_mutex_lock(&g_atfork_list_mutex);
+
+ size_t page_size = getpagesize();
+
+ for (atfork_t* page_it = page_list; page_it; page_it = page_it->next) {
+ mprotect(page_it, page_size, PROT_READ|PROT_WRITE);
+ }
+
g_atfork_list.remove_if([&](const atfork_t* entry) {
return entry->dso_handle == dso;
});
+
+ for (atfork_t* page_it = page_list; page_it; page_it = page_it->next) {
+ mprotect(page_it, page_size, PROT_READ);
+ }
+
pthread_mutex_unlock(&g_atfork_list_mutex);
}

View file

@ -0,0 +1,80 @@
From 1ebb1654556ed74d63e43fe7dbbceae5b20f569f Mon Sep 17 00:00:00 2001
From: Daniel Micay <danielmicay@gmail.com>
Date: Sat, 7 Feb 2015 20:14:24 -0500
Subject: [PATCH] add memory protection for at_quick_exit
---
.../lib/libc/stdlib/quick_exit.c | 41 ++++++++++++++++---
1 file changed, 36 insertions(+), 5 deletions(-)
diff --git a/libc/upstream-freebsd/lib/libc/stdlib/quick_exit.c b/libc/upstream-freebsd/lib/libc/stdlib/quick_exit.c
index ef8cdb1b40..b23d8642ae 100644
--- a/libc/upstream-freebsd/lib/libc/stdlib/quick_exit.c
+++ b/libc/upstream-freebsd/lib/libc/stdlib/quick_exit.c
@@ -28,6 +28,10 @@
#include <stdlib.h>
#include <pthread.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include "private/bionic_prctl.h"
/**
* Linked list of quick exit handlers. This is simpler than the atexit()
@@ -39,6 +43,10 @@ struct quick_exit_handler {
void (*cleanup)(void);
};
+static struct quick_exit_handler *pool_page;
+static struct quick_exit_handler *pool;
+static size_t pool_size;
+
/**
* Lock protecting the handlers list.
*/
@@ -51,16 +59,39 @@ static struct quick_exit_handler *handlers;
int
at_quick_exit(void (*func)(void))
{
+ size_t page_size = getpagesize();
struct quick_exit_handler *h;
-
- h = malloc(sizeof(*h));
- if (NULL == h)
- return (1);
- h->cleanup = func;
pthread_mutex_lock(&atexit_mutex);
+
+ if (pool_size < sizeof(*h)) {
+ void *ptr = mmap(NULL, page_size, PROT_READ|PROT_WRITE,
+ MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+ if (ptr == MAP_FAILED) {
+ pthread_mutex_unlock(&atexit_mutex);
+ return (1);
+ }
+ prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, page_size,
+ "at_quick_exit handlers");
+ pool_page = pool = ptr;
+ pool_size = page_size;
+ } else {
+ if (mprotect(pool_page, page_size, PROT_READ|PROT_WRITE)) {
+ pthread_mutex_unlock(&atexit_mutex);
+ return (1);
+ }
+ }
+
+ h = pool++;
+ pool_size -= sizeof(*h);
+
+ h->cleanup = func;
+
h->next = handlers;
handlers = h;
+
+ mprotect(pool_page, page_size, PROT_READ);
+
pthread_mutex_unlock(&atexit_mutex);
return (0);
}

View file

@ -0,0 +1,84 @@
From 488ba483cf9ad195fda33b3250115a308bf03f75 Mon Sep 17 00:00:00 2001
From: Daniel Micay <danielmicay@gmail.com>
Date: Wed, 27 Jan 2016 18:02:15 -0500
Subject: [PATCH] add XOR mangling mitigation for thread-local dtors
---
libc/bionic/__cxa_thread_atexit_impl.cpp | 8 +++++---
libc/bionic/libc_init_common.cpp | 2 ++
libc/private/bionic_globals.h | 1 +
3 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/libc/bionic/__cxa_thread_atexit_impl.cpp b/libc/bionic/__cxa_thread_atexit_impl.cpp
index 99077c101d..74608513ef 100644
--- a/libc/bionic/__cxa_thread_atexit_impl.cpp
+++ b/libc/bionic/__cxa_thread_atexit_impl.cpp
@@ -13,15 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#include <stdint.h>
#include <sys/cdefs.h>
#include <private/bionic_defs.h>
+#include <private/bionic_globals.h>
#include "pthread_internal.h"
class thread_local_dtor {
public:
- void (*func) (void *);
+ uintptr_t func;
void *arg;
void *dso_handle; // unused...
thread_local_dtor* next;
@@ -35,7 +37,7 @@ __BIONIC_WEAK_FOR_NATIVE_BRIDGE
int __cxa_thread_atexit_impl(void (*func) (void *), void *arg, void *dso_handle) {
thread_local_dtor* dtor = new thread_local_dtor();
- dtor->func = func;
+ dtor->func = __libc_globals->dtor_cookie ^ reinterpret_cast<uintptr_t>(func);
dtor->arg = arg;
dtor->dso_handle = dso_handle;
@@ -54,7 +56,7 @@ extern "C" __LIBC_HIDDEN__ void __cxa_thread_finalize() {
thread_local_dtor* current = thread->thread_local_dtors;
thread->thread_local_dtors = current->next;
- current->func(current->arg);
+ (reinterpret_cast<void (*)(void*)>(__libc_globals->dtor_cookie ^ current->func))(current->arg);
if (__loader_remove_thread_local_dtor != nullptr) {
__loader_remove_thread_local_dtor(current->dso_handle);
}
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index 2396c36782..47555c598a 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -45,6 +45,7 @@
#include "private/KernelArgumentBlock.h"
#include "private/WriteProtected.h"
+#include "private/bionic_arc4random.h"
#include "private/bionic_auxv.h"
#include "private/bionic_defs.h"
#include "private/bionic_globals.h"
@@ -91,6 +92,7 @@ void __libc_init_globals(KernelArgumentBlock& args) {
__libc_globals.mutate([&args](libc_globals* globals) {
__libc_init_vdso(globals, args);
__libc_init_setjmp_cookie(globals, args);
+ arc4random_buf(&globals->dtor_cookie, sizeof(globals->dtor_cookie));
});
}
diff --git a/libc/private/bionic_globals.h b/libc/private/bionic_globals.h
index 94dd7e8590..0361f4ed72 100644
--- a/libc/private/bionic_globals.h
+++ b/libc/private/bionic_globals.h
@@ -37,6 +37,7 @@
struct libc_globals {
vdso_entry vdso[VDSO_END];
+ long dtor_cookie;
long setjmp_cookie;
MallocDispatch malloc_dispatch;
};

View file

@ -0,0 +1,23 @@
From f9351d884bddaf126a8fc45c8cb14e7ca2cf463b Mon Sep 17 00:00:00 2001
From: Daniel Micay <danielmicay@gmail.com>
Date: Fri, 29 Jan 2016 20:20:09 -0500
Subject: [PATCH] use a better pthread_attr junk filling pattern
Guarantee that junk filled pointers will fault, at least on pure 64-bit.
---
libc/bionic/pthread_attr.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libc/bionic/pthread_attr.cpp b/libc/bionic/pthread_attr.cpp
index 93177f15c8..692bcf162b 100644
--- a/libc/bionic/pthread_attr.cpp
+++ b/libc/bionic/pthread_attr.cpp
@@ -53,7 +53,7 @@ int pthread_attr_init(pthread_attr_t* attr) {
__BIONIC_WEAK_FOR_NATIVE_BRIDGE
int pthread_attr_destroy(pthread_attr_t* attr) {
- memset(attr, 0x42, sizeof(pthread_attr_t));
+ memset(attr, 0xdf, sizeof(pthread_attr_t));
return 0;
}

View file

@ -0,0 +1,101 @@
From 85e5bca0a525a1cb8142aa092286ae3424983dd5 Mon Sep 17 00:00:00 2001
From: Daniel Micay <danielmicay@gmail.com>
Date: Fri, 11 Dec 2015 01:52:08 -0500
Subject: [PATCH] move pthread_internal_t out of the stack mapping
[TODO: guard pages]
---
libc/bionic/pthread_create.cpp | 20 +++++++++++---------
libc/bionic/pthread_exit.cpp | 7 +++++--
libc/bionic/pthread_internal.cpp | 1 +
3 files changed, 17 insertions(+), 11 deletions(-)
diff --git a/libc/bionic/pthread_create.cpp b/libc/bionic/pthread_create.cpp
index 8825c6f240..e70af04094 100644
--- a/libc/bionic/pthread_create.cpp
+++ b/libc/bionic/pthread_create.cpp
@@ -191,7 +191,6 @@ static int __allocate_thread(pthread_attr_t* attr, pthread_internal_t** threadp,
// The caller didn't provide a stack, so allocate one.
// Make sure the stack size and guard size are multiples of PAGE_SIZE.
if (__builtin_add_overflow(attr->stack_size, attr->guard_size, &mmap_size)) return EAGAIN;
- if (__builtin_add_overflow(mmap_size, sizeof(pthread_internal_t), &mmap_size)) return EAGAIN;
mmap_size = __BIONIC_ALIGN(mmap_size, PAGE_SIZE);
attr->guard_size = __BIONIC_ALIGN(attr->guard_size, PAGE_SIZE);
attr->stack_base = __create_thread_mapped_space(mmap_size, attr->guard_size);
@@ -210,21 +209,23 @@ static int __allocate_thread(pthread_attr_t* attr, pthread_internal_t** threadp,
// thread stack (including guard)
// To safely access the pthread_internal_t and thread stack, we need to find a 16-byte aligned boundary.
- stack_top = reinterpret_cast<uint8_t*>(
- (reinterpret_cast<uintptr_t>(stack_top) - sizeof(pthread_internal_t)) & ~0xf);
-
- pthread_internal_t* thread = reinterpret_cast<pthread_internal_t*>(stack_top);
- if (mmap_size == 0) {
- // If thread was not allocated by mmap(), it may not have been cleared to zero.
- // So assume the worst and zero it.
- memset(thread, 0, sizeof(pthread_internal_t));
+ stack_top = reinterpret_cast<uint8_t*>(reinterpret_cast<uintptr_t>(stack_top) & ~0xf);
+
+ pthread_internal_t* thread = static_cast<pthread_internal_t*>(
+ mmap(nullptr, sizeof(pthread_internal_t), PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS,
+ -1, 0));
+ if (thread == MAP_FAILED) {
+ if (thread->mmap_size != 0) munmap(thread->attr.stack_base, thread->mmap_size);
+ return EAGAIN;
}
+ prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, thread, sizeof(pthread_internal_t), "pthread_internal_t");
attr->stack_size = stack_top - reinterpret_cast<uint8_t*>(attr->stack_base);
thread->mmap_size = mmap_size;
thread->attr = *attr;
if (!__init_tls(thread)) {
if (thread->mmap_size != 0) munmap(thread->attr.stack_base, thread->mmap_size);
+ munmap(thread, sizeof(pthread_internal_t));
return EAGAIN;
}
__init_thread_stack_guard(thread);
@@ -313,6 +314,7 @@ int pthread_create(pthread_t* thread_out, pthread_attr_t const* attr,
if (thread->mmap_size != 0) {
munmap(thread->attr.stack_base, thread->mmap_size);
}
+ munmap(thread, sizeof(pthread_internal_t));
async_safe_format_log(ANDROID_LOG_WARN, "libc", "pthread_create failed: clone failed: %s",
strerror(clone_errno));
return clone_errno;
diff --git a/libc/bionic/pthread_exit.cpp b/libc/bionic/pthread_exit.cpp
index f1b65fdf7a..fe26696baf 100644
--- a/libc/bionic/pthread_exit.cpp
+++ b/libc/bionic/pthread_exit.cpp
@@ -118,7 +118,8 @@ void pthread_exit(void* return_value) {
// pthread_internal_t is freed below with stack, not here.
__pthread_internal_remove(thread);
- if (thread->mmap_size != 0) {
+ size_t mmap_size = thread->mmap_size;
+ if (mmap_size != 0) {
// We need to free mapped space for detached threads when they exit.
// That's not something we can do in C.
@@ -126,7 +127,9 @@ void pthread_exit(void* return_value) {
// That's one last thing we can do before dropping to assembler.
ScopedSignalBlocker ssb;
__pthread_unmap_tls(thread);
- _exit_with_stack_teardown(thread->attr.stack_base, thread->mmap_size);
+ void* stack_base = thread->attr.stack_base;
+ munmap(thread, sizeof(pthread_internal_t));
+ _exit_with_stack_teardown(stack_base, mmap_size);
}
}
diff --git a/libc/bionic/pthread_internal.cpp b/libc/bionic/pthread_internal.cpp
index 829194cc71..b5de202487 100644
--- a/libc/bionic/pthread_internal.cpp
+++ b/libc/bionic/pthread_internal.cpp
@@ -91,6 +91,7 @@ static void __pthread_internal_free(pthread_internal_t* thread) {
// Free mapped space, including thread stack and pthread_internal_t.
munmap(thread->attr.stack_base, thread->mmap_size);
}
+ munmap(thread, sizeof(pthread_internal_t));
}
void __pthread_internal_remove_and_free(pthread_internal_t* thread) {

View file

@ -0,0 +1,74 @@
From a3a22a63d2cf265d5edc8cf613484e13fd03e19d Mon Sep 17 00:00:00 2001
From: Daniel Micay <danielmicay@gmail.com>
Date: Sun, 8 Feb 2015 01:18:54 -0500
Subject: [PATCH] replace brk and sbrk with stubs
Pretend that there is never room to grow the heap in order to prevent
usage of these unsafe legacy functions. There are likely no users of
these in practice as it is inherently broken to use them outside of
malloc.
---
libc/bionic/brk.cpp | 48 ++++++++-------------------------------------
1 file changed, 8 insertions(+), 40 deletions(-)
diff --git a/libc/bionic/brk.cpp b/libc/bionic/brk.cpp
index e1a4b05345..ef93055139 100644
--- a/libc/bionic/brk.cpp
+++ b/libc/bionic/brk.cpp
@@ -29,48 +29,16 @@
#include <errno.h>
#include <unistd.h>
-#if defined(__LP64__)
-static void* __bionic_brk;
-#else
-void* __bionic_brk; // Accidentally exported by the NDK.
+#if !defined(__LP64__)
+void* __bionic_brk = reinterpret_cast<void*>(-1); // Accidentally exported by the NDK.
#endif
-extern "C" void* __brk(void* __addr);
-
-int brk(void* end_data) {
- __bionic_brk = __brk(end_data);
- if (__bionic_brk < end_data) {
- errno = ENOMEM;
- return -1;
- }
- return 0;
+int brk(void*) {
+ errno = ENOMEM;
+ return -1;
}
-void* sbrk(ptrdiff_t increment) {
- // Initialize __bionic_brk if necessary.
- if (__bionic_brk == NULL) {
- __bionic_brk = __brk(NULL);
- }
-
- // Don't ask the kernel if we already know the answer.
- if (increment == 0) {
- return __bionic_brk;
- }
-
- // Avoid overflow.
- uintptr_t old_brk = reinterpret_cast<uintptr_t>(__bionic_brk);
- if ((increment > 0 && static_cast<uintptr_t>(increment) > (UINTPTR_MAX - old_brk)) ||
- (increment < 0 && static_cast<uintptr_t>(-increment) > old_brk)) {
- errno = ENOMEM;
- return reinterpret_cast<void*>(-1);
- }
-
- void* desired_brk = reinterpret_cast<void*>(old_brk + increment);
- __bionic_brk = __brk(desired_brk);
- if (__bionic_brk < desired_brk) {
- errno = ENOMEM;
- return reinterpret_cast<void*>(-1);
- }
-
- return reinterpret_cast<void*>(old_brk);
+void* sbrk(ptrdiff_t) {
+ errno = ENOMEM;
+ return reinterpret_cast<void*>(-1);
}

View file

@ -0,0 +1,58 @@
From 7444dbc3cf11285fb94d5d00913016afd7b0dff2 Mon Sep 17 00:00:00 2001
From: Daniel Micay <danielmicay@gmail.com>
Date: Mon, 4 Mar 2019 04:26:04 -0500
Subject: [PATCH] use blocking getrandom and avoid urandom fallback
---
libc/bionic/getentropy.cpp | 30 ++----------------------------
1 file changed, 2 insertions(+), 28 deletions(-)
diff --git a/libc/bionic/getentropy.cpp b/libc/bionic/getentropy.cpp
index 2c6e417b87..ad49039af1 100644
--- a/libc/bionic/getentropy.cpp
+++ b/libc/bionic/getentropy.cpp
@@ -31,26 +31,6 @@
#include <sys/random.h>
#include <unistd.h>
-static int getentropy_urandom(void* buffer, size_t buffer_size, int saved_errno) {
- int fd = TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY | O_NOFOLLOW | O_CLOEXEC, 0));
- if (fd == -1) return -1;
-
- size_t collected = 0;
- while (collected < buffer_size) {
- ssize_t count = TEMP_FAILURE_RETRY(read(fd, static_cast<char*>(buffer) + collected,
- buffer_size - collected));
- if (count == -1) {
- close(fd);
- return -1;
- }
- collected += count;
- }
-
- close(fd);
- errno = saved_errno;
- return 0;
-}
-
int getentropy(void* buffer, size_t buffer_size) {
if (buffer_size > 256) {
errno = EIO;
@@ -62,15 +42,9 @@ int getentropy(void* buffer, size_t buffer_size) {
size_t collected = 0;
while (collected < buffer_size) {
long count = TEMP_FAILURE_RETRY(getrandom(static_cast<char*>(buffer) + collected,
- buffer_size - collected, GRND_NONBLOCK));
+ buffer_size - collected, 0));
if (count == -1) {
- // EAGAIN: there isn't enough entropy right now.
- // ENOSYS/EINVAL: getrandom(2) or GRND_NONBLOCK isn't supported.
- // EFAULT: `buffer` is invalid.
- // Try /dev/urandom regardless because it can't hurt,
- // and we don't need to optimize the EFAULT case.
- // See http://b/33059407 and http://b/67015565.
- return getentropy_urandom(buffer, buffer_size, saved_errno);
+ return -1;
}
collected += count;
}

View file

@ -0,0 +1,25 @@
From dcd3b72ac9cac79d4322a17be150c46f65ffb3cd Mon Sep 17 00:00:00 2001
From: Daniel Micay <danielmicay@gmail.com>
Date: Mon, 19 Sep 2016 07:57:43 -0400
Subject: [PATCH] fix undefined out-of-bounds accesses in sched.h
---
libc/include/sched.h | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/libc/include/sched.h b/libc/include/sched.h
index de6969f863..fd333a023a 100644
--- a/libc/include/sched.h
+++ b/libc/include/sched.h
@@ -71,7 +71,10 @@ int setns(int __fd, int __ns_type) __INTRODUCED_IN(21);
#define __CPU_MASK(x) ((__CPU_BITTYPE)1 << ((x) & (__CPU_BITS - 1)))
typedef struct {
- __CPU_BITTYPE __bits[ CPU_SETSIZE / __CPU_BITS ];
+ union {
+ __CPU_BITTYPE __bits_minimum[ CPU_SETSIZE / __CPU_BITS ];
+ __CPU_BITTYPE __bits[0];
+ };
} cpu_set_t;
int sched_setaffinity(pid_t __pid, size_t __set_size, const cpu_set_t* __set) __INTRODUCED_IN(12);

View file

@ -0,0 +1,46 @@
From 543e1df342cdd8720ce967d990ca28a2b9c26af2 Mon Sep 17 00:00:00 2001
From: Daniel Micay <danielmicay@gmail.com>
Date: Sat, 19 Nov 2016 09:56:14 -0500
Subject: [PATCH] stop implicitly marking mappings as mergeable
---
libc/bionic/mmap.cpp | 19 +------------------
1 file changed, 1 insertion(+), 18 deletions(-)
diff --git a/libc/bionic/mmap.cpp b/libc/bionic/mmap.cpp
index 35033199ae..c081068928 100644
--- a/libc/bionic/mmap.cpp
+++ b/libc/bionic/mmap.cpp
@@ -39,8 +39,6 @@ extern "C" void* __mmap2(void*, size_t, int, int, int, size_t);
#define MMAP2_SHIFT 12 // 2**12 == 4096
-static bool kernel_has_MADV_MERGEABLE = true;
-
void* mmap64(void* addr, size_t size, int prot, int flags, int fd, off64_t offset) {
if (offset < 0 || (offset & ((1UL << MMAP2_SHIFT)-1)) != 0) {
errno = EINVAL;
@@ -54,22 +52,7 @@ void* mmap64(void* addr, size_t size, int prot, int flags, int fd, off64_t offse
return MAP_FAILED;
}
- bool is_private_anonymous =
- (flags & (MAP_PRIVATE | MAP_ANONYMOUS)) == (MAP_PRIVATE | MAP_ANONYMOUS);
- bool is_stack_or_grows_down = (flags & (MAP_STACK | MAP_GROWSDOWN)) != 0;
-
- void* result = __mmap2(addr, size, prot, flags, fd, offset >> MMAP2_SHIFT);
-
- if (result != MAP_FAILED && kernel_has_MADV_MERGEABLE &&
- is_private_anonymous && !is_stack_or_grows_down) {
- ErrnoRestorer errno_restorer;
- int rc = madvise(result, size, MADV_MERGEABLE);
- if (rc == -1 && errno == EINVAL) {
- kernel_has_MADV_MERGEABLE = false;
- }
- }
-
- return result;
+ return __mmap2(addr, size, prot, flags, fd, offset >> MMAP2_SHIFT);
}
void* mmap(void* addr, size_t size, int prot, int flags, int fd, off_t offset) {

View file

@ -0,0 +1,39 @@
From 611e5691f7e48aba8529e49b22885021f322b31e Mon Sep 17 00:00:00 2001
From: Daniel Micay <danielmicay@gmail.com>
Date: Sat, 16 Jul 2016 23:55:16 -0400
Subject: [PATCH] replace VLA formatting buffer with dprintf
---
libc/bionic/bionic_systrace.cpp | 10 +---------
1 file changed, 1 insertion(+), 9 deletions(-)
diff --git a/libc/bionic/bionic_systrace.cpp b/libc/bionic/bionic_systrace.cpp
index bac3d88021..076e10dbfb 100644
--- a/libc/bionic/bionic_systrace.cpp
+++ b/libc/bionic/bionic_systrace.cpp
@@ -26,8 +26,6 @@
#include <cutils/trace.h> // For ATRACE_TAG_BIONIC.
-#define WRITE_OFFSET 32
-
static Lock g_lock;
static CachedProperty g_debug_atrace_tags_enableflags("debug.atrace.tags.enableflags");
static uint64_t g_tags;
@@ -61,15 +59,9 @@ void bionic_trace_begin(const char* message) {
return;
}
- // If bionic tracing has been enabled, then write the message to the
- // kernel trace_marker.
- int length = strlen(message);
- char buf[length + WRITE_OFFSET];
- size_t len = snprintf(buf, length + WRITE_OFFSET, "B|%d|%s", getpid(), message);
-
// Tracing may stop just after checking property and before writing the message.
// So the write is acceptable to fail. See b/20666100.
- TEMP_FAILURE_RETRY(write(trace_marker_fd, buf, len));
+ dprintf(trace_marker_fd, "B|%d|%s", getpid(), message);
}
void bionic_trace_end() {

View file

@ -0,0 +1,25 @@
From 8de97ce864cc781d077160a8efd4902d4338078c Mon Sep 17 00:00:00 2001
From: Daniel Micay <danielmicay@gmail.com>
Date: Fri, 17 Jul 2015 21:32:05 -0400
Subject: [PATCH] increase default pthread stack to 8MiB on 64-bit
---
libc/bionic/pthread_internal.h | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h
index 9bdf9cdf0c..d59a545459 100644
--- a/libc/bionic/pthread_internal.h
+++ b/libc/bionic/pthread_internal.h
@@ -164,7 +164,11 @@ __LIBC_HIDDEN__ void pthread_key_clean_all(void);
// stack overflows, we subtracted the same amount we were using there
// from the default thread stack size. This should keep memory usage
// roughly constant.
+#ifdef __LP64__
+#define PTHREAD_STACK_SIZE_DEFAULT ((8 * 1024 * 1024) - SIGNAL_STACK_SIZE_WITHOUT_GUARD)
+#else
#define PTHREAD_STACK_SIZE_DEFAULT ((1 * 1024 * 1024) - SIGNAL_STACK_SIZE_WITHOUT_GUARD)
+#endif
// Leave room for a guard page in the internally created signal stacks.
#define SIGNAL_STACK_SIZE (SIGNAL_STACK_SIZE_WITHOUT_GUARD + PTHREAD_GUARD_SIZE)

View file

@ -0,0 +1,47 @@
From a47571704245e5514795f35bbcffdb8a533e738a Mon Sep 17 00:00:00 2001
From: Daniel Micay <danielmicay@gmail.com>
Date: Sat, 1 Oct 2016 05:11:44 -0400
Subject: [PATCH] make __stack_chk_guard read-only at runtime
---
libc/bionic/__libc_init_main_thread.cpp | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/libc/bionic/__libc_init_main_thread.cpp b/libc/bionic/__libc_init_main_thread.cpp
index efa7dee57b..78d25fd977 100644
--- a/libc/bionic/__libc_init_main_thread.cpp
+++ b/libc/bionic/__libc_init_main_thread.cpp
@@ -28,22 +28,30 @@
#include "libc_init_common.h"
+#include <limits.h>
+#include <sys/mman.h>
+
+#include <async_safe/log.h>
+
#include "private/KernelArgumentBlock.h"
#include "private/bionic_arc4random.h"
#include "private/bionic_auxv.h"
#include "private/bionic_defs.h"
#include "private/bionic_globals.h"
-#include "private/bionic_ssp.h"
#include "pthread_internal.h"
extern "C" int __set_tls(void* ptr);
extern "C" int __set_tid_address(int* tid_address);
// Declared in "private/bionic_ssp.h".
-uintptr_t __stack_chk_guard = 0;
+__attribute__((aligned(PAGE_SIZE)))
+uintptr_t __stack_chk_guard[PAGE_SIZE / sizeof(uintptr_t)] = {0};
void __libc_init_global_stack_chk_guard(KernelArgumentBlock& args) {
- __libc_safe_arc4random_buf(&__stack_chk_guard, sizeof(__stack_chk_guard), args);
+ __libc_safe_arc4random_buf(&__stack_chk_guard[0], sizeof(__stack_chk_guard[0]), args);
+ if (mprotect(__stack_chk_guard, sizeof(__stack_chk_guard), PROT_READ) == -1) {
+ async_safe_fatal("mprotect __stack_chk_guard: %s", strerror(errno));
+ }
}
// Setup for the main thread. For dynamic executables, this is called by the

View file

@ -0,0 +1,34 @@
From 7f0947cc0e4fc52a41ef8ecfba892f5534e1fee5 Mon Sep 17 00:00:00 2001
From: Daniel Micay <danielmicay@gmail.com>
Date: Sun, 12 Mar 2017 17:49:13 -0400
Subject: [PATCH] on 64-bit, zero the leading stack canary byte
This reduces entropy of the canary from 64-bit to 56-bit in exchange for
mitigating non-terminated C string overflows.
---
libc/bionic/__libc_init_main_thread.cpp | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/libc/bionic/__libc_init_main_thread.cpp b/libc/bionic/__libc_init_main_thread.cpp
index 78d25fd977..ae2245829d 100644
--- a/libc/bionic/__libc_init_main_thread.cpp
+++ b/libc/bionic/__libc_init_main_thread.cpp
@@ -47,8 +47,18 @@ extern "C" int __set_tid_address(int* tid_address);
__attribute__((aligned(PAGE_SIZE)))
uintptr_t __stack_chk_guard[PAGE_SIZE / sizeof(uintptr_t)] = {0};
+#if __LP64__
+static const uintptr_t canary_mask = __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ ?
+ 0xffffffffffffff00UL :
+ 0x00ffffffffffffffUL;
+#endif
+
void __libc_init_global_stack_chk_guard(KernelArgumentBlock& args) {
__libc_safe_arc4random_buf(&__stack_chk_guard[0], sizeof(__stack_chk_guard[0]), args);
+#if __LP64__
+ // Sacrifice 8 bits of entropy on 64-bit to mitigate non-terminated C string overflows
+ __stack_chk_guard[0] &= canary_mask;
+#endif
if (mprotect(__stack_chk_guard, sizeof(__stack_chk_guard), PROT_READ) == -1) {
async_safe_fatal("mprotect __stack_chk_guard: %s", strerror(errno));
}

View file

@ -0,0 +1,21 @@
From abdf523d26450814fc3f5c211f3baa643c48bae3 Mon Sep 17 00:00:00 2001
From: Daniel Micay <danielmicay@gmail.com>
Date: Fri, 6 Feb 2015 11:41:57 -0500
Subject: [PATCH] zero sensitive information with explicit_bzero
---
init/security.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/init/security.cpp b/init/security.cpp
index a3494a280bd..4b6c918ab30 100644
--- a/init/security.cpp
+++ b/init/security.cpp
@@ -73,6 +73,7 @@ Result<Success> MixHwrngIntoLinuxRngAction(const BuiltinArguments&) {
}
chunk_size = TEMP_FAILURE_RETRY(write(urandom_fd, buf, chunk_size));
+ explicit_bzero(buf, chunk_size);
if (chunk_size == -1) {
return ErrnoError() << "Failed to write to /dev/urandom";
}