Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1025)

Unified Diff: content/shell/android/linker_test_apk/content_linker_test_linker_tests.cc

Issue 23717023: Android: Add chrome-specific dynamic linker. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Update content_tests.gypi Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/shell/android/linker_test_apk/content_linker_test_linker_tests.cc
diff --git a/content/shell/android/linker_test_apk/content_linker_test_linker_tests.cc b/content/shell/android/linker_test_apk/content_linker_test_linker_tests.cc
new file mode 100644
index 0000000000000000000000000000000000000000..c46e864a3c7806407da5f1a9831572ead0bb8c10
--- /dev/null
+++ b/content/shell/android/linker_test_apk/content_linker_test_linker_tests.cc
@@ -0,0 +1,185 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file implements the native methods of
+// org.content.chromium.app.LinkerTests
+// Unlike the content of linker_jni.cc, it is part of the content library and
+// can
+// thus use base/ and the C++ STL.
+
+#include "content/shell/android/linker_test_apk/content_linker_test_linker_tests.h"
+
+#include <errno.h>
+#include <sys/mman.h>
+#include <stdio.h>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/debug/proc_maps_linux.h"
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+
+#include "jni/LinkerTests_jni.h"
+
+namespace content {
+
+namespace {
+
+using base::debug::MappedMemoryRegion;
+
+jboolean RunChecks(bool in_browser_process, bool need_relros) {
+
+ // IMPORTANT NOTE: The Python test control script reads the logcat for
+ // lines like:
+ // BROWSER_LINKER_TEST: <status>
+ // RENDERER_LINKER_TEST: <status>
+ //
+ // Where <status> can be either SUCCESS or FAIL. Other lines starting
+ // with the same prefixes, but not using SUCCESS or FAIL are ignored.
+ const char* prefix =
+ in_browser_process ? "BROWSER_LINKER_TEST: " : "RENDERER_LINKER_TEST: ";
+
+ // The RELRO section(s), after being copied into an ashmem region, will
+ // appear in /proc/self/maps as a mapped memory region for a file name
+ // that begins with the following prefix.
+ //
+ // Note that the full name will be something like:
+ // "/dev/ashmem/RELRO:<libname> (deleted)"
+ //
+ // Where <libname> is the library name and '(deleted)' is actually
+ // added by the kernel to indicate there is no corresponding file
+ // on the filesystem.
+ //
+ // For regular builds, there is only one library, and thus one RELRO
+ // section, but for the component build, there are several libraries,
+ // each one with its own RELRO.
+ static const char kRelroSectionPrefix[] = "/dev/ashmem/RELRO:";
+
+ // Parse /proc/self/maps and builds a list of region mappings in this
+ // process.
+ std::string maps;
+ base::debug::ReadProcMaps(&maps);
+ if (maps.empty()) {
+ LOG(ERROR) << prefix << "FAIL Cannot parse /proc/self/maps";
+ return false;
+ }
+
+ std::vector<MappedMemoryRegion> regions;
+ base::debug::ParseProcMaps(maps, &regions);
+ if (regions.empty()) {
+ LOG(ERROR) << prefix << "FAIL Cannot read memory mappings in this process";
+ return false;
+ }
+
+ size_t num_shared_relros = 0;
+ size_t num_bad_shared_relros = 0;
+
+ for (size_t n = 0; n < regions.size(); ++n) {
+ MappedMemoryRegion& region = regions[n];
+
+ if (region.path.find(kRelroSectionPrefix) != 0) {
+ // Ignore any mapping that isn't a shared RELRO.
+ continue;
+ }
+
+ num_shared_relros++;
+
+ void* region_start = reinterpret_cast<void*>(region.start);
+ void* region_end = reinterpret_cast<void*>(region.end);
+
+ // Check that it is mapped read-only.
+ const uint8 expected_flags = MappedMemoryRegion::READ;
+ const uint8 expected_mask = MappedMemoryRegion::READ |
+ MappedMemoryRegion::WRITE |
+ MappedMemoryRegion::EXECUTE;
+
+ uint8 region_flags = region.permissions & expected_mask;
+ if (region_flags != expected_flags) {
+ LOG(ERROR)
+ << prefix
+ << base::StringPrintf(
+ "Shared RELRO section at %p-%p is not mapped read-only. "
+ "Protection flags are %d (%d expected)!",
+ region_start,
+ region_end,
+ region_flags,
+ expected_flags);
+ num_bad_shared_relros++;
+ continue;
+ }
+
+ // Check that trying to remap it read-write fails with EACCES
+ size_t region_size = region.end - region.start;
+ int ret = ::mprotect(region_start, region_size, PROT_READ | PROT_WRITE);
+ if (ret != -1) {
+ LOG(ERROR)
+ << prefix
+ << base::StringPrintf(
+ "Shared RELRO section at %p-%p could be remapped read-write!?",
+ region_start,
+ region_end);
+ num_bad_shared_relros++;
+ // Just in case.
+ ::mprotect(region_start, region_size, PROT_READ);
+ } else if (errno != EACCES) {
+ LOG(ERROR) << prefix << base::StringPrintf(
+ "Shared RELRO section at %p-%p failed "
+ "read-write mprotect with "
+ "unexpected error %d (EACCES:%d wanted): %s",
+ region_start,
+ region_end,
+ errno,
+ EACCES,
+ strerror(errno));
+ num_bad_shared_relros++;
+ }
+ }
+
+ LOG(INFO)
+ << prefix
+ << base::StringPrintf(
+ "There are %d shared RELRO sections in this process, %d are bad",
+ num_shared_relros,
+ num_bad_shared_relros);
+
+ if (num_bad_shared_relros > 0) {
+ LOG(ERROR) << prefix << "FAIL Bad Relros sections in this process";
+ return false;
+ }
+
+ if (need_relros) {
+ if (num_shared_relros == 0) {
+ LOG(ERROR) << prefix
+ << "FAIL Missing shared RELRO sections in this process!";
+ return false;
+ }
+ } else {
+ if (num_shared_relros > 0) {
+ LOG(ERROR) << prefix << "FAIL Unexpected " << num_shared_relros
+ << " shared RELRO sections in this process!";
+ return false;
+ }
+ }
+
+ LOG(INFO) << prefix << "SUCCESS";
+ return true;
+}
+
+} // namespace
+
+jboolean CheckForSharedRelros(JNIEnv* env,
+ jclass clazz,
+ jboolean in_browser_process) {
+ return RunChecks(in_browser_process, true);
+}
+
+jboolean CheckForNoSharedRelros(JNIEnv* env,
+ jclass clazz,
+ jboolean in_browser_process) {
+ return RunChecks(in_browser_process, false);
+}
+
+bool RegisterLinkerTestsJni(JNIEnv* env) { return RegisterNativesImpl(env); }
+
+} // namespace content

Powered by Google App Engine
This is Rietveld 408576698