Merge "Add per UID interface support to resolv cache"
diff --git a/libc/arch-arm/bionic/abort_arm.S b/libc/arch-arm/bionic/abort_arm.S
index 51b0871..e1ab86b 100644
--- a/libc/arch-arm/bionic/abort_arm.S
+++ b/libc/arch-arm/bionic/abort_arm.S
@@ -38,5 +38,5 @@
ENTRY(abort)
.save {r3, r14}
stmfd sp!, {r3, r14}
- blx PIC_SYM(_C_LABEL(__libc_android_abort), PLT)
+ bl PIC_SYM(_C_LABEL(__libc_android_abort), PLT)
END(abort)
diff --git a/libc/arch-x86/string/strcat.S b/libc/arch-x86/string/strcat.S
deleted file mode 100644
index c75f38a..0000000
--- a/libc/arch-x86/string/strcat.S
+++ /dev/null
@@ -1,74 +0,0 @@
-/* $OpenBSD: strcat.S,v 1.8 2005/08/07 11:30:38 espie Exp $ */
-/*
- * Written by J.T. Conklin <jtc@netbsd.org>.
- * Public domain.
- */
-
-#include <machine/asm.h>
-
-#if defined(APIWARN)
-#APP
- .section .gnu.warning.strcat
- .ascii "warning: strcat() is almost always misused, please use strlcat()"
-#NO_APP
-#endif
-
-/*
- * NOTE: I've unrolled the loop eight times: large enough to make a
- * significant difference, and small enough not to totally trash the
- * cache.
- */
-
-ENTRY(strcat)
- pushl %edi /* save edi */
- movl 8(%esp),%edi /* dst address */
- movl 12(%esp),%edx /* src address */
- pushl %edi /* push destination address */
-
- cld /* set search forward */
- xorl %eax,%eax /* set search for null terminator */
- movl $-1,%ecx /* set search for lots of characters */
- repne /* search! */
- scasb
-
- leal -1(%edi),%ecx /* correct dst address */
-
- .align 2,0x90
-L1: movb (%edx),%al /* unroll loop, but not too much */
- movb %al,(%ecx)
- testb %al,%al
- jz L2
- movb 1(%edx),%al
- movb %al,1(%ecx)
- testb %al,%al
- jz L2
- movb 2(%edx),%al
- movb %al,2(%ecx)
- testb %al,%al
- jz L2
- movb 3(%edx),%al
- movb %al,3(%ecx)
- testb %al,%al
- jz L2
- movb 4(%edx),%al
- movb %al,4(%ecx)
- testb %al,%al
- jz L2
- movb 5(%edx),%al
- movb %al,5(%ecx)
- testb %al,%al
- jz L2
- movb 6(%edx),%al
- movb %al,6(%ecx)
- testb %al,%al
- jz L2
- movb 7(%edx),%al
- movb %al,7(%ecx)
- addl $8,%edx
- addl $8,%ecx
- testb %al,%al
- jnz L1
-L2: popl %eax /* pop destination address */
- popl %edi /* restore edi */
- ret
-END(strcat)
diff --git a/libc/bionic/__strcat_chk.cpp b/libc/bionic/__strcat_chk.cpp
index fb46e0d..e0b3259 100644
--- a/libc/bionic/__strcat_chk.cpp
+++ b/libc/bionic/__strcat_chk.cpp
@@ -29,7 +29,6 @@
#include <string.h>
#include <stdlib.h>
#include "libc_logging.h"
-#include <safe_iop.h>
/*
* Runtime implementation of __builtin____strcat_chk.
@@ -42,22 +41,24 @@
* This strcat check is called if _FORTIFY_SOURCE is defined and
* greater than 0.
*/
-extern "C" char *__strcat_chk (char *dest, const char *src, size_t dest_buf_size) {
- // TODO: optimize so we don't scan src/dest twice.
- size_t src_len = strlen(src);
- size_t dest_len = strlen(dest);
- size_t sum;
+extern "C" char* __strcat_chk(
+ char* __restrict dest,
+ const char* __restrict src,
+ size_t dest_buf_size)
+{
+ char* save = dest;
+ size_t dest_len = __strlen_chk(dest, dest_buf_size);
- // sum = src_len + dest_len + 1 (with overflow protection)
- if (!safe_add3(&sum, src_len, dest_len, 1U)) {
- __fortify_chk_fail("strcat integer overflow",
- BIONIC_EVENT_STRCAT_INTEGER_OVERFLOW);
+ dest += dest_len;
+ dest_buf_size -= dest_len;
+
+ while ((*dest++ = *src++) != '\0') {
+ dest_buf_size--;
+ if (__predict_false(dest_buf_size == 0)) {
+ __fortify_chk_fail("strcat buffer overflow",
+ BIONIC_EVENT_STRCAT_BUFFER_OVERFLOW);
+ }
}
- if (sum > dest_buf_size) {
- __fortify_chk_fail("strcat buffer overflow",
- BIONIC_EVENT_STRCAT_BUFFER_OVERFLOW);
- }
-
- return strcat(dest, src);
+ return save;
}
diff --git a/libc/bionic/__strncat_chk.cpp b/libc/bionic/__strncat_chk.cpp
index ab28541..f54d838 100644
--- a/libc/bionic/__strncat_chk.cpp
+++ b/libc/bionic/__strncat_chk.cpp
@@ -29,7 +29,6 @@
#include <string.h>
#include <stdlib.h>
#include "libc_logging.h"
-#include <safe_iop.h>
/*
* Runtime implementation of __builtin____strncat_chk.
@@ -42,27 +41,33 @@
* This strncat check is called if _FORTIFY_SOURCE is defined and
* greater than 0.
*/
-extern "C" char *__strncat_chk (char *dest, const char *src,
- size_t len, size_t dest_buf_size)
+extern "C" char *__strncat_chk(
+ char* __restrict dest,
+ const char* __restrict src,
+ size_t len, size_t dest_buf_size)
{
- // TODO: optimize so we don't scan src/dest twice.
- size_t dest_len = strlen(dest);
- size_t src_len = strlen(src);
- if (src_len > len) {
- src_len = len;
+ if (len == 0) {
+ return dest;
}
- size_t sum;
- // sum = src_len + dest_len + 1 (with overflow protection)
- if (!safe_add3(&sum, src_len, dest_len, 1U)) {
- __fortify_chk_fail("strncat integer overflow",
- BIONIC_EVENT_STRNCAT_INTEGER_OVERFLOW);
+ size_t dest_len = __strlen_chk(dest, dest_buf_size);
+ char *d = dest + dest_len;
+ dest_buf_size -= dest_len;
+
+ while (*src != '\0') {
+ *d++ = *src++;
+ len--; dest_buf_size--;
+
+ if (__predict_false(dest_buf_size == 0)) {
+ __fortify_chk_fail("strncat buffer overflow",
+ BIONIC_EVENT_STRNCAT_BUFFER_OVERFLOW);
+ }
+
+ if (len == 0) {
+ break;
+ }
}
- if (sum > dest_buf_size) {
- __fortify_chk_fail("strncat buffer overflow",
- BIONIC_EVENT_STRNCAT_BUFFER_OVERFLOW);
- }
-
- return strncat(dest, src, len);
+ *d = '\0';
+ return dest;
}
diff --git a/libc/bionic/malloc_debug_common.cpp b/libc/bionic/malloc_debug_common.cpp
index f6fa83c..9cc84c3 100644
--- a/libc/bionic/malloc_debug_common.cpp
+++ b/libc/bionic/malloc_debug_common.cpp
@@ -190,7 +190,7 @@
return dlmallinfo();
}
-extern "C" size_t malloc_usable_size(void* mem) {
+extern "C" size_t malloc_usable_size(const void* mem) {
return dlmalloc_usable_size(mem);
}
diff --git a/libc/bionic/mmap.c b/libc/bionic/mmap.c
index 40a6538..e097086 100644
--- a/libc/bionic/mmap.c
+++ b/libc/bionic/mmap.c
@@ -34,10 +34,17 @@
#define MMAP2_SHIFT 12
void* mmap(void *addr, size_t size, int prot, int flags, int fd, long offset)
{
+ void *ret;
+
if (offset & ((1UL << MMAP2_SHIFT)-1)) {
errno = EINVAL;
return MAP_FAILED;
}
- return __mmap2(addr, size, prot, flags, fd, (size_t)offset >> MMAP2_SHIFT);
+ ret = __mmap2(addr, size, prot, flags, fd, (size_t)offset >> MMAP2_SHIFT);
+
+ if (ret && (flags & (MAP_PRIVATE | MAP_ANONYMOUS)))
+ madvise(ret, size, MADV_MERGEABLE);
+
+ return ret;
}
diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h
index 0eb0e0a..316a14a 100644
--- a/libc/bionic/pthread_internal.h
+++ b/libc/bionic/pthread_internal.h
@@ -30,6 +30,7 @@
#include <pthread.h>
#include <stdbool.h>
+#include <sys/cdefs.h>
__BEGIN_DECLS
diff --git a/libc/include/malloc.h b/libc/include/malloc.h
index 8875e54..eaedc49 100644
--- a/libc/include/malloc.h
+++ b/libc/include/malloc.h
@@ -33,7 +33,7 @@
extern void free(void* p);
extern void* memalign(size_t alignment, size_t byte_count) __mallocfunc __wur;
-extern size_t malloc_usable_size(void* p);
+extern size_t malloc_usable_size(const void* p);
extern void* valloc(size_t byte_count) __mallocfunc __wur;
extern void* pvalloc(size_t byte_count) __mallocfunc __wur;
diff --git a/libc/include/mntent.h b/libc/include/mntent.h
index b83da1f..8b87f71 100644
--- a/libc/include/mntent.h
+++ b/libc/include/mntent.h
@@ -29,6 +29,7 @@
#define _MNTENT_H_
#include <stdio.h>
+#include <sys/cdefs.h>
#define MNTTYPE_IGNORE "ignore"
diff --git a/libc/include/netinet/in.h b/libc/include/netinet/in.h
index c5b964e..bf3b498 100644
--- a/libc/include/netinet/in.h
+++ b/libc/include/netinet/in.h
@@ -29,11 +29,13 @@
#define _NETINET_IN_H_
#include <endian.h>
+#include <netinet/in6.h>
+#include <sys/cdefs.h>
#include <sys/socket.h>
+
#include <linux/in.h>
#include <linux/in6.h>
#include <linux/ipv6.h>
-#include <netinet/in6.h>
__BEGIN_DECLS
diff --git a/libc/include/signal.h b/libc/include/signal.h
index 8c9b170..15d2d3a 100644
--- a/libc/include/signal.h
+++ b/libc/include/signal.h
@@ -59,32 +59,32 @@
static __inline__ int sigismember(const sigset_t* set, int signum) {
int bit = signum - 1; // Signal numbers start at 1, but bit positions start at 0.
+ const unsigned long* local_set = (const unsigned long*) set;
if (set == NULL || bit < 0 || bit >= (int) (8*sizeof(sigset_t))) {
errno = EINVAL;
return -1;
}
- const unsigned long* local_set = (const unsigned long*) set;
return (int) ((local_set[bit / LONG_BIT] >> (bit % LONG_BIT)) & 1);
}
static __inline__ int sigaddset(sigset_t* set, int signum) {
int bit = signum - 1; // Signal numbers start at 1, but bit positions start at 0.
+ unsigned long* local_set = (unsigned long*) set;
if (set == NULL || bit < 0 || bit >= (int) (8*sizeof(sigset_t))) {
errno = EINVAL;
return -1;
}
- unsigned long* local_set = (unsigned long*) set;
local_set[bit / LONG_BIT] |= 1UL << (bit % LONG_BIT);
return 0;
}
static __inline__ int sigdelset(sigset_t* set, int signum) {
int bit = signum - 1; // Signal numbers start at 1, but bit positions start at 0.
+ unsigned long* local_set = (unsigned long*) set;
if (set == NULL || bit < 0 || bit >= (int) (8*sizeof(sigset_t))) {
errno = EINVAL;
return -1;
}
- unsigned long* local_set = (unsigned long*) set;
local_set[bit / LONG_BIT] &= ~(1UL << (bit % LONG_BIT));
return 0;
}
diff --git a/libc/include/string.h b/libc/include/string.h
index f8c573c..1691b16 100644
--- a/libc/include/string.h
+++ b/libc/include/string.h
@@ -49,6 +49,7 @@
extern char* strrchr(const char *, int) __purefunc;
extern size_t strlen(const char *) __purefunc;
+extern size_t __strlen_chk(const char *, size_t);
extern int strcmp(const char *, const char *) __purefunc;
extern char* strcpy(char* __restrict, const char* __restrict);
extern char* strcat(char* __restrict, const char* __restrict);
@@ -207,8 +208,6 @@
return __strlcat_chk(dest, src, size, bos);
}
-extern size_t __strlen_chk(const char *, size_t);
-
__BIONIC_FORTIFY_INLINE
size_t strlen(const char *s) {
size_t bos = __bos(s);
diff --git a/libc/include/sys/auxv.h b/libc/include/sys/auxv.h
index 918442f..0d753c3 100644
--- a/libc/include/sys/auxv.h
+++ b/libc/include/sys/auxv.h
@@ -29,6 +29,7 @@
#define _SYS_AUXV_H_
#include <linux/auxvec.h>
+#include <sys/cdefs.h>
__BEGIN_DECLS
diff --git a/libc/include/sys/personality.h b/libc/include/sys/personality.h
index 7772550..8a023f9 100644
--- a/libc/include/sys/personality.h
+++ b/libc/include/sys/personality.h
@@ -29,6 +29,7 @@
#ifndef _SYS_PERSONALITY_H_
#define _SYS_PERSONALITY_H_
+#include <sys/cdefs.h>
#include <linux/personality.h>
__BEGIN_DECLS
diff --git a/libc/include/sys/signalfd.h b/libc/include/sys/signalfd.h
index c03a0e9..a249d65 100644
--- a/libc/include/sys/signalfd.h
+++ b/libc/include/sys/signalfd.h
@@ -29,8 +29,9 @@
#ifndef _SYS_SIGNALFD_H_
#define _SYS_SIGNALFD_H_
-#include <signal.h>
#include <linux/signalfd.h>
+#include <signal.h>
+#include <sys/cdefs.h>
__BEGIN_DECLS
diff --git a/libc/include/sys/timeb.h b/libc/include/sys/timeb.h
index f2cc39c..cf6f255 100644
--- a/libc/include/sys/timeb.h
+++ b/libc/include/sys/timeb.h
@@ -28,6 +28,7 @@
#ifndef _SYS_TIMEB_H
#define _SYS_TIMEB_H
+#include <sys/cdefs.h>
#include <sys/time.h>
__BEGIN_DECLS
diff --git a/libc/netbsd/net/reentrant.h b/libc/netbsd/net/reentrant.h
index 15507eb..60bff08 100644
--- a/libc/netbsd/net/reentrant.h
+++ b/libc/netbsd/net/reentrant.h
@@ -102,6 +102,7 @@
#include <pthread.h>
#include <signal.h>
+#include <sys/cdefs.h>
#define mutex_t pthread_mutex_t
#define MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
diff --git a/libc/private/bionic_auxv.h b/libc/private/bionic_auxv.h
index 69d15b6..23b2e37 100644
--- a/libc/private/bionic_auxv.h
+++ b/libc/private/bionic_auxv.h
@@ -29,6 +29,7 @@
#define _PRIVATE_BIONIC_AUXV_H_
#include <elf.h>
+#include <sys/cdefs.h>
__BEGIN_DECLS
diff --git a/libc/private/bionic_futex.h b/libc/private/bionic_futex.h
index 6c7fdbe..69658b1 100644
--- a/libc/private/bionic_futex.h
+++ b/libc/private/bionic_futex.h
@@ -29,6 +29,7 @@
#define _BIONIC_FUTEX_H
#include <linux/futex.h>
+#include <sys/cdefs.h>
__BEGIN_DECLS
diff --git a/libc/private/bionic_time.h b/libc/private/bionic_time.h
index 464ab0f..7c80f59 100644
--- a/libc/private/bionic_time.h
+++ b/libc/private/bionic_time.h
@@ -29,6 +29,7 @@
#define _BIONIC_TIME_H
#include <time.h>
+#include <sys/cdefs.h>
__BEGIN_DECLS
diff --git a/libc/private/libc_logging.h b/libc/private/libc_logging.h
index c6e1765..e62ddf2 100644
--- a/libc/private/libc_logging.h
+++ b/libc/private/libc_logging.h
@@ -45,9 +45,6 @@
BIONIC_EVENT_MEMSET_BUFFER_OVERFLOW = 80125,
BIONIC_EVENT_STRCPY_BUFFER_OVERFLOW = 80130,
- BIONIC_EVENT_STRCAT_INTEGER_OVERFLOW = 80200,
- BIONIC_EVENT_STRNCAT_INTEGER_OVERFLOW = 80205,
-
BIONIC_EVENT_RESOLVER_OLD_RESPONSE = 80300,
BIONIC_EVENT_RESOLVER_WRONG_SERVER = 80305,
BIONIC_EVENT_RESOLVER_WRONG_QUERY = 80310,
diff --git a/libc/private/resolv_private.h b/libc/private/resolv_private.h
index 1c3c1a2..0e799ca 100644
--- a/libc/private/resolv_private.h
+++ b/libc/private/resolv_private.h
@@ -54,6 +54,8 @@
#ifndef _RESOLV_PRIVATE_H_
#define _RESOLV_PRIVATE_H_
+#include <sys/cdefs.h>
+
#include <resolv.h>
#include "resolv_static.h"
#include <net/if.h>
diff --git a/libc/private/thread_private.h b/libc/private/thread_private.h
index c03f0ab..b19ad09 100644
--- a/libc/private/thread_private.h
+++ b/libc/private/thread_private.h
@@ -20,22 +20,6 @@
extern int __isthreaded;
/*
- * Weak symbols are used in libc so that the thread library can
- * efficiently wrap libc functions.
- *
- * Use WEAK_NAME(n) to get a libc-private name for n (_weak_n),
- * WEAK_ALIAS(n) to generate the weak symbol n pointing to _weak_n,
- * WEAK_PROTOTYPE(n) to generate a prototype for _weak_n (based on n).
- */
-#define WEAK_NAME(name) __CONCAT(_weak_,name)
-#define WEAK_ALIAS(name) __weak_alias(name, WEAK_NAME(name))
-#ifdef __GNUC__
-#define WEAK_PROTOTYPE(name) __typeof__(name) WEAK_NAME(name)
-#else
-#define WEAK_PROTOTYPE(name) /* typeof() only in gcc */
-#endif
-
-/*
* helper macro to make unique names in the thread namespace
*/
#define __THREAD_NAME(name) __CONCAT(_thread_tagname_,name)
@@ -52,101 +36,6 @@
#define _THREAD_PRIVATE_MUTEX_UNLOCK(name) \
pthread_mutex_unlock( &__THREAD_NAME(name)._private_lock )
-#define _THREAD_PRIVATE_KEY(name) \
- static struct __thread_private_tag_t __THREAD_NAME(name) = { PTHREAD_MUTEX_INITIALIZER, -1 }
-
-extern void* __bionic_thread_private_storage( struct __thread_private_tag_t* ptag, void* storage, size_t objsize, void* error );
-
-#define _THREAD_PRIVATE(name, storage, error) \
- __bionic_thread_private_storage( &__THREAD_NAME(name), &(storage),sizeof(storage), error)
-
-#if 0
-/*
- * helper functions that exist as (weak) null functions in libc and
- * (strong) functions in the thread library. These functions:
- *
- * _thread_tag_lock:
- * lock the mutex associated with the given tag. If the given
- * tag is NULL a tag is first allocated.
- *
- * _thread_tag_unlock:
- * unlock the mutex associated with the given tag. If the given
- * tag is NULL a tag is first allocated.
- *
- * _thread_tag_storage:
- * return a pointer to per thread instance of data associated
- * with the given tag. If the given tag is NULL a tag is first
- * allocated.
- */
-void _thread_tag_lock(void **);
-void _thread_tag_unlock(void **);
-void *_thread_tag_storage(void **, void *, size_t, void *);
-
-/*
- * Macros used in libc to access thread mutex, keys, and per thread storage.
- * _THREAD_PRIVATE_KEY and _THREAD_PRIVATE_MUTEX are different macros for
- * historical reasons. They do the same thing, define a static variable
- * keyed by 'name' that identifies a mutex and a key to identify per thread
- * data.
- */
-#define _THREAD_PRIVATE_KEY(name) \
- static void *__THREAD_NAME(name)
-#define _THREAD_PRIVATE_MUTEX(name) \
- static void *__THREAD_NAME(name)
-#define _THREAD_PRIVATE_MUTEX_LOCK(name) \
- _thread_tag_lock(&(__THREAD_NAME(name)))
-#define _THREAD_PRIVATE_MUTEX_UNLOCK(name) \
- _thread_tag_unlock(&(__THREAD_NAME(name)))
-#define _THREAD_PRIVATE(keyname, storage, error) \
- _thread_tag_storage(&(__THREAD_NAME(keyname)), &(storage), \
- sizeof (storage), error)
-/*
- * Resolver code is special cased in that it uses global keys.
- */
-extern void *__THREAD_NAME(_res);
-extern void *__THREAD_NAME(_res_ext);
-extern void *__THREAD_NAME(serv_mutex);
-#endif
-
-/*
- * File descriptor locking definitions.
- */
-#define FD_READ 0x1
-#define FD_WRITE 0x2
-#define FD_RDWR (FD_READ | FD_WRITE)
-
-struct timespec;
-int _thread_fd_lock(int, int, struct timespec *);
-void _thread_fd_unlock(int, int);
-
-/*
- * Macros are used in libc code for historical (debug) reasons.
- * Define them here.
- */
-#define _FD_LOCK(_fd,_type,_ts) _thread_fd_lock(_fd, _type, _ts)
-#define _FD_UNLOCK(_fd,_type) _thread_fd_unlock(_fd, _type)
-
-
-/*
- * malloc lock/unlock prototypes and definitions
- */
-void _thread_malloc_init(void);
-void _thread_malloc_lock(void);
-void _thread_malloc_unlock(void);
-
-#define _MALLOC_LOCK() do { \
- if (__isthreaded) \
- _thread_malloc_lock(); \
- } while (0)
-#define _MALLOC_UNLOCK() do { \
- if (__isthreaded) \
- _thread_malloc_unlock();\
- } while (0)
-#define _MALLOC_LOCK_INIT() do { \
- if (__isthreaded) \
- _thread_malloc_init();\
- } while (0)
-
void _thread_atexit_lock(void);
void _thread_atexit_unlock(void);
diff --git a/linker/linker.cpp b/linker/linker.cpp
index c97b712..80dc624 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -440,17 +440,14 @@
#endif
static Elf32_Sym* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) {
- Elf32_Sym* s;
Elf32_Sym* symtab = si->symtab;
const char* strtab = si->strtab;
- unsigned n;
TRACE_TYPE(LOOKUP, "SEARCH %s in %s@0x%08x %08x %d",
name, si->name, si->base, hash, hash % si->nbucket);
- n = hash % si->nbucket;
- for (n = si->bucket[hash % si->nbucket]; n != 0; n = si->chain[n]) {
- s = symtab + n;
+ for (unsigned n = si->bucket[hash % si->nbucket]; n != 0; n = si->chain[n]) {
+ Elf32_Sym* s = symtab + n;
if (strcmp(strtab + s->st_name, name)) continue;
/* only concern ourselves with global and weak symbol definitions */
diff --git a/tests/fortify1_test.cpp b/tests/fortify1_test.cpp
index e237193..b5cf208 100644
--- a/tests/fortify1_test.cpp
+++ b/tests/fortify1_test.cpp
@@ -23,6 +23,8 @@
#if __BIONIC__
// We have to say "DeathTest" here so gtest knows to run this test (which exits)
// in its own process.
+
+// multibyte target where we over fill (should fail)
TEST(Fortify1_DeathTest, strcpy_fortified) {
::testing::FLAGS_gtest_death_test_style = "threadsafe";
char buf[10];
@@ -31,6 +33,33 @@
free(orig);
}
+// zero sized target with "\0" source (should fail)
+TEST(Fortify1_DeathTest, strcpy2_fortified) {
+ ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+ char buf[0];
+ char *orig = strdup("");
+ ASSERT_EXIT(strcpy(buf, orig), testing::KilledBySignal(SIGSEGV), "");
+ free(orig);
+}
+
+// zero sized target with longer source (should fail)
+TEST(Fortify1_DeathTest, strcpy3_fortified) {
+ ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+ char buf[0];
+ char *orig = strdup("1");
+ ASSERT_EXIT(strcpy(buf, orig), testing::KilledBySignal(SIGSEGV), "");
+ free(orig);
+}
+
+// one byte target with longer source (should fail)
+TEST(Fortify1_DeathTest, strcpy4_fortified) {
+ ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+ char buf[1];
+ char *orig = strdup("12");
+ ASSERT_EXIT(strcpy(buf, orig), testing::KilledBySignal(SIGSEGV), "");
+ free(orig);
+}
+
TEST(Fortify1_DeathTest, strlen_fortified) {
::testing::FLAGS_gtest_death_test_style = "threadsafe";
char buf[10];
@@ -60,3 +89,182 @@
memcpy(source_buf, "12345678901234", 15);
ASSERT_EXIT(sprintf(buf, "%s", source_buf), testing::KilledBySignal(SIGSEGV), "");
}
+
+TEST(Fortify1_DeathTest, strncat_fortified) {
+ ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+ char buf[10];
+ size_t n = atoi("10"); // avoid compiler optimizations
+ strncpy(buf, "012345678", n);
+ ASSERT_EXIT(strncat(buf, "9", n), testing::KilledBySignal(SIGSEGV), "");
+}
+
+TEST(Fortify1_DeathTest, strncat2_fortified) {
+ ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+ char buf[10];
+ buf[0] = '\0';
+ size_t n = atoi("10"); // avoid compiler optimizations
+ ASSERT_EXIT(strncat(buf, "0123456789", n), testing::KilledBySignal(SIGSEGV), "");
+}
+
+TEST(Fortify1_DeathTest, strcat_fortified) {
+ ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+ char src[11];
+ strcpy(src, "0123456789");
+ char buf[10];
+ buf[0] = '\0';
+ ASSERT_EXIT(strcat(buf, src), testing::KilledBySignal(SIGSEGV), "");
+}
+
+extern "C" char* __strncat_chk(char*, const char*, size_t, size_t);
+extern "C" char* __strcat_chk(char*, const char*, size_t);
+
+TEST(Fortify1, strncat) {
+ char buf[10];
+ memset(buf, 'A', sizeof(buf));
+ buf[0] = 'a';
+ buf[1] = '\0';
+ char* res = __strncat_chk(buf, "01234", sizeof(buf) - strlen(buf) - 1, sizeof(buf));
+ ASSERT_EQ(buf, res);
+ ASSERT_EQ('a', buf[0]);
+ ASSERT_EQ('0', buf[1]);
+ ASSERT_EQ('1', buf[2]);
+ ASSERT_EQ('2', buf[3]);
+ ASSERT_EQ('3', buf[4]);
+ ASSERT_EQ('4', buf[5]);
+ ASSERT_EQ('\0', buf[6]);
+ ASSERT_EQ('A', buf[7]);
+ ASSERT_EQ('A', buf[8]);
+ ASSERT_EQ('A', buf[9]);
+}
+
+TEST(Fortify1, strncat2) {
+ char buf[10];
+ memset(buf, 'A', sizeof(buf));
+ buf[0] = 'a';
+ buf[1] = '\0';
+ char* res = __strncat_chk(buf, "0123456789", 5, sizeof(buf));
+ ASSERT_EQ(buf, res);
+ ASSERT_EQ('a', buf[0]);
+ ASSERT_EQ('0', buf[1]);
+ ASSERT_EQ('1', buf[2]);
+ ASSERT_EQ('2', buf[3]);
+ ASSERT_EQ('3', buf[4]);
+ ASSERT_EQ('4', buf[5]);
+ ASSERT_EQ('\0', buf[6]);
+ ASSERT_EQ('A', buf[7]);
+ ASSERT_EQ('A', buf[8]);
+ ASSERT_EQ('A', buf[9]);
+}
+
+TEST(Fortify1, strncat3) {
+ char buf[10];
+ memset(buf, 'A', sizeof(buf));
+ buf[0] = '\0';
+ char* res = __strncat_chk(buf, "0123456789", 5, sizeof(buf));
+ ASSERT_EQ(buf, res);
+ ASSERT_EQ('0', buf[0]);
+ ASSERT_EQ('1', buf[1]);
+ ASSERT_EQ('2', buf[2]);
+ ASSERT_EQ('3', buf[3]);
+ ASSERT_EQ('4', buf[4]);
+ ASSERT_EQ('\0', buf[5]);
+ ASSERT_EQ('A', buf[6]);
+ ASSERT_EQ('A', buf[7]);
+ ASSERT_EQ('A', buf[8]);
+ ASSERT_EQ('A', buf[9]);
+}
+
+TEST(Fortify1, strncat4) {
+ char buf[10];
+ memset(buf, 'A', sizeof(buf));
+ buf[9] = '\0';
+ char* res = __strncat_chk(buf, "", 5, sizeof(buf));
+ ASSERT_EQ(buf, res);
+ ASSERT_EQ('A', buf[0]);
+ ASSERT_EQ('A', buf[1]);
+ ASSERT_EQ('A', buf[2]);
+ ASSERT_EQ('A', buf[3]);
+ ASSERT_EQ('A', buf[4]);
+ ASSERT_EQ('A', buf[5]);
+ ASSERT_EQ('A', buf[6]);
+ ASSERT_EQ('A', buf[7]);
+ ASSERT_EQ('A', buf[8]);
+ ASSERT_EQ('\0', buf[9]);
+}
+
+TEST(Fortify1, strncat5) {
+ char buf[10];
+ memset(buf, 'A', sizeof(buf));
+ buf[0] = 'a';
+ buf[1] = '\0';
+ char* res = __strncat_chk(buf, "01234567", 8, sizeof(buf));
+ ASSERT_EQ(buf, res);
+ ASSERT_EQ('a', buf[0]);
+ ASSERT_EQ('0', buf[1]);
+ ASSERT_EQ('1', buf[2]);
+ ASSERT_EQ('2', buf[3]);
+ ASSERT_EQ('3', buf[4]);
+ ASSERT_EQ('4', buf[5]);
+ ASSERT_EQ('5', buf[6]);
+ ASSERT_EQ('6', buf[7]);
+ ASSERT_EQ('7', buf[8]);
+ ASSERT_EQ('\0', buf[9]);
+}
+
+TEST(Fortify1, strncat6) {
+ char buf[10];
+ memset(buf, 'A', sizeof(buf));
+ buf[0] = 'a';
+ buf[1] = '\0';
+ char* res = __strncat_chk(buf, "01234567", 9, sizeof(buf));
+ ASSERT_EQ(buf, res);
+ ASSERT_EQ('a', buf[0]);
+ ASSERT_EQ('0', buf[1]);
+ ASSERT_EQ('1', buf[2]);
+ ASSERT_EQ('2', buf[3]);
+ ASSERT_EQ('3', buf[4]);
+ ASSERT_EQ('4', buf[5]);
+ ASSERT_EQ('5', buf[6]);
+ ASSERT_EQ('6', buf[7]);
+ ASSERT_EQ('7', buf[8]);
+ ASSERT_EQ('\0', buf[9]);
+}
+
+
+TEST(Fortify1, strcat) {
+ char buf[10];
+ memset(buf, 'A', sizeof(buf));
+ buf[0] = 'a';
+ buf[1] = '\0';
+ char* res = __strcat_chk(buf, "01234", sizeof(buf));
+ ASSERT_EQ(buf, res);
+ ASSERT_EQ('a', buf[0]);
+ ASSERT_EQ('0', buf[1]);
+ ASSERT_EQ('1', buf[2]);
+ ASSERT_EQ('2', buf[3]);
+ ASSERT_EQ('3', buf[4]);
+ ASSERT_EQ('4', buf[5]);
+ ASSERT_EQ('\0', buf[6]);
+ ASSERT_EQ('A', buf[7]);
+ ASSERT_EQ('A', buf[8]);
+ ASSERT_EQ('A', buf[9]);
+}
+
+TEST(Fortify1, strcat2) {
+ char buf[10];
+ memset(buf, 'A', sizeof(buf));
+ buf[0] = 'a';
+ buf[1] = '\0';
+ char* res = __strcat_chk(buf, "01234567", sizeof(buf));
+ ASSERT_EQ(buf, res);
+ ASSERT_EQ('a', buf[0]);
+ ASSERT_EQ('0', buf[1]);
+ ASSERT_EQ('1', buf[2]);
+ ASSERT_EQ('2', buf[3]);
+ ASSERT_EQ('3', buf[4]);
+ ASSERT_EQ('4', buf[5]);
+ ASSERT_EQ('5', buf[6]);
+ ASSERT_EQ('6', buf[7]);
+ ASSERT_EQ('7', buf[8]);
+ ASSERT_EQ('\0', buf[9]);
+}
diff --git a/tests/fortify2_test.cpp b/tests/fortify2_test.cpp
index ea890fe..f0c2e77 100644
--- a/tests/fortify2_test.cpp
+++ b/tests/fortify2_test.cpp
@@ -21,6 +21,8 @@
#include <string.h>
struct foo {
+ char empty[0];
+ char one[1];
char a[10];
char b[10];
};
@@ -45,6 +47,36 @@
}
#if __BIONIC__
+// zero sized target with "\0" source (should fail)
+TEST(Fortify2_DeathTest, strcpy_fortified2) {
+ ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+ foo myfoo;
+ char* src = strdup("");
+ ASSERT_EXIT(strcpy(myfoo.empty, src),
+ testing::KilledBySignal(SIGSEGV), "");
+ free(src);
+}
+
+// zero sized target with longer source (should fail)
+TEST(Fortify2_DeathTest, strcpy2_fortified2) {
+ ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+ foo myfoo;
+ char* src = strdup("1");
+ ASSERT_EXIT(strcpy(myfoo.empty, src),
+ testing::KilledBySignal(SIGSEGV), "");
+ free(src);
+}
+
+// one byte target with longer source (should fail)
+TEST(Fortify2_DeathTest, strcpy3_fortified2) {
+ ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+ foo myfoo;
+ char* src = strdup("12");
+ ASSERT_EXIT(strcpy(myfoo.one, src),
+ testing::KilledBySignal(SIGSEGV), "");
+ free(src);
+}
+
TEST(Fortify2_DeathTest, strchr_fortified2) {
::testing::FLAGS_gtest_death_test_style = "threadsafe";
foo myfoo;
@@ -64,11 +96,54 @@
}
#endif
+TEST(Fortify2_DeathTest, strncat_fortified2) {
+ ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+ foo myfoo;
+ size_t n = atoi("10"); // avoid compiler optimizations
+ strncpy(myfoo.a, "012345678", n);
+ ASSERT_EXIT(strncat(myfoo.a, "9", n), testing::KilledBySignal(SIGSEGV), "");
+}
+
+TEST(Fortify2_DeathTest, strncat2_fortified2) {
+ ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+ foo myfoo;
+ myfoo.a[0] = '\0';
+ size_t n = atoi("10"); // avoid compiler optimizations
+ ASSERT_EXIT(strncat(myfoo.a, "0123456789", n), testing::KilledBySignal(SIGSEGV), "");
+}
+
+TEST(Fortify2_DeathTest, strncat3_fortified2) {
+ ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+ foo myfoo;
+ memcpy(myfoo.a, "0123456789", sizeof(myfoo.a)); // unterminated string
+ myfoo.b[0] = '\0';
+ size_t n = atoi("10"); // avoid compiler optimizations
+ ASSERT_EXIT(strncat(myfoo.b, myfoo.a, n), testing::KilledBySignal(SIGSEGV), "");
+}
+
+TEST(Fortify2_DeathTest, strcat_fortified2) {
+ ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+ char src[11];
+ strcpy(src, "0123456789");
+ foo myfoo;
+ myfoo.a[0] = '\0';
+ ASSERT_EXIT(strcat(myfoo.a, src), testing::KilledBySignal(SIGSEGV), "");
+}
+
+TEST(Fortify2_DeathTest, strcat2_fortified2) {
+ ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+ foo myfoo;
+ memcpy(myfoo.a, "0123456789", sizeof(myfoo.a)); // unterminated string
+ myfoo.b[0] = '\0';
+ ASSERT_EXIT(strcat(myfoo.b, myfoo.a), testing::KilledBySignal(SIGSEGV), "");
+}
+
/***********************************************************/
/* TESTS BELOW HERE DUPLICATE TESTS FROM fortify1_test.cpp */
/***********************************************************/
#if __BIONIC__
+// multibyte target where we over fill (should fail)
TEST(Fortify2_DeathTest, strcpy_fortified) {
::testing::FLAGS_gtest_death_test_style = "threadsafe";
char buf[10];
@@ -77,6 +152,33 @@
free(orig);
}
+// zero sized target with "\0" source (should fail)
+TEST(Fortify2_DeathTest, strcpy2_fortified) {
+ ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+ char buf[0];
+ char *orig = strdup("");
+ ASSERT_EXIT(strcpy(buf, orig), testing::KilledBySignal(SIGSEGV), "");
+ free(orig);
+}
+
+// zero sized target with longer source (should fail)
+TEST(Fortify2_DeathTest, strcpy3_fortified) {
+ ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+ char buf[0];
+ char *orig = strdup("1");
+ ASSERT_EXIT(strcpy(buf, orig), testing::KilledBySignal(SIGSEGV), "");
+ free(orig);
+}
+
+// one byte target with longer source (should fail)
+TEST(Fortify2_DeathTest, strcpy4_fortified) {
+ ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+ char buf[1];
+ char *orig = strdup("12");
+ ASSERT_EXIT(strcpy(buf, orig), testing::KilledBySignal(SIGSEGV), "");
+ free(orig);
+}
+
TEST(Fortify2_DeathTest, strlen_fortified) {
::testing::FLAGS_gtest_death_test_style = "threadsafe";
char buf[10];
@@ -106,3 +208,28 @@
memcpy(source_buf, "12345678901234", 15);
ASSERT_EXIT(sprintf(buf, "%s", source_buf), testing::KilledBySignal(SIGSEGV), "");
}
+
+TEST(Fortify2_DeathTest, strncat_fortified) {
+ ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+ char buf[10];
+ size_t n = atoi("10"); // avoid compiler optimizations
+ strncpy(buf, "012345678", n);
+ ASSERT_EXIT(strncat(buf, "9", n), testing::KilledBySignal(SIGSEGV), "");
+}
+
+TEST(Fortify2_DeathTest, strncat2_fortified) {
+ ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+ char buf[10];
+ buf[0] = '\0';
+ size_t n = atoi("10"); // avoid compiler optimizations
+ ASSERT_EXIT(strncat(buf, "0123456789", n), testing::KilledBySignal(SIGSEGV), "");
+}
+
+TEST(Fortify2_DeathTest, strcat_fortified) {
+ ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+ char src[11];
+ strcpy(src, "0123456789");
+ char buf[10];
+ buf[0] = '\0';
+ ASSERT_EXIT(strcat(buf, src), testing::KilledBySignal(SIGSEGV), "");
+}
diff --git a/tests/string_test.cpp b/tests/string_test.cpp
index 63bfadb..91d1904 100644
--- a/tests/string_test.cpp
+++ b/tests/string_test.cpp
@@ -209,6 +209,167 @@
}
}
+// one byte target with "\0" source
+TEST(string, strcpy2) {
+ char buf[1];
+ char* orig = strdup("");
+ strcpy(buf, orig);
+ ASSERT_EQ('\0', buf[0]);
+ free(orig);
+}
+
+// multibyte target where we under fill target
+TEST(string, strcpy3) {
+ char buf[10];
+ char* orig = strdup("12345");
+ memset(buf, 'A', sizeof(buf));
+ strcpy(buf, orig);
+ ASSERT_EQ('1', buf[0]);
+ ASSERT_EQ('2', buf[1]);
+ ASSERT_EQ('3', buf[2]);
+ ASSERT_EQ('4', buf[3]);
+ ASSERT_EQ('5', buf[4]);
+ ASSERT_EQ('\0', buf[5]);
+ ASSERT_EQ('A', buf[6]);
+ ASSERT_EQ('A', buf[7]);
+ ASSERT_EQ('A', buf[8]);
+ ASSERT_EQ('A', buf[9]);
+ free(orig);
+}
+
+// multibyte target where we fill target exactly
+TEST(string, strcpy4) {
+ char buf[10];
+ char* orig = strdup("123456789");
+ memset(buf, 'A', sizeof(buf));
+ strcpy(buf, orig);
+ ASSERT_EQ('1', buf[0]);
+ ASSERT_EQ('2', buf[1]);
+ ASSERT_EQ('3', buf[2]);
+ ASSERT_EQ('4', buf[3]);
+ ASSERT_EQ('5', buf[4]);
+ ASSERT_EQ('6', buf[5]);
+ ASSERT_EQ('7', buf[6]);
+ ASSERT_EQ('8', buf[7]);
+ ASSERT_EQ('9', buf[8]);
+ ASSERT_EQ('\0', buf[9]);
+ free(orig);
+}
+
+TEST(string, strcat2) {
+ char buf[10];
+ memset(buf, 'A', sizeof(buf));
+ buf[0] = 'a';
+ buf[1] = '\0';
+ char* res = strcat(buf, "01234");
+ ASSERT_EQ(buf, res);
+ ASSERT_EQ('a', buf[0]);
+ ASSERT_EQ('0', buf[1]);
+ ASSERT_EQ('1', buf[2]);
+ ASSERT_EQ('2', buf[3]);
+ ASSERT_EQ('3', buf[4]);
+ ASSERT_EQ('4', buf[5]);
+ ASSERT_EQ('\0', buf[6]);
+ ASSERT_EQ('A', buf[7]);
+ ASSERT_EQ('A', buf[8]);
+ ASSERT_EQ('A', buf[9]);
+}
+
+TEST(string, strcat3) {
+ char buf[10];
+ memset(buf, 'A', sizeof(buf));
+ buf[0] = 'a';
+ buf[1] = '\0';
+ char* res = strcat(buf, "01234567");
+ ASSERT_EQ(buf, res);
+ ASSERT_EQ('a', buf[0]);
+ ASSERT_EQ('0', buf[1]);
+ ASSERT_EQ('1', buf[2]);
+ ASSERT_EQ('2', buf[3]);
+ ASSERT_EQ('3', buf[4]);
+ ASSERT_EQ('4', buf[5]);
+ ASSERT_EQ('5', buf[6]);
+ ASSERT_EQ('6', buf[7]);
+ ASSERT_EQ('7', buf[8]);
+ ASSERT_EQ('\0', buf[9]);
+}
+
+TEST(string, strncat2) {
+ char buf[10];
+ memset(buf, 'A', sizeof(buf));
+ buf[0] = 'a';
+ buf[1] = '\0';
+ char* res = strncat(buf, "01234", sizeof(buf) - strlen(buf) - 1);
+ ASSERT_EQ(buf, res);
+ ASSERT_EQ('a', buf[0]);
+ ASSERT_EQ('0', buf[1]);
+ ASSERT_EQ('1', buf[2]);
+ ASSERT_EQ('2', buf[3]);
+ ASSERT_EQ('3', buf[4]);
+ ASSERT_EQ('4', buf[5]);
+ ASSERT_EQ('\0', buf[6]);
+ ASSERT_EQ('A', buf[7]);
+ ASSERT_EQ('A', buf[8]);
+ ASSERT_EQ('A', buf[9]);
+}
+
+TEST(string, strncat3) {
+ char buf[10];
+ memset(buf, 'A', sizeof(buf));
+ buf[0] = 'a';
+ buf[1] = '\0';
+ char* res = strncat(buf, "0123456789", 5);
+ ASSERT_EQ(buf, res);
+ ASSERT_EQ('a', buf[0]);
+ ASSERT_EQ('0', buf[1]);
+ ASSERT_EQ('1', buf[2]);
+ ASSERT_EQ('2', buf[3]);
+ ASSERT_EQ('3', buf[4]);
+ ASSERT_EQ('4', buf[5]);
+ ASSERT_EQ('\0', buf[6]);
+ ASSERT_EQ('A', buf[7]);
+ ASSERT_EQ('A', buf[8]);
+ ASSERT_EQ('A', buf[9]);
+}
+
+TEST(string, strncat4) {
+ char buf[10];
+ memset(buf, 'A', sizeof(buf));
+ buf[0] = 'a';
+ buf[1] = '\0';
+ char* res = strncat(buf, "01234567", 8);
+ ASSERT_EQ(buf, res);
+ ASSERT_EQ('a', buf[0]);
+ ASSERT_EQ('0', buf[1]);
+ ASSERT_EQ('1', buf[2]);
+ ASSERT_EQ('2', buf[3]);
+ ASSERT_EQ('3', buf[4]);
+ ASSERT_EQ('4', buf[5]);
+ ASSERT_EQ('5', buf[6]);
+ ASSERT_EQ('6', buf[7]);
+ ASSERT_EQ('7', buf[8]);
+ ASSERT_EQ('\0', buf[9]);
+}
+
+TEST(string, strncat5) {
+ char buf[10];
+ memset(buf, 'A', sizeof(buf));
+ buf[0] = 'a';
+ buf[1] = '\0';
+ char* res = strncat(buf, "01234567", 9);
+ ASSERT_EQ(buf, res);
+ ASSERT_EQ('a', buf[0]);
+ ASSERT_EQ('0', buf[1]);
+ ASSERT_EQ('1', buf[2]);
+ ASSERT_EQ('2', buf[3]);
+ ASSERT_EQ('3', buf[4]);
+ ASSERT_EQ('4', buf[5]);
+ ASSERT_EQ('5', buf[6]);
+ ASSERT_EQ('6', buf[7]);
+ ASSERT_EQ('7', buf[8]);
+ ASSERT_EQ('\0', buf[9]);
+}
+
TEST(string, strchr_with_0) {
char buf[10];
const char* s = "01234";