diff options
author | Christopher Ferris <cferris@google.com> | 2015-05-06 16:36:34 -0700 |
---|---|---|
committer | Christopher Ferris <cferris@google.com> | 2015-05-06 16:39:17 -0700 |
commit | 944f417ccb86441060ffb670b4bdc2975fda08fc (patch) | |
tree | 2b933b06b8d6b48dd0172577e75595590c5a8f27 /libbacktrace | |
parent | 8b32c30b92be6914da2dca23089473c4f37adfb9 (diff) | |
download | core-944f417ccb86441060ffb670b4bdc2975fda08fc.tar.gz core-944f417ccb86441060ffb670b4bdc2975fda08fc.tar.bz2 core-944f417ccb86441060ffb670b4bdc2975fda08fc.zip |
Fix small ptrace reads.
The BacktracePtrace::Read function crashes if the number of bytes to
read is less than the number of bytes needed to align the read to
a word_t boundary.
Fix this and add a test for this case.
Change-Id: I50808849ece44928f65dba1d25309e3885c829a2
Diffstat (limited to 'libbacktrace')
-rw-r--r-- | libbacktrace/BacktracePtrace.cpp | 13 | ||||
-rw-r--r-- | libbacktrace/backtrace_test.cpp | 38 |
2 files changed, 35 insertions, 16 deletions
diff --git a/libbacktrace/BacktracePtrace.cpp b/libbacktrace/BacktracePtrace.cpp index 613443892..e10cce12f 100644 --- a/libbacktrace/BacktracePtrace.cpp +++ b/libbacktrace/BacktracePtrace.cpp @@ -83,13 +83,12 @@ size_t BacktracePtrace::Read(uintptr_t addr, uint8_t* buffer, size_t bytes) { if (!PtraceRead(Tid(), addr & ~(sizeof(word_t) - 1), &data_word)) { return 0; } - align_bytes = sizeof(word_t) - align_bytes; - memcpy(buffer, reinterpret_cast<uint8_t*>(&data_word) + sizeof(word_t) - align_bytes, - align_bytes); - addr += align_bytes; - buffer += align_bytes; - bytes -= align_bytes; - bytes_read += align_bytes; + size_t copy_bytes = MIN(sizeof(word_t) - align_bytes, bytes); + memcpy(buffer, reinterpret_cast<uint8_t*>(&data_word) + align_bytes, copy_bytes); + addr += copy_bytes; + buffer += copy_bytes; + bytes -= copy_bytes; + bytes_read += copy_bytes; } size_t num_words = bytes / sizeof(word_t); diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp index 28d146a32..a086547dd 100644 --- a/libbacktrace/backtrace_test.cpp +++ b/libbacktrace/backtrace_test.cpp @@ -883,6 +883,17 @@ TEST(libbacktrace, verify_map_remote) { ASSERT_EQ(waitpid(pid, nullptr, 0), pid); } +void InitMemory(uint8_t* memory, size_t bytes) { + for (size_t i = 0; i < bytes; i++) { + memory[i] = i; + if (memory[i] == '\0') { + // Don't use '\0' in our data so we can verify that an overread doesn't + // occur by using a '\0' as the character after the read data. + memory[i] = 23; + } + } +} + void* ThreadReadTest(void* data) { thread_t* thread_data = reinterpret_cast<thread_t*>(data); @@ -901,9 +912,7 @@ void* ThreadReadTest(void* data) { } // Set up a simple pattern in memory. - for (size_t i = 0; i < pagesize; i++) { - memory[i] = i; - } + InitMemory(memory, pagesize); thread_data->data = memory; @@ -931,9 +940,8 @@ void RunReadTest(Backtrace* backtrace, uintptr_t read_addr) { // Create a page of data to use to do quick compares. uint8_t* expected = new uint8_t[pagesize]; - for (size_t i = 0; i < pagesize; i++) { - expected[i] = i; - } + InitMemory(expected, pagesize); + uint8_t* data = new uint8_t[2*pagesize]; // Verify that we can only read one page worth of data. size_t bytes_read = backtrace->Read(read_addr, data, 2 * pagesize); @@ -947,6 +955,20 @@ void RunReadTest(Backtrace* backtrace, uintptr_t read_addr) { ASSERT_TRUE(memcmp(data, &expected[i], 2 * sizeof(word_t)) == 0) << "Offset at " << i << " failed"; } + + // Verify small unaligned reads. + for (size_t i = 1; i < sizeof(word_t); i++) { + for (size_t j = 1; j < sizeof(word_t); j++) { + // Set one byte past what we expect to read, to guarantee we don't overread. + data[j] = '\0'; + bytes_read = backtrace->Read(read_addr + i, data, j); + ASSERT_EQ(j, bytes_read); + ASSERT_TRUE(memcmp(data, &expected[i], j) == 0) + << "Offset at " << i << " length " << j << " miscompared"; + ASSERT_EQ('\0', data[j]) + << "Offset at " << i << " length " << j << " wrote too much data"; + } + } delete data; delete expected; } @@ -990,9 +1012,7 @@ void ForkedReadTest() { } // Set up a simple pattern in memory. - for (size_t i = 0; i < pagesize; i++) { - memory[i] = i; - } + InitMemory(memory, pagesize); g_addr = reinterpret_cast<uintptr_t>(memory); g_ready = 1; |