Skip to content

Commit

Permalink
WIP: Use libsigchain on Android
Browse files Browse the repository at this point in the history
Install page guard signal handler using AddSpecialSignalHandlerFn from
the libsigchain in the Android runtime. This prevents traced
applications from replacing our signal handler when they try to install
thier own signal handlers with sigaction.
  • Loading branch information
mikes-lunarg committed Sep 17, 2024
1 parent 544fb67 commit 2b90ddf
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 32 deletions.
91 changes: 59 additions & 32 deletions framework/util/page_guard_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ static stack_t s_old_stack = {};
static uint8_t* s_alt_stack = nullptr;
static size_t s_alt_stack_size = 0;

static void PageGuardExceptionHandler(int id, siginfo_t* info, void* data)
static bool TryHandlePageGuardException(int id, siginfo_t* info, void* data)
{
bool handled = false;
PageGuardManager* manager = PageGuardManager::Get();
Expand Down Expand Up @@ -181,8 +181,12 @@ static void PageGuardExceptionHandler(int id, siginfo_t* info, void* data)
#endif
handled = manager->HandleGuardPageViolation(info->si_addr, is_write, true);
}
return handled;
}

if (!handled)
static void PageGuardExceptionHandler(int id, siginfo_t* info, void* data)
{
if (!TryHandlePageGuardException(id, info, data))
{
// This was not a SIGSEGV signal for an address that was protected with mprotect().
// Raise the original signal handler for this case.
Expand Down Expand Up @@ -248,6 +252,13 @@ PageGuardManager::PageGuardManager(bool enable_copy_on_map,
protection_mode_ = kMProtectMode;
}

#if defined(__ANDROID__)
AddSpecialSignalHandlerFn =
reinterpret_cast<PFN_AddSpecialSignalHandlerFn>(dlsym(RTLD_DEFAULT, "AddSpecialSignalHandlerFn"));
RemoveSpecialSignalHandlerFn =
reinterpret_cast<PFN_RemoveSpecialSignalHandlerFn>(dlsym(RTLD_DEFAULT, "RemoveSpecialSignalHandlerFn"));
#endif

if (kMProtectMode == protection_mode_)
{
InitializeSystemExceptionContext();
Expand Down Expand Up @@ -497,43 +508,59 @@ void PageGuardManager::AddExceptionHandler()
exception_handler_count_ = 1;
}
#else
// Retrieve the current SIGSEGV handler info before replacing the current signal handler to determine if our
// replacement signal handler should use an alternate signal stack.
int result = sigaction(MEMPROT_SIGNAL, nullptr, &s_old_sigaction);

if (result != -1)
#if defined(__ANDROID__)
if (AddSpecialSignalHandlerFn)
{
struct sigaction sa = {};

sa.sa_flags = SA_SIGINFO;
sigemptyset(&sa.sa_mask);
sa.sa_sigaction = PageGuardExceptionHandler;
if (!special_signal_handler_installed_)
{
SigchainAction sc = {};
sc.sc_sigaction = TryHandlePageGuardException;
sigemptyset(&sc.sc_mask);
AddSpecialSignalHandlerFn(SIGSEGV, &sc);
special_signal_handler_installed_ = true;
}
}
else
#endif
{
// Retrieve the current SIGSEGV handler info before replacing the current signal handler to determine if our
// replacement signal handler should use an alternate signal stack.
int result = sigaction(MEMPROT_SIGNAL, nullptr, &s_old_sigaction);

if ((s_old_sigaction.sa_flags & SA_ONSTACK) == SA_ONSTACK)
if (result != -1)
{
// Replace the current alternate signal stack with one that is guatanteed to be valid for the page guard
// signal handler.
stack_t new_stack;
new_stack.ss_sp = s_alt_stack;
new_stack.ss_flags = 0;
new_stack.ss_size = s_alt_stack_size;
struct sigaction sa = {};

sigaltstack(&new_stack, &s_old_stack);
sa.sa_flags = SA_SIGINFO;
sigemptyset(&sa.sa_mask);
sa.sa_sigaction = PageGuardExceptionHandler;

sa.sa_flags |= SA_ONSTACK;
}
if ((s_old_sigaction.sa_flags & SA_ONSTACK) == SA_ONSTACK)
{
// Replace the current alternate signal stack with one that is guaranteed to be valid for the page
// guard signal handler.
stack_t new_stack;
new_stack.ss_sp = s_alt_stack;
new_stack.ss_flags = 0;
new_stack.ss_size = s_alt_stack_size;

result = sigaction(MEMPROT_SIGNAL, &sa, nullptr);
}
sigaltstack(&new_stack, &s_old_stack);

if (result != -1)
{
exception_handler_ = reinterpret_cast<void*>(PageGuardExceptionHandler);
exception_handler_count_ = 1;
}
else
{
GFXRECON_LOG_ERROR("PageGuardManager failed to register exception handler (errno = %d)", errno);
sa.sa_flags |= SA_ONSTACK;
}

result = sigaction(MEMPROT_SIGNAL, &sa, nullptr);
}

if (result != -1)
{
exception_handler_ = reinterpret_cast<void*>(PageGuardExceptionHandler);
exception_handler_count_ = 1;
}
else
{
GFXRECON_LOG_ERROR("PageGuardManager failed to register exception handler (errno = %d)", errno);
}
}
#endif
}
Expand Down
18 changes: 18 additions & 0 deletions framework/util/page_guard_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,18 @@
#endif
#endif

#if defined(__ANDROID__)
struct SigchainAction
{
bool (*sc_sigaction)(int, siginfo_t*, void*);
sigset_t sc_mask;
uint64_t sc_flags;
};

typedef void (*PFN_AddSpecialSignalHandlerFn)(int signal, SigchainAction* sa);
typedef void (*PFN_RemoveSpecialSignalHandlerFn)(int signal, bool (*fn)(int, siginfo_t*, void*));
#endif

GFXRECON_BEGIN_NAMESPACE(gfxrecon)
GFXRECON_BEGIN_NAMESPACE(util)

Expand Down Expand Up @@ -297,6 +309,12 @@ class PageGuardManager
std::unordered_set<uint64_t> uffd_fault_causing_threads;
#endif

#if defined(__ANDROID__)
PFN_AddSpecialSignalHandlerFn AddSpecialSignalHandlerFn = nullptr;
PFN_RemoveSpecialSignalHandlerFn RemoveSpecialSignalHandlerFn = nullptr;
bool special_signal_handler_installed_ = false;
#endif

bool InitializeUserFaultFd();
void UffdTerminate();
uint32_t UffdBlockFaultingThreads();
Expand Down

0 comments on commit 2b90ddf

Please sign in to comment.