summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYabin Cui <yabinc@google.com>2016-06-01 15:39:39 -0700
committerYabin Cui <yabinc@google.com>2016-06-10 16:36:18 -0700
commit92c688b1f744dbded59f2df547f31db1638e316b (patch)
tree1c922e700176ee8d622d8826143a23d3b9d7d95f
parent600c6341e62c165c60f526174d965cc7f1b30c38 (diff)
downloadextras-92c688b1f744dbded59f2df547f31db1638e316b.tar.gz
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)
-rw-r--r--simpleperf/cmd_list.cpp16
-rw-r--r--simpleperf/cmd_record.cpp4
-rw-r--r--simpleperf/cmd_stat.cpp4
-rw-r--r--simpleperf/environment.cpp67
-rw-r--r--simpleperf/environment.h1
-rw-r--r--simpleperf/gtest_main.cpp12
-rw-r--r--simpleperf/utils.cpp12
-rw-r--r--simpleperf/utils.h1
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 <android-base/logging.h>
#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<EventType>& 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<std::string>& args) {
+ if (!CheckPerfEventLimit()) {
+ return false;
+ }
+
static std::map<std::string, std::pair<int, std::string>> 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<std::string>& args) {
+ if (!CheckPerfEventLimit()) {
+ return false;
+ }
+
// 1. Parse options, and use default measured event type if not given.
std::vector<std::string> 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<std::string>& args) {
+ if (!CheckPerfEventLimit()) {
+ return false;
+ }
+
// 1. Parse options, and use default measured event types if not given.
std::vector<std::string> 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 <android-base/strings.h>
#include <android-base/stringprintf.h>
+#if defined(__ANDROID__)
+#include <sys/system_properties.h>
+#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<bool(const KernelSymbol&)> 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_