closes #391: M1342721 with some ideas from M1342439

This commit is contained in:
Cameron Kaiser 2017-12-13 10:42:53 -08:00
parent cb70bd9e50
commit faa6eb4c0c
8 changed files with 155 additions and 94 deletions

View File

@ -2396,9 +2396,7 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
// transplanting code, since it has no good way to handle errors. This uses
// the untrusted script limit, which is not strictly necessary since no
// actual script should run.
bool overrecursed = false;
JS_CHECK_RECURSION_CONSERVATIVE_DONT_REPORT(cx, overrecursed = true);
if (overrecursed) {
if (MOZ_UNLIKELY(!js::CheckRecursionConservativeDontReport(cx))) {
NS_WARNING("Overrecursion in SetNewDocument");
return NS_ERROR_FAILURE;
}

View File

@ -1891,7 +1891,9 @@ ReparentWrapper(JSContext* aCx, JS::Handle<JSObject*> aObjArg)
// transplanting code, since it has no good way to handle errors. This uses
// the untrusted script limit, which is not strictly necessary since no
// actual script should run.
JS_CHECK_RECURSION_CONSERVATIVE(aCx, return NS_ERROR_FAILURE);
if (MOZ_UNLIKELY(!js::CheckRecursionConservative(aCx))) {
return NS_ERROR_FAILURE;
}
JS::Rooted<JSObject*> aObj(aCx, aObjArg);
const DOMJSClass* domClass = GetDOMClass(aObj);

View File

@ -28,6 +28,8 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "jscntxtinlines.h"
#include "irregexp/RegExpEngine.h"
#include "irregexp/NativeRegExpMacroAssembler.h"

View File

@ -149,6 +149,8 @@ class ExclusiveContext : public ContextFriendFields,
return isJSContext();
}
JSRuntime* ecRuntime() const { return runtime_; } // TenFourFox issue 391
bool runtimeMatches(JSRuntime* rt) const {
return runtime_ == rt;
}

View File

@ -19,8 +19,130 @@
#include "vm/ProxyObject.h"
#include "vm/Symbol.h"
MOZ_ALWAYS_INLINE bool
JSContext::runningWithTrustedPrincipals() const
{
return !compartment() || compartment()->principals() == runtime()->trustedPrincipals();
}
namespace js {
MOZ_ALWAYS_INLINE uintptr_t
GetNativeStackLimit(JSContext* cx, StackKind kind, int extraAllowance = 0)
{
PerThreadDataFriendFields* mainThread =
PerThreadDataFriendFields::getMainThread(GetRuntime(cx));
uintptr_t limit = mainThread->nativeStackLimit[kind];
#if JS_STACK_GROWTH_DIRECTION > 0
limit += extraAllowance;
#else
limit -= extraAllowance;
#endif
return limit;
}
// Needed for issue 391 -- see below
MOZ_ALWAYS_INLINE uintptr_t
GetNativeStackLimit(ExclusiveContext* cx, StackKind kind, int extraAllowance = 0)
{
PerThreadDataFriendFields* mainThread =
PerThreadDataFriendFields::getMainThread(cx->ecRuntime());
uintptr_t limit = mainThread->nativeStackLimit[kind];
#if JS_STACK_GROWTH_DIRECTION > 0
limit += extraAllowance;
#else
limit -= extraAllowance;
#endif
return limit;
}
MOZ_ALWAYS_INLINE uintptr_t
GetNativeStackLimit(JSContext* cx, int extraAllowance = 0)
{
StackKind kind = cx->runningWithTrustedPrincipals() ? StackForTrustedScript
: StackForUntrustedScript;
return GetNativeStackLimit(cx, kind, extraAllowance);
}
/*
* These macros report a stack overflow and run |onerror| if we are close to
* using up the C stack. The JS_CHECK_CHROME_RECURSION variant gives us a
* little extra space so that we can ensure that crucial code is able to run.
* JS_CHECK_RECURSION_CONSERVATIVE allows less space than any other check,
* including a safety buffer (as in, it uses the untrusted limit and subtracts
* a little more from it).
*/
// Implement a fast path a la bug 1342439, but without all that churn.
// Leave the old limit versions here just in case.
// TenFourFox issue 391
#define JS_CHECK_RECURSION_LIMIT(cx, limit, onerror) \
JS_BEGIN_MACRO \
int stackDummy_; \
if (MOZ_UNLIKELY(!JS_CHECK_STACK_SIZE(limit, &stackDummy_))) { \
js::ReportOverRecursed(cx); \
onerror; \
} \
JS_END_MACRO
#define JS_CHECK_RECURSION(cx, onerror) \
JS_BEGIN_MACRO \
int stackDummy_; \
if (MOZ_UNLIKELY(!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx, js::StackForUntrustedScript), &stackDummy_))) { \
if (MOZ_UNLIKELY(!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx), &stackDummy_))) {\
js::ReportOverRecursed(cx); \
onerror; \
} \
} \
JS_END_MACRO
#define JS_CHECK_RECURSION_LIMIT_DONT_REPORT(cx, limit, onerror) \
JS_BEGIN_MACRO \
int stackDummy_; \
if (MOZ_UNLIKELY(!JS_CHECK_STACK_SIZE(limit, &stackDummy_))) { \
onerror; \
} \
JS_END_MACRO
#define JS_CHECK_RECURSION_DONT_REPORT(cx, onerror) \
JS_BEGIN_MACRO \
int stackDummy_; \
if (MOZ_UNLIKELY(!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx, js::StackForUntrustedScript), &stackDummy_))) { \
if (MOZ_UNLIKELY(!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx), &stackDummy_))) {\
onerror; \
} \
} \
JS_END_MACRO
#define JS_CHECK_RECURSION_WITH_SP_DONT_REPORT(cx, sp, onerror) \
JS_BEGIN_MACRO \
if (MOZ_UNLIKELY(!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx), sp))) { \
onerror; \
} \
JS_END_MACRO
#define JS_CHECK_RECURSION_WITH_SP(cx, sp, onerror) \
JS_BEGIN_MACRO \
if (MOZ_UNLIKELY(!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx), sp))) { \
js::ReportOverRecursed(cx); \
onerror; \
} \
JS_END_MACRO
#define JS_CHECK_SYSTEM_RECURSION(cx, onerror) \
JS_CHECK_RECURSION_LIMIT(cx, js::GetNativeStackLimit(cx, js::StackForSystemCode), onerror)
#define JS_CHECK_RECURSION_CONSERVATIVE(cx, onerror) \
JS_CHECK_RECURSION_LIMIT(cx, \
js::GetNativeStackLimit(cx, js::StackForUntrustedScript, -1024 * int(sizeof(size_t))), \
onerror)
#define JS_CHECK_RECURSION_CONSERVATIVE_DONT_REPORT(cx, onerror) \
JS_CHECK_RECURSION_LIMIT_DONT_REPORT(cx, \
js::GetNativeStackLimit(cx, js::StackForUntrustedScript, -1024 * int(sizeof(size_t))), \
onerror)
class CompartmentChecker
{
JSCompartment* compartment;
@ -382,12 +504,6 @@ JSContext::setPendingException(js::Value v)
MOZ_ASSERT_IF(v.isObject(), v.toObject().compartment() == compartment());
}
inline bool
JSContext::runningWithTrustedPrincipals() const
{
return !compartment() || compartment()->principals() == runtime()->trustedPrincipals();
}
inline void
js::ExclusiveContext::enterCompartment(JSCompartment* c)
{

View File

@ -385,9 +385,24 @@ js::IsObjectInContextCompartment(JSObject* obj, const JSContext* cx)
}
JS_FRIEND_API(bool)
js::RunningWithTrustedPrincipals(JSContext* cx)
js::CheckRecursion(JSContext* cx)
{
return cx->runningWithTrustedPrincipals();
JS_CHECK_RECURSION(cx, return false);
return true;
}
JS_FRIEND_API(bool)
js::CheckRecursionConservative(JSContext* cx)
{
JS_CHECK_RECURSION_CONSERVATIVE(cx, return false);
return true;
}
JS_FRIEND_API(bool)
js::CheckRecursionConservativeDontReport(JSContext* cx)
{
JS_CHECK_RECURSION_CONSERVATIVE_DONT_REPORT(cx, return false);
return true;
}
JS_FRIEND_API(JSFunction*)

View File

@ -967,89 +967,13 @@ IsObjectInContextCompartment(JSObject* obj, const JSContext* cx);
#define JSITER_SYMBOLSONLY 0x40 /* exclude string property keys */
JS_FRIEND_API(bool)
RunningWithTrustedPrincipals(JSContext* cx);
CheckRecursion(JSContext* cx);
MOZ_ALWAYS_INLINE uintptr_t
GetNativeStackLimit(JSContext* cx, StackKind kind, int extraAllowance = 0)
{
PerThreadDataFriendFields* mainThread =
PerThreadDataFriendFields::getMainThread(GetRuntime(cx));
uintptr_t limit = mainThread->nativeStackLimit[kind];
#if JS_STACK_GROWTH_DIRECTION > 0
limit += extraAllowance;
#else
limit -= extraAllowance;
#endif
return limit;
}
JS_FRIEND_API(bool)
CheckRecursionConservative(JSContext* cx);
MOZ_ALWAYS_INLINE uintptr_t
GetNativeStackLimit(JSContext* cx, int extraAllowance = 0)
{
StackKind kind = RunningWithTrustedPrincipals(cx) ? StackForTrustedScript
: StackForUntrustedScript;
return GetNativeStackLimit(cx, kind, extraAllowance);
}
/*
* These macros report a stack overflow and run |onerror| if we are close to
* using up the C stack. The JS_CHECK_CHROME_RECURSION variant gives us a
* little extra space so that we can ensure that crucial code is able to run.
* JS_CHECK_RECURSION_CONSERVATIVE allows less space than any other check,
* including a safety buffer (as in, it uses the untrusted limit and subtracts
* a little more from it).
*/
#define JS_CHECK_RECURSION_LIMIT(cx, limit, onerror) \
JS_BEGIN_MACRO \
int stackDummy_; \
if (MOZ_UNLIKELY(!JS_CHECK_STACK_SIZE(limit, &stackDummy_))) { \
js::ReportOverRecursed(cx); \
onerror; \
} \
JS_END_MACRO
#define JS_CHECK_RECURSION(cx, onerror) \
JS_CHECK_RECURSION_LIMIT(cx, js::GetNativeStackLimit(cx), onerror)
#define JS_CHECK_RECURSION_LIMIT_DONT_REPORT(cx, limit, onerror) \
JS_BEGIN_MACRO \
int stackDummy_; \
if (MOZ_UNLIKELY(!JS_CHECK_STACK_SIZE(limit, &stackDummy_))) { \
onerror; \
} \
JS_END_MACRO
#define JS_CHECK_RECURSION_DONT_REPORT(cx, onerror) \
JS_CHECK_RECURSION_LIMIT_DONT_REPORT(cx, js::GetNativeStackLimit(cx), onerror)
#define JS_CHECK_RECURSION_WITH_SP_DONT_REPORT(cx, sp, onerror) \
JS_BEGIN_MACRO \
if (MOZ_UNLIKELY(!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx), sp))) { \
onerror; \
} \
JS_END_MACRO
#define JS_CHECK_RECURSION_WITH_SP(cx, sp, onerror) \
JS_BEGIN_MACRO \
if (MOZ_UNLIKELY(!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx), sp))) { \
js::ReportOverRecursed(cx); \
onerror; \
} \
JS_END_MACRO
#define JS_CHECK_SYSTEM_RECURSION(cx, onerror) \
JS_CHECK_RECURSION_LIMIT(cx, js::GetNativeStackLimit(cx, js::StackForSystemCode), onerror)
#define JS_CHECK_RECURSION_CONSERVATIVE(cx, onerror) \
JS_CHECK_RECURSION_LIMIT(cx, \
js::GetNativeStackLimit(cx, js::StackForUntrustedScript, -1024 * int(sizeof(size_t))), \
onerror)
#define JS_CHECK_RECURSION_CONSERVATIVE_DONT_REPORT(cx, onerror) \
JS_CHECK_RECURSION_LIMIT_DONT_REPORT(cx, \
js::GetNativeStackLimit(cx, js::StackForUntrustedScript, -1024 * int(sizeof(size_t))), \
onerror)
JS_FRIEND_API(bool)
CheckRecursionConservativeDontReport(JSContext* cx);
JS_FRIEND_API(void)
StartPCCountProfiling(JSContext* cx);

View File

@ -258,7 +258,9 @@ XPCArrayHomogenizer::GetTypeForArray(JSContext* cx, HandleObject array,
bool XPCVariant::InitializeData(JSContext* cx)
{
JS_CHECK_RECURSION(cx, return false);
if (MOZ_UNLIKELY(!js::CheckRecursion(cx))) {
return false;
}
RootedValue val(cx, GetJSVal());