Merge "Add one simple thread local storage test."
diff --git a/libc/Android.mk b/libc/Android.mk
index de0bb41..5e09cf9 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -70,6 +70,8 @@
libc_common_src_files += \
bionic/__FD_chk.cpp \
bionic/__fgets_chk.cpp \
+ bionic/__fread_chk.cpp \
+ bionic/__fwrite_chk.cpp \
bionic/__memchr_chk.cpp \
bionic/__memmove_chk.cpp \
bionic/__memrchr_chk.cpp \
diff --git a/libc/arch-arm/cortex-a9/bionic/memset.S b/libc/arch-arm/cortex-a9/bionic/memset.S
index 48ba815..b39fcc4 100644
--- a/libc/arch-arm/cortex-a9/bionic/memset.S
+++ b/libc/arch-arm/cortex-a9/bionic/memset.S
@@ -69,12 +69,9 @@
ENTRY(memset)
// The neon memset only wins for less than 132.
cmp r2, #132
- bhi __memset_large_copy
+ bhi .L_memset_large_copy
- stmfd sp!, {r0}
- .cfi_def_cfa_offset 4
- .cfi_rel_offset r0, 0
-
+ mov r3, r0
vdup.8 q0, r1
/* make sure we have at least 32 bytes to write */
@@ -84,7 +81,7 @@
1: /* The main loop writes 32 bytes at a time */
subs r2, r2, #32
- vst1.8 {d0 - d3}, [r0]!
+ vst1.8 {d0 - d3}, [r3]!
bhs 1b
2: /* less than 32 left */
@@ -93,22 +90,20 @@
beq 3f
// writes 16 bytes, 128-bits aligned
- vst1.8 {d0, d1}, [r0]!
+ vst1.8 {d0, d1}, [r3]!
3: /* write up to 15-bytes (count in r2) */
movs ip, r2, lsl #29
bcc 1f
- vst1.8 {d0}, [r0]!
+ vst1.8 {d0}, [r3]!
1: bge 2f
- vst1.32 {d0[0]}, [r0]!
+ vst1.32 {d0[0]}, [r3]!
2: movs ip, r2, lsl #31
- strbmi r1, [r0], #1
- strbcs r1, [r0], #1
- strbcs r1, [r0], #1
- ldmfd sp!, {r0}
+ strbmi r1, [r3], #1
+ strbcs r1, [r3], #1
+ strbcs r1, [r3], #1
bx lr
-END(memset)
-ENTRY_PRIVATE(__memset_large_copy)
+.L_memset_large_copy:
/* compute the offset to align the destination
* offset = (4-(src&3))&3 = -src & 3
*/
@@ -180,7 +175,7 @@
movs r2, r2, lsl #2
strbcs r1, [r0]
ldmfd sp!, {r0, r4-r7, pc}
-END(__memset_large_copy)
+END(memset)
.data
error_string:
diff --git a/libc/arch-arm/krait/bionic/memset.S b/libc/arch-arm/krait/bionic/memset.S
index a4fbe17..ae05965 100644
--- a/libc/arch-arm/krait/bionic/memset.S
+++ b/libc/arch-arm/krait/bionic/memset.S
@@ -69,10 +69,7 @@
/* memset() returns its first argument. */
ENTRY(memset)
- stmfd sp!, {r0}
- .cfi_def_cfa_offset 4
- .cfi_rel_offset r0, 0
-
+ mov r3, r0
vdup.8 q0, r1
/* make sure we have at least 32 bytes to write */
@@ -82,7 +79,7 @@
1: /* The main loop writes 32 bytes at a time */
subs r2, r2, #32
- vst1.8 {d0 - d3}, [r0]!
+ vst1.8 {d0 - d3}, [r3]!
bhs 1b
2: /* less than 32 left */
@@ -91,18 +88,17 @@
beq 3f
// writes 16 bytes, 128-bits aligned
- vst1.8 {d0, d1}, [r0]!
+ vst1.8 {d0, d1}, [r3]!
3: /* write up to 15-bytes (count in r2) */
movs ip, r2, lsl #29
bcc 1f
- vst1.8 {d0}, [r0]!
+ vst1.8 {d0}, [r3]!
1: bge 2f
- vst1.32 {d0[0]}, [r0]!
+ vst1.32 {d0[0]}, [r3]!
2: movs ip, r2, lsl #31
- strbmi r1, [r0], #1
- strbcs r1, [r0], #1
- strbcs r1, [r0], #1
- ldmfd sp!, {r0}
+ strbmi r1, [r3], #1
+ strbcs r1, [r3], #1
+ strbcs r1, [r3], #1
bx lr
END(memset)
diff --git a/libc/bionic/__fread_chk.cpp b/libc/bionic/__fread_chk.cpp
new file mode 100644
index 0000000..afc8d90
--- /dev/null
+++ b/libc/bionic/__fread_chk.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#undef _FORTIFY_SOURCE
+#include <stdio.h>
+#include <sys/cdefs.h>
+#include "private/libc_logging.h"
+
+extern "C" size_t __fread_chk(void * __restrict buf, size_t size, size_t count,
+ FILE * __restrict stream, size_t buf_size) {
+ size_t total;
+ if (__predict_false(__size_mul_overflow(size, count, &total))) {
+ // overflow: trigger the error path in fread
+ return fread(buf, size, count, stream);
+ }
+
+ if (__predict_false(total > buf_size)) {
+ __fortify_chk_fail("fread: prevented write past end of buffer", 0);
+ }
+
+ return fread(buf, size, count, stream);
+}
diff --git a/libc/bionic/__fwrite_chk.cpp b/libc/bionic/__fwrite_chk.cpp
new file mode 100644
index 0000000..2af13d6
--- /dev/null
+++ b/libc/bionic/__fwrite_chk.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#undef _FORTIFY_SOURCE
+#include <stdio.h>
+#include <sys/cdefs.h>
+#include "private/libc_logging.h"
+
+extern "C" size_t __fwrite_chk(const void * __restrict buf, size_t size, size_t count,
+ FILE * __restrict stream, size_t buf_size) {
+ size_t total;
+ if (__predict_false(__size_mul_overflow(size, count, &total))) {
+ // overflow: trigger the error path in fwrite
+ return fwrite(buf, size, count, stream);
+ }
+
+ if (__predict_false(total > buf_size)) {
+ __fortify_chk_fail("fwrite: prevented read past end of buffer", 0);
+ }
+
+ return fwrite(buf, size, count, stream);
+}
diff --git a/libc/include/stdio.h b/libc/include/stdio.h
index f5ed652..c4bfb4f 100644
--- a/libc/include/stdio.h
+++ b/libc/include/stdio.h
@@ -382,6 +382,16 @@
__errordecl(__fgets_too_big_error, "fgets called with size bigger than buffer");
__errordecl(__fgets_too_small_error, "fgets called with size less than zero");
+extern size_t __fread_chk(void * __restrict, size_t, size_t, FILE * __restrict, size_t);
+extern size_t __fread_real(void * __restrict, size_t, size_t, FILE * __restrict) __RENAME(fread);
+__errordecl(__fread_too_big_error, "fread called with size * count bigger than buffer");
+__errordecl(__fread_overflow, "fread called with overflowing size * count");
+
+extern size_t __fwrite_chk(const void * __restrict, size_t, size_t, FILE * __restrict, size_t);
+extern size_t __fwrite_real(const void * __restrict, size_t, size_t, FILE * __restrict) __RENAME(fwrite);
+__errordecl(__fwrite_too_big_error, "fwrite called with size * count bigger than buffer");
+__errordecl(__fwrite_overflow, "fwrite called with overflowing size * count");
+
#if defined(__BIONIC_FORTIFY)
__BIONIC_FORTIFY_INLINE
@@ -428,6 +438,58 @@
}
#endif
+__BIONIC_FORTIFY_INLINE
+size_t fread(void * __restrict buf, size_t size, size_t count, FILE * __restrict stream) {
+ size_t bos = __bos0(buf);
+
+#if !defined(__clang__)
+ if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+ return __fread_real(buf, size, count, stream);
+ }
+
+ if (__builtin_constant_p(size) && __builtin_constant_p(count)) {
+ size_t total;
+ if (__size_mul_overflow(size, count, &total)) {
+ __fread_overflow();
+ }
+
+ if (total > bos) {
+ __fread_too_big_error();
+ }
+
+ return __fread_real(buf, size, count, stream);
+ }
+#endif
+
+ return __fread_chk(buf, size, count, stream, bos);
+}
+
+__BIONIC_FORTIFY_INLINE
+size_t fwrite(const void * __restrict buf, size_t size, size_t count, FILE * __restrict stream) {
+ size_t bos = __bos0(buf);
+
+#if !defined(__clang__)
+ if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+ return __fwrite_real(buf, size, count, stream);
+ }
+
+ if (__builtin_constant_p(size) && __builtin_constant_p(count)) {
+ size_t total;
+ if (__size_mul_overflow(size, count, &total)) {
+ __fwrite_overflow();
+ }
+
+ if (total > bos) {
+ __fwrite_too_big_error();
+ }
+
+ return __fwrite_real(buf, size, count, stream);
+ }
+#endif
+
+ return __fwrite_chk(buf, size, count, stream, bos);
+}
+
#if !defined(__clang__)
__BIONIC_FORTIFY_INLINE
diff --git a/libc/include/sys/cdefs.h b/libc/include/sys/cdefs.h
index 7df8b60..8a11bc6 100644
--- a/libc/include/sys/cdefs.h
+++ b/libc/include/sys/cdefs.h
@@ -578,4 +578,19 @@
#define _BIONIC_NOT_BEFORE_21(x)
#endif /* __ANDROID_API__ >= 21 */
+#if __has_builtin(__builtin_umul_overflow) || __GNUC__ >= 5
+#if __LP64__
+#define __size_mul_overflow(a, b, result) __builtin_umull_overflow(a, b, result)
+#else
+#define __size_mul_overflow(a, b, result) __builtin_umul_overflow(a, b, result)
+#endif
+#else
+static __inline__ __always_inline int __size_mul_overflow(__SIZE_TYPE__ a, __SIZE_TYPE__ b,
+ __SIZE_TYPE__ *result) {
+ *result = a * b;
+ static const __SIZE_TYPE__ mul_no_overflow = 1UL << (sizeof(__SIZE_TYPE__) * 4);
+ return (a >= mul_no_overflow || b >= mul_no_overflow) && a > 0 && (__SIZE_TYPE__)-1 / a < b;
+}
+#endif
+
#endif /* !_SYS_CDEFS_H_ */
diff --git a/libc/libc.map b/libc/libc.map
index ffbd29c..8c3ac9e 100644
--- a/libc/libc.map
+++ b/libc/libc.map
@@ -1334,6 +1334,8 @@
LIBC_N {
global:
+ __fread_chk;
+ __fwrite_chk;
getgrgid_r;
getgrnam_r;
} LIBC;
diff --git a/libc/stdlib/atexit.c b/libc/stdlib/atexit.c
index a6970dd..34a4db1 100644
--- a/libc/stdlib/atexit.c
+++ b/libc/stdlib/atexit.c
@@ -37,6 +37,10 @@
#include "atexit.h"
#include "private/thread_private.h"
+/* BEGIN android-changed */
+#include "private/bionic_prctl.h"
+/* END android-changed */
+
struct atexit {
struct atexit *next; /* next in list */
int ind; /* next index in this table */
@@ -95,6 +99,10 @@
MAP_ANON | MAP_PRIVATE, -1, 0);
if (p == MAP_FAILED)
goto unlock;
+/* BEGIN android-changed */
+ prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, p, pgsize,
+ "atexit handlers");
+/* END android-changed */
if (__atexit == NULL) {
memset(&p->fns[0], 0, sizeof(p->fns[0]));
p->ind = 1;
@@ -204,6 +212,10 @@
MAP_ANON | MAP_PRIVATE, -1, 0);
if (p == MAP_FAILED)
goto unlock;
+/* BEGIN android-changed */
+ prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, p, pgsize,
+ "atexit handlers");
+/* END android-changed */
p->ind = 1;
p->max = (pgsize - ((char *)&p->fns[0] - (char *)p)) /
sizeof(p->fns[0]);
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 0718efc..375b534 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -1999,9 +1999,32 @@
DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx);
return false;
}
- } else {
- // We got a definition.
+ } else { // We got a definition.
+#if !defined(__LP64__)
+ // When relocating dso with text_relocation .text segment is
+ // not executable. We need to restore elf flags before resolving
+ // STT_GNU_IFUNC symbol.
+ bool protect_segments = has_text_relocations &&
+ lsi == this &&
+ ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC;
+ if (protect_segments) {
+ if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
+ DL_ERR("can't protect segments for \"%s\": %s",
+ get_realpath(), strerror(errno));
+ return false;
+ }
+ }
+#endif
sym_addr = lsi->resolve_symbol_address(s);
+#if !defined(__LP64__)
+ if (protect_segments) {
+ if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
+ DL_ERR("can't unprotect loadable segments for \"%s\": %s",
+ get_realpath(), strerror(errno));
+ return false;
+ }
+ }
+#endif
}
count_relocation(kRelocSymbol);
}
@@ -2038,7 +2061,32 @@
TRACE_TYPE(RELO, "RELO IRELATIVE %16p <- %16p\n",
reinterpret_cast<void*>(reloc),
reinterpret_cast<void*>(load_bias + addend));
- *reinterpret_cast<ElfW(Addr)*>(reloc) = call_ifunc_resolver(load_bias + addend);
+ {
+#if !defined(__LP64__)
+ // When relocating dso with text_relocation .text segment is
+ // not executable. We need to restore elf flags for this
+ // particular call.
+ if (has_text_relocations) {
+ if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
+ DL_ERR("can't protect segments for \"%s\": %s",
+ get_realpath(), strerror(errno));
+ return false;
+ }
+ }
+#endif
+ ElfW(Addr) ifunc_addr = call_ifunc_resolver(load_bias + addend);
+#if !defined(__LP64__)
+ // Unprotect it afterwards...
+ if (has_text_relocations) {
+ if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
+ DL_ERR("can't unprotect loadable segments for \"%s\": %s",
+ get_realpath(), strerror(errno));
+ return false;
+ }
+ }
+#endif
+ *reinterpret_cast<ElfW(Addr)*>(reloc) = ifunc_addr;
+ }
break;
#if defined(__aarch64__)
diff --git a/tests/fortify_compilation_test.cpp b/tests/fortify_compilation_test.cpp
index 537b341..166e8d9 100644
--- a/tests/fortify_compilation_test.cpp
+++ b/tests/fortify_compilation_test.cpp
@@ -230,3 +230,35 @@
// clang should emit a warning, but doesn't
ppoll(fds, 2, &timeout, NULL);
}
+
+void test_fread_overflow() {
+ char buf[4];
+ // NOLINTNEXTLINE(whitespace/line_length)
+ // GCC: error: call to '__fread_overflow' declared with attribute error: fread called with overflowing size * count
+ // clang should emit a warning, but doesn't
+ fread(buf, 2, (size_t)-1, stdin);
+}
+
+void test_fread_too_big() {
+ char buf[4];
+ // NOLINTNEXTLINE(whitespace/line_length)
+ // GCC: error: call to '__fread_too_big_error' declared with attribute error: fread called with size * count bigger than buffer
+ // clang should emit a warning, but doesn't
+ fread(buf, 1, 5, stdin);
+}
+
+void test_fwrite_overflow() {
+ char buf[4];
+ // NOLINTNEXTLINE(whitespace/line_length)
+ // GCC: error: call to '__fwrite_overflow' declared with attribute error: fwrite called with overflowing size * count
+ // clang should emit a warning, but doesn't
+ fwrite(buf, 2, (size_t)-1, stdout);
+}
+
+void test_fwrite_too_big() {
+ char buf[4] = {0};
+ // NOLINTNEXTLINE(whitespace/line_length)
+ // GCC: error: call to '__fwrite_too_big_error' declared with attribute error: fwrite called with size * count bigger than buffer
+ // clang should emit a warning, but doesn't
+ fwrite(buf, 1, 5, stdout);
+}
diff --git a/tests/fortify_test.cpp b/tests/fortify_test.cpp
index 4faccb4..664e057 100644
--- a/tests/fortify_test.cpp
+++ b/tests/fortify_test.cpp
@@ -647,6 +647,22 @@
close(fd);
}
+TEST_F(DEATHTEST, fread_fortified) {
+ char buf[1];
+ size_t ct = atoi("2"); // prevent optimizations
+ FILE* fp = fopen("/dev/null", "r");
+ ASSERT_FORTIFY(fread(buf, 1, ct, fp));
+ fclose(fp);
+}
+
+TEST_F(DEATHTEST, fwrite_fortified) {
+ char buf[1] = {0};
+ size_t ct = atoi("2"); // prevent optimizations
+ FILE* fp = fopen("/dev/null", "w");
+ ASSERT_FORTIFY(fwrite(buf, 1, ct, fp));
+ fclose(fp);
+}
+
TEST_F(DEATHTEST, readlink_fortified) {
char buf[1];
size_t ct = atoi("2"); // prevent optimizations