diff options
Diffstat (limited to 'compiler-rt/lib/sanitizer_common')
16 files changed, 391 insertions, 47 deletions
diff --git a/compiler-rt/lib/sanitizer_common/CMakeLists.txt b/compiler-rt/lib/sanitizer_common/CMakeLists.txt index 90e063e1d16..19c931a7a97 100644 --- a/compiler-rt/lib/sanitizer_common/CMakeLists.txt +++ b/compiler-rt/lib/sanitizer_common/CMakeLists.txt @@ -4,7 +4,6 @@ set(SANITIZER_SOURCES sanitizer_allocator.cc sanitizer_common.cc - sanitizer_coverage.cc sanitizer_deadlock_detector1.cc sanitizer_deadlock_detector2.cc sanitizer_flags.cc @@ -31,6 +30,8 @@ set(SANITIZER_SOURCES set(SANITIZER_LIBCDEP_SOURCES sanitizer_common_libcdep.cc + sanitizer_coverage_libcdep.cc + sanitizer_coverage_mapping_libcdep.cc sanitizer_linux_libcdep.cc sanitizer_posix_libcdep.cc sanitizer_stacktrace_libcdep.cc diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common.cc b/compiler-rt/lib/sanitizer_common/sanitizer_common.cc index 305056e2472..05bd8764c61 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common.cc @@ -263,11 +263,6 @@ void DecreaseTotalMmap(uptr size) { atomic_fetch_sub(&g_total_mmaped, size, memory_order_relaxed); } -static void (*sandboxing_callback)(); -void SetSandboxingCallback(void (*f)()) { - sandboxing_callback = f; -} - } // namespace __sanitizer using namespace __sanitizer; // NOLINT @@ -300,13 +295,6 @@ void __sanitizer_set_report_path(const char *path) { } } -void NOINLINE -__sanitizer_sandbox_on_notify(__sanitizer_sandbox_arguments *args) { - PrepareForSandboxing(args); - if (sandboxing_callback) - sandboxing_callback(); -} - void __sanitizer_report_error_summary(const char *error_summary) { Printf("%s\n", error_summary); } diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common.h b/compiler-rt/lib/sanitizer_common/sanitizer_common.h index 48b7b42e689..44f56ff6af8 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common.h @@ -161,6 +161,7 @@ uptr ReadFileToBuffer(const char *file_name, char **buff, // (or NULL if the mapping failes). Stores the size of mmaped region // in '*buff_size'. void *MapFileToMemory(const char *file_name, uptr *buff_size); +void *MapWritableFileToMemory(void *addr, uptr size, uptr fd, uptr offset); // Error report formatting. const char *StripPathPrefix(const char *filepath, @@ -187,6 +188,8 @@ void PrepareForSandboxing(__sanitizer_sandbox_arguments *args); void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args); void SetSandboxingCallback(void (*f)()); +void CovUpdateMapping(); + void InitTlsSize(); uptr GetTlsSize(); @@ -479,6 +482,10 @@ class LoadedModule { const char *full_name() const { return full_name_; } uptr base_address() const { return base_address_; } + uptr n_ranges() const { return n_ranges_; } + uptr address_range_start(int i) const { return ranges_[i].beg; } + uptr address_range_end(int i) const { return ranges_[i].end; } + private: struct AddressRange { uptr beg; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc index c6ff5a69fe3..4296ec05845 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -75,6 +75,19 @@ #define COMMON_INTERCEPTOR_FILE_CLOSE(ctx, file) {} #endif +#ifndef COMMON_INTERCEPTOR_LIBRARY_LOADED +#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, map) {} +#endif + +#ifndef COMMON_INTERCEPTOR_LIBRARY_UNLOADED +#define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() {} +#endif + +#ifndef COMMON_INTERCEPTOR_ENTER_NOIGNORE +#define COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, ...) \ + COMMON_INTERCEPTOR_ENTER(ctx, __VA_ARGS__) +#endif + struct FileMetadata { // For open_memstream(). char **addr; @@ -4036,6 +4049,29 @@ INTERCEPTOR(int, fclose, __sanitizer_FILE *fp) { #define INIT_FCLOSE #endif +#if SANITIZER_INTERCEPT_DLOPEN_DLCLOSE +INTERCEPTOR(void*, dlopen, const char *filename, int flag) { + void *ctx; + COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, dlopen, filename, flag); + void *res = REAL(dlopen)(filename, flag); + COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, res); + return res; +} + +INTERCEPTOR(int, dlclose, void *handle) { + void *ctx; + COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, dlclose, handle); + int res = REAL(dlclose)(handle); + COMMON_INTERCEPTOR_LIBRARY_UNLOADED(); + return res; +} +#define INIT_DLOPEN_DLCLOSE \ + COMMON_INTERCEPT_FUNCTION(dlopen); \ + COMMON_INTERCEPT_FUNCTION(dlclose); +#else +#define INIT_DLOPEN_DLCLOSE +#endif + static void InitializeCommonInterceptors() { static u64 metadata_mem[sizeof(MetadataHashMap) / sizeof(u64) + 1]; interceptor_metadata_map = new((void *)&metadata_mem) MetadataHashMap(); @@ -4177,4 +4213,5 @@ static void InitializeCommonInterceptors() { INIT_OBSTACK; INIT_FFLUSH; INIT_FCLOSE; + INIT_DLOPEN_DLCLOSE; } diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cc b/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cc index b7041447956..e4b2d76006b 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cc @@ -41,4 +41,17 @@ bool ColorizeReports() { return internal_strcmp(flag, "always") == 0 || (internal_strcmp(flag, "auto") == 0 && PrintsToTtyCached()); } + +static void (*sandboxing_callback)(); +void SetSandboxingCallback(void (*f)()) { + sandboxing_callback = f; +} + } // namespace __sanitizer + +void NOINLINE +__sanitizer_sandbox_on_notify(__sanitizer_sandbox_arguments *args) { + PrepareForSandboxing(args); + if (sandboxing_callback) + sandboxing_callback(); +} diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_coverage.cc b/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep.cc index 0f6435d2b9d..64861d0441a 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_coverage.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep.cc @@ -45,11 +45,10 @@ atomic_uint32_t dump_once_guard; // Ensure that CovDump runs only once. // pc_array is the array containing the covered PCs. // To make the pc_array thread- and async-signal-safe it has to be large enough. // 128M counters "ought to be enough for anybody" (4M on 32-bit). -// pc_array is allocated with MmapNoReserveOrDie and so it uses only as -// much RAM as it really needs. -static const uptr kPcArraySize = FIRST_32_SECOND_64(1 << 22, 1 << 27); -static uptr *pc_array; -static atomic_uintptr_t pc_array_index; + +// With coverage_direct=1 in ASAN_OPTIONS, pc_array memory is mapped to a file. +// In this mode, __sanitizer_cov_dump does nothing, and CovUpdateMapping() +// dump current memory layout to another file. static bool cov_sandboxed = false; static int cov_fd = kInvalidFd; @@ -57,22 +56,114 @@ static unsigned int cov_max_block_size = 0; namespace __sanitizer { +class CoverageData { + public: + void Init(); + void Extend(uptr npcs); + void Add(uptr pc); + + uptr *data(); + uptr size(); + + private: + // Maximal size pc array may ever grow. + // We MmapNoReserve this space to ensure that the array is contiguous. + static const uptr kPcArrayMaxSize = FIRST_32_SECOND_64(1 << 22, 1 << 27); + // The amount file mapping for the pc array is grown by. + static const uptr kPcArrayMmapSize = 64 * 1024; + + // pc_array is allocated with MmapNoReserveOrDie and so it uses only as + // much RAM as it really needs. + uptr *pc_array; + // Index of the first available pc_array slot. + atomic_uintptr_t pc_array_index; + // Array size. + atomic_uintptr_t pc_array_size; + // Current file mapped size of the pc array. + uptr pc_array_mapped_size; + // Descriptor of the file mapped pc array. + int pc_fd; + StaticSpinMutex mu; + + void DirectInit(); +}; + +static CoverageData coverage_data; + +void CoverageData::DirectInit() { + InternalScopedString path(64); + internal_snprintf((char *)path.data(), path.size(), "%zd.sancov.raw", + internal_getpid()); + pc_fd = OpenFile(path.data(), true); + if (internal_iserror(pc_fd)) { + Report(" Coverage: failed to open %s for writing\n", path.data()); + Die(); + } + + atomic_store(&pc_array_size, 0, memory_order_relaxed); + pc_array_mapped_size = 0; + + CovUpdateMapping(); +} + +void CoverageData::Init() { + pc_array = reinterpret_cast<uptr *>( + MmapNoReserveOrDie(sizeof(uptr) * kPcArrayMaxSize, "CovInit")); + if (common_flags()->coverage_direct) { + DirectInit(); + } else { + pc_fd = 0; + atomic_store(&pc_array_size, kPcArrayMaxSize, memory_order_relaxed); + } +} + +// Extend coverage PC array to fit additional npcs elements. +void CoverageData::Extend(uptr npcs) { + // If pc_fd=0, pc array is a huge anonymous mapping that does not need to be + // resized. + if (!pc_fd) return; + SpinMutexLock l(&mu); + + uptr size = atomic_load(&pc_array_size, memory_order_relaxed); + size += npcs * sizeof(uptr); + + if (size > pc_array_mapped_size) { + uptr new_mapped_size = pc_array_mapped_size; + while (size > new_mapped_size) new_mapped_size += kPcArrayMmapSize; + + // Extend the file and map the new space at the end of pc_array. + uptr res = internal_ftruncate(pc_fd, new_mapped_size); + int err; + if (internal_iserror(res, &err)) { + Printf("failed to extend raw coverage file: %d\n", err); + Die(); + } + void *p = MapWritableFileToMemory(pc_array + pc_array_mapped_size, + new_mapped_size - pc_array_mapped_size, + pc_fd, pc_array_mapped_size); + CHECK_EQ(p, pc_array + pc_array_mapped_size); + pc_array_mapped_size = new_mapped_size; + } + + atomic_store(&pc_array_size, size, memory_order_release); +} + // Simply add the pc into the vector under lock. If the function is called more // than once for a given PC it will be inserted multiple times, which is fine. -static void CovAdd(uptr pc) { +void CoverageData::Add(uptr pc) { if (!pc_array) return; uptr idx = atomic_fetch_add(&pc_array_index, 1, memory_order_relaxed); - CHECK_LT(idx, kPcArraySize); + CHECK_LT(idx * sizeof(uptr), + atomic_load(&pc_array_size, memory_order_acquire)); pc_array[idx] = pc; } -void CovInit() { - pc_array = reinterpret_cast<uptr *>( - MmapNoReserveOrDie(sizeof(uptr) * kPcArraySize, "CovInit")); +uptr *CoverageData::data() { + return pc_array; } -static inline bool CompareLess(const uptr &a, const uptr &b) { - return a < b; +uptr CoverageData::size() { + return atomic_load(&pc_array_index, memory_order_relaxed); } // Block layout for packed file format: header, followed by module name (no @@ -150,15 +241,15 @@ static int CovOpenFile(bool packed, const char* name) { // Dump the coverage on disk. static void CovDump() { - if (!common_flags()->coverage) return; + if (!common_flags()->coverage || common_flags()->coverage_direct) return; #if !SANITIZER_WINDOWS if (atomic_fetch_add(&dump_once_guard, 1, memory_order_relaxed)) return; - uptr size = atomic_load(&pc_array_index, memory_order_relaxed); - InternalSort(&pc_array, size, CompareLess); + uptr size = coverage_data.size(); InternalMmapVector<u32> offsets(size); - const uptr *vb = pc_array; - const uptr *ve = vb + size; + uptr *vb = coverage_data.data(); + uptr *ve = vb + size; + SortArray(vb, size); MemoryMappingLayout proc_maps(/*cache_enabled*/true); uptr mb, me, off, prot; InternalScopedBuffer<char> module(4096); @@ -227,10 +318,15 @@ int MaybeOpenCovFile(const char *name) { extern "C" { SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov() { - CovAdd(StackTrace::GetPreviousInstructionPc(GET_CALLER_PC())); + coverage_data.Add(StackTrace::GetPreviousInstructionPc(GET_CALLER_PC())); } SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { CovDump(); } -SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_init() { CovInit(); } +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_init() { + coverage_data.Init(); +} +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_module_init(uptr npcs) { + coverage_data.Extend(npcs); +} SANITIZER_INTERFACE_ATTRIBUTE sptr __sanitizer_maybe_open_cov_file(const char *name) { return MaybeOpenCovFile(name); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc b/compiler-rt/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc new file mode 100644 index 00000000000..75f6162d185 --- /dev/null +++ b/compiler-rt/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc @@ -0,0 +1,97 @@ +//===-- sanitizer_coverage_mapping.cc -------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Mmap-based implementation of sanitizer coverage. +// +// This is part of the implementation of code coverage that does not require +// __sanitizer_cov_dump() call. Data is stored in 2 files per process. +// +// $pid.sancov.map describes process memory layout in the following text-based +// format: +// <pointer size in bits> // 1 line, 32 or 64 +// <mapping start> <mapping end> <base address> <dso name> // repeated +// ... +// Mapping lines are NOT sorted. This file is updated every time memory layout +// is changed (i.e. in dlopen() and dlclose() interceptors). +// +// $pid.sancov.raw is a binary dump of PC values, sizeof(uptr) each. Again, not +// sorted. This file is extended by 64Kb at a time and mapped into memory. It +// contains one or more 0 words at the end, up to the next 64Kb aligned offset. +// +// To convert these 2 files to the usual .sancov format, run sancov.py rawunpack +// $pid.sancov.raw. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_allocator_internal.h" +#include "sanitizer_libc.h" +#include "sanitizer_procmaps.h" + +namespace __sanitizer { + +static const uptr kMaxNumberOfModules = 1 << 14; + +void CovUpdateMapping() { + if (!common_flags()->coverage || !common_flags()->coverage_direct) return; + + int err; + InternalScopedString tmp_path(64); + internal_snprintf((char *)tmp_path.data(), tmp_path.size(), + "%zd.sancov.map.tmp", internal_getpid()); + uptr map_fd = OpenFile(tmp_path.data(), true); + if (internal_iserror(map_fd)) { + Report(" Coverage: failed to open %s for writing\n", tmp_path.data()); + Die(); + } + + InternalScopedBuffer<char> modules_data(kMaxNumberOfModules * + sizeof(LoadedModule)); + LoadedModule *modules = (LoadedModule *)modules_data.data(); + CHECK(modules); + int n_modules = GetListOfModules(modules, kMaxNumberOfModules, + /* filter */ 0); + + InternalScopedString line(4096); + line.append("%d\n", sizeof(uptr) * 8); + uptr res = internal_write(map_fd, line.data(), line.length()); + if (internal_iserror(res, &err)) { + Printf("sancov.map write failed: %d\n", err); + Die(); + } + line.clear(); + + for (int i = 0; i < n_modules; ++i) { + char *module_name = StripModuleName(modules[i].full_name()); + for (unsigned j = 0; j < modules[i].n_ranges(); ++j) { + line.append("%zx %zx %zx %s\n", modules[i].address_range_start(j), + modules[i].address_range_end(j), modules[i].base_address(), + module_name); + res = internal_write(map_fd, line.data(), line.length()); + if (internal_iserror(res, &err)) { + Printf("sancov.map write failed: %d\n", err); + Die(); + } + line.clear(); + } + InternalFree(module_name); + } + + internal_close(map_fd); + + InternalScopedString path(64); + internal_snprintf((char *)path.data(), path.size(), "%zd.sancov.map", + internal_getpid()); + res = internal_rename(tmp_path.data(), path.data()); + if (internal_iserror(res, &err)) { + Printf("sancov.map rename failed: %d\n", err); + Die(); + } +} + +} // namespace __sanitizer diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_flags.cc b/compiler-rt/lib/sanitizer_common/sanitizer_flags.cc index 3e88d47284b..406bb64b7f7 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_flags.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_flags.cc @@ -55,6 +55,7 @@ void SetCommonFlagsDefaults(CommonFlags *f) { f->legacy_pthread_cond = false; f->intercept_tls_get_addr = false; f->coverage = false; + f->coverage_direct = false; f->full_address_space = false; } @@ -127,6 +128,10 @@ void ParseCommonFlagsFromString(CommonFlags *f, const char *str) { ParseFlag(str, &f->coverage, "coverage", "If set, coverage information will be dumped at program shutdown (if the " "coverage instrumentation was enabled at compile time)."); + ParseFlag(str, &f->coverage_direct, "coverage_direct", + "If set, coverage information will be dumped directly to a memory " + "mapped file. This way data is not lost even if the process is " + "suddenly killed."); ParseFlag(str, &f->full_address_space, "full_address_space", "Sanitize complete address space; " "by default kernel area on 32-bit platforms will not be sanitized"); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_flags.h b/compiler-rt/lib/sanitizer_common/sanitizer_flags.h index 1d87f5a4bc6..1ad53dc6711 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_flags.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_flags.h @@ -54,6 +54,7 @@ struct CommonFlags { bool help; uptr mmap_limit_mb; bool coverage; + bool coverage_direct; bool full_address_space; }; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_libc.h b/compiler-rt/lib/sanitizer_common/sanitizer_libc.h index 3d898431fe1..6995626821a 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_libc.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_libc.h @@ -74,6 +74,7 @@ uptr internal_open(const char *filename, int flags, u32 mode); uptr internal_read(fd_t fd, void *buf, uptr count); uptr internal_write(fd_t fd, const void *buf, uptr count); +uptr internal_ftruncate(fd_t fd, uptr size); // OS uptr internal_filesize(fd_t fd); // -1 on error. @@ -83,6 +84,7 @@ uptr internal_fstat(fd_t fd, void *buf); uptr internal_dup2(int oldfd, int newfd); uptr internal_readlink(const char *path, char *buf, uptr bufsize); uptr internal_unlink(const char *path); +uptr internal_rename(const char *oldpath, const char *newpath); void NORETURN internal__exit(int exitcode); uptr internal_lseek(fd_t fd, OFF_T offset, int whence); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc index b219b700a61..f27f22e4798 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc @@ -134,7 +134,7 @@ uptr internal_open(const char *filename, int flags, u32 mode) { uptr OpenFile(const char *filename, bool write) { return internal_open(filename, - write ? O_WRONLY | O_CREAT /*| O_CLOEXEC*/ : O_RDONLY, 0660); + write ? O_RDWR | O_CREAT /*| O_CLOEXEC*/ : O_RDONLY, 0660); } uptr internal_read(fd_t fd, void *buf, uptr count) { @@ -151,6 +151,12 @@ uptr internal_write(fd_t fd, const void *buf, uptr count) { return res; } +uptr internal_ftruncate(fd_t fd, uptr size) { + sptr res; + HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(ftruncate), fd, size)); + return res; +} + #if !SANITIZER_LINUX_USES_64BIT_SYSCALLS && !SANITIZER_FREEBSD static void stat64_to_stat(struct stat64 *in, struct stat *out) { internal_memset(out, 0, sizeof(*out)); @@ -246,6 +252,15 @@ uptr internal_unlink(const char *path) { #endif } +uptr internal_rename(const char *oldpath, const char *newpath) { +#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS + return internal_syscall(SYSCALL(renameat), AT_FDCWD, (uptr)oldpath, AT_FDCWD, + (uptr)newpath); +#else + return internal_syscall(SYSCALL(rename), (uptr)oldpath, (uptr)newpath); +#endif +} + uptr internal_sched_yield() { return internal_syscall(SYSCALL(sched_yield)); } @@ -390,20 +405,6 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, } #endif // SANITIZER_GO -void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) { - // Some kinds of sandboxes may forbid filesystem access, so we won't be able - // to read the file mappings from /proc/self/maps. Luckily, neither the - // process will be able to load additional libraries, so it's fine to use the - // cached mappings. - MemoryMappingLayout::CacheMemoryMappings(); - // Same for /proc/self/exe in the symbolizer. -#if !SANITIZER_GO - if (Symbolizer *sym = Symbolizer::GetOrNull()) - sym->PrepareForSandboxing(); - CovPrepareForSandboxing(args); -#endif -} - enum MutexState { MtxUnlocked = 0, MtxLocked = 1, diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cc index 6093593eb08..396a0a8ed2f 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cc @@ -22,6 +22,7 @@ #include "sanitizer_procmaps.h" #include "sanitizer_stacktrace.h" #include "sanitizer_atomic.h" +#include "sanitizer_symbolizer.h" #include <dlfcn.h> #include <pthread.h> @@ -529,6 +530,20 @@ void SetIndirectCallWrapper(uptr wrapper) { indirect_call_wrapper = wrapper; } +void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) { + // Some kinds of sandboxes may forbid filesystem access, so we won't be able + // to read the file mappings from /proc/self/maps. Luckily, neither the + // process will be able to load additional libraries, so it's fine to use the + // cached mappings. + MemoryMappingLayout::CacheMemoryMappings(); + // Same for /proc/self/exe in the symbolizer. +#if !SANITIZER_GO + if (Symbolizer *sym = Symbolizer::GetOrNull()) + sym->PrepareForSandboxing(); + CovPrepareForSandboxing(args); +#endif +} + } // namespace __sanitizer #endif // SANITIZER_FREEBSD || SANITIZER_LINUX diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_mac.cc b/compiler-rt/lib/sanitizer_common/sanitizer_mac.cc index 683888a1a6f..5985bd2d78d 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_mac.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_mac.cc @@ -131,6 +131,14 @@ int internal_fork() { return fork(); } +uptr internal_rename(const char *oldpath, const char *newpath) { + return rename(oldpath, newpath); +} + +uptr internal_ftruncate(fd_t fd, uptr size) { + return ftruncate(fd, size); +} + // ----------------- sanitizer_common.h bool FileExists(const char *filename) { struct stat st; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h index 9b720753317..b2aeb11f1d7 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -203,5 +203,6 @@ #define SANITIZER_INTERCEPT_OBSTACK SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_FFLUSH SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_FCLOSE SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_DLOPEN_DLCLOSE SI_NOT_WINDOWS #endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc b/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc index 2cd2a7c4ddb..8df1fa72a02 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc @@ -206,6 +206,17 @@ void *MapFileToMemory(const char *file_name, uptr *buff_size) { return internal_iserror(map) ? 0 : (void *)map; } +void *MapWritableFileToMemory(void *addr, uptr size, uptr fd, uptr offset) { + uptr flags = MAP_SHARED; + if (addr) flags |= MAP_FIXED; + uptr p = internal_mmap(addr, size, PROT_READ | PROT_WRITE, flags, fd, offset); + if (internal_iserror(p)) { + Printf("could not map writable file (%zd, %zu, %zu): %zd\n", fd, offset, + size, p); + return 0; + } + return (void *)p; +} static inline bool IntervalsAreSeparate(uptr start1, uptr end1, uptr start2, uptr end2) { diff --git a/compiler-rt/lib/sanitizer_common/scripts/sancov.py b/compiler-rt/lib/sanitizer_common/scripts/sancov.py index 4354359b039..dfb65b2db2f 100755 --- a/compiler-rt/lib/sanitizer_common/scripts/sancov.py +++ b/compiler-rt/lib/sanitizer_common/scripts/sancov.py @@ -6,6 +6,8 @@ import array import struct import sys +import bisect +import os.path prog_name = ""; @@ -74,6 +76,63 @@ def Unpack(files): for f in files: UnpackOneFile(f) +def UnpackOneRawFile(path, map_path): + mem_map = [] + with open(map_path, mode="rt") as f_map: + print >> sys.stderr, "%s: reading map %s" % (prog_name, map_path) + bits = int(f_map.readline()) + for line in f_map: + parts = line.rstrip().split() + assert len(parts) == 4 + mem_map.append((int(parts[0], 16), + int(parts[1], 16), + int(parts[2], 16), + parts[3])) + mem_map.sort(key=lambda m : m[0]) + mem_map_keys = [m[0] for m in mem_map] + + print mem_map + with open(path, mode="rb") as f: + print >> sys.stderr, "%s: unpacking %s" % (prog_name, path) + + f.seek(0, 2) + size = f.tell() + f.seek(0, 0) + if bits == 64: + typecode = 'L' + else: + typecode = 'I' + pcs = array.array(typecode, f.read(size)) + mem_map_pcs = [[] for i in range(0, len(mem_map))] + + for pc in pcs: + if pc == 0: continue + map_idx = bisect.bisect(mem_map_keys, pc) - 1 + (start, end, base, module_path) = mem_map[map_idx] + print pc + print start, end, base, module_path + assert pc >= start + if pc >= end: + print >> sys.stderr, "warning: %s: pc %x outside of any known mapping" % (prog_name, pc) + continue + mem_map_pcs[map_idx].append(pc - base) + + for ((start, end, base, module_path), pc_list) in zip(mem_map, mem_map_pcs): + if len(pc_list) == 0: continue + assert path.endswith('.sancov.raw') + dst_path = module_path + '.' + os.path.basename(path)[:-4] + print "writing %d PCs to %s" % (len(pc_list), dst_path) + arr = array.array('I') + arr.fromlist(sorted(pc_list)) + with open(dst_path, 'ab') as f2: + arr.tofile(f2) + +def RawUnpack(files): + for f in files: + if not f.endswith('.sancov.raw'): + raise Exception('Unexpected raw file name %s' % f) + f_map = f[:-3] + 'map' + UnpackOneRawFile(f, f_map) if __name__ == '__main__': prog_name = sys.argv[0] @@ -85,5 +144,7 @@ if __name__ == '__main__': MergeAndPrint(sys.argv[2:]) elif sys.argv[1] == "unpack": Unpack(sys.argv[2:]) + elif sys.argv[1] == "rawunpack": + RawUnpack(sys.argv[2:]) else: Usage() |

