1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef CRASH_REPORTER_USER_COLLECTOR_H_
18 #define CRASH_REPORTER_USER_COLLECTOR_H_
19 
20 #include <string>
21 #include <vector>
22 
23 #include <base/files/file_path.h>
24 #include <base/macros.h>
25 #include <gtest/gtest_prod.h>  // for FRIEND_TEST
26 
27 #include "crash_collector.h"
28 
29 class SystemLogging;
30 
31 // User crash collector.
32 class UserCollector : public CrashCollector {
33  public:
34   UserCollector();
35 
36   // Initialize the user crash collector for detection of crashes,
37   // given a crash counting function, the path to this executable,
38   // metrics collection enabled oracle, and system logger facility.
39   // Crash detection/reporting is not enabled until Enable is called.
40   // |generate_diagnostics| is used to indicate whether or not to try
41   // to generate a minidump from crashes.
42   void Initialize(CountCrashFunction count_crash,
43                   const std::string &our_path,
44                   IsFeedbackAllowedFunction is_metrics_allowed,
45                   bool generate_diagnostics,
46                   bool core2md_failure,
47                   bool directory_failure,
48                   const std::string &filter_in);
49 
50   ~UserCollector() override;
51 
52   // Enable collection.
Enable()53   bool Enable() { return SetUpInternal(true); }
54 
55   // Disable collection.
Disable()56   bool Disable() { return SetUpInternal(false); }
57 
58   // Handle a specific user crash.  Returns true on success.
59   bool HandleCrash(const std::string &crash_attributes,
60                    const char *force_exec);
61 
62  private:
63   friend class UserCollectorTest;
64   FRIEND_TEST(UserCollectorTest, CopyOffProcFilesBadPath);
65   FRIEND_TEST(UserCollectorTest, CopyOffProcFilesBadPid);
66   FRIEND_TEST(UserCollectorTest, CopyOffProcFilesOK);
67   FRIEND_TEST(UserCollectorTest, GetExecutableBaseNameFromPid);
68   FRIEND_TEST(UserCollectorTest, GetFirstLineWithPrefix);
69   FRIEND_TEST(UserCollectorTest, GetIdFromStatus);
70   FRIEND_TEST(UserCollectorTest, GetStateFromStatus);
71   FRIEND_TEST(UserCollectorTest, GetProcessPath);
72   FRIEND_TEST(UserCollectorTest, GetSymlinkTarget);
73   FRIEND_TEST(UserCollectorTest, GetUserInfoFromName);
74   FRIEND_TEST(UserCollectorTest, ParseCrashAttributes);
75   FRIEND_TEST(UserCollectorTest, ShouldDumpChromeOverridesDeveloperImage);
76   FRIEND_TEST(UserCollectorTest, ShouldDumpDeveloperImageOverridesConsent);
77   FRIEND_TEST(UserCollectorTest, ShouldDumpUseConsentProductionImage);
78   FRIEND_TEST(UserCollectorTest, ValidateProcFiles);
79   FRIEND_TEST(UserCollectorTest, ValidateCoreFile);
80 
81   // Enumeration to pass to GetIdFromStatus.  Must match the order
82   // that the kernel lists IDs in the status file.
83   enum IdKind {
84     kIdReal = 0,  // uid and gid
85     kIdEffective = 1,  // euid and egid
86     kIdSet = 2,  // suid and sgid
87     kIdFileSystem = 3,  // fsuid and fsgid
88     kIdMax
89   };
90 
91   enum ErrorType {
92     kErrorNone,
93     kErrorSystemIssue,
94     kErrorReadCoreData,
95     kErrorUnusableProcFiles,
96     kErrorInvalidCoreFile,
97     kErrorUnsupported32BitCoreFile,
98     kErrorCore2MinidumpConversion,
99   };
100 
101   static const int kForkProblem = 255;
102 
103   // Returns an error type signature for a given |error_type| value,
104   // which is reported to the crash server along with the
105   // crash_reporter-user-collection signature.
106   std::string GetErrorTypeSignature(ErrorType error_type) const;
107 
108   bool SetUpInternal(bool enabled);
109 
110   // Returns, via |line|, the first line in |lines| that starts with |prefix|.
111   // Returns true if a line is found, or false otherwise.
112   bool GetFirstLineWithPrefix(const std::vector<std::string> &lines,
113                               const char *prefix, std::string *line);
114 
115   // Returns the identifier of |kind|, via |id|, found in |status_lines| on
116   // the line starting with |prefix|. |status_lines| contains the lines in
117   // the status file. Returns true if the identifier can be determined.
118   bool GetIdFromStatus(const char *prefix,
119                        IdKind kind,
120                        const std::vector<std::string> &status_lines,
121                        int *id);
122 
123   // Returns the process state, via |state|, found in |status_lines|, which
124   // contains the lines in the status file. Returns true if the process state
125   // can be determined.
126   bool GetStateFromStatus(const std::vector<std::string> &status_lines,
127                           std::string *state);
128 
129   void LogCollectionError(const std::string &error_message);
130   void EnqueueCollectionErrorLog(pid_t pid, ErrorType error_type,
131                                  const std::string &exec_name);
132 
133   bool CopyOffProcFiles(pid_t pid, const base::FilePath &container_dir);
134 
135   // Validates the proc files at |container_dir| and returns true if they
136   // are usable for the core-to-minidump conversion later. For instance, if
137   // a process is reaped by the kernel before the copying of its proc files
138   // takes place, some proc files like /proc/<pid>/maps may contain nothing
139   // and thus become unusable.
140   bool ValidateProcFiles(const base::FilePath &container_dir) const;
141 
142   // Validates the core file at |core_path| and returns kErrorNone if
143   // the file contains the ELF magic bytes and an ELF class that matches the
144   // platform (i.e. 32-bit ELF on a 32-bit platform or 64-bit ELF on a 64-bit
145   // platform), which is due to the limitation in core2md. It returns an error
146   // type otherwise.
147   ErrorType ValidateCoreFile(const base::FilePath &core_path) const;
148 
149   // Determines the crash directory for given pid based on pid's owner,
150   // and creates the directory if necessary with appropriate permissions.
151   // Returns true whether or not directory needed to be created, false on
152   // any failure.
153   bool GetCreatedCrashDirectory(pid_t pid, uid_t supplied_ruid,
154                                 base::FilePath *crash_file_path,
155                                 bool *out_of_capacity);
156   bool CopyStdinToCoreFile(const base::FilePath &core_path);
157   bool RunCoreToMinidump(const base::FilePath &core_path,
158                          const base::FilePath &procfs_directory,
159                          const base::FilePath &minidump_path,
160                          const base::FilePath &temp_directory);
161   ErrorType ConvertCoreToMinidump(pid_t pid,
162                                   const base::FilePath &container_dir,
163                                   const base::FilePath &core_path,
164                                   const base::FilePath &minidump_path);
165   ErrorType ConvertAndEnqueueCrash(pid_t pid, const std::string &exec_name,
166                                    uid_t supplied_ruid, bool *out_of_capacity);
167   bool ParseCrashAttributes(const std::string &crash_attributes,
168                             pid_t *pid, int *signal, uid_t *uid, gid_t *gid,
169                             std::string *kernel_supplied_name);
170 
171   bool ShouldDump(bool has_owner_consent,
172                   bool is_developer,
173                   std::string *reason);
174 
175   bool generate_diagnostics_;
176   std::string our_path_;
177   bool initialized_;
178 
179   bool core2md_failure_;
180   bool directory_failure_;
181   std::string filter_in_;
182 
183   static const char *kUserId;
184   static const char *kGroupId;
185 
186   DISALLOW_COPY_AND_ASSIGN(UserCollector);
187 };
188 
189 #endif  // CRASH_REPORTER_USER_COLLECTOR_H_
190