1*ec63e07aSXin Li // Copyright 2019 Google LLC
2*ec63e07aSXin Li //
3*ec63e07aSXin Li // Licensed under the Apache License, Version 2.0 (the "License");
4*ec63e07aSXin Li // you may not use this file except in compliance with the License.
5*ec63e07aSXin Li // You may obtain a copy of the License at
6*ec63e07aSXin Li //
7*ec63e07aSXin Li // https://www.apache.org/licenses/LICENSE-2.0
8*ec63e07aSXin Li //
9*ec63e07aSXin Li // Unless required by applicable law or agreed to in writing, software
10*ec63e07aSXin Li // distributed under the License is distributed on an "AS IS" BASIS,
11*ec63e07aSXin Li // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*ec63e07aSXin Li // See the License for the specific language governing permissions and
13*ec63e07aSXin Li // limitations under the License.
14*ec63e07aSXin Li
15*ec63e07aSXin Li #include "sandboxed_api/sandbox2/unwind/unwind.h"
16*ec63e07aSXin Li
17*ec63e07aSXin Li #include <cxxabi.h>
18*ec63e07aSXin Li #include <sys/ptrace.h>
19*ec63e07aSXin Li #include <sys/types.h>
20*ec63e07aSXin Li
21*ec63e07aSXin Li #include <cerrno>
22*ec63e07aSXin Li #include <cstdint>
23*ec63e07aSXin Li #include <cstdlib>
24*ec63e07aSXin Li #include <map>
25*ec63e07aSXin Li #include <memory>
26*ec63e07aSXin Li #include <string>
27*ec63e07aSXin Li #include <utility>
28*ec63e07aSXin Li #include <vector>
29*ec63e07aSXin Li
30*ec63e07aSXin Li #include "absl/cleanup/cleanup.h"
31*ec63e07aSXin Li #include "absl/status/status.h"
32*ec63e07aSXin Li #include "absl/status/statusor.h"
33*ec63e07aSXin Li #include "absl/strings/match.h"
34*ec63e07aSXin Li #include "absl/strings/str_cat.h"
35*ec63e07aSXin Li #include "absl/strings/string_view.h"
36*ec63e07aSXin Li //#include "libunwind-ptrace.h" Android: libunwind was removed in aosp/1670175
37*ec63e07aSXin Li #include "sandboxed_api/config.h"
38*ec63e07aSXin Li #include "sandboxed_api/sandbox2/comms.h"
39*ec63e07aSXin Li #include "sandboxed_api/sandbox2/unwind/ptrace_hook.h"
40*ec63e07aSXin Li #include "sandboxed_api/sandbox2/unwind/unwind.pb.h"
41*ec63e07aSXin Li #include "sandboxed_api/sandbox2/util/maps_parser.h"
42*ec63e07aSXin Li #include "sandboxed_api/sandbox2/util/minielf.h"
43*ec63e07aSXin Li #include "sandboxed_api/util/file_helpers.h"
44*ec63e07aSXin Li #include "sandboxed_api/util/raw_logging.h"
45*ec63e07aSXin Li #include "sandboxed_api/util/status_macros.h"
46*ec63e07aSXin Li
47*ec63e07aSXin Li namespace sandbox2 {
48*ec63e07aSXin Li namespace {
49*ec63e07aSXin Li
DemangleSymbol(const std::string & maybe_mangled)50*ec63e07aSXin Li std::string DemangleSymbol(const std::string& maybe_mangled) {
51*ec63e07aSXin Li int status;
52*ec63e07aSXin Li size_t length;
53*ec63e07aSXin Li std::unique_ptr<char, decltype(&std::free)> symbol(
54*ec63e07aSXin Li abi::__cxa_demangle(maybe_mangled.c_str(), /*output_buffer=*/nullptr,
55*ec63e07aSXin Li &length, &status),
56*ec63e07aSXin Li std::free);
57*ec63e07aSXin Li if (symbol && status == 0) {
58*ec63e07aSXin Li return std::string(symbol.get(), length);
59*ec63e07aSXin Li }
60*ec63e07aSXin Li return maybe_mangled;
61*ec63e07aSXin Li }
62*ec63e07aSXin Li
ReadMemory(pid_t pid,uintptr_t addr)63*ec63e07aSXin Li absl::StatusOr<uintptr_t> ReadMemory(pid_t pid, uintptr_t addr) {
64*ec63e07aSXin Li errno = 0;
65*ec63e07aSXin Li uintptr_t val = ptrace(PTRACE_PEEKDATA, pid, addr, 0);
66*ec63e07aSXin Li if (errno != 0) {
67*ec63e07aSXin Li return absl::ErrnoToStatus(errno, "ptrace() failed");
68*ec63e07aSXin Li }
69*ec63e07aSXin Li return val;
70*ec63e07aSXin Li }
71*ec63e07aSXin Li
UnwindUsingFramePointer(pid_t pid,int max_frames,uintptr_t fp)72*ec63e07aSXin Li absl::StatusOr<std::vector<uintptr_t>> UnwindUsingFramePointer(pid_t pid,
73*ec63e07aSXin Li int max_frames,
74*ec63e07aSXin Li uintptr_t fp) {
75*ec63e07aSXin Li #if defined(SAPI_PPC64_LE)
76*ec63e07aSXin Li constexpr int kIPOffset = 2;
77*ec63e07aSXin Li #else
78*ec63e07aSXin Li constexpr int kIPOffset = 1;
79*ec63e07aSXin Li #endif
80*ec63e07aSXin Li std::vector<uintptr_t> ips;
81*ec63e07aSXin Li for (int i = 0; fp != 0 && i < max_frames; ++i) {
82*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(uintptr_t ip,
83*ec63e07aSXin Li ReadMemory(pid, fp + kIPOffset * sizeof(void*)));
84*ec63e07aSXin Li ips.push_back(ip);
85*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(fp, ReadMemory(pid, fp));
86*ec63e07aSXin Li }
87*ec63e07aSXin Li return ips;
88*ec63e07aSXin Li }
89*ec63e07aSXin Li
90*ec63e07aSXin Li #if 0 // Android: libunwind is not available
91*ec63e07aSXin Li absl::StatusOr<std::vector<uintptr_t>> RunLibUnwind(pid_t pid, int max_frames) {
92*ec63e07aSXin Li static unw_addr_space_t as =
93*ec63e07aSXin Li unw_create_addr_space(&_UPT_accessors, 0 /* byte order */);
94*ec63e07aSXin Li if (as == nullptr) {
95*ec63e07aSXin Li return absl::InternalError("unw_create_addr_space() failed");
96*ec63e07aSXin Li }
97*ec63e07aSXin Li
98*ec63e07aSXin Li void* context = _UPT_create(pid);
99*ec63e07aSXin Li if (context == nullptr) {
100*ec63e07aSXin Li return absl::InternalError("_UPT_create() failed");
101*ec63e07aSXin Li }
102*ec63e07aSXin Li absl::Cleanup context_cleanup = [&context] { _UPT_destroy(context); };
103*ec63e07aSXin Li
104*ec63e07aSXin Li unw_cursor_t cursor;
105*ec63e07aSXin Li if (int rc = unw_init_remote(&cursor, as, context); rc < 0) {
106*ec63e07aSXin Li // Could be UNW_EINVAL (8), UNW_EUNSPEC (1) or UNW_EBADREG (3).
107*ec63e07aSXin Li return absl::InternalError(
108*ec63e07aSXin Li absl::StrCat("unw_init_remote() failed with error ", rc));
109*ec63e07aSXin Li }
110*ec63e07aSXin Li std::vector<uintptr_t> ips;
111*ec63e07aSXin Li for (int i = 0; i < max_frames; ++i) {
112*ec63e07aSXin Li unw_word_t ip;
113*ec63e07aSXin Li unw_word_t fp = 0;
114*ec63e07aSXin Li int rc = unw_get_reg(&cursor, UNW_REG_IP, &ip);
115*ec63e07aSXin Li if (rc < 0) {
116*ec63e07aSXin Li // Could be UNW_EUNSPEC or UNW_EBADREG.
117*ec63e07aSXin Li SAPI_RAW_LOG(WARNING, "unw_get_reg() failed with error %d", rc);
118*ec63e07aSXin Li break;
119*ec63e07aSXin Li }
120*ec63e07aSXin Li #if defined(SAPI_ARM64)
121*ec63e07aSXin Li constexpr int kFpReg = UNW_AARCH64_X29;
122*ec63e07aSXin Li #elif defined(SAPI_ARM)
123*ec63e07aSXin Li constexpr int kFpReg = UNW_ARM_R11;
124*ec63e07aSXin Li #elif defined(SAPI_X86_64)
125*ec63e07aSXin Li constexpr int kFpReg = UNW_X86_64_RBP;
126*ec63e07aSXin Li #elif defined(SAPI_PPC64_LE)
127*ec63e07aSXin Li constexpr int kFpReg = UNW_PPC64_R1;
128*ec63e07aSXin Li #endif
129*ec63e07aSXin Li rc = unw_get_reg(&cursor, kFpReg, &fp);
130*ec63e07aSXin Li if (rc < 0) {
131*ec63e07aSXin Li SAPI_RAW_LOG(WARNING, "unw_get_reg() failed with error %d", rc);
132*ec63e07aSXin Li }
133*ec63e07aSXin Li ips.push_back(ip);
134*ec63e07aSXin Li rc = unw_step(&cursor);
135*ec63e07aSXin Li if (rc <= 0) {
136*ec63e07aSXin Li if (rc < 0) {
137*ec63e07aSXin Li SAPI_RAW_LOG(WARNING, "unw_step() failed with error %d", rc);
138*ec63e07aSXin Li }
139*ec63e07aSXin Li if (fp != 0) {
140*ec63e07aSXin Li SAPI_RAW_LOG(INFO, "Falling back to frame based unwinding at FP: %lx",
141*ec63e07aSXin Li fp);
142*ec63e07aSXin Li absl::StatusOr<std::vector<uintptr_t>> fp_ips =
143*ec63e07aSXin Li UnwindUsingFramePointer(pid, max_frames - ips.size(), fp);
144*ec63e07aSXin Li if (!fp_ips.ok()) {
145*ec63e07aSXin Li SAPI_RAW_LOG(WARNING, "FP based unwinding failed: %s",
146*ec63e07aSXin Li std::string(fp_ips.status().message()).c_str());
147*ec63e07aSXin Li break;
148*ec63e07aSXin Li }
149*ec63e07aSXin Li ips.insert(ips.end(), fp_ips->begin(), fp_ips->end());
150*ec63e07aSXin Li }
151*ec63e07aSXin Li break;
152*ec63e07aSXin Li }
153*ec63e07aSXin Li }
154*ec63e07aSXin Li return ips;
155*ec63e07aSXin Li }
156*ec63e07aSXin Li #endif
157*ec63e07aSXin Li
SymbolizeStacktrace(pid_t pid,const std::vector<uintptr_t> & ips)158*ec63e07aSXin Li absl::StatusOr<std::vector<std::string>> SymbolizeStacktrace(
159*ec63e07aSXin Li pid_t pid, const std::vector<uintptr_t>& ips) {
160*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(auto addr_to_symbol, LoadSymbolsMap(pid));
161*ec63e07aSXin Li std::vector<std::string> stack_trace;
162*ec63e07aSXin Li stack_trace.reserve(ips.size());
163*ec63e07aSXin Li // Symbolize stacktrace
164*ec63e07aSXin Li for (uintptr_t ip : ips) {
165*ec63e07aSXin Li const std::string symbol =
166*ec63e07aSXin Li GetSymbolAt(addr_to_symbol, static_cast<uint64_t>(ip));
167*ec63e07aSXin Li stack_trace.push_back(absl::StrCat(symbol, "(0x", absl::Hex(ip), ")"));
168*ec63e07aSXin Li }
169*ec63e07aSXin Li return stack_trace;
170*ec63e07aSXin Li }
171*ec63e07aSXin Li
172*ec63e07aSXin Li } // namespace
173*ec63e07aSXin Li
GetSymbolAt(const SymbolMap & addr_to_symbol,uint64_t addr)174*ec63e07aSXin Li std::string GetSymbolAt(const SymbolMap& addr_to_symbol, uint64_t addr) {
175*ec63e07aSXin Li auto entry_for_next_symbol = addr_to_symbol.lower_bound(addr);
176*ec63e07aSXin Li if (entry_for_next_symbol != addr_to_symbol.end() &&
177*ec63e07aSXin Li entry_for_next_symbol != addr_to_symbol.begin()) {
178*ec63e07aSXin Li // Matches the addr exactly:
179*ec63e07aSXin Li if (entry_for_next_symbol->first == addr) {
180*ec63e07aSXin Li return DemangleSymbol(entry_for_next_symbol->second);
181*ec63e07aSXin Li }
182*ec63e07aSXin Li
183*ec63e07aSXin Li // Might be inside a function, return symbol+offset;
184*ec63e07aSXin Li const auto entry_for_previous_symbol = --entry_for_next_symbol;
185*ec63e07aSXin Li if (!entry_for_previous_symbol->second.empty()) {
186*ec63e07aSXin Li return absl::StrCat(DemangleSymbol(entry_for_previous_symbol->second),
187*ec63e07aSXin Li "+0x",
188*ec63e07aSXin Li absl::Hex(addr - entry_for_previous_symbol->first));
189*ec63e07aSXin Li }
190*ec63e07aSXin Li }
191*ec63e07aSXin Li return "";
192*ec63e07aSXin Li }
193*ec63e07aSXin Li
LoadSymbolsMap(pid_t pid)194*ec63e07aSXin Li absl::StatusOr<SymbolMap> LoadSymbolsMap(pid_t pid) {
195*ec63e07aSXin Li const std::string maps_filename = absl::StrCat("/proc/", pid, "/maps");
196*ec63e07aSXin Li std::string maps_content;
197*ec63e07aSXin Li SAPI_RETURN_IF_ERROR(sapi::file::GetContents(maps_filename, &maps_content,
198*ec63e07aSXin Li sapi::file::Defaults()));
199*ec63e07aSXin Li
200*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(std::vector<MapsEntry> maps,
201*ec63e07aSXin Li ParseProcMaps(maps_content));
202*ec63e07aSXin Li
203*ec63e07aSXin Li // Get symbols for each file entry in the maps entry.
204*ec63e07aSXin Li // This is not a very efficient way, so we might want to optimize it.
205*ec63e07aSXin Li SymbolMap addr_to_symbol;
206*ec63e07aSXin Li for (const MapsEntry& entry : maps) {
207*ec63e07aSXin Li if (!entry.is_executable ||
208*ec63e07aSXin Li entry.inode == 0 || // Only parse file-backed entries
209*ec63e07aSXin Li entry.path.empty() ||
210*ec63e07aSXin Li absl::EndsWith(entry.path, " (deleted)") // Skip deleted files
211*ec63e07aSXin Li ) {
212*ec63e07aSXin Li continue;
213*ec63e07aSXin Li }
214*ec63e07aSXin Li
215*ec63e07aSXin Li // Store details about start + end of this map.
216*ec63e07aSXin Li // The maps entries are ordered and thus sorted with increasing adresses.
217*ec63e07aSXin Li // This means if there is a symbol @ entry.end, it will be overwritten in
218*ec63e07aSXin Li // the next iteration.
219*ec63e07aSXin Li std::string map = absl::StrCat("map:", entry.path);
220*ec63e07aSXin Li if (entry.pgoff) {
221*ec63e07aSXin Li absl::StrAppend(&map, "+0x", absl::Hex(entry.pgoff));
222*ec63e07aSXin Li }
223*ec63e07aSXin Li addr_to_symbol[entry.start] = map;
224*ec63e07aSXin Li addr_to_symbol[entry.end] = "";
225*ec63e07aSXin Li
226*ec63e07aSXin Li absl::StatusOr<ElfFile> elf =
227*ec63e07aSXin Li ElfFile::ParseFromFile(entry.path, ElfFile::kLoadSymbols);
228*ec63e07aSXin Li if (!elf.ok()) {
229*ec63e07aSXin Li SAPI_RAW_LOG(WARNING, "Could not load symbols for %s: %s",
230*ec63e07aSXin Li entry.path.c_str(),
231*ec63e07aSXin Li std::string(elf.status().message()).c_str());
232*ec63e07aSXin Li continue;
233*ec63e07aSXin Li }
234*ec63e07aSXin Li
235*ec63e07aSXin Li for (const ElfFile::Symbol& symbol : elf->symbols()) {
236*ec63e07aSXin Li // Skip Mapping Symbols on ARM
237*ec63e07aSXin Li // ARM documentation for Mapping Symbols:
238*ec63e07aSXin Li // https://developer.arm.com/documentation/dui0803/a/Accessing-and-managing-symbols-with-armlink/About-mapping-symbols
239*ec63e07aSXin Li if constexpr (sapi::host_cpu::IsArm64() || sapi::host_cpu::IsArm()) {
240*ec63e07aSXin Li if (absl::StartsWith(symbol.name, "$x") ||
241*ec63e07aSXin Li absl::StartsWith(symbol.name, "$d") ||
242*ec63e07aSXin Li absl::StartsWith(symbol.name, "$t") ||
243*ec63e07aSXin Li absl::StartsWith(symbol.name, "$a") ||
244*ec63e07aSXin Li absl::StartsWith(symbol.name, "$v")) {
245*ec63e07aSXin Li continue;
246*ec63e07aSXin Li }
247*ec63e07aSXin Li }
248*ec63e07aSXin Li
249*ec63e07aSXin Li if (elf->position_independent()) {
250*ec63e07aSXin Li if (symbol.address >= entry.pgoff &&
251*ec63e07aSXin Li symbol.address - entry.pgoff < entry.end - entry.start) {
252*ec63e07aSXin Li addr_to_symbol[symbol.address + entry.start - entry.pgoff] =
253*ec63e07aSXin Li symbol.name;
254*ec63e07aSXin Li }
255*ec63e07aSXin Li } else {
256*ec63e07aSXin Li if (symbol.address >= entry.start && symbol.address < entry.end) {
257*ec63e07aSXin Li addr_to_symbol[symbol.address] = symbol.name;
258*ec63e07aSXin Li }
259*ec63e07aSXin Li }
260*ec63e07aSXin Li }
261*ec63e07aSXin Li }
262*ec63e07aSXin Li return addr_to_symbol;
263*ec63e07aSXin Li }
264*ec63e07aSXin Li
RunLibUnwindAndSymbolizer(Comms * comms)265*ec63e07aSXin Li bool RunLibUnwindAndSymbolizer(Comms* comms) {
266*ec63e07aSXin Li UnwindSetup setup;
267*ec63e07aSXin Li if (!comms->RecvProtoBuf(&setup)) {
268*ec63e07aSXin Li return false;
269*ec63e07aSXin Li }
270*ec63e07aSXin Li int mem_fd;
271*ec63e07aSXin Li if (!comms->RecvFD(&mem_fd)) {
272*ec63e07aSXin Li return false;
273*ec63e07aSXin Li }
274*ec63e07aSXin Li
275*ec63e07aSXin Li EnablePtraceEmulationWithUserRegs(setup.pid(), setup.regs(), mem_fd);
276*ec63e07aSXin Li
277*ec63e07aSXin Li absl::StatusOr<std::vector<std::string>> stack_trace =
278*ec63e07aSXin Li RunLibUnwindAndSymbolizer(setup.pid(), setup.default_max_frames());
279*ec63e07aSXin Li
280*ec63e07aSXin Li if (!comms->SendStatus(stack_trace.status())) {
281*ec63e07aSXin Li return false;
282*ec63e07aSXin Li }
283*ec63e07aSXin Li
284*ec63e07aSXin Li if (!stack_trace.ok()) {
285*ec63e07aSXin Li return true;
286*ec63e07aSXin Li }
287*ec63e07aSXin Li
288*ec63e07aSXin Li UnwindResult msg;
289*ec63e07aSXin Li *msg.mutable_stacktrace() = {stack_trace->begin(), stack_trace->end()};
290*ec63e07aSXin Li return comms->SendProtoBuf(msg);
291*ec63e07aSXin Li }
292*ec63e07aSXin Li
293*ec63e07aSXin Li #if 0
294*ec63e07aSXin Li absl::StatusOr<std::vector<std::string>> RunLibUnwindAndSymbolizer(
295*ec63e07aSXin Li pid_t pid, int max_frames) {
296*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(std::vector<uintptr_t> ips,
297*ec63e07aSXin Li RunLibUnwind(pid, max_frames));
298*ec63e07aSXin Li return SymbolizeStacktrace(pid, ips);
299*ec63e07aSXin Li }
300*ec63e07aSXin Li #endif
301*ec63e07aSXin Li
302*ec63e07aSXin Li } // namespace sandbox2
303