[SafeStack] Introduce public interface header and deprecate builtins (#198292)
Introduce `sanitizer/safestack_interface.h` to expose SafeStack utility functions as a public interface, similar to other sanitizers. Exposed functions: * `__safestack_get_unsafe_stack_ptr` * `__safestack_get_unsafe_stack_bottom` * `__safestack_get_unsafe_stack_top` Deprecate the existing `__builtin___get_unsafe_stack_*` builtins and emit warnings suggesting the new `__safestack_` equivalents. Runtime compatibility aliases `__get_unsafe_stack_*` are maintained.
This commit is contained in:
parent
6b90b6b4a3
commit
69215c5e4f
9 changed files with 147 additions and 28 deletions
|
|
@ -325,6 +325,11 @@ Non-comprehensive list of changes in this release
|
|||
|
||||
- Updated support for Unicode from 15.1 to 18.0.
|
||||
|
||||
- The SafeStack builtins ``__builtin___get_unsafe_stack_ptr``,
|
||||
``__builtin___get_unsafe_stack_bottom``, ``__builtin___get_unsafe_stack_top``,
|
||||
and ``__builtin___get_unsafe_stack_start`` are now deprecated. Use the
|
||||
corresponding functions from ``<sanitizer/safestack_interface.h>`` instead.
|
||||
|
||||
New Compiler Flags
|
||||
------------------
|
||||
- New option ``-fms-anonymous-structs`` / ``-fno-ms-anonymous-structs`` added
|
||||
|
|
|
|||
|
|
@ -159,29 +159,56 @@ these variables, so extra care must be taken to manually ensure that all such
|
|||
accesses are safe. Furthermore, the addresses of such local variables should
|
||||
never be stored on the heap, as it would leak the location of the SafeStack.
|
||||
|
||||
``sanitizer/safestack_interface.h``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
To use the low-level API, include the header ``<sanitizer/safestack_interface.h>``.
|
||||
|
||||
``__safestack_get_unsafe_stack_ptr()``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This function returns current unsafe stack pointer of the current thread.
|
||||
|
||||
``__safestack_get_unsafe_stack_bottom()``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This function returns a pointer to the bottom of the unsafe stack of the
|
||||
current thread.
|
||||
|
||||
``__safestack_get_unsafe_stack_top()``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This function returns a pointer to the top of the unsafe stack of the
|
||||
current thread.
|
||||
|
||||
|
||||
|
||||
Deprecated Builtins
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The following builtins are still supported but are deprecated and will emit a
|
||||
warning. Use the corresponding functions from ``<sanitizer/safestack_interface.h>``
|
||||
instead.
|
||||
|
||||
``__builtin___get_unsafe_stack_ptr()``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This builtin function returns current unsafe stack pointer of the current
|
||||
thread.
|
||||
Deprecated alias for ``__safestack_get_unsafe_stack_ptr()``.
|
||||
|
||||
``__builtin___get_unsafe_stack_bottom()``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This builtin function returns a pointer to the bottom of the unsafe stack of the
|
||||
current thread.
|
||||
Deprecated alias for ``__safestack_get_unsafe_stack_bottom()``.
|
||||
|
||||
``__builtin___get_unsafe_stack_top()``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This builtin function returns a pointer to the top of the unsafe stack of the
|
||||
current thread.
|
||||
Deprecated alias for ``__safestack_get_unsafe_stack_top()``.
|
||||
|
||||
``__builtin___get_unsafe_stack_start()``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Deprecated: This builtin function is an alias for
|
||||
``__builtin___get_unsafe_stack_bottom()``.
|
||||
Deprecated alias for ``__safestack_get_unsafe_stack_bottom()``.
|
||||
|
||||
Design
|
||||
======
|
||||
|
|
|
|||
|
|
@ -2920,6 +2920,22 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
|
|||
|
||||
FPOptions FPO;
|
||||
switch (BuiltinID) {
|
||||
case Builtin::BI__builtin___get_unsafe_stack_start:
|
||||
case Builtin::BI__builtin___get_unsafe_stack_bottom:
|
||||
Diag(TheCall->getBeginLoc(), diag::warn_deprecated_builtin)
|
||||
<< Context.BuiltinInfo.getQuotedName(BuiltinID)
|
||||
<< "__safestack_get_unsafe_stack_bottom";
|
||||
break;
|
||||
case Builtin::BI__builtin___get_unsafe_stack_top:
|
||||
Diag(TheCall->getBeginLoc(), diag::warn_deprecated_builtin)
|
||||
<< Context.BuiltinInfo.getQuotedName(BuiltinID)
|
||||
<< "__safestack_get_unsafe_stack_top";
|
||||
break;
|
||||
case Builtin::BI__builtin___get_unsafe_stack_ptr:
|
||||
Diag(TheCall->getBeginLoc(), diag::warn_deprecated_builtin)
|
||||
<< Context.BuiltinInfo.getQuotedName(BuiltinID)
|
||||
<< "__safestack_get_unsafe_stack_ptr";
|
||||
break;
|
||||
case Builtin::BI__builtin_cpu_supports:
|
||||
case Builtin::BI__builtin_cpu_is:
|
||||
if (BuiltinCpu(*this, Context.getTargetInfo(), TheCall,
|
||||
|
|
|
|||
17
clang/test/Sema/safestack-deprecated-builtins.c
Normal file
17
clang/test/Sema/safestack-deprecated-builtins.c
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
// RUN: %clang_cc1 %s -fsyntax-only -verify -fsanitize=safe-stack
|
||||
|
||||
void *test_bottom(void) {
|
||||
return __builtin___get_unsafe_stack_bottom(); // expected-warning {{builtin '__builtin___get_unsafe_stack_bottom' is deprecated; use __safestack_get_unsafe_stack_bottom instead}}
|
||||
}
|
||||
|
||||
void *test_top(void) {
|
||||
return __builtin___get_unsafe_stack_top(); // expected-warning {{builtin '__builtin___get_unsafe_stack_top' is deprecated; use __safestack_get_unsafe_stack_top instead}}
|
||||
}
|
||||
|
||||
void *test_ptr(void) {
|
||||
return __builtin___get_unsafe_stack_ptr(); // expected-warning {{builtin '__builtin___get_unsafe_stack_ptr' is deprecated; use __safestack_get_unsafe_stack_ptr instead}}
|
||||
}
|
||||
|
||||
void *test_start(void) {
|
||||
return __builtin___get_unsafe_stack_start(); // expected-warning {{builtin '__builtin___get_unsafe_stack_start' is deprecated; use __safestack_get_unsafe_stack_bottom instead}}
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ if (COMPILER_RT_BUILD_SANITIZERS)
|
|||
sanitizer/msan_interface.h
|
||||
sanitizer/netbsd_syscall_hooks.h
|
||||
sanitizer/rtsan_interface.h
|
||||
sanitizer/safestack_interface.h
|
||||
sanitizer/scudo_interface.h
|
||||
sanitizer/tsan_interface.h
|
||||
sanitizer/tsan_interface_atomic.h
|
||||
|
|
|
|||
35
compiler-rt/include/sanitizer/safestack_interface.h
Normal file
35
compiler-rt/include/sanitizer/safestack_interface.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
//===-- sanitizer/safestack_interface.h -------------------------*- C++ -*-===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of SafeStack.
|
||||
//
|
||||
// Public interface header.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef SANITIZER_SAFESTACK_INTERFACE_H
|
||||
#define SANITIZER_SAFESTACK_INTERFACE_H
|
||||
|
||||
#include <sanitizer/common_interface_defs.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// Returns the current unsafe stack pointer of the current thread.
|
||||
const void *SANITIZER_CDECL __safestack_get_unsafe_stack_ptr(void);
|
||||
|
||||
/// Returns a pointer to the bottom of the unsafe stack of the current thread.
|
||||
const void *SANITIZER_CDECL __safestack_get_unsafe_stack_bottom(void);
|
||||
|
||||
/// Returns a pointer to the top of the unsafe stack of the current thread.
|
||||
const void *SANITIZER_CDECL __safestack_get_unsafe_stack_top(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // SANITIZER_SAFESTACK_INTERFACE_H
|
||||
|
|
@ -5,6 +5,7 @@ set(SAFESTACK_SOURCES
|
|||
)
|
||||
|
||||
include_directories(..)
|
||||
include_directories(../../include)
|
||||
|
||||
set(SAFESTACK_CFLAGS ${SANITIZER_COMMON_CFLAGS})
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include "interception/interception.h"
|
||||
#include "safestack_platform.h"
|
||||
#include "safestack_util.h"
|
||||
#include "sanitizer/safestack_interface.h"
|
||||
#include "sanitizer_common/sanitizer_internal_defs.h"
|
||||
|
||||
// interception.h drags in sanitizer_redefine_builtins.h, which in turn
|
||||
|
|
@ -338,22 +339,34 @@ __attribute__((section(".preinit_array"),
|
|||
}
|
||||
#endif
|
||||
|
||||
extern "C"
|
||||
__attribute__((visibility("default"))) void *__get_unsafe_stack_bottom() {
|
||||
extern "C" SANITIZER_INTERFACE_ATTRIBUTE const void*
|
||||
__safestack_get_unsafe_stack_bottom() {
|
||||
return unsafe_stack_start;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
__attribute__((visibility("default"))) void *__get_unsafe_stack_top() {
|
||||
extern "C" SANITIZER_INTERFACE_ATTRIBUTE const void*
|
||||
__safestack_get_unsafe_stack_top() {
|
||||
return (char*)unsafe_stack_start + unsafe_stack_size;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
__attribute__((visibility("default"))) void *__get_unsafe_stack_start() {
|
||||
return unsafe_stack_start;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
__attribute__((visibility("default"))) void *__get_unsafe_stack_ptr() {
|
||||
extern "C" SANITIZER_INTERFACE_ATTRIBUTE const void*
|
||||
__safestack_get_unsafe_stack_ptr() {
|
||||
return __safestack_unsafe_stack_ptr;
|
||||
}
|
||||
|
||||
// Compatibility aliases
|
||||
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void* __get_unsafe_stack_bottom() {
|
||||
return const_cast<void*>(__safestack_get_unsafe_stack_bottom());
|
||||
}
|
||||
|
||||
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void* __get_unsafe_stack_top() {
|
||||
return const_cast<void*>(__safestack_get_unsafe_stack_top());
|
||||
}
|
||||
|
||||
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void* __get_unsafe_stack_start() {
|
||||
return const_cast<void*>(__safestack_get_unsafe_stack_bottom());
|
||||
}
|
||||
|
||||
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void* __get_unsafe_stack_ptr() {
|
||||
return const_cast<void*>(__safestack_get_unsafe_stack_ptr());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,22 +15,24 @@
|
|||
// Test that safe stack works with sigaltstack.
|
||||
int puts(const char *);
|
||||
|
||||
extern void *__get_unsafe_stack_ptr();
|
||||
extern void *__get_unsafe_stack_top();
|
||||
extern void *__get_unsafe_stack_bottom();
|
||||
#include <sanitizer/safestack_interface.h>
|
||||
|
||||
__thread int signal_handlers_called = 0;
|
||||
|
||||
void signal_handler(int signo) {
|
||||
signal_handlers_called += 1;
|
||||
assert(__get_unsafe_stack_ptr() <= __get_unsafe_stack_top() &&
|
||||
__get_unsafe_stack_ptr() >= __get_unsafe_stack_bottom());
|
||||
assert(__safestack_get_unsafe_stack_ptr() <=
|
||||
__safestack_get_unsafe_stack_top() &&
|
||||
__safestack_get_unsafe_stack_ptr() >=
|
||||
__safestack_get_unsafe_stack_bottom());
|
||||
}
|
||||
|
||||
void signal_sigaction(int signo, siginfo_t *si, void *uc) {
|
||||
signal_handlers_called += 1;
|
||||
assert(__get_unsafe_stack_ptr() <= __get_unsafe_stack_top() &&
|
||||
__get_unsafe_stack_ptr() >= __get_unsafe_stack_bottom());
|
||||
assert(__safestack_get_unsafe_stack_ptr() <=
|
||||
__safestack_get_unsafe_stack_top() &&
|
||||
__safestack_get_unsafe_stack_ptr() >=
|
||||
__safestack_get_unsafe_stack_bottom());
|
||||
}
|
||||
|
||||
void *t1_start(void *ptr) {
|
||||
|
|
@ -113,8 +115,10 @@ int main() {
|
|||
raise(SIGUSR2);
|
||||
|
||||
// Check that unsafe stack is set to the normal unsafe stack.
|
||||
assert(__get_unsafe_stack_ptr() <= __get_unsafe_stack_top() &&
|
||||
__get_unsafe_stack_ptr() >= __get_unsafe_stack_bottom());
|
||||
assert(__safestack_get_unsafe_stack_ptr() <=
|
||||
__safestack_get_unsafe_stack_top() &&
|
||||
__safestack_get_unsafe_stack_ptr() >=
|
||||
__safestack_get_unsafe_stack_bottom());
|
||||
|
||||
assert(signal_handlers_called == 4);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue