From: Josh Gao Date: Thu, 16 Feb 2017 22:12:41 +0000 (-0800) Subject: Add tests for ptrace resumption behavior. X-Git-Tag: android-x86-8.1-r1~224^2^2^2^2 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=5e3fe9506c6021876442c70af347b3d87a5e36d9;p=android-x86%2Fbionic.git Add tests for ptrace resumption behavior. Add tests that ensure that the kernel behaves properly w.r.t. resumption of ptraced processes when the tracer dies. Bug: http://b/34516140 Test: /data/nativetest/bionic-unit-tests/bionic-unit-tests --gtest_filter="PtraceResumption*" Change-Id: Id35e069a7e5edd6964637dd3f6358ad59db19792 --- diff --git a/tests/sys_ptrace_test.cpp b/tests/sys_ptrace_test.cpp index 74837547a..8fe7a295f 100644 --- a/tests/sys_ptrace_test.cpp +++ b/tests/sys_ptrace_test.cpp @@ -17,14 +17,21 @@ #include #include +#include #include #include +#include #include #include +#include #include #include +#include + +using android::base::unique_fd; + // Host libc does not define this. #ifndef TRAP_HWBKPT #define TRAP_HWBKPT 4 @@ -313,3 +320,94 @@ TEST(sys_ptrace, hardware_breakpoint) { ASSERT_EQ(0, ptrace(PTRACE_GETSIGINFO, child, nullptr, &siginfo)) << strerror(errno); ASSERT_EQ(TRAP_HWBKPT, siginfo.si_code); } + +class PtraceResumptionTest : public ::testing::Test { + public: + pid_t worker = -1; + PtraceResumptionTest() { + } + + ~PtraceResumptionTest() { + } + + void AssertDeath(int signo); + void Start(std::function f) { + unique_fd worker_pipe_read, worker_pipe_write; + int pipefd[2]; + ASSERT_EQ(0, pipe2(pipefd, O_CLOEXEC)); + worker_pipe_read.reset(pipefd[0]); + worker_pipe_write.reset(pipefd[1]); + + worker = fork(); + ASSERT_NE(-1, worker); + if (worker == 0) { + char buf; + worker_pipe_write.reset(); + TEMP_FAILURE_RETRY(read(worker_pipe_read.get(), &buf, sizeof(buf))); + exit(0); + } + + pid_t tracer = fork(); + ASSERT_NE(-1, tracer); + if (tracer == 0) { + f(); + if (HasFatalFailure()) { + exit(1); + } + exit(0); + } + + int result; + pid_t rc = waitpid(tracer, &result, 0); + ASSERT_EQ(tracer, rc); + EXPECT_TRUE(WIFEXITED(result) || WIFSIGNALED(result)); + if (WIFEXITED(result)) { + if (WEXITSTATUS(result) != 0) { + FAIL() << "tracer failed"; + } + } + + rc = waitpid(worker, &result, WNOHANG); + ASSERT_EQ(0, rc); + + worker_pipe_write.reset(); + + rc = waitpid(worker, &result, 0); + ASSERT_EQ(worker, rc); + EXPECT_TRUE(WIFEXITED(result)); + EXPECT_EQ(WEXITSTATUS(result), 0); + } +}; + +static void wait_for_ptrace_stop(pid_t pid) { + while (true) { + int status; + pid_t rc = TEMP_FAILURE_RETRY(waitpid(pid, &status, __WALL)); + if (rc != pid) { + abort(); + } + if (WIFSTOPPED(status)) { + return; + } + } +} + +TEST_F(PtraceResumptionTest, seize) { + Start([this]() { ASSERT_EQ(0, ptrace(PTRACE_SEIZE, worker, 0, 0)) << strerror(errno); }); +} + +TEST_F(PtraceResumptionTest, seize_interrupt) { + Start([this]() { + ASSERT_EQ(0, ptrace(PTRACE_SEIZE, worker, 0, 0)) << strerror(errno); + ASSERT_EQ(0, ptrace(PTRACE_INTERRUPT, worker, 0, 0)) << strerror(errno); + }); +} + +TEST_F(PtraceResumptionTest, seize_interrupt_cont) { + Start([this]() { + ASSERT_EQ(0, ptrace(PTRACE_SEIZE, worker, 0, 0)) << strerror(errno); + ASSERT_EQ(0, ptrace(PTRACE_INTERRUPT, worker, 0, 0)) << strerror(errno); + wait_for_ptrace_stop(worker); + ASSERT_EQ(0, ptrace(PTRACE_CONT, worker, 0, 0)) << strerror(errno); + }); +}