diff options
author | 2017-04-17 18:31:26 -0700 | |
---|---|---|
committer | 2017-04-18 14:04:20 -0700 | |
commit | 682282eaac86202652e17752ef32f14c89e2ccda (patch) | |
tree | c779c7a48e7fa41b4aad0cb1f7bb4953fde241cc | |
parent | c36a970fcd4878eafd03d41eeff0a4cbdd400326 (diff) |
base: add SafeCopy.
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
-rw-r--r-- | runtime/Android.bp | 2 | ||||
-rw-r--r-- | runtime/base/safe_copy.cc | 48 | ||||
-rw-r--r-- | runtime/base/safe_copy.h | 30 | ||||
-rw-r--r-- | runtime/base/safe_copy_test.cc | 58 |
4 files changed, 138 insertions, 0 deletions
diff --git a/runtime/Android.bp b/runtime/Android.bp index 6c3bc0450b..8972e91321 100644 --- a/runtime/Android.bp +++ b/runtime/Android.bp @@ -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 index 0000000000..b69a56ff06 --- /dev/null +++ b/runtime/base/safe_copy.cc @@ -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 index 0000000000..2eee2120fc --- /dev/null +++ b/runtime/base/safe_copy.h @@ -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 index 0000000000..d5b8cdb05d --- /dev/null +++ b/runtime/base/safe_copy_test.cc @@ -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 |