Ticket #20283: 0001-Bug-20283-Tor-Browser-should-run-without-a-proc-file.patch

File 0001-Bug-20283-Tor-Browser-should-run-without-a-proc-file.patch, 5.6 KB (added by pospeselr, 12 months ago)

js::GetNativeStackBaseImpl fix

  • js/src/jsnativestack.cpp

    From 14359c7f33f2dfd37e34b74abb9d5672dc9df991 Mon Sep 17 00:00:00 2001
    From: Richard Pospesel <richard@torproject.org>
    Date: Mon, 9 Apr 2018 11:40:32 -0700
    Subject: [PATCH] Bug 20283: Tor Browser should run without a `/proc`
     filesystem.
    
    Firefox uses the current stack frame address and the stack size
    as a sort of heuristic for various things in the javascript
    engine.  The js::GetNativeStackBaseImpl() function is used to
    get the base stack address (ie the address from which the stack
    grows, so this can be either the first or last memory address of
    the stack memory space depending on the CPU architecture).
    
    On Linux, this function is implemented using the pthreads APIs.
    For non-main threads, the queried thread info is stored in
    memory.  The main thread does not have this information on hand,
    so it gets the stack memory range via the /proc/self/maps file
    ( see glibc's pthread_get_attr_np.c ).
    
    Fortunately (per discussions with the firefox devs in #jsapi)
    the base address only needs to be approximation.  In reality,
    environment variables, args, and other things are stored in space
    between the end/beginning of the mapped stack memory and the 'top'
    of the stack space used by stack frames.
    
    We can get the top of this usable stack from __libc_stack_end,
    which is a void* set by glibc during program initialization.
    Non-main threads still get their stack-base through the usual
    pthreads APIs.
    
    This patch integrates the latest jsnativestack.cpp from mozilla-
    central, and creates a specific implementation of 
    js::GetNativeStackBaseImpl() for non-android Linux using the
    described __libc_stack_end read.
    ---
     js/src/jsnativestack.cpp | 88 +++++++++++++++++++++++++++++-------------------
     1 file changed, 54 insertions(+), 34 deletions(-)
    
    diff --git a/js/src/jsnativestack.cpp b/js/src/jsnativestack.cpp
    index 05928ea3dff3..0f4dae156c2b 100644
    a b  
    88
    99#ifdef XP_WIN
    1010# include "jswin.h"
    11 
    1211#elif defined(XP_DARWIN) || defined(DARWIN) || defined(XP_UNIX)
    1312# include <pthread.h>
    14 
    1513# if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
    1614#  include <pthread_np.h>
    1715# endif
    18 
    19 # if defined(ANDROID)
     16# if defined(ANDROID) && !defined(__aarch64__)
    2017#  include <sys/types.h>
    2118#  include <unistd.h>
    2219# endif
    23 
    2420#else
    2521# error "Unsupported platform"
    26 
    2722#endif
    2823
    2924#if defined(XP_WIN)
     
    3126void*
    3227js::GetNativeStackBaseImpl()
    3328{
    34 # if defined(_M_IX86) && defined(_MSC_VER)
    35     /*
    36      * offset 0x18 from the FS segment register gives a pointer to
    37      * the thread information block for the current thread
    38      */
    39     NT_TIB* pTib;
    40     __asm {
    41         MOV EAX, FS:[18h]
    42         MOV pTib, EAX
    43     }
    44     return static_cast<void*>(pTib->StackBase);
    45 
    46 # elif defined(_M_X64)
    47     PNT_TIB64 pTib = reinterpret_cast<PNT_TIB64>(NtCurrentTeb());
    48     return reinterpret_cast<void*>(pTib->StackBase);
    49 
    50 # elif defined(_M_ARM)
    5129    PNT_TIB pTib = reinterpret_cast<PNT_TIB>(NtCurrentTeb());
    5230    return static_cast<void*>(pTib->StackBase);
    53 
    54 # elif defined(_WIN32) && defined(__GNUC__)
    55     NT_TIB* pTib;
    56     asm ("movl %%fs:0x18, %0\n" : "=r" (pTib));
    57     return static_cast<void*>(pTib->StackBase);
    58 
    59 # endif
    6031}
    6132
    6233#elif defined(SOLARIS)
    js::GetNativeStackBaseImpl() 
    8859        context.uc_stack.ss_size;
    8960}
    9061
     62#elif defined(XP_LINUX) && !defined(ANDROID)
     63
     64# include <dlfcn.h>
     65# include <sys/syscall.h>
     66static pid_t
     67gettid()
     68{
     69    return syscall(__NR_gettid);
     70}
     71
     72void*
     73js::GetNativeStackBaseImpl()
     74{
     75    // main thread, get stack base from __libc_stack_end rather than pthread APIs
     76    // to avoid filesystem calls /proc/self/maps
     77    if(gettid() == getpid()) {
     78        void** pLibcStackEnd = (void**)dlsym(RTLD_DEFAULT, "__libc_stack_end");
     79        // if __libc_stack_end is not found, architecture specific frame pointer hopping will need
     80        // to be implemented
     81        MOZ_ASSERT(pLibcStackEnd);
     82        void* stackBase = *pLibcStackEnd;
     83        MOZ_ASSERT(stackBase);
     84        // we don't need to fix stackBase, as it already roughly points to beginning of the stack
     85        return stackBase;
     86    }
     87    // non-main threads have the required info stored in memory, no filesystem calls are made
     88    else {
     89        pthread_t thread = pthread_self();
     90        pthread_attr_t sattr;
     91        pthread_attr_init(&sattr);
     92        pthread_getattr_np(thread, &sattr);
     93        // stackBase will be the lowest address on all architectures
     94        void* stackBase = nullptr;
     95        size_t stackSize = 0;
     96        int rc = pthread_attr_getstack(&sattr, &stackBase, &stackSize);
     97        if(rc) {
     98            MOZ_CRASH();
     99        }
     100        MOZ_ASSERT(stackBase);
     101        pthread_attr_destroy(&sattr);
     102
     103# if JS_STACK_GROWTH_DIRECTION > 0
     104        return stackBase;
     105# else
     106        return static_cast<char*>(stackBase) + stackSize;
     107# endif
     108    }
     109}
     110
    91111#else /* XP_UNIX */
    92112
    93113void*
    js::GetNativeStackBaseImpl() 
    120140    rc = pthread_stackseg_np(pthread_self(), &ss);
    121141    stackBase = (void*)((size_t) ss.ss_sp - ss.ss_size);
    122142    stackSize = ss.ss_size;
    123 # elif defined(ANDROID)
     143# elif defined(ANDROID) && !defined(__aarch64__)
    124144    if (gettid() == getpid()) {
    125         // bionic's pthread_attr_getstack doesn't tell the truth for the main
    126         // thread (see bug 846670). So we scan /proc/self/maps to find the
    127         // segment which contains the stack.
     145        // bionic's pthread_attr_getstack prior to API 21 doesn't tell the truth
     146        // for the main thread (see bug 846670). So we scan /proc/self/maps to
     147        // find the segment which contains the stack.
    128148        rc = -1;
    129149
    130150        // Put the string on the stack, otherwise there is the danger that it