summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEvgeniy Stepanov <eugeni.stepanov@gmail.com>2013-10-24 11:56:03 +0000
committerEvgeniy Stepanov <eugeni.stepanov@gmail.com>2013-10-24 11:56:03 +0000
commit450eee655289a622ab9acf87d863f38991b184c9 (patch)
treea4fcb2f6680db8b4ddf7945edd32f276f9513420
parent48ed0580871e66c61e856a2281280929f6f77593 (diff)
downloadcompiler-rt-450eee655289a622ab9acf87d863f38991b184c9.tar.gz
compiler-rt-450eee655289a622ab9acf87d863f38991b184c9.tar.bz2
compiler-rt-450eee655289a622ab9acf87d863f38991b184c9.tar.xz
[msan] Fix invalid origin copying.
Origin copying may destroy valid origin info. This is caused by __msan_copy_origin widening the address range to the nearest 4-byte aligned addresses both on the left and on the right. If the target buffer is uninitialized and the source is fully initialized, this will result in overriding valid origin of target buffer with stale (possibly 0) origin of the source buffer. With this change the widened origin is copied only if corresponding shadow values are non zero. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@193338 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/msan/msan.h11
-rw-r--r--lib/msan/msan_interceptors.cc38
-rw-r--r--lib/msan/tests/msan_test.cc29
3 files changed, 67 insertions, 11 deletions
diff --git a/lib/msan/msan.h b/lib/msan/msan.h
index fe7f20ae..51fa2ebb 100644
--- a/lib/msan/msan.h
+++ b/lib/msan/msan.h
@@ -25,11 +25,12 @@
# define MSAN_REPLACE_OPERATORS_NEW_AND_DELETE 1
#endif
-#define MEM_TO_SHADOW(mem) (((uptr)mem) & ~0x400000000000ULL)
-#define MEM_TO_ORIGIN(mem) (MEM_TO_SHADOW(mem) + 0x200000000000ULL)
-#define MEM_IS_APP(mem) ((uptr)mem >= 0x600000000000ULL)
-#define MEM_IS_SHADOW(mem) ((uptr)mem >= 0x200000000000ULL && \
- (uptr)mem <= 0x400000000000ULL)
+#define MEM_TO_SHADOW(mem) (((uptr)mem) & ~0x400000000000ULL)
+#define SHADOW_TO_ORIGIN(shadow) (((uptr)shadow) + 0x200000000000ULL)
+#define MEM_TO_ORIGIN(mem) (SHADOW_TO_ORIGIN(MEM_TO_SHADOW(mem)))
+#define MEM_IS_APP(mem) ((uptr)mem >= 0x600000000000ULL)
+#define MEM_IS_SHADOW(mem) \
+ ((uptr)mem >= 0x200000000000ULL && (uptr)mem <= 0x400000000000ULL)
const int kMsanParamTlsSizeInWords = 100;
const int kMsanRetvalTlsSizeInWords = 100;
diff --git a/lib/msan/msan_interceptors.cc b/lib/msan/msan_interceptors.cc
index c200e6c5..849949d3 100644
--- a/lib/msan/msan_interceptors.cc
+++ b/lib/msan/msan_interceptors.cc
@@ -1278,15 +1278,41 @@ void __msan_clear_and_unpoison(void *a, uptr size) {
fast_memset((void*)MEM_TO_SHADOW((uptr)a), 0, size);
}
+u32 get_origin_if_poisoned(uptr a, uptr size) {
+ unsigned char *s = (unsigned char *)MEM_TO_SHADOW(a);
+ for (uptr i = 0; i < size; ++i)
+ if (s[i])
+ return *(uptr *)SHADOW_TO_ORIGIN((s + i) & ~3UL);
+ return 0;
+}
+
void __msan_copy_origin(void *dst, const void *src, uptr size) {
if (!__msan_get_track_origins()) return;
if (!MEM_IS_APP(dst) || !MEM_IS_APP(src)) return;
- uptr d = MEM_TO_ORIGIN(dst);
- uptr s = MEM_TO_ORIGIN(src);
- uptr beg = d & ~3UL; // align down.
- uptr end = (d + size + 3) & ~3UL; // align up.
- s = s & ~3UL; // align down.
- fast_memcpy((void*)beg, (void*)s, end - beg);
+ uptr d = (uptr)dst;
+ uptr beg = d & ~3UL;
+ // Copy left unaligned origin if that memory is poisoned.
+ if (beg < d) {
+ u32 o = get_origin_if_poisoned(beg, d - beg);
+ if (o)
+ *(uptr *)MEM_TO_ORIGIN(beg) = o;
+ beg += 4;
+ }
+
+ uptr end = (d + size + 3) & ~3UL;
+ // Copy right unaligned origin if that memory is poisoned.
+ if (end > d + size) {
+ u32 o = get_origin_if_poisoned(d + size, end - d - size);
+ if (o)
+ *(uptr *)MEM_TO_ORIGIN(end - 4) = o;
+ end -= 4;
+ }
+
+ if (beg < end) {
+ // Align src up.
+ uptr s = ((uptr)src + 3) & ~3UL;
+ fast_memcpy((void*)MEM_TO_ORIGIN(beg), (void*)MEM_TO_ORIGIN(s), end - beg);
+ }
}
void __msan_copy_poison(void *dst, const void *src, uptr size) {
diff --git a/lib/msan/tests/msan_test.cc b/lib/msan/tests/msan_test.cc
index fcb5fc81..f185a31d 100644
--- a/lib/msan/tests/msan_test.cc
+++ b/lib/msan/tests/msan_test.cc
@@ -1210,6 +1210,35 @@ TEST(MemorySanitizer, memcpy) {
EXPECT_POISONED(y[1]);
}
+void TestUnalignedMemcpy(int left, int right, bool src_is_aligned) {
+ const int sz = 20;
+ char *dst = (char *)malloc(sz);
+ U4 origin = __msan_get_origin(dst);
+
+ char *src = (char *)malloc(sz);
+ memset(src, 0, sz);
+
+ memcpy(dst + left, src_is_aligned ? src + left : src, sz - left - right);
+ for (int i = 0; i < left; ++i)
+ EXPECT_POISONED_O(dst[i], origin);
+ for (int i = 0; i < right; ++i)
+ EXPECT_POISONED_O(dst[sz - i - 1], origin);
+ EXPECT_NOT_POISONED(dst[left]);
+ EXPECT_NOT_POISONED(dst[sz - right - 1]);
+
+ free(dst);
+ free(src);
+}
+
+TEST(MemorySanitizer, memcpy_unaligned) {
+ for (int i = 0; i < 4; ++i) {
+ for (int j = 0; j < 4; ++j) {
+ TestUnalignedMemcpy(i, j, true);
+ TestUnalignedMemcpy(i, j, false);
+ }
+ }
+}
+
TEST(MemorySanitizer, memmove) {
char* x = new char[2];
char* y = new char[2];