Rework stacktrace mounttree logic

The previous one was not quite correct in cases where the outside binary path
did not match the inside path. This should be fixed with this.

PiperOrigin-RevId: 276075886
Change-Id: I1c7c4fa0191960437a2d2360b805c7098b1407c9
This commit is contained in:
Kevin Hamacher 2019-10-22 09:05:13 -07:00 committed by Copybara-Service
parent 254abe04fe
commit 4da8f68aa8
3 changed files with 40 additions and 9 deletions

View File

@ -254,6 +254,28 @@ sapi::Status Mounts::AddDirectoryAt(absl::string_view outside,
return Insert(inside, node); return Insert(inside, node);
} }
const MountTree::Node* Mounts::GetNode(const std::string& path) const {
std::string fixed_path = file::CleanPath(path);
absl::string_view cur = fixed_path;
std::vector<std::string> parts;
while (cur != "/") {
auto split = file::SplitPath(cur);
cur = split.first;
parts.push_back(std::string(split.second));
}
const MountTree* curtree = &mount_tree_;
for (auto part = parts.rbegin(); part != parts.rend(); ++part) {
const auto& p = curtree->entries().find(*part);
if (p == curtree->entries().end()) {
return nullptr;
}
curtree = &p->second;
}
return &curtree->node();
}
namespace { namespace {
void LogContainer(const std::vector<std::string>& container) { void LogContainer(const std::vector<std::string>& container) {

View File

@ -57,6 +57,8 @@ class Mounts {
void RecursivelyListMounts(std::vector<std::string>* outside_entries, void RecursivelyListMounts(std::vector<std::string>* outside_entries,
std::vector<std::string>* inside_entries); std::vector<std::string>* inside_entries);
const MountTree::Node* GetNode(const std::string& path) const;
private: private:
friend class MountTreeTest; friend class MountTreeTest;
sapi::Status Insert(absl::string_view path, const MountTree::Node& node); sapi::Status Insert(absl::string_view path, const MountTree::Node& node);

View File

@ -19,6 +19,7 @@
#include <sys/capability.h> #include <sys/capability.h>
#include <sys/resource.h> #include <sys/resource.h>
#include <syscall.h> #include <syscall.h>
#include <memory> #include <memory>
#include <utility> #include <utility>
#include <vector> #include <vector>
@ -199,20 +200,28 @@ bool StackTracePeer::LaunchLibunwindSandbox(const Regs* regs,
} }
// Get path to the binary. // Get path to the binary.
// app_path contains the path like it is also in /proc/pid/maps. This is // app_path contains the path like it is also in /proc/pid/maps. It is
// important when the file was removed, it will have a ' (deleted)' suffix. // relative to the sandboxee's mount namespace. If it is not existing
// (anymore) it will have a ' (deleted)' suffix.
std::string app_path; std::string app_path;
// The exe_path will have a mountable path of the application, even if it was
// removed.
std::string exe_path;
std::string proc_pid_exe = file::JoinPath("/proc", absl::StrCat(pid), "exe"); std::string proc_pid_exe = file::JoinPath("/proc", absl::StrCat(pid), "exe");
if (!file_util::fileops::ReadLinkAbsolute(proc_pid_exe, &app_path)) { if (!file_util::fileops::ReadLinkAbsolute(proc_pid_exe, &app_path)) {
LOG(WARNING) << "Could not obtain absolute path to the binary"; LOG(WARNING) << "Could not obtain absolute path to the binary";
return false; return false;
} }
// Check whether the file still exists or not (SAPI). // The exe_path will have a mountable path of the application, even if it was
if (access(app_path.c_str(), F_OK) == -1) { // removed.
std::string exe_path;
// Resolve app_path backing file.
const auto* app_node = mounts.GetNode(app_path);
if (app_node) {
exe_path = app_node->file_node().outside();
}
if (exe_path.empty()) {
// File was probably removed.
LOG(WARNING) << "File was removed, using /proc/pid/exe."; LOG(WARNING) << "File was removed, using /proc/pid/exe.";
app_path = std::string(absl::StripSuffix(app_path, " (deleted)")); app_path = std::string(absl::StripSuffix(app_path, " (deleted)"));
// Create a copy of /proc/pid/exe, mount that one. // Create a copy of /proc/pid/exe, mount that one.
@ -221,8 +230,6 @@ bool StackTracePeer::LaunchLibunwindSandbox(const Regs* regs,
LOG(WARNING) << "Could not copy /proc/pid/exe"; LOG(WARNING) << "Could not copy /proc/pid/exe";
return false; return false;
} }
} else {
exe_path = app_path;
} }
VLOG(1) << "Resolved binary: " << app_path << " / " << exe_path; VLOG(1) << "Resolved binary: " << app_path << " / " << exe_path;