summaryrefslogtreecommitdiff
path: root/init/security.cpp
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2020-01-22 04:22:18 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2020-01-22 04:22:18 +0000
commitdd7b0034f18fe2adb98d89bc2d4eeaa7dbd099a2 (patch)
treef7681478921146427edb73e4e70162d18bdfa0b4 /init/security.cpp
parent5e8b40f3bb00ced5da858e373345795c519e74dc (diff)
parentdaec2f4f88253e2e6c9ac38c1903e9ef0e1c07fe (diff)
Snap for 6152176 from daec2f4f88253e2e6c9ac38c1903e9ef0e1c07fe to rvc-release
Change-Id: Icf074761856709508e65f435e25a8f64aeab708d
Diffstat (limited to 'init/security.cpp')
-rw-r--r--init/security.cpp61
1 files changed, 61 insertions, 0 deletions
diff --git a/init/security.cpp b/init/security.cpp
index 586d0c72b..6cbe642c0 100644
--- a/init/security.cpp
+++ b/init/security.cpp
@@ -18,14 +18,19 @@
#include <errno.h>
#include <fcntl.h>
+#include <linux/perf_event.h>
+#include <sys/ioctl.h>
+#include <sys/syscall.h>
#include <unistd.h>
#include <fstream>
#include <android-base/logging.h>
+#include <android-base/properties.h>
#include <android-base/unique_fd.h>
using android::base::unique_fd;
+using android::base::SetProperty;
namespace android {
namespace init {
@@ -197,5 +202,61 @@ Result<void> SetKptrRestrictAction(const BuiltinArguments&) {
return {};
}
+// Test for whether the kernel has SELinux hooks for the perf_event_open()
+// syscall. If the hooks are present, we can stop using the other permission
+// mechanism (perf_event_paranoid sysctl), and use only the SELinux policy to
+// control access to the syscall. The hooks are expected on all Android R
+// release kernels, but might be absent on devices that upgrade while keeping an
+// older kernel.
+//
+// There is no direct/synchronous way of finding out that a syscall failed due
+// to SELinux. Therefore we test for a combination of a success and a failure
+// that are explained by the platform's SELinux policy for the "init" domain:
+// * cpu-scoped perf_event is allowed
+// * ioctl() on the event fd is disallowed with EACCES
+//
+// Since init has CAP_SYS_ADMIN, these tests are not affected by the system-wide
+// perf_event_paranoid sysctl.
+//
+// If the SELinux hooks are detected, a special sysprop
+// (sys.init.perf_lsm_hooks) is set, which translates to a modification of
+// perf_event_paranoid (through init.rc sysprop actions).
+//
+// TODO(b/137092007): this entire test can be removed once the platform stops
+// supporting kernels that precede the perf_event_open hooks (Android common
+// kernels 4.4 and 4.9).
+Result<void> TestPerfEventSelinuxAction(const BuiltinArguments&) {
+ // Use a trivial event that will be configured, but not started.
+ struct perf_event_attr pe = {
+ .type = PERF_TYPE_SOFTWARE,
+ .size = sizeof(struct perf_event_attr),
+ .config = PERF_COUNT_SW_TASK_CLOCK,
+ .disabled = 1,
+ .exclude_kernel = 1,
+ };
+
+ // Open the above event targeting cpu 0. (EINTR not possible.)
+ unique_fd fd(static_cast<int>(syscall(__NR_perf_event_open, &pe, /*pid=*/-1,
+ /*cpu=*/0,
+ /*group_fd=*/-1, /*flags=*/0)));
+ if (fd == -1) {
+ PLOG(ERROR) << "Unexpected perf_event_open error";
+ return {};
+ }
+
+ int ioctl_ret = ioctl(fd, PERF_EVENT_IOC_RESET);
+ if (ioctl_ret != -1) {
+ // Success implies that the kernel doesn't have the hooks.
+ return {};
+ } else if (errno != EACCES) {
+ PLOG(ERROR) << "Unexpected perf_event ioctl error";
+ return {};
+ }
+
+ // Conclude that the SELinux hooks are present.
+ SetProperty("sys.init.perf_lsm_hooks", "1");
+ return {};
+}
+
} // namespace init
} // namespace android