mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-02-02 07:06:33 +00:00
[libc] Add x86-64 stack protector support.
This commit is contained in:
parent
eb1905d2b6
commit
28245b4ecb
@ -10,6 +10,7 @@ add_startup_object(
|
||||
libc.src.__support.threads.thread
|
||||
libc.src.__support.OSUtil.osutil
|
||||
libc.src.stdlib.exit
|
||||
libc.src.stdlib.abort
|
||||
libc.src.stdlib.atexit
|
||||
libc.src.string.memory_utils.inline_memcpy
|
||||
libc.src.unistd.environ
|
||||
|
@ -7,8 +7,10 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "config/linux/app.h"
|
||||
#include "src/__support/OSUtil/io.h"
|
||||
#include "src/__support/OSUtil/syscall.h"
|
||||
#include "src/__support/threads/thread.h"
|
||||
#include "src/stdlib/abort.h"
|
||||
#include "src/stdlib/atexit.h"
|
||||
#include "src/stdlib/exit.h"
|
||||
#include "src/string/memory_utils/inline_memcpy.h"
|
||||
@ -23,6 +25,11 @@
|
||||
|
||||
extern "C" int main(int, char **, char **);
|
||||
|
||||
extern "C" void __stack_chk_fail() {
|
||||
LIBC_NAMESPACE::write_to_stderr("stack smashing detected");
|
||||
LIBC_NAMESPACE::abort();
|
||||
}
|
||||
|
||||
namespace LIBC_NAMESPACE {
|
||||
|
||||
#ifdef SYS_mmap2
|
||||
@ -54,7 +61,9 @@ void init_tls(TLSDescriptor &tls_descriptor) {
|
||||
// Per the x86_64 TLS ABI, the entry pointed to by the thread pointer is the
|
||||
// address of the TLS block. So, we add more size to accomodate this address
|
||||
// entry.
|
||||
uintptr_t tlsSizeWithAddr = tlsSize + sizeof(uintptr_t);
|
||||
// We also need to include space for the stack canary. The canary is at
|
||||
// offset 0x28 (40) and is of size uintptr_t.
|
||||
uintptr_t tlsSizeWithAddr = tlsSize + sizeof(uintptr_t) + 40;
|
||||
|
||||
// We cannot call the mmap function here as the functions set errno on
|
||||
// failure. Since errno is implemented via a thread local variable, we cannot
|
||||
@ -76,6 +85,16 @@ void init_tls(TLSDescriptor &tls_descriptor) {
|
||||
LIBC_NAMESPACE::inline_memcpy(reinterpret_cast<char *>(tlsAddr),
|
||||
reinterpret_cast<const char *>(app.tls.address),
|
||||
app.tls.init_size);
|
||||
uintptr_t *stackGuardAddr = reinterpret_cast<uintptr_t *>(endPtr + 40);
|
||||
// Setting the stack guard to a random value.
|
||||
// We cannot call the get_random function here as the function sets errno on
|
||||
// failure. Since errno is implemented via a thread local variable, we cannot
|
||||
// use errno before TLS is setup.
|
||||
ssize_t stackGuardRetVal = LIBC_NAMESPACE::syscall_impl<ssize_t>(
|
||||
SYS_getrandom, reinterpret_cast<long>(stackGuardAddr), sizeof(uint64_t),
|
||||
0);
|
||||
if (stackGuardRetVal < 0)
|
||||
LIBC_NAMESPACE::syscall_impl(SYS_exit, 1);
|
||||
|
||||
tls_descriptor = {tlsSizeWithAddr, uintptr_t(tlsAddr), endPtr};
|
||||
return;
|
||||
|
@ -33,6 +33,29 @@ add_integration_test(
|
||||
libc.src.unistd.fork
|
||||
)
|
||||
|
||||
if((${LIBC_TARGET_OS} STREQUAL "linux") AND (${LIBC_TARGET_ARCHITECTURE_IS_X86}))
|
||||
add_integration_test(
|
||||
stack_smashing_test
|
||||
SUITE
|
||||
unistd-integration-tests
|
||||
SRCS
|
||||
stack_smashing_test.cpp
|
||||
DEPENDS
|
||||
libc.include.errno
|
||||
libc.include.signal
|
||||
libc.include.sys_wait
|
||||
libc.include.unistd
|
||||
libc.src.pthread.pthread_atfork
|
||||
libc.src.signal.raise
|
||||
libc.src.sys.wait.wait
|
||||
libc.src.sys.wait.wait4
|
||||
libc.src.sys.wait.waitpid
|
||||
libc.src.unistd.fork
|
||||
COMPILE_OPTIONS
|
||||
-fstack-protector-all
|
||||
)
|
||||
endif()
|
||||
|
||||
add_executable(
|
||||
libc_execv_test_normal_exit
|
||||
EXCLUDE_FROM_ALL
|
||||
|
68
libc/test/integration/src/unistd/stack_smashing_test.cpp
Normal file
68
libc/test/integration/src/unistd/stack_smashing_test.cpp
Normal file
@ -0,0 +1,68 @@
|
||||
//===--- Stack smashing test to check stack canary set up ----------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "src/__support/CPP/string.h"
|
||||
#include "src/__support/OSUtil/io.h"
|
||||
#include "src/pthread/pthread_atfork.h"
|
||||
#include "src/signal/raise.h"
|
||||
#include "src/sys/wait/wait.h"
|
||||
#include "src/sys/wait/wait4.h"
|
||||
#include "src/sys/wait/waitpid.h"
|
||||
#include "src/unistd/fork.h"
|
||||
|
||||
#include "test/IntegrationTest/test.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void no_stack_smashing_normal_exit() {
|
||||
pid_t pid = LIBC_NAMESPACE::fork();
|
||||
if (pid == 0) {
|
||||
// Child process
|
||||
char foo[30];
|
||||
for (int i = 0; i < 30; i++)
|
||||
foo[i] = (foo[i] != 42) ? 42 : 24;
|
||||
return;
|
||||
}
|
||||
ASSERT_TRUE(pid > 0);
|
||||
int status;
|
||||
pid_t cpid = LIBC_NAMESPACE::wait(&status);
|
||||
ASSERT_TRUE(cpid > 0);
|
||||
ASSERT_EQ(cpid, pid);
|
||||
ASSERT_TRUE(WIFEXITED(status));
|
||||
}
|
||||
|
||||
void stack_smashing_abort() {
|
||||
pid_t pid = LIBC_NAMESPACE::fork();
|
||||
if (pid == 0) {
|
||||
// Child process
|
||||
char foo[30];
|
||||
char *frame_ptr = static_cast<char *>(__builtin_frame_address(0));
|
||||
char *cur_ptr = &foo[0];
|
||||
// Corrupt the stack
|
||||
while (cur_ptr != frame_ptr) {
|
||||
*cur_ptr = (*cur_ptr != 42) ? 42 : 24;
|
||||
cur_ptr++;
|
||||
}
|
||||
return;
|
||||
}
|
||||
ASSERT_TRUE(pid > 0);
|
||||
int status;
|
||||
pid_t cpid = LIBC_NAMESPACE::wait(&status);
|
||||
ASSERT_TRUE(cpid > 0);
|
||||
ASSERT_EQ(cpid, pid);
|
||||
ASSERT_TRUE(WTERMSIG(status) == SIGABRT);
|
||||
}
|
||||
|
||||
TEST_MAIN(int argc, char **argv, char **envp) {
|
||||
no_stack_smashing_normal_exit();
|
||||
stack_smashing_abort();
|
||||
return 0;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user