blob: d0e8330cbc225fb25b8a1a5203dda3adf03e5df5 [file] [log] [blame]
Mike Frysingerc0871522013-09-16 14:07:27 -04001// Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Alex Vakulenko262be3f2014-07-30 15:25:50 -07005#include "debugd/src/crash_sender_tool.h"
Mike Frysingerc0871522013-09-16 14:07:27 -04006
Ian Barkley-Yeung7b7b0352019-04-23 12:52:04 -07007#include <fcntl.h>
8#include <sys/stat.h>
9#include <sys/types.h>
10#include <unistd.h>
11
12#include <memory>
13
Qijiang Fan713061e2021-03-08 15:45:12 +090014#include <base/check.h>
Ian Barkley-Yeung7b7b0352019-04-23 12:52:04 -070015#include <base/files/file.h>
16#include <base/files/file_util.h>
17#include <base/files/scoped_temp_dir.h>
18#include <base/strings/string_number_conversions.h>
Ian Barkley-Yeungc68cfc32019-07-15 16:43:57 -070019#include <brillo/dbus/exported_property_set.h>
Ian Barkley-Yeung7b7b0352019-04-23 12:52:04 -070020
21#include "debugd/src/error_utils.h"
Alex Vakulenko262be3f2014-07-30 15:25:50 -070022#include "debugd/src/process_with_id.h"
Mike Frysingerc0871522013-09-16 14:07:27 -040023
24namespace debugd {
Ian Barkley-Yeung7b7b0352019-04-23 12:52:04 -070025namespace {
26constexpr char kErrorIOError[] = "org.chromium.debugd.error.IOError";
27} // namespace
28
29constexpr char CrashSenderTool::kErrorBadFileName[];
Mike Frysingerc0871522013-09-16 14:07:27 -040030
Eric Carusoc93a15c2017-04-24 16:15:12 -070031void CrashSenderTool::UploadCrashes() {
Ian Barkley-Yeung7b7b0352019-04-23 12:52:04 -070032 RunCrashSender(false /* ignore_hold_off_time */,
33 base::FilePath("") /* crash_directory */);
34}
35
36bool CrashSenderTool::UploadSingleCrash(
37 const std::vector<std::tuple<std::string, base::ScopedFD>>& in_files,
38 brillo::ErrorPtr* error) {
39 // debugd runs in a non-root mount namespace and mounts a new tmpfs on /tmp
40 // inside the namespace, so this should be invisible to all other processes
41 // and not written to disk.
42 //
43 // *It is a privacy violation* if these files are visible to non-root
44 // processes or are written unencrypted to disk!
45 base::FilePath crash_directory("/tmp/crash");
Qijiang Fan26fd9222020-03-31 20:16:40 +090046 crash_directory = crash_directory.AddExtension(
47 base::NumberToString(next_crash_directory_id_));
Ian Barkley-Yeung7b7b0352019-04-23 12:52:04 -070048 next_crash_directory_id_++;
49
50 // We need to be sure to clean up the tmp directory to avoid leaking
51 // resources.
52 base::ScopedTempDir crash_directory_holder;
53 if (!crash_directory_holder.Set(crash_directory)) {
54 DEBUGD_ADD_ERROR(error, kErrorIOError, "Create directory failed");
55 return false;
56 }
57
58 for (const auto& in_file_tuple : in_files) {
59 base::FilePath file_name(std::get<0>(in_file_tuple));
60 const base::ScopedFD& file_descriptor = std::get<1>(in_file_tuple);
61
62 // Sanitize file names to ensure a bad actor cannot ask us to write to
63 // arbitrary files. crash_reporter should only send us the base file name,
64 // so if it's not just a base file name, it's not from crash_reporter.
65 // Also check for "..", "/", and "."
66 if (file_name != file_name.BaseName() || file_name.ReferencesParent() ||
67 file_name.IsAbsolute() ||
68 file_name.value() == base::FilePath::kCurrentDirectory) {
69 DEBUGD_ADD_ERROR(error, kErrorBadFileName, "Bad File Name");
70 return false;
71 }
72
73 // Copy contents of file_descriptor to a new file named file_name inside
74 // crash_directory.
75 base::FilePath file_path = crash_directory.Append(file_name);
76 base::File new_file(file_path,
77 base::File::FLAG_CREATE | base::File::FLAG_WRITE);
78 if (!new_file.IsValid()) {
79 LOG(WARNING) << "Error creating file " << file_path.value() << ": "
80 << base::File::ErrorToString(new_file.error_details());
81 continue;
82 }
83
84 if (lseek(file_descriptor.get(), SEEK_SET, 0) == static_cast<off_t>(-1)) {
85 PLOG(WARNING) << "lseek failed";
86 }
87 const int kBufferSize = 1 << 16;
88 std::unique_ptr<char[]> buf(new char[kBufferSize]);
89 ssize_t len;
90 while ((len = HANDLE_EINTR(
91 read(file_descriptor.get(), buf.get(), kBufferSize))) > 0) {
92 if (!new_file.WriteAtCurrentPos(buf.get(), len)) {
93 LOG(WARNING) << "Error writing to file " << file_path.value() << ": "
94 << base::File::ErrorToString(new_file.error_details());
95 break;
96 }
97 }
98
99 if (len < 0) {
100 PLOG(WARNING) << "Failed to read from passed file descriptor";
101 }
102
103 // Ensure data is visible to crash_sender.
104 new_file.Flush();
105 }
106
107 // Since crash_sender jails itself, it won't actually see our /tmp/crash.###
108 // directory. Instead, open the directory and pass the /proc path to the
109 // directory file descriptor as the crash directory.
110 base::ScopedFD crash_directory_fd(
111 HANDLE_EINTR(open(crash_directory.value().c_str(), O_RDONLY)));
112 if (!crash_directory_fd.is_valid()) {
113 DEBUGD_ADD_ERROR(error, kErrorIOError, "Open directory failed");
114 return false;
115 }
116
117 base::FilePath munged_crash_directory("/proc/self/fd");
118 munged_crash_directory = munged_crash_directory.Append(
Qijiang Fan26fd9222020-03-31 20:16:40 +0900119 base::NumberToString(crash_directory_fd.get()));
Ian Barkley-Yeung7b7b0352019-04-23 12:52:04 -0700120
121 const bool ignore_hold_off_time = true; // We already flushed all the files.
122 RunCrashSender(ignore_hold_off_time, munged_crash_directory);
123
124 return true;
125}
126
127void CrashSenderTool::RunCrashSender(bool ignore_hold_off_time,
128 const base::FilePath& crash_directory) {
Jorge Lucangeli Obes623f8ca2014-09-18 10:50:06 -0700129 // 'crash_sender' requires accessing user mounts to upload user crashes.
130 ProcessWithId* p =
131 CreateProcess(false /* sandboxed */, true /* access_root_mount_ns */);
Mike Frysingerc0871522013-09-16 14:07:27 -0400132 p->AddArg("/sbin/crash_sender");
Ian Barkley-Yeung56ea2d42019-04-08 17:23:03 -0700133 // This is being invoked directly by the user. Override some of the limits
134 // we normally use to avoid interfering with user tasks.
Satoru Takabayashid3e8a2b2019-01-18 14:46:56 +0900135 p->AddArg("--max_spread_time=0");
Ian Barkley-Yeung56ea2d42019-04-08 17:23:03 -0700136 p->AddArg("--ignore_rate_limits");
Ian Barkley-Yeung7b7b0352019-04-23 12:52:04 -0700137
138 if (ignore_hold_off_time) {
139 p->AddArg("--ignore_hold_off_time");
140 }
141
142 if (!crash_directory.empty()) {
143 p->AddArg("--crash_directory=" + crash_directory.value());
144 }
145
Ian Barkley-Yeungc68cfc32019-07-15 16:43:57 -0700146 if (test_mode_) {
147 p->AddArg("--test_mode");
148 }
149
Mike Frysingerc0871522013-09-16 14:07:27 -0400150 p->Run();
151}
152
Ian Barkley-Yeungc68cfc32019-07-15 16:43:57 -0700153void CrashSenderTool::OnTestModeChanged(
Tom Hughesd6c2d392020-08-24 18:12:11 -0700154 const brillo::dbus_utils::ExportedPropertyBase* test_mode_property) {
Ian Barkley-Yeungc68cfc32019-07-15 16:43:57 -0700155 const auto* property =
156 dynamic_cast<const brillo::dbus_utils::ExportedProperty<bool>*>(
Tom Hughesd6c2d392020-08-24 18:12:11 -0700157 test_mode_property);
Ian Barkley-Yeungc68cfc32019-07-15 16:43:57 -0700158 DCHECK(property);
159 test_mode_ = property->value();
160 LOG(INFO) << "CrashSenderTestMode set to " << std::boolalpha << test_mode_;
161}
162
Ben Chana0011d82014-05-13 00:19:29 -0700163} // namespace debugd