libc: add limited FORTIFY_SOURCE support for clang
In 829c089f83ddee37203b52bcb294867a9ae7bdbc, we disabled all FORTIFY_SOURCE support when compiling under clang. At the time, we didn't have proper test cases, and couldn't easily create targeted clang tests. This change re-enables FORTIFY_SOURCE support under clang for a limited set of functions, where we have explicit unittests available. The functions are: * memcpy * memmove * strcpy * strncpy * strcat * strncat * memset * strlen (with modifications) * strchr (with modifications) * strrchr (with modifications) It may be possible, in the future, to enable other functions. However, I need to write unittests first. For strlen, strchr, and strrchr, clang unconditionally calls the fortified version of the relevant function. If it doesn't know the size of the buffer it's dealing with, it passes in ((size_t) -1), which is the largest possible size_t. I added two new clang specific unittest files, primarily copied from fortify?_test.cpp. I've also rebuild the entire system with these changes, and didn't observe any obvious problems. Change-Id: If12a15089bb0ffe93824b485290d05b14355fcaa
This commit is contained in:
parent
b24c0637d0
commit
16d1af167f
@ -49,7 +49,7 @@ extern int unlinkat(int dirfd, const char *pathname, int flags);
|
||||
extern int fcntl(int fd, int command, ...);
|
||||
extern int creat(const char* path, mode_t mode);
|
||||
|
||||
#if defined(__BIONIC_FORTIFY)
|
||||
#if defined(__BIONIC_FORTIFY) && !defined(__clang__)
|
||||
__errordecl(__creat_error, "called with O_CREAT, but missing mode");
|
||||
__errordecl(__too_many_args_error, "too many arguments");
|
||||
extern int __open_real(const char *pathname, int flags, ...)
|
||||
@ -98,7 +98,7 @@ int openat(int dirfd, const char *pathname, int flags, ...) {
|
||||
return __openat_real(dirfd, pathname, flags, __builtin_va_arg_pack());
|
||||
}
|
||||
|
||||
#endif /* defined(__BIONIC_FORTIFY) */
|
||||
#endif /* defined(__BIONIC_FORTIFY) && !defined(__clang__) */
|
||||
|
||||
__END_DECLS
|
||||
|
||||
|
@ -450,7 +450,7 @@ int vfdprintf(int, const char*, __va_list)
|
||||
__END_DECLS
|
||||
#endif /* _GNU_SOURCE */
|
||||
|
||||
#if defined(__BIONIC_FORTIFY)
|
||||
#if defined(__BIONIC_FORTIFY) && !defined(__clang__)
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
@ -523,6 +523,6 @@ char *fgets(char *dest, int size, FILE *stream)
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /* defined(__BIONIC_FORTIFY) */
|
||||
#endif /* defined(__BIONIC_FORTIFY) && !defined(__clang__) */
|
||||
|
||||
#endif /* _STDIO_H_ */
|
||||
|
@ -91,7 +91,7 @@ __errordecl(__memcpy_dest_size_error, "memcpy called with size bigger than desti
|
||||
__errordecl(__memcpy_src_size_error, "memcpy called with size bigger than source");
|
||||
|
||||
__BIONIC_FORTIFY_INLINE
|
||||
void *memcpy (void* __restrict dest, const void* __restrict src, size_t copy_amount) {
|
||||
void* memcpy(void* __restrict dest, const void* __restrict src, size_t copy_amount) {
|
||||
char *d = (char *) dest;
|
||||
const char *s = (const char *) src;
|
||||
size_t s_len = __builtin_object_size(s, 0);
|
||||
@ -109,19 +109,19 @@ void *memcpy (void* __restrict dest, const void* __restrict src, size_t copy_amo
|
||||
}
|
||||
|
||||
__BIONIC_FORTIFY_INLINE
|
||||
void *memmove (void *dest, const void *src, size_t len) {
|
||||
void* memmove(void *dest, const void *src, size_t len) {
|
||||
return __builtin___memmove_chk(dest, src, len, __builtin_object_size (dest, 0));
|
||||
}
|
||||
|
||||
__BIONIC_FORTIFY_INLINE
|
||||
char *strcpy(char* __restrict dest, const char* __restrict src) {
|
||||
char* strcpy(char* __restrict dest, const char* __restrict src) {
|
||||
return __builtin___strcpy_chk(dest, src, __bos(dest));
|
||||
}
|
||||
|
||||
__errordecl(__strncpy_error, "strncpy called with size bigger than buffer");
|
||||
|
||||
__BIONIC_FORTIFY_INLINE
|
||||
char *strncpy(char* __restrict dest, const char* __restrict src, size_t n) {
|
||||
char* strncpy(char* __restrict dest, const char* __restrict src, size_t n) {
|
||||
size_t bos = __bos(dest);
|
||||
if (__builtin_constant_p(n) && (n > bos)) {
|
||||
__strncpy_error();
|
||||
@ -130,7 +130,7 @@ char *strncpy(char* __restrict dest, const char* __restrict src, size_t n) {
|
||||
}
|
||||
|
||||
__BIONIC_FORTIFY_INLINE
|
||||
char *strcat(char* __restrict dest, const char* __restrict src) {
|
||||
char* strcat(char* __restrict dest, const char* __restrict src) {
|
||||
return __builtin___strcat_chk(dest, src, __bos(dest));
|
||||
}
|
||||
|
||||
@ -140,10 +140,11 @@ char *strncat(char* __restrict dest, const char* __restrict src, size_t n) {
|
||||
}
|
||||
|
||||
__BIONIC_FORTIFY_INLINE
|
||||
void *memset (void *s, int c, size_t n) {
|
||||
void* memset(void *s, int c, size_t n) {
|
||||
return __builtin___memset_chk(s, c, n, __builtin_object_size (s, 0));
|
||||
}
|
||||
|
||||
#if !defined(__clang__)
|
||||
extern size_t __strlcpy_real(char* __restrict, const char* __restrict, size_t)
|
||||
__asm__(__USER_LABEL_PREFIX__ "strlcpy");
|
||||
__errordecl(__strlcpy_error, "strlcpy called with size bigger than buffer");
|
||||
@ -172,7 +173,9 @@ size_t strlcpy(char* __restrict dest, const char* __restrict src, size_t size) {
|
||||
|
||||
return __strlcpy_chk(dest, src, size, bos);
|
||||
}
|
||||
#endif /* !defined(__clang__) */
|
||||
|
||||
#if !defined(__clang__)
|
||||
extern size_t __strlcat_real(char* __restrict, const char* __restrict, size_t)
|
||||
__asm__(__USER_LABEL_PREFIX__ "strlcat");
|
||||
__errordecl(__strlcat_error, "strlcat called with size bigger than buffer");
|
||||
@ -202,11 +205,13 @@ size_t strlcat(char* __restrict dest, const char* __restrict src, size_t size) {
|
||||
|
||||
return __strlcat_chk(dest, src, size, bos);
|
||||
}
|
||||
#endif /* !defined(__clang__) */
|
||||
|
||||
__BIONIC_FORTIFY_INLINE
|
||||
size_t strlen(const char *s) {
|
||||
size_t bos = __bos(s);
|
||||
|
||||
#if !defined(__clang__)
|
||||
// Compiler doesn't know destination size. Don't call __strlen_chk
|
||||
if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
|
||||
return __builtin_strlen(s);
|
||||
@ -216,6 +221,7 @@ size_t strlen(const char *s) {
|
||||
if (__builtin_constant_p(slen)) {
|
||||
return slen;
|
||||
}
|
||||
#endif /* !defined(__clang__) */
|
||||
|
||||
return __strlen_chk(s, bos);
|
||||
}
|
||||
@ -226,6 +232,7 @@ __BIONIC_FORTIFY_INLINE
|
||||
char* strchr(const char *s, int c) {
|
||||
size_t bos = __bos(s);
|
||||
|
||||
#if !defined(__clang__)
|
||||
// Compiler doesn't know destination size. Don't call __strchr_chk
|
||||
if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
|
||||
return __builtin_strchr(s, c);
|
||||
@ -235,6 +242,7 @@ char* strchr(const char *s, int c) {
|
||||
if (__builtin_constant_p(slen) && (slen < bos)) {
|
||||
return __builtin_strchr(s, c);
|
||||
}
|
||||
#endif /* !defined(__clang__) */
|
||||
|
||||
return __strchr_chk(s, c, bos);
|
||||
}
|
||||
@ -245,6 +253,7 @@ __BIONIC_FORTIFY_INLINE
|
||||
char* strrchr(const char *s, int c) {
|
||||
size_t bos = __bos(s);
|
||||
|
||||
#if !defined(__clang__)
|
||||
// Compiler doesn't know destination size. Don't call __strrchr_chk
|
||||
if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
|
||||
return __builtin_strrchr(s, c);
|
||||
@ -254,6 +263,7 @@ char* strrchr(const char *s, int c) {
|
||||
if (__builtin_constant_p(slen) && (slen < bos)) {
|
||||
return __builtin_strrchr(s, c);
|
||||
}
|
||||
#endif /* !defined(__clang__) */
|
||||
|
||||
return __strrchr_chk(s, c, bos);
|
||||
}
|
||||
|
@ -50,12 +50,12 @@ char *index(const char *, int);
|
||||
int strcasecmp(const char *, const char *);
|
||||
int strncasecmp(const char *, const char *, size_t);
|
||||
|
||||
#if defined(__BIONIC_FORTIFY)
|
||||
#if defined(__BIONIC_FORTIFY) && !defined(__clang__)
|
||||
__BIONIC_FORTIFY_INLINE
|
||||
void bzero (void *s, size_t n) {
|
||||
__builtin___memset_chk(s, '\0', n, __builtin_object_size (s, 0));
|
||||
}
|
||||
#endif /* defined(__BIONIC_FORTIFY) */
|
||||
#endif /* defined(__BIONIC_FORTIFY) && !defined(__clang__) */
|
||||
|
||||
__END_DECLS
|
||||
|
||||
|
@ -524,7 +524,7 @@
|
||||
#define __BIONIC__ 1
|
||||
#include <android/api-level.h>
|
||||
|
||||
#if defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE > 0 && defined(__OPTIMIZE__) && __OPTIMIZE__ > 0 && !defined(__clang__)
|
||||
#if defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE > 0 && defined(__OPTIMIZE__) && __OPTIMIZE__ > 0
|
||||
#define __BIONIC_FORTIFY 1
|
||||
#if _FORTIFY_SOURCE == 2
|
||||
#define __bos(s) __builtin_object_size((s), 1)
|
||||
@ -535,8 +535,7 @@
|
||||
#define __BIONIC_FORTIFY_INLINE \
|
||||
extern inline \
|
||||
__attribute__ ((always_inline)) \
|
||||
__attribute__ ((gnu_inline)) \
|
||||
__attribute__ ((artificial))
|
||||
__attribute__ ((gnu_inline))
|
||||
#endif
|
||||
#define __BIONIC_FORTIFY_UNKNOWN_SIZE ((size_t) -1)
|
||||
|
||||
|
@ -129,7 +129,7 @@ extern int lstat(const char *, struct stat *);
|
||||
extern int mknod(const char *, mode_t, dev_t);
|
||||
extern mode_t umask(mode_t);
|
||||
|
||||
#if defined(__BIONIC_FORTIFY)
|
||||
#if defined(__BIONIC_FORTIFY) && !defined(__clang__)
|
||||
|
||||
extern mode_t __umask_chk(mode_t);
|
||||
extern mode_t __umask_real(mode_t)
|
||||
@ -146,7 +146,7 @@ mode_t umask(mode_t mode) {
|
||||
}
|
||||
return __umask_chk(mode);
|
||||
}
|
||||
#endif /* defined(__BIONIC_FORTIFY) */
|
||||
#endif /* defined(__BIONIC_FORTIFY) && !defined(__clang__) */
|
||||
|
||||
|
||||
#define stat64 stat
|
||||
|
@ -96,6 +96,7 @@ LOCAL_CFLAGS += $(test_c_flags)
|
||||
LOCAL_LDFLAGS += $(test_dynamic_ldflags)
|
||||
LOCAL_SHARED_LIBRARIES += libdl
|
||||
LOCAL_SRC_FILES := $(test_src_files) $(test_dynamic_src_files)
|
||||
LOCAL_WHOLE_STATIC_LIBRARIES := bionic-unit-tests-clang
|
||||
include $(BUILD_NATIVE_TEST)
|
||||
|
||||
# Build tests for the device (with bionic's .a). Run with:
|
||||
@ -107,6 +108,7 @@ LOCAL_CFLAGS += $(test_c_flags)
|
||||
LOCAL_FORCE_STATIC_EXECUTABLE := true
|
||||
LOCAL_SRC_FILES := $(test_src_files)
|
||||
LOCAL_STATIC_LIBRARIES += libstlport_static libstdc++ libm libc
|
||||
LOCAL_WHOLE_STATIC_LIBRARIES := bionic-unit-tests-clang
|
||||
include $(BUILD_NATIVE_TEST)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
@ -143,4 +145,26 @@ LOCAL_SRC_FILES := $(test_src_files) $(test_dynamic_src_files)
|
||||
include $(BUILD_HOST_NATIVE_TEST)
|
||||
endif
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Unit tests which depend on clang as the compiler
|
||||
# -----------------------------------------------------------------------------
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_SRC_FILES := fortify1_test_clang.cpp fortify2_test_clang.cpp
|
||||
LOCAL_MODULE := bionic-unit-tests-clang
|
||||
LOCAL_CLANG := true
|
||||
|
||||
# -Wno-error=unused-parameter needed as
|
||||
# external/stlport/stlport/stl/_threads.c (included from
|
||||
# external/gtest/include/gtest/gtest.h) does not compile cleanly under
|
||||
# clang. TODO: fix this.
|
||||
LOCAL_CFLAGS += $(test_c_flags) -Wno-error=unused-parameter
|
||||
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
|
||||
LOCAL_C_INCLUDES += bionic \
|
||||
bionic/libstdc++/include \
|
||||
external/stlport/stlport \
|
||||
external/gtest/include
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
endif # !BUILD_TINY_ANDROID
|
||||
|
@ -115,6 +115,32 @@ TEST(Fortify1_DeathTest, strcat_fortified) {
|
||||
ASSERT_EXIT(strcat(buf, src), testing::KilledBySignal(SIGABRT), "");
|
||||
}
|
||||
|
||||
TEST(Fortify1_DeathTest, memmove_fortified) {
|
||||
::testing::FLAGS_gtest_death_test_style = "threadsafe";
|
||||
char buf[20];
|
||||
strcpy(buf, "0123456789");
|
||||
size_t n = atoi("10");
|
||||
ASSERT_EXIT(memmove(buf + 11, buf, n), testing::KilledBySignal(SIGABRT), "");
|
||||
}
|
||||
|
||||
TEST(Fortify1_DeathTest, memcpy_fortified) {
|
||||
::testing::FLAGS_gtest_death_test_style = "threadsafe";
|
||||
char bufa[10];
|
||||
char bufb[10];
|
||||
strcpy(bufa, "012345678");
|
||||
size_t n = atoi("11");
|
||||
ASSERT_EXIT(memcpy(bufb, bufa, n), testing::KilledBySignal(SIGABRT), "");
|
||||
}
|
||||
|
||||
TEST(Fortify1_DeathTest, strncpy_fortified) {
|
||||
::testing::FLAGS_gtest_death_test_style = "threadsafe";
|
||||
char bufa[15];
|
||||
char bufb[10];
|
||||
strcpy(bufa, "01234567890123");
|
||||
size_t n = strlen(bufa);
|
||||
ASSERT_EXIT(strncpy(bufb, bufa, n), testing::KilledBySignal(SIGABRT), "");
|
||||
}
|
||||
|
||||
extern "C" char* __strncat_chk(char*, const char*, size_t, size_t);
|
||||
extern "C" char* __strcat_chk(char*, const char*, size_t);
|
||||
|
||||
|
298
tests/fortify1_test_clang.cpp
Normal file
298
tests/fortify1_test_clang.cpp
Normal file
@ -0,0 +1,298 @@
|
||||
/*
|
||||
* Copyright (C) 2013 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#undef _FORTIFY_SOURCE
|
||||
#define _FORTIFY_SOURCE 1
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <string.h>
|
||||
|
||||
#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_Clang_DeathTest, strcpy_fortified) {
|
||||
::testing::FLAGS_gtest_death_test_style = "threadsafe";
|
||||
char buf[10];
|
||||
char *orig = strdup("0123456789");
|
||||
ASSERT_EXIT(strcpy(buf, orig), testing::KilledBySignal(SIGABRT), "");
|
||||
free(orig);
|
||||
}
|
||||
|
||||
// zero sized target with "\0" source (should fail)
|
||||
TEST(Fortify1_Clang_DeathTest, strcpy2_fortified) {
|
||||
::testing::FLAGS_gtest_death_test_style = "threadsafe";
|
||||
char buf[0];
|
||||
char *orig = strdup("");
|
||||
ASSERT_EXIT(strcpy(buf, orig), testing::KilledBySignal(SIGABRT), "");
|
||||
free(orig);
|
||||
}
|
||||
|
||||
// zero sized target with longer source (should fail)
|
||||
TEST(Fortify1_Clang_DeathTest, strcpy3_fortified) {
|
||||
::testing::FLAGS_gtest_death_test_style = "threadsafe";
|
||||
char buf[0];
|
||||
char *orig = strdup("1");
|
||||
ASSERT_EXIT(strcpy(buf, orig), testing::KilledBySignal(SIGABRT), "");
|
||||
free(orig);
|
||||
}
|
||||
|
||||
// one byte target with longer source (should fail)
|
||||
TEST(Fortify1_Clang_DeathTest, strcpy4_fortified) {
|
||||
::testing::FLAGS_gtest_death_test_style = "threadsafe";
|
||||
char buf[1];
|
||||
char *orig = strdup("12");
|
||||
ASSERT_EXIT(strcpy(buf, orig), testing::KilledBySignal(SIGABRT), "");
|
||||
free(orig);
|
||||
}
|
||||
|
||||
TEST(Fortify1_Clang_DeathTest, strlen_fortified) {
|
||||
::testing::FLAGS_gtest_death_test_style = "threadsafe";
|
||||
char buf[10];
|
||||
memcpy(buf, "0123456789", sizeof(buf));
|
||||
ASSERT_EXIT(printf("%d", strlen(buf)), testing::KilledBySignal(SIGABRT), "");
|
||||
}
|
||||
|
||||
TEST(Fortify1_Clang_DeathTest, strchr_fortified) {
|
||||
::testing::FLAGS_gtest_death_test_style = "threadsafe";
|
||||
char buf[10];
|
||||
memcpy(buf, "0123456789", sizeof(buf));
|
||||
ASSERT_EXIT(printf("%s", strchr(buf, 'a')), testing::KilledBySignal(SIGABRT), "");
|
||||
}
|
||||
|
||||
TEST(Fortify1_Clang_DeathTest, strrchr_fortified) {
|
||||
::testing::FLAGS_gtest_death_test_style = "threadsafe";
|
||||
char buf[10];
|
||||
memcpy(buf, "0123456789", sizeof(buf));
|
||||
ASSERT_EXIT(printf("%s", strrchr(buf, 'a')), testing::KilledBySignal(SIGABRT), "");
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(Fortify1_Clang_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(SIGABRT), "");
|
||||
}
|
||||
|
||||
TEST(Fortify1_Clang_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(SIGABRT), "");
|
||||
}
|
||||
|
||||
TEST(Fortify1_Clang_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(SIGABRT), "");
|
||||
}
|
||||
|
||||
TEST(Fortify1_Clang_DeathTest, memmove_fortified) {
|
||||
::testing::FLAGS_gtest_death_test_style = "threadsafe";
|
||||
char buf[20];
|
||||
strcpy(buf, "0123456789");
|
||||
size_t n = atoi("10");
|
||||
ASSERT_EXIT(memmove(buf + 11, buf, n), testing::KilledBySignal(SIGABRT), "");
|
||||
}
|
||||
|
||||
TEST(Fortify1_Clang_DeathTest, memcpy_fortified) {
|
||||
::testing::FLAGS_gtest_death_test_style = "threadsafe";
|
||||
char bufa[10];
|
||||
char bufb[10];
|
||||
strcpy(bufa, "012345678");
|
||||
size_t n = atoi("11");
|
||||
ASSERT_EXIT(memcpy(bufb, bufa, n), testing::KilledBySignal(SIGABRT), "");
|
||||
}
|
||||
|
||||
TEST(Fortify1_Clang_DeathTest, strncpy_fortified) {
|
||||
::testing::FLAGS_gtest_death_test_style = "threadsafe";
|
||||
char bufa[15];
|
||||
char bufb[10];
|
||||
strcpy(bufa, "01234567890123");
|
||||
size_t n = strlen(bufa);
|
||||
ASSERT_EXIT(strncpy(bufb, bufa, n), testing::KilledBySignal(SIGABRT), "");
|
||||
}
|
||||
|
||||
extern "C" char* __strncat_chk(char*, const char*, size_t, size_t);
|
||||
extern "C" char* __strcat_chk(char*, const char*, size_t);
|
||||
|
||||
TEST(Fortify1_Clang, 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_Clang, 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_Clang, 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_Clang, 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_Clang, 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_Clang, 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_Clang, 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_Clang, 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]);
|
||||
}
|
||||
|
||||
__BIONIC_FORTIFY_INLINE
|
||||
size_t test_fortify_inline(char* buf) {
|
||||
return __bos(buf);
|
||||
}
|
||||
|
||||
TEST(Fortify1_Clang, fortify_inline) {
|
||||
char buf[1024];
|
||||
ASSERT_EQ(test_fortify_inline(buf), sizeof(buf));
|
||||
}
|
@ -233,3 +233,29 @@ TEST(Fortify2_DeathTest, strcat_fortified) {
|
||||
buf[0] = '\0';
|
||||
ASSERT_EXIT(strcat(buf, src), testing::KilledBySignal(SIGABRT), "");
|
||||
}
|
||||
|
||||
TEST(Fortify2_DeathTest, memmove_fortified) {
|
||||
::testing::FLAGS_gtest_death_test_style = "threadsafe";
|
||||
char buf[20];
|
||||
strcpy(buf, "0123456789");
|
||||
size_t n = atoi("10");
|
||||
ASSERT_EXIT(memmove(buf + 11, buf, n), testing::KilledBySignal(SIGABRT), "");
|
||||
}
|
||||
|
||||
TEST(Fortify2_DeathTest, memcpy_fortified) {
|
||||
::testing::FLAGS_gtest_death_test_style = "threadsafe";
|
||||
char bufa[10];
|
||||
char bufb[10];
|
||||
strcpy(bufa, "012345678");
|
||||
size_t n = atoi("11");
|
||||
ASSERT_EXIT(memcpy(bufb, bufa, n), testing::KilledBySignal(SIGABRT), "");
|
||||
}
|
||||
|
||||
TEST(Fortify2_DeathTest, strncpy_fortified) {
|
||||
::testing::FLAGS_gtest_death_test_style = "threadsafe";
|
||||
char bufa[15];
|
||||
char bufb[10];
|
||||
strcpy(bufa, "01234567890123");
|
||||
size_t n = strlen(bufa);
|
||||
ASSERT_EXIT(strncpy(bufb, bufa, n), testing::KilledBySignal(SIGABRT), "");
|
||||
}
|
||||
|
171
tests/fortify2_test_clang.cpp
Normal file
171
tests/fortify2_test_clang.cpp
Normal file
@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright (C) 2013 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#undef _FORTIFY_SOURCE
|
||||
#define _FORTIFY_SOURCE 2
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <string.h>
|
||||
|
||||
struct foo {
|
||||
char empty[0];
|
||||
char one[1];
|
||||
char a[10];
|
||||
char b[10];
|
||||
};
|
||||
|
||||
// We have to say "DeathTest" here so gtest knows to run this test (which exits)
|
||||
// in its own process.
|
||||
TEST(Fortify2_Clang_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(SIGABRT), "");
|
||||
}
|
||||
|
||||
TEST(Fortify2_Clang_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(SIGABRT), "");
|
||||
}
|
||||
|
||||
/*****************************************************************/
|
||||
/* TESTS BELOW HERE DUPLICATE TESTS FROM fortify1_test_clang.cpp */
|
||||
/*****************************************************************/
|
||||
|
||||
#if __BIONIC__
|
||||
// multibyte target where we over fill (should fail)
|
||||
TEST(Fortify2_Clang_DeathTest, strcpy_fortified) {
|
||||
::testing::FLAGS_gtest_death_test_style = "threadsafe";
|
||||
char buf[10];
|
||||
char *orig = strdup("0123456789");
|
||||
ASSERT_EXIT(strcpy(buf, orig), testing::KilledBySignal(SIGABRT), "");
|
||||
free(orig);
|
||||
}
|
||||
|
||||
// zero sized target with "\0" source (should fail)
|
||||
TEST(Fortify2_Clang_DeathTest, strcpy2_fortified) {
|
||||
::testing::FLAGS_gtest_death_test_style = "threadsafe";
|
||||
char buf[0];
|
||||
char *orig = strdup("");
|
||||
ASSERT_EXIT(strcpy(buf, orig), testing::KilledBySignal(SIGABRT), "");
|
||||
free(orig);
|
||||
}
|
||||
|
||||
// zero sized target with longer source (should fail)
|
||||
TEST(Fortify2_Clang_DeathTest, strcpy3_fortified) {
|
||||
::testing::FLAGS_gtest_death_test_style = "threadsafe";
|
||||
char buf[0];
|
||||
char *orig = strdup("1");
|
||||
ASSERT_EXIT(strcpy(buf, orig), testing::KilledBySignal(SIGABRT), "");
|
||||
free(orig);
|
||||
}
|
||||
|
||||
// one byte target with longer source (should fail)
|
||||
TEST(Fortify2_Clang_DeathTest, strcpy4_fortified) {
|
||||
::testing::FLAGS_gtest_death_test_style = "threadsafe";
|
||||
char buf[1];
|
||||
char *orig = strdup("12");
|
||||
ASSERT_EXIT(strcpy(buf, orig), testing::KilledBySignal(SIGABRT), "");
|
||||
free(orig);
|
||||
}
|
||||
|
||||
TEST(Fortify2_Clang_DeathTest, strlen_fortified) {
|
||||
::testing::FLAGS_gtest_death_test_style = "threadsafe";
|
||||
char buf[10];
|
||||
memcpy(buf, "0123456789", sizeof(buf));
|
||||
ASSERT_EXIT(printf("%d", strlen(buf)), testing::KilledBySignal(SIGABRT), "");
|
||||
}
|
||||
|
||||
TEST(Fortify2_Clang_DeathTest, strchr_fortified) {
|
||||
::testing::FLAGS_gtest_death_test_style = "threadsafe";
|
||||
char buf[10];
|
||||
memcpy(buf, "0123456789", sizeof(buf));
|
||||
ASSERT_EXIT(printf("%s", strchr(buf, 'a')), testing::KilledBySignal(SIGABRT), "");
|
||||
}
|
||||
|
||||
TEST(Fortify2_Clang_DeathTest, strrchr_fortified) {
|
||||
::testing::FLAGS_gtest_death_test_style = "threadsafe";
|
||||
char buf[10];
|
||||
memcpy(buf, "0123456789", sizeof(buf));
|
||||
ASSERT_EXIT(printf("%s", strrchr(buf, 'a')), testing::KilledBySignal(SIGABRT), "");
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(Fortify2_Clang_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(SIGABRT), "");
|
||||
}
|
||||
|
||||
TEST(Fortify2_Clang_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(SIGABRT), "");
|
||||
}
|
||||
|
||||
TEST(Fortify2_Clang_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(SIGABRT), "");
|
||||
}
|
||||
|
||||
TEST(Fortify2_Clang_DeathTest, memmove_fortified) {
|
||||
::testing::FLAGS_gtest_death_test_style = "threadsafe";
|
||||
char buf[20];
|
||||
strcpy(buf, "0123456789");
|
||||
size_t n = atoi("10");
|
||||
ASSERT_EXIT(memmove(buf + 11, buf, n), testing::KilledBySignal(SIGABRT), "");
|
||||
}
|
||||
|
||||
TEST(Fortify2_Clang_DeathTest, memcpy_fortified) {
|
||||
::testing::FLAGS_gtest_death_test_style = "threadsafe";
|
||||
char bufa[10];
|
||||
char bufb[10];
|
||||
strcpy(bufa, "012345678");
|
||||
size_t n = atoi("11");
|
||||
ASSERT_EXIT(memcpy(bufb, bufa, n), testing::KilledBySignal(SIGABRT), "");
|
||||
}
|
||||
|
||||
TEST(Fortify2_Clang_DeathTest, strncpy_fortified) {
|
||||
::testing::FLAGS_gtest_death_test_style = "threadsafe";
|
||||
char bufa[15];
|
||||
char bufb[10];
|
||||
strcpy(bufa, "01234567890123");
|
||||
size_t n = strlen(bufa);
|
||||
ASSERT_EXIT(strncpy(bufb, bufa, n), testing::KilledBySignal(SIGABRT), "");
|
||||
}
|
||||
|
||||
__BIONIC_FORTIFY_INLINE
|
||||
size_t test_fortify2_inline(char* buf) {
|
||||
return __bos(buf);
|
||||
}
|
||||
|
||||
TEST(Fortify2_Clang, fortify_inline) {
|
||||
char buf[1024];
|
||||
ASSERT_EQ(test_fortify2_inline(buf), sizeof(buf));
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user