mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-16 19:56:38 +00:00
[sanitizer] Change the way GetThreadStackAndTls() obtains the thread descriptor address.
Instead of using arch_prctl(ARCH_GET_FS), read the address from the tread descriptor itself. This lets us avoid sandboxing issues. Also, GetThreadStackAndTls() can now be implemented on i386. llvm-svn: 182853
This commit is contained in:
parent
677003140c
commit
89bcec8117
@ -55,6 +55,8 @@ void AdjustStackSizeLinux(void *attr, int verbosity);
|
||||
|
||||
// Exposed for testing.
|
||||
uptr ThreadDescriptorSize();
|
||||
uptr ThreadSelf();
|
||||
uptr ThreadSelfOffset();
|
||||
|
||||
// Matches a library's file name against a base name (stripping path and version
|
||||
// information).
|
||||
|
@ -19,19 +19,12 @@
|
||||
#include "sanitizer_procmaps.h"
|
||||
#include "sanitizer_stacktrace.h"
|
||||
|
||||
#ifdef __x86_64__
|
||||
#include <asm/prctl.h>
|
||||
#endif
|
||||
#include <dlfcn.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/resource.h>
|
||||
#include <unwind.h>
|
||||
|
||||
#ifdef __x86_64__
|
||||
extern "C" int arch_prctl(int code, __sanitizer::uptr *addr);
|
||||
#endif
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
|
||||
@ -200,20 +193,37 @@ uptr GetTlsSize() {
|
||||
return g_tls_size;
|
||||
}
|
||||
|
||||
#if defined(__x86_64__) || defined(i386)
|
||||
// sizeof(struct thread) from glibc.
|
||||
#ifdef __x86_64__
|
||||
const uptr kThreadDescriptorSize = 2304;
|
||||
const uptr kThreadDescriptorSize = FIRST_32_SECOND_64(1216, 2304);
|
||||
|
||||
uptr ThreadDescriptorSize() {
|
||||
return kThreadDescriptorSize;
|
||||
}
|
||||
|
||||
// The offset at which pointer to self is located in the thread descriptor.
|
||||
const uptr kThreadSelfOffset = FIRST_32_SECOND_64(8, 16);
|
||||
|
||||
uptr ThreadSelfOffset() {
|
||||
return kThreadSelfOffset;
|
||||
}
|
||||
|
||||
uptr ThreadSelf() {
|
||||
uptr descr_addr;
|
||||
#ifdef __i386__
|
||||
asm("mov %%gs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset));
|
||||
#else
|
||||
asm("mov %%fs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset));
|
||||
#endif
|
||||
return descr_addr;
|
||||
}
|
||||
#endif // defined(__x86_64__) || defined(i386)
|
||||
|
||||
void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
|
||||
uptr *tls_addr, uptr *tls_size) {
|
||||
#ifndef SANITIZER_GO
|
||||
#ifdef __x86_64__
|
||||
arch_prctl(ARCH_GET_FS, tls_addr);
|
||||
#if defined(__x86_64__) || defined(i386)
|
||||
*tls_addr = ThreadSelf();
|
||||
*tls_size = GetTlsSize();
|
||||
*tls_addr -= *tls_size;
|
||||
*tls_addr += kThreadDescriptorSize;
|
||||
|
@ -19,9 +19,6 @@
|
||||
#include "sanitizer_common/sanitizer_common.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#ifdef __x86_64__
|
||||
#include <asm/prctl.h>
|
||||
#endif
|
||||
#include <pthread.h>
|
||||
#include <sched.h>
|
||||
#include <stdlib.h>
|
||||
@ -29,10 +26,6 @@
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#ifdef __x86_64__
|
||||
extern "C" int arch_prctl(int code, __sanitizer::uptr *addr);
|
||||
#endif
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
struct TidReporterArgument {
|
||||
@ -202,23 +195,37 @@ TEST(SanitizerCommon, SetEnvTest) {
|
||||
EXPECT_EQ(0, getenv(kEnvName));
|
||||
}
|
||||
|
||||
#ifdef __x86_64__
|
||||
// libpthread puts the thread descriptor (%fs:0x0) at the end of stack space.
|
||||
void *thread_descriptor_test_func(void *arg) {
|
||||
uptr fs;
|
||||
arch_prctl(ARCH_GET_FS, &fs);
|
||||
#if defined(__x86_64__) || defined(i386)
|
||||
void *thread_self_offset_test_func(void *arg) {
|
||||
bool result =
|
||||
*(uptr *)((char *)ThreadSelf() + ThreadSelfOffset()) == ThreadSelf();
|
||||
return (void *)result;
|
||||
}
|
||||
|
||||
TEST(SanitizerLinux, ThreadSelfOffset) {
|
||||
EXPECT_TRUE((bool)thread_self_offset_test_func(0));
|
||||
pthread_t tid;
|
||||
void *result;
|
||||
ASSERT_EQ(0, pthread_create(&tid, 0, thread_self_offset_test_func, 0));
|
||||
ASSERT_EQ(0, pthread_join(tid, &result));
|
||||
EXPECT_TRUE((bool)result);
|
||||
}
|
||||
|
||||
// libpthread puts the thread descriptor at the end of stack space.
|
||||
void *thread_descriptor_size_test_func(void *arg) {
|
||||
uptr descr_addr = ThreadSelf();
|
||||
pthread_attr_t attr;
|
||||
pthread_getattr_np(pthread_self(), &attr);
|
||||
void *stackaddr;
|
||||
uptr stacksize;
|
||||
size_t stacksize;
|
||||
pthread_attr_getstack(&attr, &stackaddr, &stacksize);
|
||||
return (void *)((uptr)stackaddr + stacksize - fs);
|
||||
return (void *)((uptr)stackaddr + stacksize - descr_addr);
|
||||
}
|
||||
|
||||
TEST(SanitizerLinux, ThreadDescriptorSize) {
|
||||
pthread_t tid;
|
||||
void *result;
|
||||
pthread_create(&tid, 0, thread_descriptor_test_func, 0);
|
||||
ASSERT_EQ(0, pthread_create(&tid, 0, thread_descriptor_size_test_func, 0));
|
||||
ASSERT_EQ(0, pthread_join(tid, &result));
|
||||
EXPECT_EQ((uptr)result, ThreadDescriptorSize());
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user