1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "gtest/gtest.h"
18 
19 #include <signal.h>
20 #include <sys/ptrace.h>
21 #include <sys/types.h>
22 #include <sys/wait.h>
23 #include <unistd.h>
24 
25 namespace {
26 
27 class ScopedSigKill {
28  public:
ScopedSigKill(pid_t p)29   ScopedSigKill(pid_t p) : pid_(p) {}
~ScopedSigKill()30   ~ScopedSigKill() { kill(pid_, SIGKILL); }
31 
32  private:
33   pid_t pid_;
34 };
35 
PrepareTracee()36 pid_t PrepareTracee() {
37   pid_t child_pid = fork();
38   if (child_pid == 0) {
39     // Child.
40     ptrace(PTRACE_TRACEME, 0, 0, 0);
41     raise(SIGSTOP);
42     exit(0);
43   }
44   // Parent waits for child to stop.
45   int status;
46   EXPECT_GE(waitpid(child_pid, &status, 0), 0);
47   EXPECT_TRUE(WIFSTOPPED(status));
48   EXPECT_EQ(WSTOPSIG(status), SIGSTOP);
49   if (testing::Test::HasFatalFailure()) {
50     kill(child_pid, SIGKILL);
51   }
52   return child_pid;
53 }
54 
55 }  // namespace
56 
TEST(Ptrace,PeekPokeData)57 TEST(Ptrace, PeekPokeData) {
58   long data = 0xfeed;
59   pid_t child_pid;
60   ASSERT_NO_FATAL_FAILURE({ child_pid = PrepareTracee(); });
61   // Asserts may exit early, make sure we always kill the child.
62   ScopedSigKill scoped_sig_kill(child_pid);
63 
64   // Clobber data in parent.
65   data = 0xdead;
66   // Child still has the original value.
67   ASSERT_EQ(ptrace(PTRACE_PEEKDATA, child_pid, &data, 0), 0xfeed);
68   // Update the value.
69   ASSERT_EQ(ptrace(PTRACE_POKEDATA, child_pid, &data, 0xabcd), 0);
70   // Observe the updated value.
71   ASSERT_EQ(ptrace(PTRACE_PEEKDATA, child_pid, &data, 0), 0xabcd);
72 }
73 
TEST(Ptrace,SetOptions)74 TEST(Ptrace, SetOptions) {
75   pid_t child_pid;
76   ASSERT_NO_FATAL_FAILURE({ child_pid = PrepareTracee(); });
77   // Asserts may exit early, make sure we always kill the child.
78   ScopedSigKill scoped_sig_kill(child_pid);
79 
80   ASSERT_EQ(ptrace(PTRACE_SETOPTIONS, child_pid, nullptr, 0), 0);
81 }
82