crashpad/compat/android/sys/mman_mmap.cc
Joshua Peraza 3e065b11d0 linux, mac: disable cfi-icall for cross-dso calls
CFI attempts to verify that the dynamic type of a function object
matches the static type of the function pointer used to call it.

https://clang.llvm.org/docs/ControlFlowIntegrity.html#indirect-function-call-checking

However, the analyzer does not have enough information to check
cross-dso calls. In these instances, CFI crashes upon calling the
function with an error like:

pthread_create_linux.cc:60:16: runtime error:
control flow integrity check for type
'int (unsigned long *, const pthread_attr_t *, void *(*)(void *), void *)'
failed during indirect function call
(/lib/x86_64-linux-gnu/libpthread.so.0+0x9200):
note: (unknown) defined here pthread_create_linux.cc:60:16:
note: check failed in crashpad_handler,
destination function located in /lib/x86_64-linux-gnu/libpthread.so.0

Change-Id: Ib29dabfe714f2ee9cc06a5d17e6899ff81a06df4
Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2339332
Commit-Queue: Joshua Peraza <jperaza@chromium.org>
Reviewed-by: Mark Mentovai <mark@chromium.org>
2020-09-10 22:15:29 +00:00

106 lines
3.2 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright 2017 The Crashpad Authors. All rights reserved.
//
// 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 <sys/mman.h>
#include <dlfcn.h>
#include <errno.h>
#include <stdint.h>
#include <unistd.h>
#include "dlfcn_internal.h"
#include "util/misc/no_cfi_icall.h"
#if defined(__USE_FILE_OFFSET64) && __ANDROID_API__ < 21
// Bionic has provided a wrapper for __mmap2() since the beginning of time. See
// bionic/libc/SYSCALLS.TXT in any Android version.
extern "C" void* __mmap2(void* addr,
size_t size,
int prot,
int flags,
int fd,
size_t pgoff);
namespace {
template <typename T>
T Align(T value, size_t alignment) {
return (value + alignment - 1) & ~(alignment - 1);
}
// Adapted from Android 8.0.0 bionic/libc/bionic/mmap.cpp.
void* LocalMmap64(void* addr,
size_t size,
int prot,
int flags,
int fd,
off64_t offset) {
constexpr int kMmap2Shift = 12;
if (offset < 0 || (offset & ((1UL << kMmap2Shift) - 1)) != 0) {
errno = EINVAL;
return MAP_FAILED;
}
const size_t rounded = Align(size, getpagesize());
if (rounded < size || rounded > PTRDIFF_MAX) {
errno = ENOMEM;
return MAP_FAILED;
}
const bool is_private_anonymous =
(flags & (MAP_PRIVATE | MAP_ANONYMOUS)) == (MAP_PRIVATE | MAP_ANONYMOUS);
const bool is_stack_or_grows_down =
(flags & (MAP_STACK | MAP_GROWSDOWN)) != 0;
void* const result =
__mmap2(addr, size, prot, flags, fd, offset >> kMmap2Shift);
static bool kernel_has_MADV_MERGEABLE = true;
if (result != MAP_FAILED && kernel_has_MADV_MERGEABLE &&
is_private_anonymous && !is_stack_or_grows_down) {
const int saved_errno = errno;
const int rc = madvise(result, size, MADV_MERGEABLE);
if (rc == -1 && errno == EINVAL) {
kernel_has_MADV_MERGEABLE = false;
}
errno = saved_errno;
}
return result;
}
} // namespace
extern "C" {
void* mmap(void* addr, size_t size, int prot, int flags, int fd, off_t offset) {
// Use the systems mmap64() wrapper if available. It will be available on
// Android 5.0 (“Lollipop”) and later.
static const crashpad::NoCfiIcall<decltype(LocalMmap64)*> mmap64(
crashpad::internal::Dlsym(RTLD_DEFAULT, "mmap64"));
if (mmap64) {
return mmap64(addr, size, prot, flags, fd, offset);
}
// Otherwise, use the local implementation, which should amount to exactly the
// same thing.
return LocalMmap64(addr, size, prot, flags, fd, offset);
}
} // extern "C"
#endif // defined(__USE_FILE_OFFSET64) && __ANDROID_API__ < 21