16c34c2576eb241f134431b2cc847a6c7d70ef012Steve Fung/* 26c34c2576eb241f134431b2cc847a6c7d70ef012Steve Fung * Copyright (C) 2012 The Android Open Source Project 36c34c2576eb241f134431b2cc847a6c7d70ef012Steve Fung * 46c34c2576eb241f134431b2cc847a6c7d70ef012Steve Fung * Licensed under the Apache License, Version 2.0 (the "License"); 56c34c2576eb241f134431b2cc847a6c7d70ef012Steve Fung * you may not use this file except in compliance with the License. 66c34c2576eb241f134431b2cc847a6c7d70ef012Steve Fung * You may obtain a copy of the License at 76c34c2576eb241f134431b2cc847a6c7d70ef012Steve Fung * 86c34c2576eb241f134431b2cc847a6c7d70ef012Steve Fung * http://www.apache.org/licenses/LICENSE-2.0 96c34c2576eb241f134431b2cc847a6c7d70ef012Steve Fung * 106c34c2576eb241f134431b2cc847a6c7d70ef012Steve Fung * Unless required by applicable law or agreed to in writing, software 116c34c2576eb241f134431b2cc847a6c7d70ef012Steve Fung * distributed under the License is distributed on an "AS IS" BASIS, 126c34c2576eb241f134431b2cc847a6c7d70ef012Steve Fung * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136c34c2576eb241f134431b2cc847a6c7d70ef012Steve Fung * See the License for the specific language governing permissions and 146c34c2576eb241f134431b2cc847a6c7d70ef012Steve Fung * limitations under the License. 156c34c2576eb241f134431b2cc847a6c7d70ef012Steve Fung */ 160340316050044e0995b98fea87ed41ea77abb28bKen Mixter 17129bea543b7572bfdf09c6a7b3cebbe3b57ce723Steve Fung#include "crash_collector.h" 180340316050044e0995b98fea87ed41ea77abb28bKen Mixter 1904ec10fc93b08057657503559ecf511661b55c9fKen Mixter#include <dirent.h> 209b346474538a255bc7144ae358bb0ee129163d58Ken Mixter#include <fcntl.h> // For file creation modes. 217589aff9f0410512168914bda2d7640649858066Alex Vakulenko#include <inttypes.h> 22f3811f50c8783b24607c776844a3cf66c15c439fBen Chan#include <linux/limits.h> // PATH_MAX 230340316050044e0995b98fea87ed41ea77abb28bKen Mixter#include <pwd.h> // For struct passwd. 240340316050044e0995b98fea87ed41ea77abb28bKen Mixter#include <sys/types.h> // for mode_t. 259b346474538a255bc7144ae358bb0ee129163d58Ken Mixter#include <sys/wait.h> // For waitpid. 269b346474538a255bc7144ae358bb0ee129163d58Ken Mixter#include <unistd.h> // For execv and fork. 270340316050044e0995b98fea87ed41ea77abb28bKen Mixter 28ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter#include <set> 297e77690375bc8a896a8de318d69d515e67c7aefeBen Chan#include <utility> 30f70060c5e610ed0aa648dcb6aaea5d859834b8baSimon Que#include <vector> 31ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter 32ab6cc90503ca2db976a3cb9c9382a9da85c4b5a2Ben Chan#include <base/files/file_util.h> 337e77690375bc8a896a8de318d69d515e67c7aefeBen Chan#include <base/logging.h> 347e77690375bc8a896a8de318d69d515e67c7aefeBen Chan#include <base/posix/eintr_wrapper.h> 357e77690375bc8a896a8de318d69d515e67c7aefeBen Chan#include <base/strings/string_split.h> 367e77690375bc8a896a8de318d69d515e67c7aefeBen Chan#include <base/strings/string_util.h> 377e77690375bc8a896a8de318d69d515e67c7aefeBen Chan#include <base/strings/stringprintf.h> 3874dc62460b8cdd5bfeac47bfe8e759fc04b55ef8Alex Vakulenko#include <brillo/key_value_store.h> 3974dc62460b8cdd5bfeac47bfe8e759fc04b55ef8Alex Vakulenko#include <brillo/process.h> 400340316050044e0995b98fea87ed41ea77abb28bKen Mixter 41731da3379bd7ead7222b1a7add45e307bec7c865Daniel Eratnamespace { 42731da3379bd7ead7222b1a7add45e307bec7c865Daniel Erat 43731da3379bd7ead7222b1a7add45e307bec7c865Daniel Eratconst char kCollectChromeFile[] = 444fe30db1405498dd21162436eda081486f400fa8Michael Krebs "/mnt/stateful_partition/etc/collect_chrome_crashes"; 450e8746d895dedf0d8e286d8168d11f67d36cb233Steve Fungconst char kCrashTestInProgressPath[] = 460e8746d895dedf0d8e286d8168d11f67d36cb233Steve Fung "/data/misc/crash_reporter/tmp/crash-test-in-progress"; 47731da3379bd7ead7222b1a7add45e307bec7c865Daniel Eratconst char kDefaultLogConfig[] = "/etc/crash_reporter_logs.conf"; 48731da3379bd7ead7222b1a7add45e307bec7c865Daniel Eratconst char kDefaultUserName[] = "chronos"; 490e8746d895dedf0d8e286d8168d11f67d36cb233Steve Fungconst char kLeaveCoreFile[] = "/data/misc/crash_reporter/.leave_core"; 500e8746d895dedf0d8e286d8168d11f67d36cb233Steve Fungconst char kShellPath[] = "/system/bin/sh"; 51ab2ac7d11442975f700bbde5702a96d020d82254Steve Fungconst char kSystemCrashPath[] = "/data/misc/crash_reporter/crash"; 52731da3379bd7ead7222b1a7add45e307bec7c865Daniel Eratconst char kUploadVarPrefix[] = "upload_var_"; 53731da3379bd7ead7222b1a7add45e307bec7c865Daniel Eratconst char kUploadFilePrefix[] = "upload_file_"; 54731da3379bd7ead7222b1a7add45e307bec7c865Daniel Erat 55f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger// Normally this path is not used. Unfortunately, there are a few edge cases 56f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger// where we need this. Any process that runs as kDefaultUserName that crashes 57f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger// is consider a "user crash". That includes the initial Chrome browser that 58f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger// runs the login screen. If that blows up, there is no logged in user yet, 59f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger// so there is no per-user dir for us to stash things in. Instead we fallback 60f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger// to this path as it is at least encrypted on a per-system basis. 61f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger// 62f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger// This also comes up when running autotests. The GUI is sitting at the login 63f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger// screen while tests are sshing in, changing users, and triggering crashes as 64f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger// the user (purposefully). 65731da3379bd7ead7222b1a7add45e307bec7c865Daniel Eratconst char kFallbackUserCrashPath[] = "/home/chronos/crash"; 660340316050044e0995b98fea87ed41ea77abb28bKen Mixter 670340316050044e0995b98fea87ed41ea77abb28bKen Mixter// Directory mode of the user crash spool directory. 68731da3379bd7ead7222b1a7add45e307bec7c865Daniel Eratconst mode_t kUserCrashPathMode = 0755; 690340316050044e0995b98fea87ed41ea77abb28bKen Mixter 700340316050044e0995b98fea87ed41ea77abb28bKen Mixter// Directory mode of the system crash spool directory. 71731da3379bd7ead7222b1a7add45e307bec7c865Daniel Eratconst mode_t kSystemCrashPathMode = 01755; 72731da3379bd7ead7222b1a7add45e307bec7c865Daniel Erat 73731da3379bd7ead7222b1a7add45e307bec7c865Daniel Eratconst uid_t kRootOwner = 0; 74731da3379bd7ead7222b1a7add45e307bec7c865Daniel Eratconst uid_t kRootGroup = 0; 750340316050044e0995b98fea87ed41ea77abb28bKen Mixter 76731da3379bd7ead7222b1a7add45e307bec7c865Daniel Erat} // namespace 770340316050044e0995b98fea87ed41ea77abb28bKen Mixter 78da5db7a8304e22af6c57733460516857e9211b32Ken Mixter// Maximum crash reports per crash spool directory. Note that this is 79da5db7a8304e22af6c57733460516857e9211b32Ken Mixter// a separate maximum from the maximum rate at which we upload these 80da5db7a8304e22af6c57733460516857e9211b32Ken Mixter// diagnostics. The higher this rate is, the more space we allow for 81da5db7a8304e22af6c57733460516857e9211b32Ken Mixter// core files, minidumps, and kcrash logs, and equivalently the more 82da5db7a8304e22af6c57733460516857e9211b32Ken Mixter// processor and I/O bandwidth we dedicate to handling these crashes when 83da5db7a8304e22af6c57733460516857e9211b32Ken Mixter// many occur at once. Also note that if core files are configured to 84da5db7a8304e22af6c57733460516857e9211b32Ken Mixter// be left on the file system, we stop adding crashes when either the 85da5db7a8304e22af6c57733460516857e9211b32Ken Mixter// number of core files or minidumps reaches this number. 86da5db7a8304e22af6c57733460516857e9211b32Ken Mixterconst int CrashCollector::kMaxCrashDirectorySize = 32; 8704ec10fc93b08057657503559ecf511661b55c9fKen Mixter 889f90acaa4d420530d7b4ddd37112518df68e373aSimon Queusing base::FilePath; 89a557c1187ff19d422db2a9c951ecd8f7243e79bdMike Frysingerusing base::StringPrintf; 909f90acaa4d420530d7b4ddd37112518df68e373aSimon Que 91afcf80821c57a189b53b7a66f76d13855d63821eKen MixterCrashCollector::CrashCollector() 928ed101bab5d01b1ab0c648586c1d5259404b79c4Steve Fung : log_config_path_(kDefaultLogConfig) { 930340316050044e0995b98fea87ed41ea77abb28bKen Mixter} 940340316050044e0995b98fea87ed41ea77abb28bKen Mixter 950340316050044e0995b98fea87ed41ea77abb28bKen MixterCrashCollector::~CrashCollector() { 960340316050044e0995b98fea87ed41ea77abb28bKen Mixter} 970340316050044e0995b98fea87ed41ea77abb28bKen Mixter 980340316050044e0995b98fea87ed41ea77abb28bKen Mixtervoid CrashCollector::Initialize( 990340316050044e0995b98fea87ed41ea77abb28bKen Mixter CrashCollector::CountCrashFunction count_crash_function, 100a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter CrashCollector::IsFeedbackAllowedFunction is_feedback_allowed_function) { 101262d798b380a59ef691ede4c6a32aa71ff191295Ben Chan CHECK(count_crash_function); 102262d798b380a59ef691ede4c6a32aa71ff191295Ben Chan CHECK(is_feedback_allowed_function); 1030340316050044e0995b98fea87ed41ea77abb28bKen Mixter 1040340316050044e0995b98fea87ed41ea77abb28bKen Mixter count_crash_function_ = count_crash_function; 1050340316050044e0995b98fea87ed41ea77abb28bKen Mixter is_feedback_allowed_function_ = is_feedback_allowed_function; 1060340316050044e0995b98fea87ed41ea77abb28bKen Mixter} 1070340316050044e0995b98fea87ed41ea77abb28bKen Mixter 1089b346474538a255bc7144ae358bb0ee129163d58Ken Mixterint CrashCollector::WriteNewFile(const FilePath &filename, 1099b346474538a255bc7144ae358bb0ee129163d58Ken Mixter const char *data, 1109b346474538a255bc7144ae358bb0ee129163d58Ken Mixter int size) { 1119b346474538a255bc7144ae358bb0ee129163d58Ken Mixter int fd = HANDLE_EINTR(open(filename.value().c_str(), 1129b346474538a255bc7144ae358bb0ee129163d58Ken Mixter O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0666)); 1139b346474538a255bc7144ae358bb0ee129163d58Ken Mixter if (fd < 0) { 1149b346474538a255bc7144ae358bb0ee129163d58Ken Mixter return -1; 1159b346474538a255bc7144ae358bb0ee129163d58Ken Mixter } 1169b346474538a255bc7144ae358bb0ee129163d58Ken Mixter 117859ee45cd2d9feb5e937c0c06f9e6c230979136eAlex Vakulenko int rv = base::WriteFileDescriptor(fd, data, size) ? size : -1; 118f1a5014637180457af21cc40a5ca64ab18a6947bMike Frysinger IGNORE_EINTR(close(fd)); 1199b346474538a255bc7144ae358bb0ee129163d58Ken Mixter return rv; 1209b346474538a255bc7144ae358bb0ee129163d58Ken Mixter} 1219b346474538a255bc7144ae358bb0ee129163d58Ken Mixter 122ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixterstd::string CrashCollector::Sanitize(const std::string &name) { 1239895096f8b8046456bec96292f9c547b11913248Thiemo Nagel // Make sure the sanitized name does not include any periods. 1249895096f8b8046456bec96292f9c547b11913248Thiemo Nagel // The logic in crash_sender relies on this. 125ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter std::string result = name; 126ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter for (size_t i = 0; i < name.size(); ++i) { 127ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter if (!isalnum(result[i]) && result[i] != '_') 128ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter result[i] = '_'; 129ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter } 130ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter return result; 131ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter} 132ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter 1330340316050044e0995b98fea87ed41ea77abb28bKen Mixterstd::string CrashCollector::FormatDumpBasename(const std::string &exec_name, 1340340316050044e0995b98fea87ed41ea77abb28bKen Mixter time_t timestamp, 1350340316050044e0995b98fea87ed41ea77abb28bKen Mixter pid_t pid) { 1360340316050044e0995b98fea87ed41ea77abb28bKen Mixter struct tm tm; 1370340316050044e0995b98fea87ed41ea77abb28bKen Mixter localtime_r(×tamp, &tm); 138ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter std::string sanitized_exec_name = Sanitize(exec_name); 1390340316050044e0995b98fea87ed41ea77abb28bKen Mixter return StringPrintf("%s.%04d%02d%02d.%02d%02d%02d.%d", 140ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter sanitized_exec_name.c_str(), 1410340316050044e0995b98fea87ed41ea77abb28bKen Mixter tm.tm_year + 1900, 1420340316050044e0995b98fea87ed41ea77abb28bKen Mixter tm.tm_mon + 1, 1430340316050044e0995b98fea87ed41ea77abb28bKen Mixter tm.tm_mday, 1440340316050044e0995b98fea87ed41ea77abb28bKen Mixter tm.tm_hour, 1450340316050044e0995b98fea87ed41ea77abb28bKen Mixter tm.tm_min, 1460340316050044e0995b98fea87ed41ea77abb28bKen Mixter tm.tm_sec, 1470340316050044e0995b98fea87ed41ea77abb28bKen Mixter pid); 1480340316050044e0995b98fea87ed41ea77abb28bKen Mixter} 1490340316050044e0995b98fea87ed41ea77abb28bKen Mixter 150207694d3f491ef602a859c30cc1379584f2d61cfKen MixterFilePath CrashCollector::GetCrashPath(const FilePath &crash_directory, 151207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter const std::string &basename, 152207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter const std::string &extension) { 153207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter return crash_directory.Append(StringPrintf("%s.%s", 154207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter basename.c_str(), 155207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter extension.c_str())); 156207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter} 157207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter 1580340316050044e0995b98fea87ed41ea77abb28bKen MixterFilePath CrashCollector::GetCrashDirectoryInfo( 1590340316050044e0995b98fea87ed41ea77abb28bKen Mixter mode_t *mode, 1600340316050044e0995b98fea87ed41ea77abb28bKen Mixter uid_t *directory_owner, 1610340316050044e0995b98fea87ed41ea77abb28bKen Mixter gid_t *directory_group) { 162ab2ac7d11442975f700bbde5702a96d020d82254Steve Fung *mode = kSystemCrashPathMode; 163ab2ac7d11442975f700bbde5702a96d020d82254Steve Fung *directory_owner = kRootOwner; 164ab2ac7d11442975f700bbde5702a96d020d82254Steve Fung *directory_group = kRootGroup; 165ab2ac7d11442975f700bbde5702a96d020d82254Steve Fung return FilePath(kSystemCrashPath); 1660340316050044e0995b98fea87ed41ea77abb28bKen Mixter} 1670340316050044e0995b98fea87ed41ea77abb28bKen Mixter 1680340316050044e0995b98fea87ed41ea77abb28bKen Mixterbool CrashCollector::GetUserInfoFromName(const std::string &name, 1690340316050044e0995b98fea87ed41ea77abb28bKen Mixter uid_t *uid, 1700340316050044e0995b98fea87ed41ea77abb28bKen Mixter gid_t *gid) { 1710340316050044e0995b98fea87ed41ea77abb28bKen Mixter char storage[256]; 1720340316050044e0995b98fea87ed41ea77abb28bKen Mixter struct passwd passwd_storage; 173262d798b380a59ef691ede4c6a32aa71ff191295Ben Chan struct passwd *passwd_result = nullptr; 1740340316050044e0995b98fea87ed41ea77abb28bKen Mixter 1750340316050044e0995b98fea87ed41ea77abb28bKen Mixter if (getpwnam_r(name.c_str(), &passwd_storage, storage, sizeof(storage), 176262d798b380a59ef691ede4c6a32aa71ff191295Ben Chan &passwd_result) != 0 || passwd_result == nullptr) { 177a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter LOG(ERROR) << "Cannot find user named " << name; 1780340316050044e0995b98fea87ed41ea77abb28bKen Mixter return false; 1790340316050044e0995b98fea87ed41ea77abb28bKen Mixter } 1800340316050044e0995b98fea87ed41ea77abb28bKen Mixter 1810340316050044e0995b98fea87ed41ea77abb28bKen Mixter *uid = passwd_result->pw_uid; 1820340316050044e0995b98fea87ed41ea77abb28bKen Mixter *gid = passwd_result->pw_gid; 1830340316050044e0995b98fea87ed41ea77abb28bKen Mixter return true; 1840340316050044e0995b98fea87ed41ea77abb28bKen Mixter} 1850340316050044e0995b98fea87ed41ea77abb28bKen Mixter 1860340316050044e0995b98fea87ed41ea77abb28bKen Mixterbool CrashCollector::GetCreatedCrashDirectoryByEuid(uid_t euid, 187207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter FilePath *crash_directory, 188207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter bool *out_of_capacity) { 189262d798b380a59ef691ede4c6a32aa71ff191295Ben Chan if (out_of_capacity) *out_of_capacity = false; 190207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter 1910340316050044e0995b98fea87ed41ea77abb28bKen Mixter // For testing. 1929b1f300139689eb9c7b7a35e91a4fbc1eab93b4eLei Zhang if (!forced_crash_directory_.empty()) { 1939b1f300139689eb9c7b7a35e91a4fbc1eab93b4eLei Zhang *crash_directory = forced_crash_directory_; 1940340316050044e0995b98fea87ed41ea77abb28bKen Mixter return true; 1950340316050044e0995b98fea87ed41ea77abb28bKen Mixter } 1960340316050044e0995b98fea87ed41ea77abb28bKen Mixter 1970340316050044e0995b98fea87ed41ea77abb28bKen Mixter mode_t directory_mode; 1980340316050044e0995b98fea87ed41ea77abb28bKen Mixter uid_t directory_owner; 1990340316050044e0995b98fea87ed41ea77abb28bKen Mixter gid_t directory_group; 2000340316050044e0995b98fea87ed41ea77abb28bKen Mixter *crash_directory = 201ab2ac7d11442975f700bbde5702a96d020d82254Steve Fung GetCrashDirectoryInfo(&directory_mode, 2020340316050044e0995b98fea87ed41ea77abb28bKen Mixter &directory_owner, 2030340316050044e0995b98fea87ed41ea77abb28bKen Mixter &directory_group); 2040340316050044e0995b98fea87ed41ea77abb28bKen Mixter 205a557c1187ff19d422db2a9c951ecd8f7243e79bdMike Frysinger if (!base::PathExists(*crash_directory)) { 2060340316050044e0995b98fea87ed41ea77abb28bKen Mixter // Create the spool directory with the appropriate mode (regardless of 2070340316050044e0995b98fea87ed41ea77abb28bKen Mixter // umask) and ownership. 2080340316050044e0995b98fea87ed41ea77abb28bKen Mixter mode_t old_mask = umask(0); 2090340316050044e0995b98fea87ed41ea77abb28bKen Mixter if (mkdir(crash_directory->value().c_str(), directory_mode) < 0 || 2100340316050044e0995b98fea87ed41ea77abb28bKen Mixter chown(crash_directory->value().c_str(), 2110340316050044e0995b98fea87ed41ea77abb28bKen Mixter directory_owner, 2120340316050044e0995b98fea87ed41ea77abb28bKen Mixter directory_group) < 0) { 213a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter LOG(ERROR) << "Unable to create appropriate crash directory"; 2140340316050044e0995b98fea87ed41ea77abb28bKen Mixter return false; 2150340316050044e0995b98fea87ed41ea77abb28bKen Mixter } 2160340316050044e0995b98fea87ed41ea77abb28bKen Mixter umask(old_mask); 2170340316050044e0995b98fea87ed41ea77abb28bKen Mixter } 2180340316050044e0995b98fea87ed41ea77abb28bKen Mixter 219a557c1187ff19d422db2a9c951ecd8f7243e79bdMike Frysinger if (!base::PathExists(*crash_directory)) { 220a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter LOG(ERROR) << "Unable to create crash directory " 221a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter << crash_directory->value().c_str(); 2220340316050044e0995b98fea87ed41ea77abb28bKen Mixter return false; 2230340316050044e0995b98fea87ed41ea77abb28bKen Mixter } 2240340316050044e0995b98fea87ed41ea77abb28bKen Mixter 22504ec10fc93b08057657503559ecf511661b55c9fKen Mixter if (!CheckHasCapacity(*crash_directory)) { 226262d798b380a59ef691ede4c6a32aa71ff191295Ben Chan if (out_of_capacity) *out_of_capacity = true; 227ab2ac7d11442975f700bbde5702a96d020d82254Steve Fung LOG(ERROR) << "Directory " << crash_directory->value() 228ab2ac7d11442975f700bbde5702a96d020d82254Steve Fung << " is out of capacity."; 22904ec10fc93b08057657503559ecf511661b55c9fKen Mixter return false; 23004ec10fc93b08057657503559ecf511661b55c9fKen Mixter } 23104ec10fc93b08057657503559ecf511661b55c9fKen Mixter 2320340316050044e0995b98fea87ed41ea77abb28bKen Mixter return true; 2330340316050044e0995b98fea87ed41ea77abb28bKen Mixter} 23404ec10fc93b08057657503559ecf511661b55c9fKen Mixter 235426fcc0bd579a87102ea50fb570dbf9834fa2962Albert ChaulkFilePath CrashCollector::GetProcessPath(pid_t pid) { 236426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk return FilePath(StringPrintf("/proc/%d", pid)); 237426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk} 238426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk 239426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulkbool CrashCollector::GetSymlinkTarget(const FilePath &symlink, 2408563d20e108c3801f107d640c9b161f1099e6bebBen Chan FilePath *target) { 241f3811f50c8783b24607c776844a3cf66c15c439fBen Chan ssize_t max_size = 64; 242f3811f50c8783b24607c776844a3cf66c15c439fBen Chan std::vector<char> buffer; 243f3811f50c8783b24607c776844a3cf66c15c439fBen Chan 244426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk while (true) { 245f3811f50c8783b24607c776844a3cf66c15c439fBen Chan buffer.resize(max_size + 1); 246f3811f50c8783b24607c776844a3cf66c15c439fBen Chan ssize_t size = readlink(symlink.value().c_str(), buffer.data(), max_size); 247426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk if (size < 0) { 248426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk int saved_errno = errno; 249426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk LOG(ERROR) << "Readlink failed on " << symlink.value() << " with " 250426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk << saved_errno; 251426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk return false; 252426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk } 253f3811f50c8783b24607c776844a3cf66c15c439fBen Chan 254426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk buffer[size] = 0; 255426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk if (size == max_size) { 256f3811f50c8783b24607c776844a3cf66c15c439fBen Chan max_size *= 2; 257f3811f50c8783b24607c776844a3cf66c15c439fBen Chan if (max_size > PATH_MAX) { 258426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk return false; 259426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk } 260f3811f50c8783b24607c776844a3cf66c15c439fBen Chan continue; 261426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk } 262426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk break; 263426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk } 264426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk 265f3811f50c8783b24607c776844a3cf66c15c439fBen Chan *target = FilePath(buffer.data()); 266426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk return true; 267426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk} 268426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk 269426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulkbool CrashCollector::GetExecutableBaseNameFromPid(pid_t pid, 270426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk std::string *base_name) { 271426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk FilePath target; 272426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk FilePath process_path = GetProcessPath(pid); 273426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk FilePath exe_path = process_path.Append("exe"); 274426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk if (!GetSymlinkTarget(exe_path, &target)) { 275426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk LOG(INFO) << "GetSymlinkTarget failed - Path " << process_path.value() 276426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk << " DirectoryExists: " 277a557c1187ff19d422db2a9c951ecd8f7243e79bdMike Frysinger << base::DirectoryExists(process_path); 278426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk // Try to further diagnose exe readlink failure cause. 279426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk struct stat buf; 280426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk int stat_result = stat(exe_path.value().c_str(), &buf); 281426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk int saved_errno = errno; 282426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk if (stat_result < 0) { 283426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk LOG(INFO) << "stat " << exe_path.value() << " failed: " << stat_result 284426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk << " " << saved_errno; 285426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk } else { 286426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk LOG(INFO) << "stat " << exe_path.value() << " succeeded: st_mode=" 287426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk << buf.st_mode; 288426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk } 289426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk return false; 290426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk } 291426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk *base_name = target.BaseName().value(); 292426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk return true; 293426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk} 294426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk 29504ec10fc93b08057657503559ecf511661b55c9fKen Mixter// Return true if the given crash directory has not already reached 29604ec10fc93b08057657503559ecf511661b55c9fKen Mixter// maximum capacity. 29704ec10fc93b08057657503559ecf511661b55c9fKen Mixterbool CrashCollector::CheckHasCapacity(const FilePath &crash_directory) { 29804ec10fc93b08057657503559ecf511661b55c9fKen Mixter DIR* dir = opendir(crash_directory.value().c_str()); 29904ec10fc93b08057657503559ecf511661b55c9fKen Mixter if (!dir) { 300ab2ac7d11442975f700bbde5702a96d020d82254Steve Fung LOG(WARNING) << "Unable to open crash directory " 301ab2ac7d11442975f700bbde5702a96d020d82254Steve Fung << crash_directory.value(); 30204ec10fc93b08057657503559ecf511661b55c9fKen Mixter return false; 30304ec10fc93b08057657503559ecf511661b55c9fKen Mixter } 30404ec10fc93b08057657503559ecf511661b55c9fKen Mixter struct dirent ent_buf; 30504ec10fc93b08057657503559ecf511661b55c9fKen Mixter struct dirent* ent; 30604ec10fc93b08057657503559ecf511661b55c9fKen Mixter bool full = false; 307ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter std::set<std::string> basenames; 308262d798b380a59ef691ede4c6a32aa71ff191295Ben Chan while (readdir_r(dir, &ent_buf, &ent) == 0 && ent) { 30904ec10fc93b08057657503559ecf511661b55c9fKen Mixter if ((strcmp(ent->d_name, ".") == 0) || 31004ec10fc93b08057657503559ecf511661b55c9fKen Mixter (strcmp(ent->d_name, "..") == 0)) 31104ec10fc93b08057657503559ecf511661b55c9fKen Mixter continue; 31204ec10fc93b08057657503559ecf511661b55c9fKen Mixter 313ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter std::string filename(ent->d_name); 314ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter size_t last_dot = filename.rfind("."); 315ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter std::string basename; 316ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter // If there is a valid looking extension, use the base part of the 317ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter // name. If the only dot is the first byte (aka a dot file), treat 318ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter // it as unique to avoid allowing a directory full of dot files 319ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter // from accumulating. 320ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter if (last_dot != std::string::npos && last_dot != 0) 321ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter basename = filename.substr(0, last_dot); 322ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter else 323ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter basename = filename; 324ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter basenames.insert(basename); 32504ec10fc93b08057657503559ecf511661b55c9fKen Mixter 326ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter if (basenames.size() >= static_cast<size_t>(kMaxCrashDirectorySize)) { 327a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter LOG(WARNING) << "Crash directory " << crash_directory.value() 328a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter << " already full with " << kMaxCrashDirectorySize 329a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter << " pending reports"; 33004ec10fc93b08057657503559ecf511661b55c9fKen Mixter full = true; 33104ec10fc93b08057657503559ecf511661b55c9fKen Mixter break; 33204ec10fc93b08057657503559ecf511661b55c9fKen Mixter } 33304ec10fc93b08057657503559ecf511661b55c9fKen Mixter } 33404ec10fc93b08057657503559ecf511661b55c9fKen Mixter closedir(dir); 33504ec10fc93b08057657503559ecf511661b55c9fKen Mixter return !full; 33604ec10fc93b08057657503559ecf511661b55c9fKen Mixter} 337ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter 338c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixterbool CrashCollector::GetLogContents(const FilePath &config_path, 339c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter const std::string &exec_name, 340c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter const FilePath &output_file) { 34174dc62460b8cdd5bfeac47bfe8e759fc04b55ef8Alex Vakulenko brillo::KeyValueStore store; 342731da3379bd7ead7222b1a7add45e307bec7c865Daniel Erat if (!store.Load(config_path)) { 343a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter LOG(INFO) << "Unable to read log configuration file " 344a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter << config_path.value(); 345c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter return false; 346c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter } 347c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter 348731da3379bd7ead7222b1a7add45e307bec7c865Daniel Erat std::string command; 349731da3379bd7ead7222b1a7add45e307bec7c865Daniel Erat if (!store.GetString(exec_name, &command)) 350c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter return false; 351c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter 35274dc62460b8cdd5bfeac47bfe8e759fc04b55ef8Alex Vakulenko brillo::ProcessImpl diag_process; 353a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter diag_process.AddArg(kShellPath); 354731da3379bd7ead7222b1a7add45e307bec7c865Daniel Erat diag_process.AddStringOption("-c", command); 355a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter diag_process.RedirectOutput(output_file.value()); 356c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter 357731da3379bd7ead7222b1a7add45e307bec7c865Daniel Erat const int result = diag_process.Run(); 358a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter if (result != 0) { 359731da3379bd7ead7222b1a7add45e307bec7c865Daniel Erat LOG(INFO) << "Log command \"" << command << "\" exited with " << result; 360c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter return false; 361c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter } 362c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter return true; 363c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter} 364c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter 365afcf80821c57a189b53b7a66f76d13855d63821eKen Mixtervoid CrashCollector::AddCrashMetaData(const std::string &key, 366afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter const std::string &value) { 367afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter extra_metadata_.append(StringPrintf("%s=%s\n", key.c_str(), value.c_str())); 368afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter} 369afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter 37033dfd47146c14bbdf57494051fe1c1c50949305fAlbert Chaulkvoid CrashCollector::AddCrashMetaUploadFile(const std::string &key, 37133dfd47146c14bbdf57494051fe1c1c50949305fAlbert Chaulk const std::string &path) { 37233dfd47146c14bbdf57494051fe1c1c50949305fAlbert Chaulk if (!path.empty()) 37333dfd47146c14bbdf57494051fe1c1c50949305fAlbert Chaulk AddCrashMetaData(kUploadFilePrefix + key, path); 37433dfd47146c14bbdf57494051fe1c1c50949305fAlbert Chaulk} 37533dfd47146c14bbdf57494051fe1c1c50949305fAlbert Chaulk 37633dfd47146c14bbdf57494051fe1c1c50949305fAlbert Chaulkvoid CrashCollector::AddCrashMetaUploadData(const std::string &key, 37733dfd47146c14bbdf57494051fe1c1c50949305fAlbert Chaulk const std::string &value) { 37833dfd47146c14bbdf57494051fe1c1c50949305fAlbert Chaulk if (!value.empty()) 37933dfd47146c14bbdf57494051fe1c1c50949305fAlbert Chaulk AddCrashMetaData(kUploadVarPrefix + key, value); 38033dfd47146c14bbdf57494051fe1c1c50949305fAlbert Chaulk} 38133dfd47146c14bbdf57494051fe1c1c50949305fAlbert Chaulk 382ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixtervoid CrashCollector::WriteCrashMetaData(const FilePath &meta_path, 383c909b6944602bd6c1eb6d3c54ec41b1a4fc57b07Ken Mixter const std::string &exec_name, 384c909b6944602bd6c1eb6d3c54ec41b1a4fc57b07Ken Mixter const std::string &payload_path) { 385f84ea21aab3c1c6ef1f358534e5c437878675d74Ben Chan int64_t payload_size = -1; 386a557c1187ff19d422db2a9c951ecd8f7243e79bdMike Frysinger base::GetFileSize(FilePath(payload_path), &payload_size); 387afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter std::string meta_data = StringPrintf("%sexec_name=%s\n" 388207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter "payload=%s\n" 389eaf060c265f4cd84eb718b625b3670987e155a1bAlex Vakulenko "payload_size=%" PRId64 "\n" 390ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter "done=1\n", 391afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter extra_metadata_.c_str(), 392ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter exec_name.c_str(), 393207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter payload_path.c_str(), 394c909b6944602bd6c1eb6d3c54ec41b1a4fc57b07Ken Mixter payload_size); 395f30c641225e55055641ffe3fd679a96e44f34af6Ben Chan // We must use WriteNewFile instead of base::WriteFile as we 3969b346474538a255bc7144ae358bb0ee129163d58Ken Mixter // do not want to write with root access to a symlink that an attacker 3979b346474538a255bc7144ae358bb0ee129163d58Ken Mixter // might have created. 3989b346474538a255bc7144ae358bb0ee129163d58Ken Mixter if (WriteNewFile(meta_path, meta_data.c_str(), meta_data.size()) < 0) { 399a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter LOG(ERROR) << "Unable to write " << meta_path.value(); 400ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter } 401ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter} 4021652fb2cc2bc6d08ac3719fd3d90b43485d539feThieu Le 4031652fb2cc2bc6d08ac3719fd3d90b43485d539feThieu Lebool CrashCollector::IsCrashTestInProgress() { 404a557c1187ff19d422db2a9c951ecd8f7243e79bdMike Frysinger return base::PathExists(FilePath(kCrashTestInProgressPath)); 4051652fb2cc2bc6d08ac3719fd3d90b43485d539feThieu Le} 4064fe30db1405498dd21162436eda081486f400fa8Michael Krebs 4074fe30db1405498dd21162436eda081486f400fa8Michael Krebsbool CrashCollector::IsDeveloperImage() { 4084fe30db1405498dd21162436eda081486f400fa8Michael Krebs // If we're testing crash reporter itself, we don't want to special-case 4094fe30db1405498dd21162436eda081486f400fa8Michael Krebs // for developer images. 4104fe30db1405498dd21162436eda081486f400fa8Michael Krebs if (IsCrashTestInProgress()) 4114fe30db1405498dd21162436eda081486f400fa8Michael Krebs return false; 412a557c1187ff19d422db2a9c951ecd8f7243e79bdMike Frysinger return base::PathExists(FilePath(kLeaveCoreFile)); 4134fe30db1405498dd21162436eda081486f400fa8Michael Krebs} 414