crashpad/util/posix/scoped_mmap.cc

182 lines
4.9 KiB
C++
Raw Normal View History

// 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 "util/posix/scoped_mmap.h"
#include <unistd.h>
#include <algorithm>
#include "base/check_op.h"
#include "base/logging.h"
#include "base/memory/page_size.h"
#include "base/numerics/safe_conversions.h"
#include "base/numerics/safe_math.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
// TODO(crbug.com/1052397): Revisit once build flag switch of lacros-chrome is
// complete.
Use BUILDFLAG for OS checking Use BUILDFLAG(IS_*) instead of defined(OS_*). This was generated mostly mechnically by performing the following steps: - sed -i '' -E -e 's/defined\(OS_/BUILDFLAG(IS_/g' \ -e 's%([ !])OS_([A-Z]+)%\1BUILDFLAG(IS_\2)%g' \ $(git grep -l 'OS_' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm') - sed -i '' -e 's/#ifdef BUILDFLAG(/#if BUILDFLAG(/' \ $(git grep -l '#ifdef BUILDFLAG(' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm') - gsed -i -z -E -e \ 's%(.*)#include "%\1#include "build/buildflag.h"\n#include "%' \ $(git grep -l 'BUILDFLAG(IS_' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm') - Spot checks to move #include "build/buildflag.h" to the correct parts of files. - sed -i '' -E -e \ 's%^(#include "build/buildflag.h")$%#include "build/build_config.h"\n\1%' \ $(grep -L '^#include "build/build_config.h"$' $(git grep -l 'BUILDFLAG(IS_' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm')) - Add “clang-format off” around tool usage messages. - git cl format - Update mini_chromium to 85ba51f98278 (intermediate step). TESTING ONLY). - for f in $(git grep -l '^#include "build/buildflag.h"$' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm'); do \ grep -v '^#include "build/buildflag.h"$' "${f}" > /tmp/z; \ cp /tmp/z "${f}"; done - git cl format - Update mini_chromium to 735143774c5f (intermediate step). - Update mini_chromium to f41420eb45fa (as checked in). - Update mini_chromium to 6e2f204b4ae1 (as checked in). For ease of review and inspection, each of these steps is uploaded as a new patch set in a review series. This includes an update of mini_chromium to 6e2f204b4ae1: f41420eb45fa Use BUILDFLAG for OS checking 6e2f204b4ae1 Include what you use: string_util.h uses build_config.h Bug: chromium:1234043 Change-Id: Ieef86186f094c64e59b853729737e36982f8cf69 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3400258 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org>
2022-01-19 15:00:24 -05:00
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
#include "third_party/lss/lss.h"
#endif
namespace {
// TODO(crbug.com/1052397): Revisit once build flag switch of lacros-chrome is
// complete.
Use BUILDFLAG for OS checking Use BUILDFLAG(IS_*) instead of defined(OS_*). This was generated mostly mechnically by performing the following steps: - sed -i '' -E -e 's/defined\(OS_/BUILDFLAG(IS_/g' \ -e 's%([ !])OS_([A-Z]+)%\1BUILDFLAG(IS_\2)%g' \ $(git grep -l 'OS_' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm') - sed -i '' -e 's/#ifdef BUILDFLAG(/#if BUILDFLAG(/' \ $(git grep -l '#ifdef BUILDFLAG(' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm') - gsed -i -z -E -e \ 's%(.*)#include "%\1#include "build/buildflag.h"\n#include "%' \ $(git grep -l 'BUILDFLAG(IS_' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm') - Spot checks to move #include "build/buildflag.h" to the correct parts of files. - sed -i '' -E -e \ 's%^(#include "build/buildflag.h")$%#include "build/build_config.h"\n\1%' \ $(grep -L '^#include "build/build_config.h"$' $(git grep -l 'BUILDFLAG(IS_' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm')) - Add “clang-format off” around tool usage messages. - git cl format - Update mini_chromium to 85ba51f98278 (intermediate step). TESTING ONLY). - for f in $(git grep -l '^#include "build/buildflag.h"$' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm'); do \ grep -v '^#include "build/buildflag.h"$' "${f}" > /tmp/z; \ cp /tmp/z "${f}"; done - git cl format - Update mini_chromium to 735143774c5f (intermediate step). - Update mini_chromium to f41420eb45fa (as checked in). - Update mini_chromium to 6e2f204b4ae1 (as checked in). For ease of review and inspection, each of these steps is uploaded as a new patch set in a review series. This includes an update of mini_chromium to 6e2f204b4ae1: f41420eb45fa Use BUILDFLAG for OS checking 6e2f204b4ae1 Include what you use: string_util.h uses build_config.h Bug: chromium:1234043 Change-Id: Ieef86186f094c64e59b853729737e36982f8cf69 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3400258 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org>
2022-01-19 15:00:24 -05:00
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
void* CallMmap(void* addr,
size_t len,
int prot,
int flags,
int fd,
off_t offset) {
return sys_mmap(addr, len, prot, flags, fd, offset);
}
int CallMunmap(void* addr, size_t len) {
return sys_munmap(addr, len);
}
int CallMprotect(void* addr, size_t len, int prot) {
return sys_mprotect(addr, len, prot);
}
#else
void* CallMmap(void* addr,
size_t len,
int prot,
int flags,
int fd,
off_t offset) {
return mmap(addr, len, prot, flags, fd, offset);
}
int CallMunmap(void* addr, size_t len) {
return munmap(addr, len);
}
int CallMprotect(void* addr, size_t len, int prot) {
return mprotect(addr, len, prot);
}
#endif
bool LoggingMunmap(uintptr_t addr, size_t len, bool can_log) {
if (CallMunmap(reinterpret_cast<void*>(addr), len) != 0) {
PLOG_IF(ERROR, can_log) << "munmap";
return false;
}
return true;
}
size_t RoundPage(size_t size) {
const size_t kPageMask = base::checked_cast<size_t>(base::GetPageSize()) - 1;
return (size + kPageMask) & ~kPageMask;
}
} // namespace
namespace crashpad {
ScopedMmap::ScopedMmap(bool can_log) : can_log_(can_log) {}
ScopedMmap::~ScopedMmap() {
if (is_valid()) {
LoggingMunmap(
reinterpret_cast<uintptr_t>(addr_), RoundPage(len_), can_log_);
}
}
bool ScopedMmap::Reset() {
return ResetAddrLen(MAP_FAILED, 0);
}
bool ScopedMmap::ResetAddrLen(void* addr, size_t len) {
const uintptr_t new_addr = reinterpret_cast<uintptr_t>(addr);
const size_t new_len_round = RoundPage(len);
if (addr == MAP_FAILED) {
DCHECK_EQ(len, 0u);
} else {
DCHECK_NE(len, 0u);
DCHECK_EQ(new_addr % base::GetPageSize(), 0u);
DCHECK((base::CheckedNumeric<uintptr_t>(new_addr) + (new_len_round - 1))
.IsValid());
}
bool result = true;
if (is_valid()) {
const uintptr_t old_addr = reinterpret_cast<uintptr_t>(addr_);
const size_t old_len_round = RoundPage(len_);
if (old_addr < new_addr) {
result &= LoggingMunmap(
old_addr, std::min(old_len_round, new_addr - old_addr), can_log_);
}
if (old_addr + old_len_round > new_addr + new_len_round) {
uintptr_t unmap_start = std::max(old_addr, new_addr + new_len_round);
result &= LoggingMunmap(
unmap_start, old_addr + old_len_round - unmap_start, can_log_);
}
}
addr_ = addr;
len_ = len;
return result;
}
bool ScopedMmap::ResetMmap(void* addr,
size_t len,
int prot,
int flags,
int fd,
off_t offset) {
// Reset() first, so that a new anonymous mapping can use the address space
// occupied by the old mapping if appropriate. The new mapping will be
// attempted even if there was something wrong with the old mapping, so dont
// consider the return value from Reset().
Reset();
void* new_addr = CallMmap(addr, len, prot, flags, fd, offset);
if (new_addr == MAP_FAILED) {
PLOG_IF(ERROR, can_log_) << "mmap";
return false;
}
// The new mapping is effective even if there was something wrong with the old
// mapping, so dont consider the return value from ResetAddrLen().
ResetAddrLen(new_addr, len);
return true;
}
bool ScopedMmap::Mprotect(int prot) {
if (CallMprotect(addr_, RoundPage(len_), prot) < 0) {
PLOG_IF(ERROR, can_log_) << "mprotect";
return false;
}
return true;
}
void* ScopedMmap::release() {
void* retval = addr_;
addr_ = MAP_FAILED;
len_ = 0;
return retval;
}
} // namespace crashpad