Skip to content

Commit

Permalink
[libc] Fix msan/asan memcpy reentrancy
Browse files Browse the repository at this point in the history
This is needed to prevent asan/msan instrumentation to redirect CopyBlock to `__asan_memcpy` (resp. `__msan_memcpy`).
These functions would then differ operation to `memcpy` which leads to reentrancy issues.

With this patch, `memcpy` is fully instrumented and covered by asan/msan.

If this turns out to be too expensive, instrumentation can be selectively or fully disabled through the use of the `__attribute__((no_sanitize(address, memory)))` annotation.

Differential Revision: https://reviews.llvm.org/D99598
  • Loading branch information
gchatelet committed Mar 30, 2021
1 parent a6950c3 commit 77d81c2
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 23 deletions.
2 changes: 1 addition & 1 deletion libc/src/__support/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ add_header_library(
common
HDRS
common.h
sanitizer_annotations.h
sanitizer.h
)

add_header_library(
Expand Down
52 changes: 52 additions & 0 deletions libc/src/__support/sanitizer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//===-- Convenient sanitizer macros ---------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_SRC_SUPPORT_SANITIZER_H
#define LLVM_LIBC_SRC_SUPPORT_SANITIZER_H

#ifdef __has_feature
#define LLVM_LIBC_HAVE_FEATURE(f) __has_feature(f)
#else
#define LLVM_LIBC_HAVE_FEATURE(f) 0
#endif

// MemorySanitizer (MSan) is a detector of uninitialized reads. It consists of
// a compiler instrumentation module and a run-time library.
#ifdef LLVM_LIBC_HAVE_MEMORY_SANITIZER
#error "LLVM_LIBC_HAVE_MEMORY_SANITIZER cannot be directly set."
#elif defined(MEMORY_SANITIZER)
// The MEMORY_SANITIZER macro is deprecated but we will continue to honor it
// for now.
#define LLVM_LIBC_HAVE_MEMORY_SANITIZER 1
#elif defined(__SANITIZE_MEMORY__)
#define LLVM_LIBC_HAVE_MEMORY_SANITIZER 1
#elif !defined(__native_client__) && LLVM_LIBC_HAVE_FEATURE(memory_sanitizer)
#define LLVM_LIBC_HAVE_MEMORY_SANITIZER 1
#endif

// AddressSanitizer (ASan) is a fast memory error detector.
#ifdef LLVM_LIBC_HAVE_ADDRESS_SANITIZER
#error "LLVM_LIBC_HAVE_ADDRESS_SANITIZER cannot be directly set."
#elif defined(ADDRESS_SANITIZER)
// The ADDRESS_SANITIZER macro is deprecated but we will continue to honor it
// for now.
#define LLVM_LIBC_HAVE_ADDRESS_SANITIZER 1
#elif defined(__SANITIZE_ADDRESS__)
#define LLVM_LIBC_HAVE_ADDRESS_SANITIZER 1
#elif LLVM_LIBC_HAVE_FEATURE(address_sanitizer)
#define LLVM_LIBC_HAVE_ADDRESS_SANITIZER 1
#endif

#if LLVM_LIBC_HAVE_MEMORY_SANITIZER
#include <sanitizer/msan_interface.h>
#define SANITIZER_MEMORY_INITIALIZED(addr, size) __msan_unpoison(addr, size)
#else
#define SANITIZER_MEMORY_INITIALIZED(ptr, size)
#endif

#endif // LLVM_LIBC_SRC_SUPPORT_SANITIZER_H
19 changes: 0 additions & 19 deletions libc/src/__support/sanitizer_annotations.h

This file was deleted.

15 changes: 13 additions & 2 deletions libc/src/string/memory_utils/memcpy_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#ifndef LIBC_SRC_STRING_MEMORY_UTILS_MEMCPY_UTILS_H
#define LIBC_SRC_STRING_MEMORY_UTILS_MEMCPY_UTILS_H

#include "src/__support/sanitizer.h"
#include "src/string/memory_utils/utils.h"
#include <stddef.h> // size_t

Expand All @@ -30,18 +31,28 @@ extern "C" void LLVM_LIBC_MEMCPY_MONITOR(char *__restrict,
const char *__restrict, size_t);
#endif

// Copies `kBlockSize` bytes from `src` to `dst` using a for loop.
// This code requires the use of `-fno-buitin-memcpy` to prevent the compiler
// from turning the for-loop back into `__builtin_memcpy`.
template <size_t kBlockSize>
static void ForLoopCopy(char *__restrict dst, const char *__restrict src) {
for (size_t i = 0; i < kBlockSize; ++i)
dst[i] = src[i];
}

// Copies `kBlockSize` bytes from `src` to `dst`.
template <size_t kBlockSize>
static void CopyBlock(char *__restrict dst, const char *__restrict src) {
#if defined(LLVM_LIBC_MEMCPY_MONITOR)
LLVM_LIBC_MEMCPY_MONITOR(dst, src, kBlockSize);
#elif LLVM_LIBC_HAVE_MEMORY_SANITIZER || LLVM_LIBC_HAVE_ADDRESS_SANITIZER
ForLoopCopy<kBlockSize>(dst, src);
#elif defined(USE_BUILTIN_MEMCPY_INLINE)
__builtin_memcpy_inline(dst, src, kBlockSize);
#elif defined(USE_BUILTIN_MEMCPY)
__builtin_memcpy(dst, src, kBlockSize);
#else
for (size_t i = 0; i < kBlockSize; ++i)
dst[i] = src[i];
ForLoopCopy<kBlockSize>(dst, src);
#endif
}

Expand Down
2 changes: 1 addition & 1 deletion libc/utils/FPUtil/x86_64/FEnv.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
#include <fenv.h>
#include <stdint.h>

#include "src/__support/sanitizer_annotations.h"
#include "src/__support/sanitizer.h"

namespace __llvm_libc {
namespace fputil {
Expand Down

0 comments on commit 77d81c2

Please sign in to comment.