From ccf03c13ebfae7dec60e28c9a07decc78a43549a Mon Sep 17 00:00:00 2001 From: Tobias Sargeant Date: Fri, 24 Feb 2017 19:58:13 +0000 Subject: Improve stack sanitization unittests. Rather than relying on the process stack having all the things that should/shouldn't be sanitized, create synthetic stacks to test all of the important cases. BUG=664460 Change-Id: I959266390e94d6fb83ca8ef11ac19fac89e68c31 Reviewed-on: https://chromium-review.googlesource.com/446108 Reviewed-by: Robert Sesek --- .../linux_ptrace_dumper_unittest.cc | 115 +++++++++++++-------- 1 file changed, 70 insertions(+), 45 deletions(-) (limited to 'src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc') diff --git a/src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc b/src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc index d693df32..2ef1c494 100644 --- a/src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc +++ b/src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc @@ -490,58 +490,83 @@ TEST_F(LinuxPtraceDumperTest, SanitizeStackCopy) { ThreadInfo thread_info; EXPECT_TRUE(dumper.GetThreadInfoByIndex(0, &thread_info)); - const void* stack; - size_t stack_len; - EXPECT_TRUE(dumper.GetStackInfo(&stack, &stack_len, thread_info.stack_pointer)); - - uint8_t* stack_copy = new uint8_t[stack_len]; - dumper.CopyFromProcess(stack_copy, child_pid, stack, stack_len); - - size_t stack_offset = - thread_info.stack_pointer - reinterpret_cast(stack); - - const size_t word_count = (stack_len - stack_offset) / sizeof(uintptr_t); - uintptr_t* stack_words = new uintptr_t[word_count]; - - memcpy(stack_words, stack_copy + stack_offset, word_count * sizeof(uintptr_t)); - std::map pre_sanitization_words; - for (size_t i = 0; i < word_count; ++i) - ++pre_sanitization_words[stack_words[i]]; - - dumper.SanitizeStackCopy(stack_copy, stack_len, thread_info.stack_pointer, - stack_offset); + const uintptr_t defaced = +#if defined(__LP64__) + 0x0defaced0defaced; +#else + 0x0defaced; +#endif - // Memory below the stack pointer should be zeroed. - for (size_t i = 0; i < stack_offset; ++i) { - ASSERT_EQ(0, stack_copy[i]); + uintptr_t simulated_stack[2]; + + // Pointers into the stack shouldn't be sanitized. + memset(simulated_stack, 0xff, sizeof(simulated_stack)); + simulated_stack[1] = thread_info.stack_pointer; + dumper.SanitizeStackCopy(reinterpret_cast(&simulated_stack), + sizeof(simulated_stack), thread_info.stack_pointer, + sizeof(uintptr_t)); + ASSERT_NE(simulated_stack[1], defaced); + + // Memory prior to the stack pointer should be cleared. + ASSERT_EQ(simulated_stack[0], 0u); + + // Small integers should not be sanitized. + for (int i = -4096; i <= 4096; ++i) { + memset(simulated_stack, 0, sizeof(simulated_stack)); + simulated_stack[0] = static_cast(i); + dumper.SanitizeStackCopy(reinterpret_cast(&simulated_stack), + sizeof(simulated_stack), thread_info.stack_pointer, + 0u); + ASSERT_NE(simulated_stack[0], defaced); } - memcpy(stack_words, stack_copy + stack_offset, word_count * sizeof(uintptr_t)); - std::map post_sanitization_words; - for (size_t i = 0; i < word_count; ++i) - ++post_sanitization_words[stack_words[i]]; - - std::set words; - for (auto &word : pre_sanitization_words) words.insert(word.first); - for (auto &word : post_sanitization_words) words.insert(word.first); - - for (auto word : words) { - if (word == static_cast(0X0DEFACED0DEFACEDull)) { - continue; - } - - bool should_be_sanitized = true; - if (static_cast(word) <= 4096 && - static_cast(word) >= -4096) should_be_sanitized = false; - if (dumper.FindMappingNoBias(word)) should_be_sanitized = false; - - ASSERT_EQ(should_be_sanitized, post_sanitization_words[word] == 0); - } + // The instruction pointer definitely should point into an executable mapping. + const MappingInfo* mapping_info = dumper.FindMappingNoBias( + reinterpret_cast(thread_info.GetInstructionPointer())); + ASSERT_NE(mapping_info, nullptr); + ASSERT_TRUE(mapping_info->exec); + + // Pointers to code shouldn't be sanitized. + memset(simulated_stack, 0, sizeof(simulated_stack)); + simulated_stack[1] = thread_info.GetInstructionPointer(); + dumper.SanitizeStackCopy(reinterpret_cast(&simulated_stack), + sizeof(simulated_stack), thread_info.stack_pointer, + 0u); + ASSERT_NE(simulated_stack[0], defaced); + + // String fragments should be sanitized. + memcpy(simulated_stack, "abcdefghijklmnop", sizeof(simulated_stack)); + dumper.SanitizeStackCopy(reinterpret_cast(&simulated_stack), + sizeof(simulated_stack), thread_info.stack_pointer, + 0u); + ASSERT_EQ(simulated_stack[0], defaced); + ASSERT_EQ(simulated_stack[1], defaced); + + // Heap pointers should be sanititzed. +#if defined(__ARM_EABI__) + uintptr_t heap_addr = thread_info.regs.uregs[3]; +#elif defined(__aarch64__) + uintptr_t heap_addr = thread_info.regs.regs[3]; +#elif defined(__i386) + uintptr_t heap_addr = thread_info.regs.ecx; +#elif defined(__x86_64) + uintptr_t heap_addr = thread_info.regs.rcx; +#elif defined(__mips__) + uintptr_t heap_addr = thread_info.mcontext.gregs[1]; +#else +#error This test has not been ported to this platform. +#endif + memset(simulated_stack, 0, sizeof(simulated_stack)); + simulated_stack[0] = heap_addr; + dumper.SanitizeStackCopy(reinterpret_cast(&simulated_stack), + sizeof(simulated_stack), thread_info.stack_pointer, + 0u); + ASSERT_EQ(simulated_stack[0], defaced); EXPECT_TRUE(dumper.ThreadsResume()); kill(child_pid, SIGKILL); - // Reap child + // Reap child. int status; ASSERT_NE(-1, HANDLE_EINTR(waitpid(child_pid, &status, 0))); ASSERT_TRUE(WIFSIGNALED(status)); -- cgit v1.2.1