1*288bf522SAndroid Build Coastguard Worker /*
2*288bf522SAndroid Build Coastguard Worker * Copyright (C) 2020 The Android Open Source Project
3*288bf522SAndroid Build Coastguard Worker *
4*288bf522SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*288bf522SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*288bf522SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*288bf522SAndroid Build Coastguard Worker *
8*288bf522SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*288bf522SAndroid Build Coastguard Worker *
10*288bf522SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*288bf522SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*288bf522SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*288bf522SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*288bf522SAndroid Build Coastguard Worker * limitations under the License.
15*288bf522SAndroid Build Coastguard Worker */
16*288bf522SAndroid Build Coastguard Worker #include "kallsyms.h"
17*288bf522SAndroid Build Coastguard Worker
18*288bf522SAndroid Build Coastguard Worker #include <inttypes.h>
19*288bf522SAndroid Build Coastguard Worker
20*288bf522SAndroid Build Coastguard Worker #include <string>
21*288bf522SAndroid Build Coastguard Worker
22*288bf522SAndroid Build Coastguard Worker #include <android-base/file.h>
23*288bf522SAndroid Build Coastguard Worker #include <android-base/logging.h>
24*288bf522SAndroid Build Coastguard Worker #include <android-base/properties.h>
25*288bf522SAndroid Build Coastguard Worker
26*288bf522SAndroid Build Coastguard Worker #include "environment.h"
27*288bf522SAndroid Build Coastguard Worker #include "read_elf.h"
28*288bf522SAndroid Build Coastguard Worker #include "utils.h"
29*288bf522SAndroid Build Coastguard Worker
30*288bf522SAndroid Build Coastguard Worker namespace simpleperf {
31*288bf522SAndroid Build Coastguard Worker
32*288bf522SAndroid Build Coastguard Worker #if defined(__linux__)
33*288bf522SAndroid Build Coastguard Worker
34*288bf522SAndroid Build Coastguard Worker namespace {
35*288bf522SAndroid Build Coastguard Worker
36*288bf522SAndroid Build Coastguard Worker const char kKallsymsPath[] = "/proc/kallsyms";
37*288bf522SAndroid Build Coastguard Worker const char kProcModulesPath[] = "/proc/modules";
38*288bf522SAndroid Build Coastguard Worker const char kPtrRestrictPath[] = "/proc/sys/kernel/kptr_restrict";
39*288bf522SAndroid Build Coastguard Worker const char kLowerPtrRestrictAndroidProp[] = "security.lower_kptr_restrict";
40*288bf522SAndroid Build Coastguard Worker const unsigned int kMinLineTestNonNullSymbols = 10;
41*288bf522SAndroid Build Coastguard Worker
42*288bf522SAndroid Build Coastguard Worker // Tries to read the kernel symbol file and ensure that at least some symbol
43*288bf522SAndroid Build Coastguard Worker // addresses are non-null.
CanReadKernelSymbolAddresses()44*288bf522SAndroid Build Coastguard Worker bool CanReadKernelSymbolAddresses() {
45*288bf522SAndroid Build Coastguard Worker LineReader reader(kKallsymsPath);
46*288bf522SAndroid Build Coastguard Worker if (!reader.Ok()) {
47*288bf522SAndroid Build Coastguard Worker LOG(DEBUG) << "Failed to read " << kKallsymsPath;
48*288bf522SAndroid Build Coastguard Worker return false;
49*288bf522SAndroid Build Coastguard Worker }
50*288bf522SAndroid Build Coastguard Worker auto symbol_callback = [&](const KernelSymbol& symbol) { return (symbol.addr != 0u); };
51*288bf522SAndroid Build Coastguard Worker for (unsigned int i = 0; i < kMinLineTestNonNullSymbols; i++) {
52*288bf522SAndroid Build Coastguard Worker std::string* line = reader.ReadLine();
53*288bf522SAndroid Build Coastguard Worker if (line == nullptr) {
54*288bf522SAndroid Build Coastguard Worker return false;
55*288bf522SAndroid Build Coastguard Worker }
56*288bf522SAndroid Build Coastguard Worker if (ProcessKernelSymbols(*line, symbol_callback)) {
57*288bf522SAndroid Build Coastguard Worker return true;
58*288bf522SAndroid Build Coastguard Worker }
59*288bf522SAndroid Build Coastguard Worker }
60*288bf522SAndroid Build Coastguard Worker return false;
61*288bf522SAndroid Build Coastguard Worker }
62*288bf522SAndroid Build Coastguard Worker
63*288bf522SAndroid Build Coastguard Worker // Define a scope in which access to kallsyms is possible.
64*288bf522SAndroid Build Coastguard Worker // This is based on the Perfetto implementation.
65*288bf522SAndroid Build Coastguard Worker class ScopedKptrUnrestrict {
66*288bf522SAndroid Build Coastguard Worker public:
67*288bf522SAndroid Build Coastguard Worker ScopedKptrUnrestrict(); // Lowers kptr_restrict if necessary.
68*288bf522SAndroid Build Coastguard Worker ~ScopedKptrUnrestrict(); // Restores the initial kptr_restrict.
69*288bf522SAndroid Build Coastguard Worker
70*288bf522SAndroid Build Coastguard Worker // Indicates if access to kallsyms should be successful.
KallsymsAvailable()71*288bf522SAndroid Build Coastguard Worker bool KallsymsAvailable() { return kallsyms_available_; }
72*288bf522SAndroid Build Coastguard Worker
ResetWarning()73*288bf522SAndroid Build Coastguard Worker static void ResetWarning() { kernel_address_warning_printed_ = false; }
74*288bf522SAndroid Build Coastguard Worker
75*288bf522SAndroid Build Coastguard Worker private:
76*288bf522SAndroid Build Coastguard Worker bool WriteKptrRestrict(const std::string& value);
77*288bf522SAndroid Build Coastguard Worker void PrintWarning();
78*288bf522SAndroid Build Coastguard Worker
79*288bf522SAndroid Build Coastguard Worker bool restore_property_ = false;
80*288bf522SAndroid Build Coastguard Worker bool restore_restrict_value_ = false;
81*288bf522SAndroid Build Coastguard Worker std::string saved_restrict_value_;
82*288bf522SAndroid Build Coastguard Worker bool kallsyms_available_ = false;
83*288bf522SAndroid Build Coastguard Worker
84*288bf522SAndroid Build Coastguard Worker static bool kernel_address_warning_printed_;
85*288bf522SAndroid Build Coastguard Worker };
86*288bf522SAndroid Build Coastguard Worker
87*288bf522SAndroid Build Coastguard Worker bool ScopedKptrUnrestrict::kernel_address_warning_printed_ = false;
88*288bf522SAndroid Build Coastguard Worker
ScopedKptrUnrestrict()89*288bf522SAndroid Build Coastguard Worker ScopedKptrUnrestrict::ScopedKptrUnrestrict() {
90*288bf522SAndroid Build Coastguard Worker if (CanReadKernelSymbolAddresses()) {
91*288bf522SAndroid Build Coastguard Worker // Everything seems to work (e.g., we are running as root and kptr_restrict
92*288bf522SAndroid Build Coastguard Worker // is < 2). Don't touching anything.
93*288bf522SAndroid Build Coastguard Worker kallsyms_available_ = true;
94*288bf522SAndroid Build Coastguard Worker return;
95*288bf522SAndroid Build Coastguard Worker }
96*288bf522SAndroid Build Coastguard Worker
97*288bf522SAndroid Build Coastguard Worker if (GetAndroidVersion() >= 12 && IsRoot()) {
98*288bf522SAndroid Build Coastguard Worker // Enable kernel addresses by setting property.
99*288bf522SAndroid Build Coastguard Worker if (!android::base::SetProperty(kLowerPtrRestrictAndroidProp, "1")) {
100*288bf522SAndroid Build Coastguard Worker LOG(DEBUG) << "Unable to set " << kLowerPtrRestrictAndroidProp << " to 1.";
101*288bf522SAndroid Build Coastguard Worker PrintWarning();
102*288bf522SAndroid Build Coastguard Worker return;
103*288bf522SAndroid Build Coastguard Worker }
104*288bf522SAndroid Build Coastguard Worker restore_property_ = true;
105*288bf522SAndroid Build Coastguard Worker // Init takes some time to react to the property change.
106*288bf522SAndroid Build Coastguard Worker // Unfortunately, we cannot read kptr_restrict because of SELinux. Instead,
107*288bf522SAndroid Build Coastguard Worker // we detect this by reading the initial lines of kallsyms and checking
108*288bf522SAndroid Build Coastguard Worker // that they are non-zero. This loop waits for at most 250ms (50 * 5ms).
109*288bf522SAndroid Build Coastguard Worker for (int attempt = 1; attempt <= 50; ++attempt) {
110*288bf522SAndroid Build Coastguard Worker usleep(5000);
111*288bf522SAndroid Build Coastguard Worker if (CanReadKernelSymbolAddresses()) {
112*288bf522SAndroid Build Coastguard Worker kallsyms_available_ = true;
113*288bf522SAndroid Build Coastguard Worker return;
114*288bf522SAndroid Build Coastguard Worker }
115*288bf522SAndroid Build Coastguard Worker }
116*288bf522SAndroid Build Coastguard Worker LOG(DEBUG) << "kallsyms addresses are still masked after setting "
117*288bf522SAndroid Build Coastguard Worker << kLowerPtrRestrictAndroidProp;
118*288bf522SAndroid Build Coastguard Worker PrintWarning();
119*288bf522SAndroid Build Coastguard Worker return;
120*288bf522SAndroid Build Coastguard Worker }
121*288bf522SAndroid Build Coastguard Worker
122*288bf522SAndroid Build Coastguard Worker // Otherwise, read the kptr_restrict value and lower it if needed.
123*288bf522SAndroid Build Coastguard Worker if (!android::base::ReadFileToString(kPtrRestrictPath, &saved_restrict_value_)) {
124*288bf522SAndroid Build Coastguard Worker LOG(DEBUG) << "Failed to read " << kPtrRestrictPath;
125*288bf522SAndroid Build Coastguard Worker PrintWarning();
126*288bf522SAndroid Build Coastguard Worker return;
127*288bf522SAndroid Build Coastguard Worker }
128*288bf522SAndroid Build Coastguard Worker
129*288bf522SAndroid Build Coastguard Worker // Progressively lower kptr_restrict until we can read kallsyms.
130*288bf522SAndroid Build Coastguard Worker for (int value = atoi(saved_restrict_value_.c_str()); value > 0; --value) {
131*288bf522SAndroid Build Coastguard Worker if (!WriteKptrRestrict(std::to_string(value))) {
132*288bf522SAndroid Build Coastguard Worker break;
133*288bf522SAndroid Build Coastguard Worker }
134*288bf522SAndroid Build Coastguard Worker restore_restrict_value_ = true;
135*288bf522SAndroid Build Coastguard Worker if (CanReadKernelSymbolAddresses()) {
136*288bf522SAndroid Build Coastguard Worker kallsyms_available_ = true;
137*288bf522SAndroid Build Coastguard Worker return;
138*288bf522SAndroid Build Coastguard Worker }
139*288bf522SAndroid Build Coastguard Worker }
140*288bf522SAndroid Build Coastguard Worker PrintWarning();
141*288bf522SAndroid Build Coastguard Worker }
142*288bf522SAndroid Build Coastguard Worker
~ScopedKptrUnrestrict()143*288bf522SAndroid Build Coastguard Worker ScopedKptrUnrestrict::~ScopedKptrUnrestrict() {
144*288bf522SAndroid Build Coastguard Worker if (restore_property_) {
145*288bf522SAndroid Build Coastguard Worker android::base::SetProperty(kLowerPtrRestrictAndroidProp, "0");
146*288bf522SAndroid Build Coastguard Worker }
147*288bf522SAndroid Build Coastguard Worker if (restore_restrict_value_) {
148*288bf522SAndroid Build Coastguard Worker WriteKptrRestrict(saved_restrict_value_);
149*288bf522SAndroid Build Coastguard Worker }
150*288bf522SAndroid Build Coastguard Worker }
151*288bf522SAndroid Build Coastguard Worker
WriteKptrRestrict(const std::string & value)152*288bf522SAndroid Build Coastguard Worker bool ScopedKptrUnrestrict::WriteKptrRestrict(const std::string& value) {
153*288bf522SAndroid Build Coastguard Worker if (!android::base::WriteStringToFile(value, kPtrRestrictPath)) {
154*288bf522SAndroid Build Coastguard Worker LOG(DEBUG) << "Failed to set " << kPtrRestrictPath << " to " << value;
155*288bf522SAndroid Build Coastguard Worker return false;
156*288bf522SAndroid Build Coastguard Worker }
157*288bf522SAndroid Build Coastguard Worker return true;
158*288bf522SAndroid Build Coastguard Worker }
159*288bf522SAndroid Build Coastguard Worker
PrintWarning()160*288bf522SAndroid Build Coastguard Worker void ScopedKptrUnrestrict::PrintWarning() {
161*288bf522SAndroid Build Coastguard Worker if (!kernel_address_warning_printed_) {
162*288bf522SAndroid Build Coastguard Worker kernel_address_warning_printed_ = true;
163*288bf522SAndroid Build Coastguard Worker LOG(WARNING) << "Access to kernel symbol addresses is restricted. If "
164*288bf522SAndroid Build Coastguard Worker << "possible, please do `echo 0 >/proc/sys/kernel/kptr_restrict` "
165*288bf522SAndroid Build Coastguard Worker << "to fix this.";
166*288bf522SAndroid Build Coastguard Worker }
167*288bf522SAndroid Build Coastguard Worker }
168*288bf522SAndroid Build Coastguard Worker
169*288bf522SAndroid Build Coastguard Worker } // namespace
170*288bf522SAndroid Build Coastguard Worker
GetLoadedModules()171*288bf522SAndroid Build Coastguard Worker std::vector<KernelMmap> GetLoadedModules() {
172*288bf522SAndroid Build Coastguard Worker ScopedKptrUnrestrict kptr_unrestrict;
173*288bf522SAndroid Build Coastguard Worker if (!kptr_unrestrict.KallsymsAvailable()) return {};
174*288bf522SAndroid Build Coastguard Worker std::vector<KernelMmap> result;
175*288bf522SAndroid Build Coastguard Worker LineReader reader(kProcModulesPath);
176*288bf522SAndroid Build Coastguard Worker if (!reader.Ok()) {
177*288bf522SAndroid Build Coastguard Worker // There is no /proc/modules on Android devices, so we don't print error if failed to open it.
178*288bf522SAndroid Build Coastguard Worker PLOG(DEBUG) << "failed to open file /proc/modules";
179*288bf522SAndroid Build Coastguard Worker return result;
180*288bf522SAndroid Build Coastguard Worker }
181*288bf522SAndroid Build Coastguard Worker std::string* line;
182*288bf522SAndroid Build Coastguard Worker std::string name_buf;
183*288bf522SAndroid Build Coastguard Worker while ((line = reader.ReadLine()) != nullptr) {
184*288bf522SAndroid Build Coastguard Worker // Parse line like: nf_defrag_ipv6 34768 1 nf_conntrack_ipv6, Live 0xffffffffa0fe5000
185*288bf522SAndroid Build Coastguard Worker name_buf.resize(line->size());
186*288bf522SAndroid Build Coastguard Worker char* name = name_buf.data();
187*288bf522SAndroid Build Coastguard Worker uint64_t addr;
188*288bf522SAndroid Build Coastguard Worker uint64_t len;
189*288bf522SAndroid Build Coastguard Worker if (sscanf(line->data(), "%s%" PRIu64 "%*u%*s%*s 0x%" PRIx64, name, &len, &addr) == 3) {
190*288bf522SAndroid Build Coastguard Worker KernelMmap map;
191*288bf522SAndroid Build Coastguard Worker map.name = name;
192*288bf522SAndroid Build Coastguard Worker map.start_addr = addr;
193*288bf522SAndroid Build Coastguard Worker map.len = len;
194*288bf522SAndroid Build Coastguard Worker result.push_back(map);
195*288bf522SAndroid Build Coastguard Worker }
196*288bf522SAndroid Build Coastguard Worker }
197*288bf522SAndroid Build Coastguard Worker bool all_zero = true;
198*288bf522SAndroid Build Coastguard Worker for (const auto& map : result) {
199*288bf522SAndroid Build Coastguard Worker if (map.start_addr != 0) {
200*288bf522SAndroid Build Coastguard Worker all_zero = false;
201*288bf522SAndroid Build Coastguard Worker }
202*288bf522SAndroid Build Coastguard Worker }
203*288bf522SAndroid Build Coastguard Worker if (all_zero) {
204*288bf522SAndroid Build Coastguard Worker LOG(DEBUG) << "addresses in /proc/modules are all zero, so ignore kernel modules";
205*288bf522SAndroid Build Coastguard Worker return std::vector<KernelMmap>();
206*288bf522SAndroid Build Coastguard Worker }
207*288bf522SAndroid Build Coastguard Worker return result;
208*288bf522SAndroid Build Coastguard Worker }
209*288bf522SAndroid Build Coastguard Worker
GetKernelStartAddress()210*288bf522SAndroid Build Coastguard Worker uint64_t GetKernelStartAddress() {
211*288bf522SAndroid Build Coastguard Worker ScopedKptrUnrestrict kptr_unrestrict;
212*288bf522SAndroid Build Coastguard Worker if (!kptr_unrestrict.KallsymsAvailable()) return 0;
213*288bf522SAndroid Build Coastguard Worker LineReader reader(kKallsymsPath);
214*288bf522SAndroid Build Coastguard Worker if (!reader.Ok()) {
215*288bf522SAndroid Build Coastguard Worker return 0;
216*288bf522SAndroid Build Coastguard Worker }
217*288bf522SAndroid Build Coastguard Worker std::string* line;
218*288bf522SAndroid Build Coastguard Worker while ((line = reader.ReadLine()) != nullptr) {
219*288bf522SAndroid Build Coastguard Worker if (strstr(line->data(), "_stext") != nullptr) {
220*288bf522SAndroid Build Coastguard Worker uint64_t addr;
221*288bf522SAndroid Build Coastguard Worker if (sscanf(line->data(), "%" PRIx64, &addr) == 1) {
222*288bf522SAndroid Build Coastguard Worker return addr;
223*288bf522SAndroid Build Coastguard Worker }
224*288bf522SAndroid Build Coastguard Worker }
225*288bf522SAndroid Build Coastguard Worker }
226*288bf522SAndroid Build Coastguard Worker return 0;
227*288bf522SAndroid Build Coastguard Worker }
228*288bf522SAndroid Build Coastguard Worker
LoadKernelSymbols(std::string * kallsyms)229*288bf522SAndroid Build Coastguard Worker bool LoadKernelSymbols(std::string* kallsyms) {
230*288bf522SAndroid Build Coastguard Worker ScopedKptrUnrestrict kptr_unrestrict;
231*288bf522SAndroid Build Coastguard Worker if (kptr_unrestrict.KallsymsAvailable()) {
232*288bf522SAndroid Build Coastguard Worker return android::base::ReadFileToString(kKallsymsPath, kallsyms);
233*288bf522SAndroid Build Coastguard Worker }
234*288bf522SAndroid Build Coastguard Worker return false;
235*288bf522SAndroid Build Coastguard Worker }
236*288bf522SAndroid Build Coastguard Worker
ResetKernelAddressWarning()237*288bf522SAndroid Build Coastguard Worker void ResetKernelAddressWarning() {
238*288bf522SAndroid Build Coastguard Worker ScopedKptrUnrestrict::ResetWarning();
239*288bf522SAndroid Build Coastguard Worker }
240*288bf522SAndroid Build Coastguard Worker
241*288bf522SAndroid Build Coastguard Worker #endif // defined(__linux__)
242*288bf522SAndroid Build Coastguard Worker
ProcessKernelSymbols(std::string & symbol_data,const std::function<bool (const KernelSymbol &)> & callback)243*288bf522SAndroid Build Coastguard Worker bool ProcessKernelSymbols(std::string& symbol_data,
244*288bf522SAndroid Build Coastguard Worker const std::function<bool(const KernelSymbol&)>& callback) {
245*288bf522SAndroid Build Coastguard Worker char* p = &symbol_data[0];
246*288bf522SAndroid Build Coastguard Worker char* data_end = p + symbol_data.size();
247*288bf522SAndroid Build Coastguard Worker while (p < data_end) {
248*288bf522SAndroid Build Coastguard Worker char* line_end = strchr(p, '\n');
249*288bf522SAndroid Build Coastguard Worker if (line_end != nullptr) {
250*288bf522SAndroid Build Coastguard Worker *line_end = '\0';
251*288bf522SAndroid Build Coastguard Worker }
252*288bf522SAndroid Build Coastguard Worker size_t line_size = (line_end != nullptr) ? (line_end - p) : (data_end - p);
253*288bf522SAndroid Build Coastguard Worker // Parse line like: ffffffffa005c4e4 d __warned.41698 [libsas]
254*288bf522SAndroid Build Coastguard Worker char name[line_size];
255*288bf522SAndroid Build Coastguard Worker char module[line_size];
256*288bf522SAndroid Build Coastguard Worker strcpy(module, "");
257*288bf522SAndroid Build Coastguard Worker
258*288bf522SAndroid Build Coastguard Worker KernelSymbol symbol;
259*288bf522SAndroid Build Coastguard Worker int ret = sscanf(p, "%" PRIx64 " %c %s%s", &symbol.addr, &symbol.type, name, module);
260*288bf522SAndroid Build Coastguard Worker if (line_end != nullptr) {
261*288bf522SAndroid Build Coastguard Worker *line_end = '\n';
262*288bf522SAndroid Build Coastguard Worker p = line_end + 1;
263*288bf522SAndroid Build Coastguard Worker } else {
264*288bf522SAndroid Build Coastguard Worker p = data_end;
265*288bf522SAndroid Build Coastguard Worker }
266*288bf522SAndroid Build Coastguard Worker if (ret >= 3) {
267*288bf522SAndroid Build Coastguard Worker if (IsArmMappingSymbol(name)) {
268*288bf522SAndroid Build Coastguard Worker continue;
269*288bf522SAndroid Build Coastguard Worker }
270*288bf522SAndroid Build Coastguard Worker
271*288bf522SAndroid Build Coastguard Worker symbol.name = name;
272*288bf522SAndroid Build Coastguard Worker size_t module_len = strlen(module);
273*288bf522SAndroid Build Coastguard Worker if (module_len > 2 && module[0] == '[' && module[module_len - 1] == ']') {
274*288bf522SAndroid Build Coastguard Worker module[module_len - 1] = '\0';
275*288bf522SAndroid Build Coastguard Worker symbol.module = &module[1];
276*288bf522SAndroid Build Coastguard Worker } else {
277*288bf522SAndroid Build Coastguard Worker symbol.module = nullptr;
278*288bf522SAndroid Build Coastguard Worker }
279*288bf522SAndroid Build Coastguard Worker
280*288bf522SAndroid Build Coastguard Worker if (callback(symbol)) {
281*288bf522SAndroid Build Coastguard Worker return true;
282*288bf522SAndroid Build Coastguard Worker }
283*288bf522SAndroid Build Coastguard Worker }
284*288bf522SAndroid Build Coastguard Worker }
285*288bf522SAndroid Build Coastguard Worker return false;
286*288bf522SAndroid Build Coastguard Worker }
287*288bf522SAndroid Build Coastguard Worker
288*288bf522SAndroid Build Coastguard Worker } // namespace simpleperf
289