1 // Copyright 2019 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 // A binary that exits via different modes: crashes, causes violation, exits
16 // normally or times out, to test the stack tracing symbolizer.
17
18 #include <syscall.h>
19 #include <unistd.h>
20
21 #include <cstdlib>
22
23 #include "absl/base/attributes.h"
24 #include "absl/strings/numbers.h"
25 #include "sandboxed_api/sandbox2/testcases/symbolize_lib.h"
26 #include "sandboxed_api/util/raw_logging.h"
27
28 // Sometimes we don't have debug info to properly unwind through libc (a frame
29 // is skipped).
30 // Workaround by putting another frame on the call stack.
31 template <typename F>
IndirectLibcCall(F func)32 ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL void IndirectLibcCall(
33 F func) {
34 func();
35 }
36
37 ABSL_ATTRIBUTE_NOINLINE
CrashMe(char x=0)38 void CrashMe(char x = 0) {
39 volatile char* null = nullptr;
40 *null = x;
41 }
42
43 ABSL_ATTRIBUTE_NOINLINE
44 ABSL_ATTRIBUTE_NO_TAIL_CALL
ViolatePolicy(int x=0)45 void ViolatePolicy(int x = 0) {
46 IndirectLibcCall([x]() { syscall(__NR_ptrace, x); });
47 }
48
49 ABSL_ATTRIBUTE_NOINLINE
50 ABSL_ATTRIBUTE_NO_TAIL_CALL
ExitNormally(int x=0)51 void ExitNormally(int x = 0) {
52 IndirectLibcCall([x]() {
53 // _exit is marked noreturn, which makes stack traces a bit trickier -
54 // work around by using a volatile read
55 volatile int y = 1;
56 if (y) {
57 _exit(x);
58 }
59 });
60 }
61
62 ABSL_ATTRIBUTE_NOINLINE
63 ABSL_ATTRIBUTE_NO_TAIL_CALL
SleepForXSeconds(int x=0)64 void SleepForXSeconds(int x = 0) {
65 IndirectLibcCall([x]() { sleep(x); });
66 }
67
68 ABSL_ATTRIBUTE_NOINLINE
69 ABSL_ATTRIBUTE_NO_TAIL_CALL
RunTest(int testno)70 void RunTest(int testno) {
71 switch (testno) {
72 case 1:
73 CrashMe();
74 break;
75 case 2:
76 ViolatePolicy();
77 break;
78 case 3:
79 ExitNormally();
80 break;
81 case 4:
82 SleepForXSeconds(10);
83 break;
84 case 5: {
85 constexpr int kMaxForks = 16;
86 for (int i = 0; i < kMaxForks; ++i) {
87 if (fork() == 0) {
88 if (i == kMaxForks - 1) {
89 ViolatePolicy();
90 }
91 break;
92 }
93 }
94 SleepForXSeconds(10);
95 break;
96 }
97 default:
98 SAPI_RAW_LOG(FATAL, "Unknown test case: %d", testno);
99 }
100 }
101
102 ABSL_ATTRIBUTE_NOINLINE
103 ABSL_ATTRIBUTE_NO_TAIL_CALL
104 void RecurseA(int testno, int n);
105
106 ABSL_ATTRIBUTE_NOINLINE
107 ABSL_ATTRIBUTE_NO_TAIL_CALL
RecurseB(int testno,int n)108 void RecurseB(int testno, int n) {
109 if (n > 1) {
110 return RecurseA(testno, n - 1);
111 }
112 return RunTest(testno);
113 }
114
RecurseA(int testno,int n)115 void RecurseA(int testno, int n) {
116 if (n > 1) {
117 return RecurseB(testno, n - 1);
118 }
119 return RunTest(testno);
120 }
121
main(int argc,char * argv[])122 int main(int argc, char* argv[]) {
123 SAPI_RAW_CHECK(argc >= 3, "Not enough arguments");
124 int testno;
125 int testmode;
126 SAPI_RAW_CHECK(absl::SimpleAtoi(argv[1], &testno), "testno not a number");
127 SAPI_RAW_CHECK(absl::SimpleAtoi(argv[2], &testmode), "testmode not a number");
128 switch (testmode) {
129 case 1:
130 RunTest(testno);
131 break;
132 case 2:
133 RecurseA(testno, 10);
134 break;
135 case 3:
136 LibRecurse(&RunTest, testno, 10);
137 break;
138 default:
139 SAPI_RAW_LOG(FATAL, "Unknown test mode: %d", testmode);
140 }
141 return EXIT_SUCCESS;
142 }
143