OSDN Git Service

base: add SafeCopy.
authorJosh Gao <jmgao@google.com>
Tue, 18 Apr 2017 01:31:26 +0000 (18:31 -0700)
committerJosh Gao <jmgao@google.com>
Tue, 18 Apr 2017 21:04:20 +0000 (14:04 -0700)
Add a function that uses process_vm_readv on Linux to safely
dereference pointers without the risk of segfault.

Bug: http://b/30836730
Test: safe_copy_test on host
Change-Id: I10bafcffe2172e17b00f65455d1dd6a08aa631d7

runtime/Android.bp
runtime/base/safe_copy.cc [new file with mode: 0644]
runtime/base/safe_copy.h [new file with mode: 0644]
runtime/base/safe_copy_test.cc [new file with mode: 0644]

index 6c3bc04..8972e91 100644 (file)
@@ -37,6 +37,7 @@ cc_defaults {
         "base/hex_dump.cc",
         "base/logging.cc",
         "base/mutex.cc",
+        "base/safe_copy.cc",
         "base/scoped_arena_allocator.cc",
         "base/scoped_flock.cc",
         "base/stringpiece.cc",
@@ -522,6 +523,7 @@ art_cc_test {
         "base/hex_dump_test.cc",
         "base/histogram_test.cc",
         "base/mutex_test.cc",
+        "base/safe_copy_test.cc",
         "base/scoped_flock_test.cc",
         "base/time_utils_test.cc",
         "base/timing_logger_test.cc",
diff --git a/runtime/base/safe_copy.cc b/runtime/base/safe_copy.cc
new file mode 100644 (file)
index 0000000..b69a56f
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "safe_copy.h"
+
+#include <unistd.h>
+#include <sys/uio.h>
+
+#include <android-base/macros.h>
+
+namespace art {
+
+ssize_t SafeCopy(void *dst, const void *src, size_t len) {
+#if defined(__linux__)
+  struct iovec dst_iov = {
+    .iov_base = dst,
+    .iov_len = len,
+  };
+  struct iovec src_iov = {
+    .iov_base = const_cast<void*>(src),
+    .iov_len = len,
+  };
+
+  ssize_t rc = process_vm_readv(getpid(), &dst_iov, 1, &src_iov, 1, 0);
+  if (rc == -1) {
+    return 0;
+  }
+  return rc;
+#else
+  UNUSED(dst, src, len);
+  return -1;
+#endif
+}
+
+}  // namespace art
diff --git a/runtime/base/safe_copy.h b/runtime/base/safe_copy.h
new file mode 100644 (file)
index 0000000..2eee212
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_BASE_SAFE_COPY_H_
+#define ART_RUNTIME_BASE_SAFE_COPY_H_
+
+#include <sys/types.h>
+
+namespace art {
+
+// Safely dereference a pointer.
+// Returns -1 if safe copy isn't implemented on the platform, 0 if src is unreadable.
+ssize_t SafeCopy(void *dst, const void *src, size_t len);
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_BASE_SAFE_COPY_H_
diff --git a/runtime/base/safe_copy_test.cc b/runtime/base/safe_copy_test.cc
new file mode 100644 (file)
index 0000000..d5b8cdb
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "safe_copy.h"
+
+#include "common_runtime_test.h"
+
+#include <sys/mman.h>
+#include <sys/user.h>
+
+namespace art {
+
+#if defined(__linux__)
+
+TEST(SafeCopyTest, smoke) {
+  // Map two pages, and mark the second one as PROT_NONE.
+  void* map = mmap(nullptr, PAGE_SIZE * 2, PROT_READ | PROT_WRITE,
+                   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  ASSERT_NE(MAP_FAILED, map);
+  char* page1 = static_cast<char*>(map);
+  ASSERT_EQ(0, mprotect(page1 + PAGE_SIZE, PAGE_SIZE, PROT_NONE));
+
+  page1[0] = 'a';
+  page1[PAGE_SIZE - 1] = 'z';
+
+  char buf[PAGE_SIZE];
+
+  // Completely valid read.
+  memset(buf, 0xCC, sizeof(buf));
+  EXPECT_EQ(static_cast<ssize_t>(PAGE_SIZE), SafeCopy(buf, page1, PAGE_SIZE));
+  EXPECT_EQ(0, memcmp(buf, page1, PAGE_SIZE));
+
+  // Reading off of the end.
+  memset(buf, 0xCC, sizeof(buf));
+  EXPECT_EQ(static_cast<ssize_t>(PAGE_SIZE - 1), SafeCopy(buf, page1 + 1, PAGE_SIZE));
+  EXPECT_EQ(0, memcmp(buf, page1 + 1, PAGE_SIZE - 1));
+
+  // Completely invalid.
+  EXPECT_EQ(0, SafeCopy(buf, page1 + PAGE_SIZE, PAGE_SIZE));
+  ASSERT_EQ(0, munmap(map, PAGE_SIZE * 2));
+}
+
+#endif  // defined(__linux__)
+
+}  // namespace art