1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "base/linux_util.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <dirent.h>
8*6777b538SAndroid Build Coastguard Worker #include <errno.h>
9*6777b538SAndroid Build Coastguard Worker #include <fcntl.h>
10*6777b538SAndroid Build Coastguard Worker #include <limits.h>
11*6777b538SAndroid Build Coastguard Worker #include <stdlib.h>
12*6777b538SAndroid Build Coastguard Worker #include <sys/stat.h>
13*6777b538SAndroid Build Coastguard Worker #include <sys/types.h>
14*6777b538SAndroid Build Coastguard Worker #include <unistd.h>
15*6777b538SAndroid Build Coastguard Worker
16*6777b538SAndroid Build Coastguard Worker #include <iomanip>
17*6777b538SAndroid Build Coastguard Worker #include <memory>
18*6777b538SAndroid Build Coastguard Worker #include <string_view>
19*6777b538SAndroid Build Coastguard Worker
20*6777b538SAndroid Build Coastguard Worker #include "base/base_export.h"
21*6777b538SAndroid Build Coastguard Worker #include "base/files/dir_reader_posix.h"
22*6777b538SAndroid Build Coastguard Worker #include "base/files/file_util.h"
23*6777b538SAndroid Build Coastguard Worker #include "base/files/scoped_file.h"
24*6777b538SAndroid Build Coastguard Worker #include "base/strings/safe_sprintf.h"
25*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_number_conversions.h"
26*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_split.h"
27*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_tokenizer.h"
28*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
29*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
30*6777b538SAndroid Build Coastguard Worker #include "build/chromeos_buildflags.h"
31*6777b538SAndroid Build Coastguard Worker
32*6777b538SAndroid Build Coastguard Worker namespace base {
33*6777b538SAndroid Build Coastguard Worker
34*6777b538SAndroid Build Coastguard Worker namespace {
35*6777b538SAndroid Build Coastguard Worker
36*6777b538SAndroid Build Coastguard Worker #if !BUILDFLAG(IS_CHROMEOS_ASH)
GetKeyValueFromOSReleaseFile(const std::string & input,const char * key)37*6777b538SAndroid Build Coastguard Worker std::string GetKeyValueFromOSReleaseFile(const std::string& input,
38*6777b538SAndroid Build Coastguard Worker const char* key) {
39*6777b538SAndroid Build Coastguard Worker StringPairs key_value_pairs;
40*6777b538SAndroid Build Coastguard Worker SplitStringIntoKeyValuePairs(input, '=', '\n', &key_value_pairs);
41*6777b538SAndroid Build Coastguard Worker for (const auto& pair : key_value_pairs) {
42*6777b538SAndroid Build Coastguard Worker const std::string& key_str = pair.first;
43*6777b538SAndroid Build Coastguard Worker const std::string& value_str = pair.second;
44*6777b538SAndroid Build Coastguard Worker if (key_str == key) {
45*6777b538SAndroid Build Coastguard Worker // It can contain quoted characters.
46*6777b538SAndroid Build Coastguard Worker std::stringstream ss;
47*6777b538SAndroid Build Coastguard Worker std::string pretty_name;
48*6777b538SAndroid Build Coastguard Worker ss << value_str;
49*6777b538SAndroid Build Coastguard Worker // Quoted with a single tick?
50*6777b538SAndroid Build Coastguard Worker if (value_str[0] == '\'')
51*6777b538SAndroid Build Coastguard Worker ss >> std::quoted(pretty_name, '\'');
52*6777b538SAndroid Build Coastguard Worker else
53*6777b538SAndroid Build Coastguard Worker ss >> std::quoted(pretty_name);
54*6777b538SAndroid Build Coastguard Worker
55*6777b538SAndroid Build Coastguard Worker return pretty_name;
56*6777b538SAndroid Build Coastguard Worker }
57*6777b538SAndroid Build Coastguard Worker }
58*6777b538SAndroid Build Coastguard Worker
59*6777b538SAndroid Build Coastguard Worker return "";
60*6777b538SAndroid Build Coastguard Worker }
61*6777b538SAndroid Build Coastguard Worker
ReadDistroFromOSReleaseFile(const char * file)62*6777b538SAndroid Build Coastguard Worker bool ReadDistroFromOSReleaseFile(const char* file) {
63*6777b538SAndroid Build Coastguard Worker static const char kPrettyName[] = "PRETTY_NAME";
64*6777b538SAndroid Build Coastguard Worker
65*6777b538SAndroid Build Coastguard Worker std::string os_release_content;
66*6777b538SAndroid Build Coastguard Worker if (!ReadFileToString(FilePath(file), &os_release_content))
67*6777b538SAndroid Build Coastguard Worker return false;
68*6777b538SAndroid Build Coastguard Worker
69*6777b538SAndroid Build Coastguard Worker std::string pretty_name =
70*6777b538SAndroid Build Coastguard Worker GetKeyValueFromOSReleaseFile(os_release_content, kPrettyName);
71*6777b538SAndroid Build Coastguard Worker if (pretty_name.empty())
72*6777b538SAndroid Build Coastguard Worker return false;
73*6777b538SAndroid Build Coastguard Worker
74*6777b538SAndroid Build Coastguard Worker SetLinuxDistro(pretty_name);
75*6777b538SAndroid Build Coastguard Worker return true;
76*6777b538SAndroid Build Coastguard Worker }
77*6777b538SAndroid Build Coastguard Worker
78*6777b538SAndroid Build Coastguard Worker // https://www.freedesktop.org/software/systemd/man/os-release.html
79*6777b538SAndroid Build Coastguard Worker class DistroNameGetter {
80*6777b538SAndroid Build Coastguard Worker public:
DistroNameGetter()81*6777b538SAndroid Build Coastguard Worker DistroNameGetter() {
82*6777b538SAndroid Build Coastguard Worker static const char* const kFilesToCheck[] = {"/etc/os-release",
83*6777b538SAndroid Build Coastguard Worker "/usr/lib/os-release"};
84*6777b538SAndroid Build Coastguard Worker for (const char* file : kFilesToCheck) {
85*6777b538SAndroid Build Coastguard Worker if (ReadDistroFromOSReleaseFile(file))
86*6777b538SAndroid Build Coastguard Worker return;
87*6777b538SAndroid Build Coastguard Worker }
88*6777b538SAndroid Build Coastguard Worker }
89*6777b538SAndroid Build Coastguard Worker };
90*6777b538SAndroid Build Coastguard Worker #endif // !BUILDFLAG(IS_CHROMEOS_ASH)
91*6777b538SAndroid Build Coastguard Worker
GetThreadsFromProcessDir(const char * dir_path,std::vector<pid_t> * tids)92*6777b538SAndroid Build Coastguard Worker bool GetThreadsFromProcessDir(const char* dir_path, std::vector<pid_t>* tids) {
93*6777b538SAndroid Build Coastguard Worker DirReaderPosix dir_reader(dir_path);
94*6777b538SAndroid Build Coastguard Worker
95*6777b538SAndroid Build Coastguard Worker if (!dir_reader.IsValid()) {
96*6777b538SAndroid Build Coastguard Worker DLOG(WARNING) << "Cannot open " << dir_path;
97*6777b538SAndroid Build Coastguard Worker return false;
98*6777b538SAndroid Build Coastguard Worker }
99*6777b538SAndroid Build Coastguard Worker
100*6777b538SAndroid Build Coastguard Worker while (dir_reader.Next()) {
101*6777b538SAndroid Build Coastguard Worker pid_t tid;
102*6777b538SAndroid Build Coastguard Worker if (StringToInt(dir_reader.name(), &tid)) {
103*6777b538SAndroid Build Coastguard Worker tids->push_back(tid);
104*6777b538SAndroid Build Coastguard Worker }
105*6777b538SAndroid Build Coastguard Worker }
106*6777b538SAndroid Build Coastguard Worker
107*6777b538SAndroid Build Coastguard Worker return true;
108*6777b538SAndroid Build Coastguard Worker }
109*6777b538SAndroid Build Coastguard Worker
110*6777b538SAndroid Build Coastguard Worker // Account for the terminating null character.
111*6777b538SAndroid Build Coastguard Worker constexpr int kDistroSize = 128 + 1;
112*6777b538SAndroid Build Coastguard Worker
113*6777b538SAndroid Build Coastguard Worker } // namespace
114*6777b538SAndroid Build Coastguard Worker
115*6777b538SAndroid Build Coastguard Worker // We use this static string to hold the Linux distro info. If we
116*6777b538SAndroid Build Coastguard Worker // crash, the crash handler code will send this in the crash dump.
117*6777b538SAndroid Build Coastguard Worker char g_linux_distro[kDistroSize] =
118*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_CHROMEOS_ASH)
119*6777b538SAndroid Build Coastguard Worker "CrOS";
120*6777b538SAndroid Build Coastguard Worker #elif BUILDFLAG(IS_ANDROID)
121*6777b538SAndroid Build Coastguard Worker "Android";
122*6777b538SAndroid Build Coastguard Worker #else
123*6777b538SAndroid Build Coastguard Worker "Unknown";
124*6777b538SAndroid Build Coastguard Worker #endif
125*6777b538SAndroid Build Coastguard Worker
126*6777b538SAndroid Build Coastguard Worker // This function is only supposed to be used in tests. The declaration in the
127*6777b538SAndroid Build Coastguard Worker // header file is guarded by "#if defined(UNIT_TEST)" so that they can be used
128*6777b538SAndroid Build Coastguard Worker // by tests but not non-test code. However, this .cc file is compiled as part
129*6777b538SAndroid Build Coastguard Worker // of "base" where "UNIT_TEST" is not defined. So we need to specify
130*6777b538SAndroid Build Coastguard Worker // "BASE_EXPORT" here again so that they are visible to tests.
GetKeyValueFromOSReleaseFileForTesting(const std::string & input,const char * key)131*6777b538SAndroid Build Coastguard Worker BASE_EXPORT std::string GetKeyValueFromOSReleaseFileForTesting(
132*6777b538SAndroid Build Coastguard Worker const std::string& input,
133*6777b538SAndroid Build Coastguard Worker const char* key) {
134*6777b538SAndroid Build Coastguard Worker #if !BUILDFLAG(IS_CHROMEOS_ASH)
135*6777b538SAndroid Build Coastguard Worker return GetKeyValueFromOSReleaseFile(input, key);
136*6777b538SAndroid Build Coastguard Worker #else
137*6777b538SAndroid Build Coastguard Worker return "";
138*6777b538SAndroid Build Coastguard Worker #endif // !BUILDFLAG(IS_CHROMEOS_ASH)
139*6777b538SAndroid Build Coastguard Worker }
140*6777b538SAndroid Build Coastguard Worker
GetLinuxDistro()141*6777b538SAndroid Build Coastguard Worker std::string GetLinuxDistro() {
142*6777b538SAndroid Build Coastguard Worker #if !BUILDFLAG(IS_CHROMEOS_ASH)
143*6777b538SAndroid Build Coastguard Worker // We do this check only once per process. If it fails, there's
144*6777b538SAndroid Build Coastguard Worker // little reason to believe it will work if we attempt to run it again.
145*6777b538SAndroid Build Coastguard Worker static DistroNameGetter distro_name_getter;
146*6777b538SAndroid Build Coastguard Worker #endif
147*6777b538SAndroid Build Coastguard Worker return g_linux_distro;
148*6777b538SAndroid Build Coastguard Worker }
149*6777b538SAndroid Build Coastguard Worker
SetLinuxDistro(const std::string & distro)150*6777b538SAndroid Build Coastguard Worker void SetLinuxDistro(const std::string& distro) {
151*6777b538SAndroid Build Coastguard Worker std::string trimmed_distro;
152*6777b538SAndroid Build Coastguard Worker TrimWhitespaceASCII(distro, TRIM_ALL, &trimmed_distro);
153*6777b538SAndroid Build Coastguard Worker strlcpy(g_linux_distro, trimmed_distro.c_str(), kDistroSize);
154*6777b538SAndroid Build Coastguard Worker }
155*6777b538SAndroid Build Coastguard Worker
GetThreadsForProcess(pid_t pid,std::vector<pid_t> * tids)156*6777b538SAndroid Build Coastguard Worker bool GetThreadsForProcess(pid_t pid, std::vector<pid_t>* tids) {
157*6777b538SAndroid Build Coastguard Worker // 25 > strlen("/proc//task") + strlen(std::to_string(INT_MAX)) + 1 = 22
158*6777b538SAndroid Build Coastguard Worker char buf[25];
159*6777b538SAndroid Build Coastguard Worker strings::SafeSPrintf(buf, "/proc/%d/task", pid);
160*6777b538SAndroid Build Coastguard Worker return GetThreadsFromProcessDir(buf, tids);
161*6777b538SAndroid Build Coastguard Worker }
162*6777b538SAndroid Build Coastguard Worker
GetThreadsForCurrentProcess(std::vector<pid_t> * tids)163*6777b538SAndroid Build Coastguard Worker bool GetThreadsForCurrentProcess(std::vector<pid_t>* tids) {
164*6777b538SAndroid Build Coastguard Worker return GetThreadsFromProcessDir("/proc/self/task", tids);
165*6777b538SAndroid Build Coastguard Worker }
166*6777b538SAndroid Build Coastguard Worker
FindThreadIDWithSyscall(pid_t pid,const std::string & expected_data,bool * syscall_supported)167*6777b538SAndroid Build Coastguard Worker pid_t FindThreadIDWithSyscall(pid_t pid, const std::string& expected_data,
168*6777b538SAndroid Build Coastguard Worker bool* syscall_supported) {
169*6777b538SAndroid Build Coastguard Worker if (syscall_supported)
170*6777b538SAndroid Build Coastguard Worker *syscall_supported = false;
171*6777b538SAndroid Build Coastguard Worker
172*6777b538SAndroid Build Coastguard Worker std::vector<pid_t> tids;
173*6777b538SAndroid Build Coastguard Worker if (!GetThreadsForProcess(pid, &tids))
174*6777b538SAndroid Build Coastguard Worker return -1;
175*6777b538SAndroid Build Coastguard Worker
176*6777b538SAndroid Build Coastguard Worker std::vector<char> syscall_data(expected_data.size());
177*6777b538SAndroid Build Coastguard Worker for (pid_t tid : tids) {
178*6777b538SAndroid Build Coastguard Worker char buf[256];
179*6777b538SAndroid Build Coastguard Worker snprintf(buf, sizeof(buf), "/proc/%d/task/%d/syscall", pid, tid);
180*6777b538SAndroid Build Coastguard Worker ScopedFD fd(open(buf, O_RDONLY));
181*6777b538SAndroid Build Coastguard Worker if (!fd.is_valid())
182*6777b538SAndroid Build Coastguard Worker continue;
183*6777b538SAndroid Build Coastguard Worker
184*6777b538SAndroid Build Coastguard Worker *syscall_supported = true;
185*6777b538SAndroid Build Coastguard Worker if (!ReadFromFD(fd.get(), syscall_data)) {
186*6777b538SAndroid Build Coastguard Worker continue;
187*6777b538SAndroid Build Coastguard Worker }
188*6777b538SAndroid Build Coastguard Worker
189*6777b538SAndroid Build Coastguard Worker if (0 == strncmp(expected_data.c_str(), syscall_data.data(),
190*6777b538SAndroid Build Coastguard Worker expected_data.size())) {
191*6777b538SAndroid Build Coastguard Worker return tid;
192*6777b538SAndroid Build Coastguard Worker }
193*6777b538SAndroid Build Coastguard Worker }
194*6777b538SAndroid Build Coastguard Worker return -1;
195*6777b538SAndroid Build Coastguard Worker }
196*6777b538SAndroid Build Coastguard Worker
FindThreadID(pid_t pid,pid_t ns_tid,bool * ns_pid_supported)197*6777b538SAndroid Build Coastguard Worker pid_t FindThreadID(pid_t pid, pid_t ns_tid, bool* ns_pid_supported) {
198*6777b538SAndroid Build Coastguard Worker *ns_pid_supported = false;
199*6777b538SAndroid Build Coastguard Worker
200*6777b538SAndroid Build Coastguard Worker std::vector<pid_t> tids;
201*6777b538SAndroid Build Coastguard Worker if (!GetThreadsForProcess(pid, &tids))
202*6777b538SAndroid Build Coastguard Worker return -1;
203*6777b538SAndroid Build Coastguard Worker
204*6777b538SAndroid Build Coastguard Worker for (pid_t tid : tids) {
205*6777b538SAndroid Build Coastguard Worker char buf[256];
206*6777b538SAndroid Build Coastguard Worker snprintf(buf, sizeof(buf), "/proc/%d/task/%d/status", pid, tid);
207*6777b538SAndroid Build Coastguard Worker std::string status;
208*6777b538SAndroid Build Coastguard Worker if (!ReadFileToString(FilePath(buf), &status))
209*6777b538SAndroid Build Coastguard Worker return -1;
210*6777b538SAndroid Build Coastguard Worker StringTokenizer tokenizer(status, "\n");
211*6777b538SAndroid Build Coastguard Worker while (tokenizer.GetNext()) {
212*6777b538SAndroid Build Coastguard Worker std::string_view value_str(tokenizer.token_piece());
213*6777b538SAndroid Build Coastguard Worker if (!StartsWith(value_str, "NSpid"))
214*6777b538SAndroid Build Coastguard Worker continue;
215*6777b538SAndroid Build Coastguard Worker
216*6777b538SAndroid Build Coastguard Worker *ns_pid_supported = true;
217*6777b538SAndroid Build Coastguard Worker std::vector<std::string_view> split_value_str = SplitStringPiece(
218*6777b538SAndroid Build Coastguard Worker value_str, "\t", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
219*6777b538SAndroid Build Coastguard Worker DCHECK_GE(split_value_str.size(), 2u);
220*6777b538SAndroid Build Coastguard Worker int value;
221*6777b538SAndroid Build Coastguard Worker // The last value in the list is the PID in the namespace.
222*6777b538SAndroid Build Coastguard Worker if (StringToInt(split_value_str.back(), &value) && value == ns_tid) {
223*6777b538SAndroid Build Coastguard Worker // The second value in the list is the real PID.
224*6777b538SAndroid Build Coastguard Worker if (StringToInt(split_value_str[1], &value))
225*6777b538SAndroid Build Coastguard Worker return value;
226*6777b538SAndroid Build Coastguard Worker }
227*6777b538SAndroid Build Coastguard Worker break;
228*6777b538SAndroid Build Coastguard Worker }
229*6777b538SAndroid Build Coastguard Worker }
230*6777b538SAndroid Build Coastguard Worker return -1;
231*6777b538SAndroid Build Coastguard Worker }
232*6777b538SAndroid Build Coastguard Worker
233*6777b538SAndroid Build Coastguard Worker } // namespace base
234