blob: 63218aaf88e35cec129e06082152d2533edb9a4f [file] [log] [blame]
// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "crash-reporter/vm_support_proper.h"
#include <base/logging.h>
#include <base/strings/stringprintf.h>
#include <chromeos/constants/vm_tools.h>
#include <grpcpp/grpcpp.h>
#include <sys/socket.h>
#include <utility>
#include <linux/vm_sockets.h>
#include "crash-reporter/user_collector.h"
VmSupportProper::VmSupportProper() {
std::string addr = base::StringPrintf("vsock:%u:%u", VMADDR_CID_HOST,
vm_tools::kCrashListenerPort);
// It's safe to use an unencrypted/authenticated channel here because the
// whole channel exists within a single machine, and so we can rely on the
// kernel to provide us with confidentiality and integrity. Our usage of a
// vsock address guarantees this.
auto channel =
grpc::CreateChannel(std::move(addr), grpc::InsecureChannelCredentials());
stub_ = std::make_unique<vm_tools::cicerone::CrashListener::Stub>(
std::move(channel));
}
void VmSupportProper::AddMetadata(UserCollector* collector) {
// TODO(hollingum): implement me.
}
void VmSupportProper::FinishCrash(const base::FilePath& crash_meta_path) {
LOG(INFO) << "A program crashed in the VM and was logged at: "
<< crash_meta_path.value();
// TODO(hollingum): implement me.
}
bool VmSupportProper::GetMetricsConsent() {
grpc::ClientContext ctx;
vm_tools::EmptyMessage request;
vm_tools::cicerone::MetricsConsentResponse response;
grpc::Status status = stub_->CheckMetricsConsent(&ctx, request, &response);
return status.ok() && response.consent_granted();
}
bool VmSupportProper::ShouldDump(pid_t pid, std::string* out_reason) {
// Namespaces are accessed via the /proc/*/ns/* set of paths. The kernel
// guarantees that if two processes share a namespace, their corresponding
// namespace files will have the same inode number, as reported by stat.
//
// For now, we are only interested in processes in the root PID
// namespace. When invoked by the kernel in response to a crash,
// crash_reporter will be run in the root of all the namespace hierarchies, so
// we can easily check this by comparing the crashed process PID namespace
// with our own.
struct stat st;
auto namespace_path = base::StringPrintf("/proc/%d/ns/pid", pid);
if (stat(namespace_path.c_str(), &st) < 0) {
*out_reason = "failed to get process PID namespace";
return false;
}
ino_t inode = st.st_ino;
if (stat("/proc/self/ns/pid", &st) < 0) {
*out_reason = "failed to get own PID namespace";
return false;
}
ino_t self_inode = st.st_ino;
if (inode != self_inode) {
*out_reason = "ignoring - process not in root namespace";
return false;
}
return true;
}