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 <linux/sched.h>
20 #include <sched.h>
21 #include <sys/wait.h>
22 
23 #include <atomic>
24 #include <csignal>
25 #include <cstdlib>
26 
27 #include "berberis/ndk_program_tests/scoped_sigaction.h"
28 
29 namespace {
30 
31 constexpr size_t kChildStack = 1024;
32 
33 bool g_parent_handler_called;
34 bool g_child_handler_called;
35 bool g_grandchild_handler_called;
36 
VerifySignalHandler(bool * flag)37 void VerifySignalHandler(bool* flag) {
38   *flag = false;
39   raise(SIGPWR);
40   ASSERT_TRUE(*flag);
41 }
42 
43 template <size_t kStackSize, typename Runner>
CloneVMAndWait(Runner runner,int extra_flags,int expect_return)44 void CloneVMAndWait(Runner runner, int extra_flags, int expect_return) {
45   void* child_stack[kStackSize];
46   pid_t tid = clone(runner, &child_stack[kStackSize], CLONE_VM | extra_flags, nullptr);
47   int status;
48   ASSERT_EQ(tid, TEMP_FAILURE_RETRY(waitpid(tid, &status, __WCLONE)));
49   ASSERT_TRUE(WIFEXITED(status));
50   ASSERT_EQ(WEXITSTATUS(status), expect_return);
51 }
52 
SharedSighandRunner(void *)53 int SharedSighandRunner(void*) {
54   // Grandchild shared handlers with child.
55   VerifySignalHandler(&g_child_handler_called);
56   struct sigaction sa {
57     .sa_handler = +[](int) { g_grandchild_handler_called = true; }
58   };
59   // We intentionally do not restore sigaction to verify that this change
60   // will also change the handler in child (parent of grandchild).
61   EXPECT_EQ(sigaction(SIGPWR, &sa, nullptr), 0);
62   VerifySignalHandler(&g_grandchild_handler_called);
63   return 21;
64 }
65 
UnsharedSighandRunner(void *)66 int UnsharedSighandRunner(void*) {
67   // Child inherits a copy of parent handlers.
68   VerifySignalHandler(&g_parent_handler_called);
69   struct sigaction sa {
70     .sa_handler = +[](int) { g_child_handler_called = true; }
71   };
72   // We intentionally do not restore sigaction to verify that this change
73   // doesn't affect signal handlers in parent.
74   EXPECT_EQ(sigaction(SIGPWR, &sa, nullptr), 0);
75   VerifySignalHandler(&g_child_handler_called);
76   // Now clone with shared handlers.
77   CloneVMAndWait<kChildStack>(SharedSighandRunner, CLONE_SIGHAND, 21);
78   VerifySignalHandler(&g_grandchild_handler_called);
79   return 42;
80 }
81 
TEST(Clone,CloneVMSighandSharing)82 TEST(Clone, CloneVMSighandSharing) {
83   struct sigaction sa {
84     .sa_handler = +[](int) { g_parent_handler_called = true; }
85   };
86   ScopedSigaction scoped_sa(SIGPWR, &sa);
87   // Clone a child with non-shared signal handlers.
88   // Note that child's stack contains grandchild's stack, so should be larger.
89   CloneVMAndWait<kChildStack * 2>(UnsharedSighandRunner, 0, 42);
90   // Verify that children didn't alter parent's signal handlers.
91   VerifySignalHandler(&g_parent_handler_called);
92 }
93 
94 // We cannot accurately detect when grandchild stack can be free'd. So
95 // we just keep it in a global variable and never free.
96 void* g_grandchild_stack[kChildStack];
97 std::atomic<bool> g_child_finished;
98 std::atomic<bool> g_grandchild_finished;
99 
WaitUntilParentExitsAndVerifySignalHandlers(void *)100 int WaitUntilParentExitsAndVerifySignalHandlers(void*) {
101   while (!g_child_finished) {
102     sched_yield();
103   }
104 
105   // Grandchild shares handlers with child and should still
106   // be able to use them after child terminated.
107   VerifySignalHandler(&g_child_handler_called);
108 
109   g_grandchild_finished = true;
110   return 0;
111 }
112 
CloneOutlivingChild(void *)113 int CloneOutlivingChild(void*) {
114   struct sigaction sa {
115     .sa_handler = +[](int) { g_child_handler_called = true; }
116   };
117   EXPECT_EQ(sigaction(SIGPWR, &sa, nullptr), 0);
118 
119   clone(WaitUntilParentExitsAndVerifySignalHandlers,
120         &g_grandchild_stack[kChildStack],
121         CLONE_VM | CLONE_SIGHAND,
122         nullptr);
123   return 42;
124 }
125 
TEST(Clone,CloneVMChildOutlivingParent)126 TEST(Clone, CloneVMChildOutlivingParent) {
127   // We'll test grandchild outliving child.
128   g_child_finished = false;
129   g_grandchild_finished = false;
130 
131   CloneVMAndWait<kChildStack>(CloneOutlivingChild, 0, 42);
132 
133   g_child_finished = true;
134 
135   // Wait for grandchild to finish.
136   while (!g_grandchild_finished) {
137     sched_yield();
138   }
139 }
140 
141 }  // namespace
142