From 92c688b1f744dbded59f2df547f31db1638e316b Mon Sep 17 00:00:00 2001 From: Yabin Cui Date: Wed, 1 Jun 2016 15:39:39 -0700 Subject: [PATCH] simpleperf: check perf event limit. The property security.perf_harden is added in https://android-review.googlesource.com/#/c/233736/5. And simpleperf needs to notice that. Bug: 29054680 Change-Id: I5f1593f5b389d182a56c4bf3bd438a1dc2b66686 (cherry picked from commit ebf79f3a65c81ef0f8cd7a3b875771be88157fcc) --- simpleperf/cmd_list.cpp | 16 ++++++++--- simpleperf/cmd_record.cpp | 4 +++ simpleperf/cmd_stat.cpp | 4 +++ simpleperf/environment.cpp | 67 ++++++++++++++++++++++++++++++++++++++++++++++ simpleperf/environment.h | 1 + simpleperf/gtest_main.cpp | 12 --------- simpleperf/utils.cpp | 12 +++++++++ simpleperf/utils.h | 1 + 8 files changed, 102 insertions(+), 15 deletions(-) diff --git a/simpleperf/cmd_list.cpp b/simpleperf/cmd_list.cpp index b6bf817c..273a8037 100644 --- a/simpleperf/cmd_list.cpp +++ b/simpleperf/cmd_list.cpp @@ -22,6 +22,7 @@ #include #include "command.h" +#include "environment.h" #include "event_attr.h" #include "event_fd.h" #include "event_type.h" @@ -30,9 +31,14 @@ static void PrintEventTypesOfType(uint32_t type, const std::string& type_name, const std::vector& event_types) { printf("List of %s:\n", type_name.c_str()); for (auto& event_type : event_types) { - if (event_type.type == type && - IsEventAttrSupportedByKernel(CreateDefaultPerfEventAttr(event_type))) { - printf(" %s\n", event_type.name.c_str()); + if (event_type.type == type) { + perf_event_attr attr = CreateDefaultPerfEventAttr(event_type); + // Exclude kernel to list supported events even when + // /proc/sys/kernel/perf_event_paranoid is 2. + attr.exclude_kernel = 1; + if (IsEventAttrSupportedByKernel(attr)) { + printf(" %s\n", event_type.name.c_str()); + } } } printf("\n"); @@ -50,6 +56,10 @@ class ListCommand : public Command { }; bool ListCommand::Run(const std::vector& args) { + if (!CheckPerfEventLimit()) { + return false; + } + static std::map> type_map = { {"hw", {PERF_TYPE_HARDWARE, "hardware events"}}, {"sw", {PERF_TYPE_SOFTWARE, "software events"}}, diff --git a/simpleperf/cmd_record.cpp b/simpleperf/cmd_record.cpp index 910bc3e9..ae025b03 100644 --- a/simpleperf/cmd_record.cpp +++ b/simpleperf/cmd_record.cpp @@ -188,6 +188,10 @@ class RecordCommand : public Command { }; bool RecordCommand::Run(const std::vector& args) { + if (!CheckPerfEventLimit()) { + return false; + } + // 1. Parse options, and use default measured event type if not given. std::vector workload_args; if (!ParseOptions(args, &workload_args)) { diff --git a/simpleperf/cmd_stat.cpp b/simpleperf/cmd_stat.cpp index 228b4edc..488e731b 100644 --- a/simpleperf/cmd_stat.cpp +++ b/simpleperf/cmd_stat.cpp @@ -101,6 +101,10 @@ class StatCommand : public Command { }; bool StatCommand::Run(const std::vector& args) { + if (!CheckPerfEventLimit()) { + return false; + } + // 1. Parse options, and use default measured event types if not given. std::vector workload_args; if (!ParseOptions(args, &workload_args)) { diff --git a/simpleperf/environment.cpp b/simpleperf/environment.cpp index 996a5e43..5a8552a2 100644 --- a/simpleperf/environment.cpp +++ b/simpleperf/environment.cpp @@ -31,6 +31,10 @@ #include #include +#if defined(__ANDROID__) +#include +#endif + #include "read_elf.h" #include "utils.h" @@ -410,3 +414,66 @@ bool GetExecPath(std::string* exec_path) { *exec_path = path; return true; } + +/* + * perf event paranoia level: + * -1 - not paranoid at all + * 0 - disallow raw tracepoint access for unpriv + * 1 - disallow cpu events for unpriv + * 2 - disallow kernel profiling for unpriv + * 3 - disallow user profiling for unpriv + */ +static bool ReadPerfEventParanoid(int* value) { + std::string s; + if (!android::base::ReadFileToString("/proc/sys/kernel/perf_event_paranoid", &s)) { + PLOG(ERROR) << "failed to read /proc/sys/kernel/perf_event_paranoid"; + return false; + } + s = android::base::Trim(s); + if (!android::base::ParseInt(s.c_str(), value)) { + PLOG(ERROR) << "failed to parse /proc/sys/kernel/perf_event_paranoid: " << s; + return false; + } + return true; +} + +static const char* GetLimitLevelDescription(int limit_level) { + switch (limit_level) { + case -1: return "unlimited"; + case 0: return "disallowing raw tracepoint access for unpriv"; + case 1: return "disallowing cpu events for unpriv"; + case 2: return "disallowing kernel profiling for unpriv"; + case 3: return "disallowing user profiling for unpriv"; + default: return "unknown level"; + } +} + +bool CheckPerfEventLimit() { + // root is not limited by /proc/sys/kernel/perf_event_paranoid. + if (IsRoot()) { + return true; + } + int limit_level; + if (!ReadPerfEventParanoid(&limit_level)) { + return false; + } + if (limit_level <= 1) { + return true; + } +#if defined(__ANDROID__) + // Try to enable perf_event_paranoid by setprop security.perf_harden=0. + if (__system_property_set("security.perf_harden", "0") == 0) { + sleep(1); + if (ReadPerfEventParanoid(&limit_level) && limit_level <= 1) { + return true; + } + } + LOG(WARNING) << "/proc/sys/kernel/perf_event_paranoid is " << limit_level + << ", " << GetLimitLevelDescription(limit_level) << "."; + LOG(WARNING) << "Try using `adb shell setprop security.perf_harden 0` to allow profiling."; +#else + LOG(WARNING) << "/proc/sys/kernel/perf_event_paranoid is " << limit_level + << ", " << GetLimitLevelDescription(limit_level) << "."; +#endif + return true; +} diff --git a/simpleperf/environment.h b/simpleperf/environment.h index c405af8f..6da632b9 100644 --- a/simpleperf/environment.h +++ b/simpleperf/environment.h @@ -79,5 +79,6 @@ struct KernelSymbol { bool ProcessKernelSymbols(const std::string& symbol_file, std::function callback); +bool CheckPerfEventLimit(); #endif // SIMPLE_PERF_ENVIRONMENT_H_ diff --git a/simpleperf/gtest_main.cpp b/simpleperf/gtest_main.cpp index c9a066ed..ec4768fc 100644 --- a/simpleperf/gtest_main.cpp +++ b/simpleperf/gtest_main.cpp @@ -145,15 +145,3 @@ std::string GetTestData(const std::string& filename) { const std::string& GetTestDataDir() { return testdata_dir; } - -bool IsRoot() { - static int is_root = -1; - if (is_root == -1) { -#if defined(__linux__) - is_root = (getuid() == 0) ? 1 : 0; -#else - is_root = 0; -#endif - } - return is_root == 1; -} diff --git a/simpleperf/utils.cpp b/simpleperf/utils.cpp index fb24d1ee..d14d20ca 100644 --- a/simpleperf/utils.cpp +++ b/simpleperf/utils.cpp @@ -197,3 +197,15 @@ bool GetLogSeverity(const std::string& name, android::base::LogSeverity* severit } return false; } + +bool IsRoot() { + static int is_root = -1; + if (is_root == -1) { +#if defined(__linux__) + is_root = (getuid() == 0) ? 1 : 0; +#else + is_root = 0; +#endif + } + return is_root == 1; +} diff --git a/simpleperf/utils.h b/simpleperf/utils.h index c65641cc..420fcc97 100644 --- a/simpleperf/utils.h +++ b/simpleperf/utils.h @@ -121,4 +121,5 @@ bool MkdirWithParents(const std::string& path); bool GetLogSeverity(const std::string& name, android::base::LogSeverity* severity); +bool IsRoot(); #endif // SIMPLE_PERF_UTILS_H_ -- 2.11.0