Index: content/test/content_android_linker_unittest.cc |
diff --git a/content/test/content_android_linker_unittest.cc b/content/test/content_android_linker_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..aaab0f9b82621366e7ca70b0cc3d2554188158dc |
--- /dev/null |
+++ b/content/test/content_android_linker_unittest.cc |
@@ -0,0 +1,129 @@ |
+// Copyright (c) 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. |
+ |
+#ifndef CONTENT_TEST_CONTENT_LINKER_UNITTEST_H |
+#define CONTENT_TEST_CONTENT_LINKER_UNITTEST_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/strings/stringprintf.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+namespace content { |
+ |
+namespace { |
+ |
+// 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:"; |
+ |
+using base::debug::MappedMemoryRegion; |
+ |
+class ContentLinkerTest : public ::testing::Test { |
+ public: |
+ ContentLinkerTest() |
+ : regions_(), relro_section_prefix_(kRelroSectionPrefix) {} |
+ |
+ protected: |
+ virtual void SetUp() { |
+ regions_.clear(); |
+ std::string maps; |
+ base::debug::ReadProcMaps(&maps); |
+ base::debug::ParseProcMaps(maps, ®ions_); |
+ } |
+ |
+ virtual void TearDown() {} |
+ |
+ std::vector<MappedMemoryRegion> regions_; |
+ std::string relro_section_prefix_; |
+}; |
+ |
+} // namespace |
+ |
+// This test checks that our content-based library has been loaded |
+// and that its RELRO section is in an ashmem region, with a name |
+// that begins with /dev/ashmem/RELRO: |
+// |
+TEST_F(ContentLinkerTest, RelroInAshmem) { |
+ size_t count = 0; |
+ |
+ for (size_t n = 0; n < regions_.size(); ++n) { |
+ MappedMemoryRegion& region = regions_[n]; |
+ |
+ if (region.path.find(relro_section_prefix_) == 0) |
+ count++; |
+ } |
+ |
+ // Can't use EXPECT_EQ here due to the component build having |
+ // many libraries loaded through our linker, each one with its own |
+ // shared RELRO section. There are also plenty of system libraries |
+ // without a shared RELRO section as well. |
+ EXPECT_GE(count, 1U) |
+ << "The number of RELRO sections in ashmem regions in this process\n"; |
+} |
+ |
+// This test checks that every shared RELRO section is always read-only |
+// and non-executable. |
+TEST_F(ContentLinkerTest, RelroIsReadOnly) { |
+ uint8 expected_flags = MappedMemoryRegion::READ; |
+ uint8 expected_mask = MappedMemoryRegion::READ | MappedMemoryRegion::WRITE | |
+ MappedMemoryRegion::EXECUTE; |
+ |
+ for (size_t n = 0; n < regions_.size(); ++n) { |
+ MappedMemoryRegion& region = regions_[n]; |
+ |
+ if (region.path.find(relro_section_prefix_) != 0) |
+ continue; |
+ |
+ EXPECT_EQ(expected_flags, region.permissions & expected_mask) |
+ << base::StringPrintf( |
+ "Checking permissions for RELRO region at %p-%p\n", |
+ reinterpret_cast<void*>(region.start), |
+ reinterpret_cast<void*>(region.end)); |
+ } |
+} |
+ |
+// This test checks that each RELRO section cannot be remapped read-write |
+// with mprotect(), for security reasons. |
+TEST_F(ContentLinkerTest, RelroCantBeRemappedWritable) { |
+ for (size_t n = 0; n < regions_.size(); ++n) { |
+ MappedMemoryRegion& region = regions_[n]; |
+ |
+ if (region.path.find(relro_section_prefix_) != 0) |
+ continue; |
+ |
+ std::string text = base::StringPrintf( |
+ "Checking non-writability for RELRO region at %p-%p\n", |
+ reinterpret_cast<void*>(region.start), |
+ reinterpret_cast<void*>(region.end)); |
+ |
+ EXPECT_EQ(-1, |
+ ::mprotect(reinterpret_cast<void*>(region.start), |
+ region.end - region.start, |
+ PROT_READ | PROT_WRITE)) |
+ << text; |
+ EXPECT_EQ(EACCES, errno) << text; |
+ } |
+} |
+ |
+} // namespace content |
+ |
+#endif // CONTENT_TEST_CONTENT_LINKER_UNITTEST_H |