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(&timestamp, &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