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 <errno.h>
20 #include <pthread.h>
21 #include <semaphore.h>
22 #include <setjmp.h>
23 #include <signal.h>
24 #include <sys/mman.h>
25 #include <sys/syscall.h>
26 #include <sys/time.h>
27
28 #include <atomic>
29
30 #include "berberis/ndk_program_tests/scoped_sigaction.h"
31
32 namespace {
33
EnsureSignalsChecked()34 void EnsureSignalsChecked() {
35 // Emulated signals should be checked on return from wrapped syscall.
36 // Real signals should be checked on exit from kernel mode.
37 syscall(SYS_gettid);
38 }
39
HandleSignal(int)40 void HandleSignal(int) {
41 return;
42 }
43
TEST(Signal,SigkillSigactionFails)44 TEST(Signal, SigkillSigactionFails) {
45 struct sigaction sa {};
46 sa.sa_handler = HandleSignal;
47 ASSERT_EQ(sigaction(SIGKILL, &sa, nullptr), -1);
48 }
49
50 struct ThreadParam {
51 pthread_t self;
52 int id;
53 std::atomic_bool started;
54 std::atomic_bool stop;
55 };
56
57 const int kMaxThreads = 20;
58 ThreadParam g_params[kMaxThreads];
59
AreAllThreadsStarted()60 bool AreAllThreadsStarted() {
61 for (int i = 0; i < kMaxThreads; i++) {
62 if (!g_params[i].started) {
63 return false;
64 }
65 }
66 return true;
67 }
68
AreAllThreadsStopped()69 bool AreAllThreadsStopped() {
70 for (int i = 0; i < kMaxThreads; i++) {
71 if (!g_params[i].stop) {
72 return false;
73 }
74 }
75 return true;
76 }
77
ThreadSignalHandler(int,siginfo_t *,void *)78 void ThreadSignalHandler(int /* sig */, siginfo_t* /* info */, void* /* ctx */) {
79 pthread_t me = pthread_self();
80 for (int i = 0; i < kMaxThreads; i++) {
81 if (g_params[i].self == me) {
82 g_params[i].stop = true;
83 return;
84 }
85 }
86 }
87
ThreadRunner(void * arg)88 void* ThreadRunner(void* arg) {
89 ThreadParam* param = reinterpret_cast<ThreadParam*>(arg);
90 fprintf(stderr, "Thread %d started\n", param->id);
91 param->started = true;
92 while (!param->stop) {
93 sched_yield();
94 }
95 fprintf(stderr, "Thread %d exited\n", param->id);
96 return nullptr;
97 }
98
TEST(Signal,PthreadKillTest)99 TEST(Signal, PthreadKillTest) {
100 const int sig_num = SIGPWR;
101
102 struct sigaction sa;
103 sa.sa_flags = SA_SIGINFO;
104 sigemptyset(&sa.sa_mask);
105 sa.sa_sigaction = ThreadSignalHandler;
106 ScopedSigaction scoped_sa(sig_num, &sa);
107
108 // Initialize globals here to allow test repetition.
109 for (int i = 0; i < kMaxThreads; i++) {
110 g_params[i].id = i;
111 g_params[i].started = false;
112 g_params[i].stop = false;
113 }
114
115 for (int i = 0; i < kMaxThreads; i++) {
116 int rv = pthread_create(&g_params[i].self, nullptr, ThreadRunner, &g_params[i]);
117 ASSERT_EQ(rv, 0);
118 }
119 fprintf(stderr, "All threads created\n");
120
121 while (!AreAllThreadsStarted()) {
122 sched_yield();
123 }
124 fprintf(stderr, "All threads started\n");
125
126 // Send them a signal.
127 for (int i = 0; i < kMaxThreads; i++) {
128 int rv = pthread_kill(g_params[i].self, sig_num);
129 ASSERT_EQ(rv, 0);
130 }
131 fprintf(stderr, "All threads killed\n");
132
133 while (!AreAllThreadsStopped()) {
134 sched_yield();
135 }
136 fprintf(stderr, "All threads stopped\n");
137
138 for (int i = 0; i < kMaxThreads; i++) {
139 int rv = pthread_join(g_params[i].self, nullptr);
140 ASSERT_EQ(rv, 0);
141 }
142 fprintf(stderr, "All threads exited\n");
143 }
144
145 int* g_data_page;
146
SigsegvSignalHandler(int,siginfo_t * info,void *)147 void SigsegvSignalHandler(int /* sig */, siginfo_t* info, void* /* ctx */) {
148 fprintf(stderr, "SIGSEGV caught\n");
149 EXPECT_TRUE(SI_FROMKERNEL(info));
150 mprotect(g_data_page, 4096, PROT_WRITE);
151 }
152
TEST(Signal,Sigsegv)153 TEST(Signal, Sigsegv) {
154 g_data_page = static_cast<int*>(mmap(0, 4096, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
155
156 struct sigaction sa;
157 sa.sa_flags = SA_SIGINFO;
158 sigemptyset(&sa.sa_mask);
159 sa.sa_sigaction = SigsegvSignalHandler;
160 ScopedSigaction scoped_sa(SIGSEGV, &sa);
161
162 g_data_page[5] = 0;
163
164 munmap(g_data_page, 4096);
165 }
166
167 bool g_async_sigsegv_received = false;
168
AsyncSigsegvSignalHandler(int,siginfo_t * info,void *)169 void AsyncSigsegvSignalHandler(int /* sig */, siginfo_t* info, void* /* ctx */) {
170 fprintf(stderr, "Async SIGSEGV caught\n");
171 // si_pid must be set for signals sent by kill.
172 EXPECT_EQ(getpid(), info->si_pid);
173 EXPECT_TRUE(SI_FROMUSER(info));
174 g_async_sigsegv_received = true;
175 }
176
AsyncSigsegvSender(void * arg)177 void* AsyncSigsegvSender(void* arg) {
178 pthread_t* parent_id = static_cast<pthread_t*>(arg);
179 EXPECT_EQ(pthread_kill(*parent_id, SIGSEGV), 0);
180 return nullptr;
181 }
182
TEST(Signal,AsyncSigsegv)183 TEST(Signal, AsyncSigsegv) {
184 struct sigaction sa {};
185 sa.sa_flags = SA_SIGINFO;
186 sa.sa_sigaction = AsyncSigsegvSignalHandler;
187 ScopedSigaction scoped_sa(SIGSEGV, &sa);
188
189 g_async_sigsegv_received = false;
190 pthread_t parent_id = pthread_self();
191 pthread_t child_id;
192 ASSERT_EQ(pthread_create(&child_id, nullptr, AsyncSigsegvSender, &parent_id), 0);
193 ASSERT_EQ(pthread_join(child_id, nullptr), 0);
194 EnsureSignalsChecked();
195 ASSERT_TRUE(g_async_sigsegv_received);
196 }
197
198 // Must be valid instruction address. 0 is invalid as the compiler optimizes call(0) to UD.
199 constexpr uintptr_t kNoExecAddr = 4096;
200
201 sigjmp_buf g_recover_no_exec;
202
NoExecSignalHandler(int,siginfo_t * info,void *)203 void NoExecSignalHandler(int /* sig */, siginfo_t* info, void* /* ctx */) {
204 uintptr_t addr = reinterpret_cast<uintptr_t>(info->si_addr);
205 EXPECT_EQ(addr, kNoExecAddr);
206 longjmp(g_recover_no_exec, 1);
207 }
208
TEST(Signal,RecoverFromNoExec)209 TEST(Signal, RecoverFromNoExec) {
210 struct sigaction sa;
211 sa.sa_flags = SA_SIGINFO;
212 sigemptyset(&sa.sa_mask);
213 sa.sa_sigaction = NoExecSignalHandler;
214 ScopedSigaction scoped_sa(SIGSEGV, &sa);
215
216 if (setjmp(g_recover_no_exec) == 0) {
217 using Func = void (*)();
218 (reinterpret_cast<Func>(kNoExecAddr))();
219 // Signal handler should longjmp out!
220 FAIL();
221 }
222 }
223
224 int g_expected_signal;
225 bool g_is_received;
226
CheckExpectedSignalHandler(int signal)227 void CheckExpectedSignalHandler(int signal) {
228 ASSERT_EQ(signal, g_expected_signal);
229 g_is_received = true;
230 }
231
TEST(Signal,SigMask)232 TEST(Signal, SigMask) {
233 struct sigaction sa;
234 memset(&sa, 0, sizeof(sa));
235 sigemptyset(&sa.sa_mask);
236 sa.sa_handler = CheckExpectedSignalHandler;
237
238 // Walk signals customizable by apps. Avoid signals handled by ART.
239 const int test_signals[] = {SIGILL, SIGXCPU, SIGPWR};
240
241 for (size_t i = 0; i < sizeof(test_signals) / sizeof(test_signals[0]); ++i) {
242 int signal = test_signals[i];
243 ScopedSigaction scoped_sa(signal, &sa);
244
245 sigset_t mask;
246
247 // Block signal.
248 ASSERT_EQ(sigemptyset(&mask), 0);
249 ASSERT_EQ(sigaddset(&mask, signal), 0);
250 ASSERT_EQ(pthread_sigmask(SIG_BLOCK, &mask, nullptr), 0);
251
252 // Send signal to itself. Expect it not to be delivered.
253 // NOTE: sending SIGILL with pthread_kill when blocked is well-defined!
254 g_expected_signal = -1;
255 g_is_received = false;
256 // raise() is not supported.
257 ASSERT_EQ(pthread_kill(pthread_self(), signal), 0);
258
259 // This shouldn't trigger delivering of blocked signal.
260 EnsureSignalsChecked();
261
262 // Unblock signal and expect it to be delivered.
263 g_expected_signal = signal;
264 ASSERT_EQ(sigemptyset(&mask), 0);
265 ASSERT_EQ(pthread_sigmask(SIG_SETMASK, &mask, nullptr), 0);
266
267 // Wait until we receive it.
268 while (!g_is_received) {
269 sched_yield();
270 }
271 }
272 }
273
274 std::atomic_bool g_started;
275 std::atomic_bool g_suspend_sent;
276 std::atomic_bool g_resume_sent;
277 std::atomic_bool g_suspend_handler_visited;
278 std::atomic_bool g_resume_handler_visited;
279 int g_expected_resume_signal;
280
ResumeHandler(int signal)281 void ResumeHandler(int signal) {
282 ASSERT_EQ(signal, g_expected_resume_signal);
283 g_resume_handler_visited = true;
284 }
285
SuspendHandler(int signal)286 void SuspendHandler(int signal) {
287 ASSERT_EQ(signal, SIGPWR);
288 g_suspend_handler_visited = true;
289
290 // Check resume signal is blocked.
291 sigset_t current_mask;
292 pthread_sigmask(SIG_BLOCK, nullptr, ¤t_mask);
293 ASSERT_EQ(sigismember(¤t_mask, SIGXCPU), 1);
294
295 while (!g_resume_sent) {
296 sched_yield();
297 }
298 // Resume is sent, but should still be blocked.
299 EnsureSignalsChecked();
300
301 // Now catch signal in sigsuspend with empty mask.
302 g_expected_resume_signal = SIGXCPU;
303 sigset_t suspend_mask;
304 sigemptyset(&suspend_mask);
305 sigsuspend(&suspend_mask);
306
307 // Mask should be restored.
308 pthread_sigmask(SIG_BLOCK, nullptr, ¤t_mask);
309 ASSERT_EQ(sigismember(¤t_mask, SIGXCPU), 1);
310 }
311
WaitForSuspendRunner(void *)312 void* WaitForSuspendRunner(void* /* arg */) {
313 g_started = true;
314 while (!g_suspend_sent) {
315 sched_yield();
316 }
317 EnsureSignalsChecked();
318 return nullptr;
319 }
320
TEST(Signal,SigActionAndSuspendMasks)321 TEST(Signal, SigActionAndSuspendMasks) {
322 // Set resume sigaction.
323 struct sigaction sa;
324 memset(&sa, 0, sizeof(sa));
325 sigemptyset(&sa.sa_mask);
326 sa.sa_handler = ResumeHandler;
327 ScopedSigaction scoped_xcpu(SIGXCPU, &sa);
328
329 // Set suspend sigaction to block SIGXCPU in handler.
330 sigaddset(&sa.sa_mask, SIGXCPU);
331 sa.sa_handler = SuspendHandler;
332 ScopedSigaction scoped_pwr(SIGPWR, &sa);
333
334 g_started = false;
335 g_suspend_sent = false;
336 g_resume_sent = false;
337 g_suspend_handler_visited = false;
338 g_resume_handler_visited = false;
339 g_expected_resume_signal = -1;
340
341 // Start the second thread.
342 pthread_t child_id;
343 ASSERT_EQ(pthread_create(&child_id, nullptr, WaitForSuspendRunner, nullptr), 0);
344 while (!g_started) {
345 sched_yield();
346 }
347
348 // Direct it into suspend handler and wait while it gets there.
349 ASSERT_EQ(pthread_kill(child_id, SIGPWR), 0);
350 g_suspend_sent = true;
351 while (!g_suspend_handler_visited) {
352 sched_yield();
353 }
354
355 // Direct it further into resume handler and wait while it gets there.
356 ASSERT_EQ(pthread_kill(child_id, SIGXCPU), 0);
357 g_resume_sent = true;
358 while (!g_resume_handler_visited) {
359 sched_yield();
360 }
361 }
362
363 volatile int g_handler_counter;
364
SigActionDeferHandler(int signal)365 void SigActionDeferHandler(int signal) {
366 ASSERT_EQ(signal, SIGPWR);
367
368 static volatile bool in_handler = false;
369 ASSERT_FALSE(in_handler);
370 in_handler = true;
371
372 if (g_handler_counter++ == 0) {
373 ASSERT_EQ(pthread_kill(pthread_self(), SIGPWR), 0);
374 EnsureSignalsChecked();
375 }
376
377 in_handler = false;
378 }
379
TEST(Signal,SigActionDefer)380 TEST(Signal, SigActionDefer) {
381 // Set resume sigaction.
382 struct sigaction sa;
383 memset(&sa, 0, sizeof(sa));
384
385 g_handler_counter = 0;
386
387 // When SA_NODEFER is unset, signal in blocked in its handler.
388 ASSERT_EQ(sigemptyset(&sa.sa_mask), 0);
389 sa.sa_handler = SigActionDeferHandler;
390 ScopedSigaction scoped_sa(SIGPWR, &sa);
391
392 ASSERT_EQ(pthread_kill(pthread_self(), SIGPWR), 0);
393 // Should catch two signals: one from here and one from handler.
394 EnsureSignalsChecked();
395 EnsureSignalsChecked();
396 ASSERT_EQ(g_handler_counter, 2);
397 }
398
SigActionNoDeferHandler(int signal)399 void SigActionNoDeferHandler(int signal) {
400 ASSERT_EQ(signal, SIGPWR);
401
402 static volatile bool in_handler = false;
403 ASSERT_EQ(in_handler, (g_handler_counter == 1));
404 in_handler = true;
405
406 if (g_handler_counter++ == 0) {
407 ASSERT_EQ(pthread_kill(pthread_self(), SIGPWR), 0);
408 EnsureSignalsChecked();
409 }
410
411 // We set is to false while returning from the second handler
412 // to the first one. But it is ok, since we don't use it in
413 // the first handler anymore.
414 in_handler = false;
415 }
416
TEST(Signal,SigActionNoDefer)417 TEST(Signal, SigActionNoDefer) {
418 // Set resume sigaction.
419 struct sigaction sa;
420 memset(&sa, 0, sizeof(sa));
421
422 g_handler_counter = 0;
423
424 // Now set sigaction with SA_NODEFER.
425 sa.sa_handler = SigActionNoDeferHandler;
426 sa.sa_flags |= SA_NODEFER;
427 ScopedSigaction scoped_sa(SIGPWR, &sa);
428
429 ASSERT_EQ(pthread_kill(pthread_self(), SIGPWR), 0);
430 EnsureSignalsChecked();
431 ASSERT_EQ(g_handler_counter, 2);
432 }
433
434 sem_t g_kill_and_wait_sem;
435
KillAndSemWaitHandler(int signal)436 void KillAndSemWaitHandler(int signal) {
437 ASSERT_EQ(signal, SIGPWR);
438 // Notify parent that child is in handler.
439 ASSERT_EQ(sem_post(&g_kill_and_wait_sem), 0);
440 }
441
KillAndSemWaitRunner(void *)442 void KillAndSemWaitRunner(void* /* arg */) {
443 // Register handler
444 struct sigaction sa;
445 memset(&sa, 0, sizeof(sa));
446 ASSERT_EQ(sigemptyset(&sa.sa_mask), 0);
447 sa.sa_handler = KillAndSemWaitHandler;
448 ScopedSigaction scoped_sa(SIGPWR, &sa);
449
450 // Notify parent that child is ready to receive signals.
451 ASSERT_EQ(sem_post(&g_kill_and_wait_sem), 0);
452
453 sigset_t suspend_mask;
454 ASSERT_EQ(sigemptyset(&suspend_mask), 0);
455
456 // Ensure receiving some signals before exiting.
457 // Warning: we receive signals even outside sigsuspend!
458 for (int i = 0; i < 10; ++i) {
459 ASSERT_EQ(sigsuspend(&suspend_mask), -1);
460 ASSERT_EQ(errno, EINTR);
461 }
462 }
463
KillAndSemWaitRunnerWrapper(void * arg)464 void* KillAndSemWaitRunnerWrapper(void* arg) {
465 // Assertions cannot be used in a function that returns non-void.
466 KillAndSemWaitRunner(arg);
467 return nullptr;
468 }
469
470 // TODO(b/28014551): this test might be wrong, it seems even when pthread_kill returns 0 there is no
471 // guarantee that signal handler will be executed. For example, signal might be blocked until thread
472 // exit. Or, thread might be killed before starting the signal handler. Also, it is not clear what
473 // happens if signal arrives right when thread is going to finish.
474 // Investigate more if this test is valid or not!
TEST(Signal,DISABLED_SignalKillAndSemWaitTest)475 TEST(Signal, DISABLED_SignalKillAndSemWaitTest) {
476 sem_init(&g_kill_and_wait_sem, 0, 0);
477
478 // Start thread.
479 pthread_t child_id;
480 ASSERT_EQ(pthread_create(&child_id, nullptr, KillAndSemWaitRunnerWrapper, nullptr), 0);
481
482 // Wait for child able to receive signals.
483 ASSERT_EQ(sem_wait(&g_kill_and_wait_sem), 0);
484
485 // If signal is successfully sent, child must handle it
486 // notifying parent with semaphore.
487 while (pthread_kill(child_id, SIGPWR) == 0) {
488 ASSERT_EQ(sem_wait(&g_kill_and_wait_sem), 0);
489 }
490 }
491
492 std::atomic_bool g_is_in_loop;
493 std::atomic_bool g_is_received_in_loop;
494
495 // POSIX recommends using itimerspec instead, but we don't support it in Berberis yet.
496 constexpr itimerval kTenMillisecondIntervalTimer = itimerval{
497 // Fire after 10 millisecond initially then every 10 millisecond further on (in case we haven't
498 // entered the loop when the first signal arrived).
499 .it_interval = {.tv_sec = 0, .tv_usec = 10000},
500 .it_value = {.tv_sec = 0, .tv_usec = 10000},
501 };
502
InterruptLoopHandler(int signal)503 void InterruptLoopHandler(int signal) {
504 EXPECT_EQ(signal, SIGALRM);
505 g_is_received_in_loop = g_is_in_loop.load();
506 }
507
InterruptLoopHelper(void (* LoopRunner)())508 void InterruptLoopHelper(void (*LoopRunner)()) {
509 struct sigaction sa {};
510 sa.sa_handler = InterruptLoopHandler;
511 ScopedSigaction scoped_sa(SIGALRM, &sa);
512
513 g_is_in_loop = false;
514 g_is_received_in_loop = false;
515
516 struct itimerval old_itimer;
517 setitimer(ITIMER_REAL, &kTenMillisecondIntervalTimer, &old_itimer);
518
519 LoopRunner();
520
521 setitimer(ITIMER_REAL, &old_itimer, nullptr);
522 }
523
TEST(Signal,InterruptLoopWithinRegion)524 TEST(Signal, InterruptLoopWithinRegion) {
525 InterruptLoopHelper(+[]() {
526 while (!g_is_received_in_loop) {
527 // Keep it simple to facilitate having it in single translation region.
528 g_is_in_loop = true;
529 }
530 });
531 }
532
RegionBreaker()533 void __attribute__((noinline)) RegionBreaker() {
534 g_is_in_loop = true;
535 }
536
TEST(Signal,InterruptInterRegionLoop)537 TEST(Signal, InterruptInterRegionLoop) {
538 InterruptLoopHelper(+[]() {
539 while (!g_is_received_in_loop) {
540 // Facilitate translated regions break (due to call/return) so that the loop
541 // is not inside one region.
542 RegionBreaker();
543 }
544 });
545 }
546
547 } // namespace
548