mozjs78/backport-CVE-2023-29543-Part-1-Disallow-GC-while-iterating-global-s-debugger.patch
2025-05-18 17:11:07 +00:00

146 lines
6.4 KiB
Diff

From aee1effa487849cc3c48c28c60a866211b05ebae Mon Sep 17 00:00:00 2001
From: Jon Coppeard <jcoppeard@mozilla.com>
Date: Tue, 14 Feb 2023 10:32:47 +0000
Subject: [PATCH] Part 1: Disallow GC while iterating global's debugger vector
Conflict:NA
Reference:https://hg.mozilla.org/integration/autoland/rev/760275af660b20d35ace80f4d245c4ad9c4a3869
---
js/src/debugger/Debugger.cpp | 37 +++++++++++++++++++++++-------------
js/src/debugger/Debugger.h | 10 ++++++----
js/src/gc/GC.h | 2 +-
3 files changed, 31 insertions(+), 18 deletions(-)
diff --git a/js/src/debugger/Debugger.cpp b/js/src/debugger/Debugger.cpp
index be22c18354..56a172c457 100644
--- a/js/src/debugger/Debugger.cpp
+++ b/js/src/debugger/Debugger.cpp
@@ -1240,8 +1240,9 @@ bool DebugAPI::slowPathOnNewGenerator(JSContext* cx, AbstractFramePtr frame,
MakeScopeExit([&] { Debugger::terminateDebuggerFrames(cx, frame); });
bool ok = true;
+ gc::AutoSuppressGC nogc(cx);
Debugger::forEachOnStackDebuggerFrame(
- frame, [&](Debugger* dbg, DebuggerFrame* frameObjPtr) {
+ frame, nogc, [&](Debugger* dbg, DebuggerFrame* frameObjPtr) {
if (!ok) {
return;
}
@@ -3265,7 +3266,10 @@ bool Debugger::updateExecutionObservabilityOfScripts(
template <typename FrameFn>
/* static */
-void Debugger::forEachOnStackDebuggerFrame(AbstractFramePtr frame, FrameFn fn) {
+void Debugger::forEachOnStackDebuggerFrame(AbstractFramePtr frame,
+ const JS::AutoRequireNoGC& nogc,
+ FrameFn fn) {
+ // GC is disallowed because it may mutate the vector we are iterating.
for (Realm::DebuggerVectorEntry& entry : frame.global()->getDebuggers()) {
Debugger* dbg = entry.dbg;
if (FrameMap::Ptr frameEntry = dbg->frames.lookup(frame)) {
@@ -3276,9 +3280,10 @@ void Debugger::forEachOnStackDebuggerFrame(AbstractFramePtr frame, FrameFn fn) {
template <typename FrameFn>
/* static */
-void Debugger::forEachOnStackOrSuspendedDebuggerFrame(JSContext* cx,
- AbstractFramePtr frame,
- FrameFn fn) {
+void Debugger::forEachOnStackOrSuspendedDebuggerFrame(
+ JSContext* cx, AbstractFramePtr frame, const JS::AutoRequireNoGC& nogc,
+ FrameFn fn) {
+ // GC is disallowed because it may mutate the vector we are iterating.
Rooted<AbstractGeneratorObject*> genObj(
cx, frame.isGeneratorFrame() ? GetGeneratorObjectForFrame(cx, frame)
: nullptr);
@@ -3304,11 +3309,13 @@ void Debugger::forEachOnStackOrSuspendedDebuggerFrame(JSContext* cx,
bool Debugger::getDebuggerFrames(AbstractFramePtr frame,
MutableHandle<DebuggerFrameVector> frames) {
bool hadOOM = false;
- forEachOnStackDebuggerFrame(frame, [&](Debugger*, DebuggerFrame* frameobj) {
- if (!hadOOM && !frames.append(frameobj)) {
- hadOOM = true;
- }
- });
+ JS::AutoAssertNoGC nogc;
+ forEachOnStackDebuggerFrame(frame, nogc,
+ [&](Debugger*, DebuggerFrame* frameobj) {
+ if (!hadOOM && !frames.append(frameobj)) {
+ hadOOM = true;
+ }
+ });
return !hadOOM;
}
@@ -6466,8 +6473,10 @@ bool Debugger::replaceFrameGuts(JSContext* cx, AbstractFramePtr from,
/* static */
bool DebugAPI::inFrameMaps(AbstractFramePtr frame) {
bool foundAny = false;
+ JS::AutoAssertNoGC nogc;
Debugger::forEachOnStackDebuggerFrame(
- frame, [&](Debugger*, DebuggerFrame* frameobj) { foundAny = true; });
+ frame, nogc,
+ [&](Debugger*, DebuggerFrame* frameobj) { foundAny = true; });
return foundAny;
}
@@ -6475,8 +6484,9 @@ bool DebugAPI::inFrameMaps(AbstractFramePtr frame) {
void Debugger::suspendGeneratorDebuggerFrames(JSContext* cx,
AbstractFramePtr frame) {
JSFreeOp* fop = cx->runtime()->defaultFreeOp();
+ JS::AutoAssertNoGC nogc;
forEachOnStackDebuggerFrame(
- frame, [&](Debugger* dbg, DebuggerFrame* dbgFrame) {
+ frame, nogc, [&](Debugger* dbg, DebuggerFrame* dbgFrame) {
dbg->frames.remove(frame);
#if DEBUG
@@ -6495,8 +6505,9 @@ void Debugger::suspendGeneratorDebuggerFrames(JSContext* cx,
void Debugger::terminateDebuggerFrames(JSContext* cx, AbstractFramePtr frame) {
JSFreeOp* fop = cx->runtime()->defaultFreeOp();
+ JS::AutoAssertNoGC nogc;
forEachOnStackOrSuspendedDebuggerFrame(
- cx, frame, [&](Debugger* dbg, DebuggerFrame* dbgFrame) {
+ cx, frame, nogc, [&](Debugger* dbg, DebuggerFrame* dbgFrame) {
Debugger::terminateDebuggerFrame(fop, dbg, dbgFrame, frame);
});
diff --git a/js/src/debugger/Debugger.h b/js/src/debugger/Debugger.h
index bc89e4bfb1..d9da8bbe36 100644
--- a/js/src/debugger/Debugger.h
+++ b/js/src/debugger/Debugger.h
@@ -930,11 +930,13 @@ class Debugger : private mozilla::LinkedListElement<Debugger> {
IsObserving observing);
template <typename FrameFn /* void (Debugger*, DebuggerFrame*) */>
- static void forEachOnStackDebuggerFrame(AbstractFramePtr frame, FrameFn fn);
+ static void forEachOnStackDebuggerFrame(AbstractFramePtr frame,
+ const JS::AutoRequireNoGC& nogc,
+ FrameFn fn);
template <typename FrameFn /* void (Debugger*, DebuggerFrame*) */>
- static void forEachOnStackOrSuspendedDebuggerFrame(JSContext* cx,
- AbstractFramePtr frame,
- FrameFn fn);
+ static void forEachOnStackOrSuspendedDebuggerFrame(
+ JSContext* cx, AbstractFramePtr frame, const JS::AutoRequireNoGC& nogc,
+ FrameFn fn);
/*
* Return a vector containing all Debugger.Frame instances referring to
diff --git a/js/src/gc/GC.h b/js/src/gc/GC.h
index 9cee0190b6..c6fe40c263 100644
--- a/js/src/gc/GC.h
+++ b/js/src/gc/GC.h
@@ -179,7 +179,7 @@ static inline void MaybeVerifyBarriers(JSContext* cx, bool always = false) {}
* This works by updating the |JSContext::suppressGC| counter which is checked
* at the start of GC.
*/
-class MOZ_RAII JS_HAZ_GC_SUPPRESSED AutoSuppressGC {
+class MOZ_RAII JS_HAZ_GC_SUPPRESSED AutoSuppressGC : public JS::AutoRequireNoGC {
int32_t& suppressGC_;
public:
--
2.33.0