diff options
author | Nick Kralevich <nnk@google.com> | 2012-07-12 15:10:03 -0700 |
---|---|---|
committer | Nick Kralevich <nnk@google.com> | 2012-07-12 15:38:15 -0700 |
commit | f3913b5b68347ce9a4cb17977df2c33f1e8f6000 (patch) | |
tree | fae959e2f8c146b61eb43af80d9ae4918640d2c0 /libc/include/string.h | |
parent | 86a4fca0b473c49bcbcf2deb6b5822aa9ab9631e (diff) | |
download | android_bionic-f3913b5b68347ce9a4cb17977df2c33f1e8f6000.tar.gz android_bionic-f3913b5b68347ce9a4cb17977df2c33f1e8f6000.tar.bz2 android_bionic-f3913b5b68347ce9a4cb17977df2c33f1e8f6000.zip |
FORTIFY_SOURCE: enhanced memcpy protections.
Two changes:
1) Detect memory read overruns.
For example:
int main() {
char buf[10];
memcpy(buf, "abcde", sizeof(buf));
sprintf("%s\n", buf);
}
because "abcde" is only 6 bytes, copying 10 bytes from it is a bug.
This particular bug will be detected at compile time. Other similar
bugs may be detected at runtime.
2) Detect overlapping buffers on memcpy()
It is a bug to call memcpy() on buffers which overlap. For
example, the following code is buggy:
char buf3[0x800];
char *first_half = &buf3[0x400];
char *second_half = &buf3[1];
memset(buf3, 0, sizeof(buf3));
memcpy(first_half, second_half, 0x400);
printf("1: %s\n", buf3);
We now detect this at compile and run time.
Change-Id: I092bd89f11f18e08e8a9dda0ca903aaea8e06d91
Diffstat (limited to 'libc/include/string.h')
-rw-r--r-- | libc/include/string.h | 37 |
1 files changed, 35 insertions, 2 deletions
diff --git a/libc/include/string.h b/libc/include/string.h index 32fd25f5b..269f7ac4e 100644 --- a/libc/include/string.h +++ b/libc/include/string.h @@ -87,9 +87,42 @@ extern size_t strxfrm(char *, const char *, size_t); #if defined(__BIONIC_FORTIFY_INLINE) +extern void __memcpy_dest_size_error() + __attribute__((__error__("memcpy called with size bigger than destination"))); +extern void __memcpy_src_size_error() + __attribute__((__error__("memcpy called with size bigger than source"))); +extern void __memcpy_overlap_error() + __attribute__((__error__("memcpy called with overlapping regions"))); +extern void *__memcpy_real(void *, const void *, size_t) + __asm__(__USER_LABEL_PREFIX__ "memcpy"); +extern void *__memcpy_chk2(void *, const void *, size_t, size_t, size_t); + + __BIONIC_FORTIFY_INLINE -void *memcpy (void *dest, const void *src, size_t len) { - return __builtin___memcpy_chk(dest, src, len, __builtin_object_size (dest, 0)); +void *memcpy (void *dest, const void *src, size_t copy_amount) { + char *d = (char *) dest; + const char *s = (const char *) src; + size_t s_len = __builtin_object_size(s, 0); + size_t d_len = __builtin_object_size(d, 0); + + if (__builtin_constant_p(copy_amount) && (copy_amount > d_len)) { + __memcpy_dest_size_error(); + } + + if (__builtin_constant_p(copy_amount) && (copy_amount > s_len)) { + __memcpy_src_size_error(); + } + + if (__builtin_constant_p(d - s) && __builtin_constant_p(copy_amount) + && (((size_t)(d - s) < copy_amount) || ((size_t)(s - d) < copy_amount))) { + __memcpy_overlap_error(); + } + + if (__builtin_constant_p(copy_amount) && __builtin_constant_p(d - s)) { + return __memcpy_real(dest, src, copy_amount); + } + + return __memcpy_chk2(dest, src, copy_amount, d_len, s_len); } __BIONIC_FORTIFY_INLINE |