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/js/src/jsnativestack.cpp
+++ b/js/src/jsnativestack.cpp
@@ -8,22 +8,17 @@
 
 #ifdef XP_WIN
 # include "jswin.h"
-
 #elif defined(XP_DARWIN) || defined(DARWIN) || defined(XP_UNIX)
 # include <pthread.h>
-
 # if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
 #  include <pthread_np.h>
 # endif
-
-# if defined(ANDROID)
+# if defined(ANDROID) && !defined(__aarch64__)
 #  include <sys/types.h>
 #  include <unistd.h>
 # endif
-
 #else
 # error "Unsupported platform"
-
 #endif
 
 #if defined(XP_WIN)
@@ -31,32 +26,8 @@
 void*
 js::GetNativeStackBaseImpl()
 {
-# if defined(_M_IX86) && defined(_MSC_VER)
-    /*
-     * offset 0x18 from the FS segment register gives a pointer to
-     * the thread information block for the current thread
-     */
-    NT_TIB* pTib;
-    __asm {
-        MOV EAX, FS:[18h]
-        MOV pTib, EAX
-    }
-    return static_cast<void*>(pTib->StackBase);
-
-# elif defined(_M_X64)
-    PNT_TIB64 pTib = reinterpret_cast<PNT_TIB64>(NtCurrentTeb());
-    return reinterpret_cast<void*>(pTib->StackBase);
-
-# elif defined(_M_ARM)
     PNT_TIB pTib = reinterpret_cast<PNT_TIB>(NtCurrentTeb());
     return static_cast<void*>(pTib->StackBase);
-
-# elif defined(_WIN32) && defined(__GNUC__)
-    NT_TIB* pTib;
-    asm ("movl %%fs:0x18, %0\n" : "=r" (pTib));
-    return static_cast<void*>(pTib->StackBase);
-
-# endif
 }
 
 #elif defined(SOLARIS)
@@ -88,6 +59,55 @@ js::GetNativeStackBaseImpl()
         context.uc_stack.ss_size;
 }
 
+#elif defined(XP_LINUX) && !defined(ANDROID)
+
+# include <dlfcn.h>
+# include <sys/syscall.h>
+static pid_t
+gettid()
+{
+    return syscall(__NR_gettid);
+}
+
+void*
+js::GetNativeStackBaseImpl()
+{
+    // main thread, get stack base from __libc_stack_end rather than pthread APIs
+    // to avoid filesystem calls /proc/self/maps
+    if(gettid() == getpid()) {
+        void** pLibcStackEnd = (void**)dlsym(RTLD_DEFAULT, "__libc_stack_end");
+        // if __libc_stack_end is not found, architecture specific frame pointer hopping will need
+        // to be implemented
+        MOZ_ASSERT(pLibcStackEnd);
+        void* stackBase = *pLibcStackEnd;
+        MOZ_ASSERT(stackBase);
+        // we don't need to fix stackBase, as it already roughly points to beginning of the stack
+        return stackBase;
+    }
+    // non-main threads have the required info stored in memory, no filesystem calls are made
+    else {
+        pthread_t thread = pthread_self();
+        pthread_attr_t sattr;
+        pthread_attr_init(&sattr);
+        pthread_getattr_np(thread, &sattr);
+        // stackBase will be the lowest address on all architectures
+        void* stackBase = nullptr;
+        size_t stackSize = 0;
+        int rc = pthread_attr_getstack(&sattr, &stackBase, &stackSize);
+        if(rc) {
+            MOZ_CRASH();
+        }
+        MOZ_ASSERT(stackBase);
+        pthread_attr_destroy(&sattr);
+
+# if JS_STACK_GROWTH_DIRECTION > 0
+        return stackBase;
+# else
+        return static_cast<char*>(stackBase) + stackSize;
+# endif
+    }
+}
+
 #else /* XP_UNIX */
 
 void*
@@ -120,11 +140,11 @@ js::GetNativeStackBaseImpl()
     rc = pthread_stackseg_np(pthread_self(), &ss);
     stackBase = (void*)((size_t) ss.ss_sp - ss.ss_size);
     stackSize = ss.ss_size;
-# elif defined(ANDROID)
+# elif defined(ANDROID) && !defined(__aarch64__)
     if (gettid() == getpid()) {
-        // bionic's pthread_attr_getstack doesn't tell the truth for the main
-        // thread (see bug 846670). So we scan /proc/self/maps to find the
-        // segment which contains the stack.
+        // bionic's pthread_attr_getstack prior to API 21 doesn't tell the truth
+        // for the main thread (see bug 846670). So we scan /proc/self/maps to
+        // find the segment which contains the stack.
         rc = -1;
 
         // Put the string on the stack, otherwise there is the danger that it
-- 
2.14.1

