blob: 25e5eca0d1014506459b79ab7b5356075288eaa6 [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2012 The Chromium Authors
[email protected]75ae5422009-04-21 17:20:102// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Tom Sepez8726d30e2025-01-29 02:11:085#ifdef UNSAFE_BUFFERS_BUILD
6// TODO(crbug.com/390223051): Remove C-library calls to fix the errors.
7#pragma allow_unsafe_libc_calls
8#endif
9
[email protected]912c6452009-07-17 05:55:5110#include "base/linux_util.h"
[email protected]75ae5422009-04-21 17:20:1011
[email protected]85ebe8f2009-10-29 04:02:5512#include <dirent.h>
13#include <errno.h>
[email protected]662183142010-07-16 19:28:1714#include <fcntl.h>
avi9b6f42932015-12-26 22:15:1415#include <limits.h>
[email protected]75ae5422009-04-21 17:20:1016#include <stdlib.h>
[email protected]85ebe8f2009-10-29 04:02:5517#include <sys/stat.h>
[email protected]662183142010-07-16 19:28:1718#include <sys/types.h>
[email protected]85ebe8f2009-10-29 04:02:5519#include <unistd.h>
[email protected]75ae5422009-04-21 17:20:1020
Tomas Popela5b9b01f2019-09-10 19:42:3121#include <iomanip>
dcheng093de9b2016-04-04 21:25:5122#include <memory>
Helmut Januschka91069ddb2024-04-09 01:42:1623#include <string_view>
[email protected]912c6452009-07-17 05:55:5124
David Sanders6e709942022-04-05 06:49:2625#include "base/base_export.h"
Alexandr Ilind4f4b342019-01-08 15:34:0926#include "base/files/dir_reader_posix.h"
[email protected]e3177dd52014-08-13 20:22:1427#include "base/files/file_util.h"
Lei Zhang3bf06692020-02-03 19:41:0528#include "base/files/scoped_file.h"
Alexandr Ilind4f4b342019-01-08 15:34:0929#include "base/strings/safe_sprintf.h"
Tom Sepez5a0c23c42025-01-06 20:45:3230#include "base/strings/span_printf.h"
reveman7b97c322016-09-20 02:10:5831#include "base/strings/string_number_conversions.h"
32#include "base/strings/string_split.h"
revemane5aece572017-09-04 07:18:3333#include "base/strings/string_tokenizer.h"
[email protected]d529cb02013-06-10 19:06:5734#include "base/strings/string_util.h"
avi9b6f42932015-12-26 22:15:1435#include "build/build_config.h"
[email protected]87fc1682009-07-22 00:22:4936
Tomas Popela5b9b01f2019-09-10 19:42:3137namespace base {
38
[email protected]87fc1682009-07-22 00:22:4939namespace {
40
Georg Neisff37fb52025-02-05 09:05:2641#if !BUILDFLAG(IS_CHROMEOS)
Tomas Popela5b9b01f2019-09-10 19:42:3142std::string GetKeyValueFromOSReleaseFile(const std::string& input,
43 const char* key) {
44 StringPairs key_value_pairs;
45 SplitStringIntoKeyValuePairs(input, '=', '\n', &key_value_pairs);
46 for (const auto& pair : key_value_pairs) {
47 const std::string& key_str = pair.first;
48 const std::string& value_str = pair.second;
49 if (key_str == key) {
50 // It can contain quoted characters.
51 std::stringstream ss;
52 std::string pretty_name;
53 ss << value_str;
54 // Quoted with a single tick?
Peter Kasting134ef9af2024-12-28 02:30:0955 if (value_str[0] == '\'') {
Tomas Popela5b9b01f2019-09-10 19:42:3156 ss >> std::quoted(pretty_name, '\'');
Peter Kasting134ef9af2024-12-28 02:30:0957 } else {
Tomas Popela5b9b01f2019-09-10 19:42:3158 ss >> std::quoted(pretty_name);
Peter Kasting134ef9af2024-12-28 02:30:0959 }
Tomas Popela5b9b01f2019-09-10 19:42:3160
61 return pretty_name;
62 }
63 }
64
65 return "";
66}
67
68bool ReadDistroFromOSReleaseFile(const char* file) {
69 static const char kPrettyName[] = "PRETTY_NAME";
70
71 std::string os_release_content;
Peter Kasting134ef9af2024-12-28 02:30:0972 if (!ReadFileToString(FilePath(file), &os_release_content)) {
Tomas Popela5b9b01f2019-09-10 19:42:3173 return false;
Peter Kasting134ef9af2024-12-28 02:30:0974 }
Tomas Popela5b9b01f2019-09-10 19:42:3175
76 std::string pretty_name =
77 GetKeyValueFromOSReleaseFile(os_release_content, kPrettyName);
Peter Kasting134ef9af2024-12-28 02:30:0978 if (pretty_name.empty()) {
Tomas Popela5b9b01f2019-09-10 19:42:3179 return false;
Peter Kasting134ef9af2024-12-28 02:30:0980 }
Tomas Popela5b9b01f2019-09-10 19:42:3181
82 SetLinuxDistro(pretty_name);
83 return true;
84}
85
86// https://www.freedesktop.org/software/systemd/man/os-release.html
Tom Anderson02185a02020-02-01 03:49:2587class DistroNameGetter {
88 public:
89 DistroNameGetter() {
90 static const char* const kFilesToCheck[] = {"/etc/os-release",
91 "/usr/lib/os-release"};
92 for (const char* file : kFilesToCheck) {
Peter Kasting134ef9af2024-12-28 02:30:0993 if (ReadDistroFromOSReleaseFile(file)) {
Tom Anderson02185a02020-02-01 03:49:2594 return;
Peter Kasting134ef9af2024-12-28 02:30:0995 }
Tom Anderson02185a02020-02-01 03:49:2596 }
Tomas Popela5b9b01f2019-09-10 19:42:3197 }
Tom Anderson02185a02020-02-01 03:49:2598};
Georg Neisff37fb52025-02-05 09:05:2699#endif // !BUILDFLAG(IS_CHROMEOS)
[email protected]19467c02009-10-13 02:51:07100
Igor Kraskevichbfc62af2023-10-17 15:09:28101bool GetThreadsFromProcessDir(const char* dir_path, std::vector<pid_t>* tids) {
102 DirReaderPosix dir_reader(dir_path);
103
104 if (!dir_reader.IsValid()) {
105 DLOG(WARNING) << "Cannot open " << dir_path;
106 return false;
107 }
108
109 while (dir_reader.Next()) {
110 pid_t tid;
111 if (StringToInt(dir_reader.name(), &tid)) {
112 tids->push_back(tid);
113 }
114 }
115
116 return true;
117}
118
[email protected]6dde9d72010-08-26 08:55:22119// Account for the terminating null character.
Lei Zhang3bf06692020-02-03 19:41:05120constexpr int kDistroSize = 128 + 1;
121
122} // namespace
[email protected]6dde9d72010-08-26 08:55:22123
[email protected]912c6452009-07-17 05:55:51124// We use this static string to hold the Linux distro info. If we
125// crash, the crash handler code will send this in the crash dump.
[email protected]6dde9d72010-08-26 08:55:22126char g_linux_distro[kDistroSize] =
Georg Neisff37fb52025-02-05 09:05:26127#if BUILDFLAG(IS_CHROMEOS)
[email protected]78f6f512009-10-21 19:04:17128 "CrOS";
Xiaohan Wang38e4ebb2022-01-19 06:57:43129#elif BUILDFLAG(IS_ANDROID)
[email protected]84a1ab5a2012-07-18 01:49:22130 "Android";
Tom Anderson02185a02020-02-01 03:49:25131#else
[email protected]78f6f512009-10-21 19:04:17132 "Unknown";
133#endif
[email protected]912c6452009-07-17 05:55:51134
Raphael Kubo da Costa71c31f52019-09-11 16:17:00135// This function is only supposed to be used in tests. The declaration in the
136// header file is guarded by "#if defined(UNIT_TEST)" so that they can be used
137// by tests but not non-test code. However, this .cc file is compiled as part
138// of "base" where "UNIT_TEST" is not defined. So we need to specify
139// "BASE_EXPORT" here again so that they are visible to tests.
Tomas Popela5b9b01f2019-09-10 19:42:31140BASE_EXPORT std::string GetKeyValueFromOSReleaseFileForTesting(
141 const std::string& input,
142 const char* key) {
Georg Neisff37fb52025-02-05 09:05:26143#if !BUILDFLAG(IS_CHROMEOS)
Tomas Popela5b9b01f2019-09-10 19:42:31144 return GetKeyValueFromOSReleaseFile(input, key);
145#else
146 return "";
Georg Neisff37fb52025-02-05 09:05:26147#endif // !BUILDFLAG(IS_CHROMEOS)
Tomas Popela5b9b01f2019-09-10 19:42:31148}
149
[email protected]912c6452009-07-17 05:55:51150std::string GetLinuxDistro() {
Georg Neisff37fb52025-02-05 09:05:26151#if !BUILDFLAG(IS_CHROMEOS)
[email protected]84a1ab5a2012-07-18 01:49:22152 // We do this check only once per process. If it fails, there's
Tomas Popela5b9b01f2019-09-10 19:42:31153 // little reason to believe it will work if we attempt to run it again.
Avi Drissmanded77172021-07-02 18:23:00154 static DistroNameGetter distro_name_getter;
[email protected]78f6f512009-10-21 19:04:17155#endif
Tom Anderson02185a02020-02-01 03:49:25156 return g_linux_distro;
[email protected]912c6452009-07-17 05:55:51157}
158
[email protected]6dde9d72010-08-26 08:55:22159void SetLinuxDistro(const std::string& distro) {
160 std::string trimmed_distro;
olli.raula36aa8be2015-09-10 11:14:22161 TrimWhitespaceASCII(distro, TRIM_ALL, &trimmed_distro);
162 strlcpy(g_linux_distro, trimmed_distro.c_str(), kDistroSize);
[email protected]6dde9d72010-08-26 08:55:22163}
164
Alexandr Ilind4f4b342019-01-08 15:34:09165bool GetThreadsForProcess(pid_t pid, std::vector<pid_t>* tids) {
Ho Cheung42097f62024-10-22 13:34:22166 // 25 > strlen("/proc//task") + strlen(base::NumberToString(INT_MAX)) + 1 = 22
Alexandr Ilind4f4b342019-01-08 15:34:09167 char buf[25];
Tomas Popela5b9b01f2019-09-10 19:42:31168 strings::SafeSPrintf(buf, "/proc/%d/task", pid);
Igor Kraskevichbfc62af2023-10-17 15:09:28169 return GetThreadsFromProcessDir(buf, tids);
170}
Alexandr Ilind4f4b342019-01-08 15:34:09171
Igor Kraskevichbfc62af2023-10-17 15:09:28172bool GetThreadsForCurrentProcess(std::vector<pid_t>* tids) {
173 return GetThreadsFromProcessDir("/proc/self/task", tids);
Alexandr Ilind4f4b342019-01-08 15:34:09174}
175
Peter Kasting134ef9af2024-12-28 02:30:09176pid_t FindThreadIDWithSyscall(pid_t pid,
177 const std::string& expected_data,
[email protected]cb7d53e2011-06-21 04:21:06178 bool* syscall_supported) {
Peter Kasting134ef9af2024-12-28 02:30:09179 if (syscall_supported) {
[email protected]cb7d53e2011-06-21 04:21:06180 *syscall_supported = false;
Peter Kasting134ef9af2024-12-28 02:30:09181 }
[email protected]cb7d53e2011-06-21 04:21:06182
[email protected]662183142010-07-16 19:28:17183 std::vector<pid_t> tids;
Peter Kasting134ef9af2024-12-28 02:30:09184 if (!GetThreadsForProcess(pid, &tids)) {
reveman7b97c322016-09-20 02:10:58185 return -1;
Peter Kasting134ef9af2024-12-28 02:30:09186 }
[email protected]662183142010-07-16 19:28:17187
Lei Zhang3bf06692020-02-03 19:41:05188 std::vector<char> syscall_data(expected_data.size());
reveman7b97c322016-09-20 02:10:58189 for (pid_t tid : tids) {
190 char buf[256];
Tom Sepez5a0c23c42025-01-06 20:45:32191 base::SpanPrintf(buf, "/proc/%d/task/%d/syscall", pid, tid);
Lei Zhang3bf06692020-02-03 19:41:05192 ScopedFD fd(open(buf, O_RDONLY));
Peter Kasting134ef9af2024-12-28 02:30:09193 if (!fd.is_valid()) {
[email protected]662183142010-07-16 19:28:17194 continue;
Peter Kasting134ef9af2024-12-28 02:30:09195 }
[email protected]662183142010-07-16 19:28:17196
Lei Zhang3bf06692020-02-03 19:41:05197 *syscall_supported = true;
Austin Sullivan49f97442024-01-08 20:26:27198 if (!ReadFromFD(fd.get(), syscall_data)) {
Lei Zhang3bf06692020-02-03 19:41:05199 continue;
Austin Sullivan49f97442024-01-08 20:26:27200 }
Lei Zhang3bf06692020-02-03 19:41:05201
202 if (0 == strncmp(expected_data.c_str(), syscall_data.data(),
203 expected_data.size())) {
reveman7b97c322016-09-20 02:10:58204 return tid;
205 }
206 }
207 return -1;
208}
209
210pid_t FindThreadID(pid_t pid, pid_t ns_tid, bool* ns_pid_supported) {
Lei Zhang3bf06692020-02-03 19:41:05211 *ns_pid_supported = false;
reveman7b97c322016-09-20 02:10:58212
213 std::vector<pid_t> tids;
Peter Kasting134ef9af2024-12-28 02:30:09214 if (!GetThreadsForProcess(pid, &tids)) {
reveman7b97c322016-09-20 02:10:58215 return -1;
Peter Kasting134ef9af2024-12-28 02:30:09216 }
reveman7b97c322016-09-20 02:10:58217
218 for (pid_t tid : tids) {
219 char buf[256];
Tom Sepez5a0c23c42025-01-06 20:45:32220 base::SpanPrintf(buf, "/proc/%d/task/%d/status", pid, tid);
reveman7b97c322016-09-20 02:10:58221 std::string status;
Peter Kasting134ef9af2024-12-28 02:30:09222 if (!ReadFileToString(FilePath(buf), &status)) {
reveman7b97c322016-09-20 02:10:58223 return -1;
Peter Kasting134ef9af2024-12-28 02:30:09224 }
revemane5aece572017-09-04 07:18:33225 StringTokenizer tokenizer(status, "\n");
Lei Zhang09b218e52024-09-12 19:21:55226 while (std::optional<std::string_view> token =
227 tokenizer.GetNextTokenView()) {
228 if (!StartsWith(token.value(), "NSpid")) {
revemane5aece572017-09-04 07:18:33229 continue;
Lei Zhang09b218e52024-09-12 19:21:55230 }
Lei Zhang3bf06692020-02-03 19:41:05231
232 *ns_pid_supported = true;
Helmut Januschka91069ddb2024-04-09 01:42:16233 std::vector<std::string_view> split_value_str = SplitStringPiece(
Lei Zhang09b218e52024-09-12 19:21:55234 token.value(), "\t", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
revemane5aece572017-09-04 07:18:33235 DCHECK_GE(split_value_str.size(), 2u);
236 int value;
237 // The last value in the list is the PID in the namespace.
238 if (StringToInt(split_value_str.back(), &value) && value == ns_tid) {
239 // The second value in the list is the real PID.
Peter Kasting134ef9af2024-12-28 02:30:09240 if (StringToInt(split_value_str[1], &value)) {
revemane5aece572017-09-04 07:18:33241 return value;
Peter Kasting134ef9af2024-12-28 02:30:09242 }
reveman7b97c322016-09-20 02:10:58243 }
revemane5aece572017-09-04 07:18:33244 break;
[email protected]662183142010-07-16 19:28:17245 }
246 }
247 return -1;
248}
249
[email protected]75ae5422009-04-21 17:20:10250} // namespace base