Firefox · DOM
CVE-2026-14241
Memory Corruption in DOM
Overview
High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifdom/webserial/SerialPort.cpp |
modified |
Files Changed
dom/webserial/SerialPort.cppdom/webserial/SerialPort.h
Patch
diff --git a/dom/webserial/SerialPort.cpp b/dom/webserial/SerialPort.cpp
index 818fb9acea0..d5dcee6705a 100644
--- a/dom/webserial/SerialPort.cpp
+++ b/dom/webserial/SerialPort.cpp
@@ -137,7 +137,7 @@ void SerialPort::Shutdown() {
if (mState == State::Opened || mState == State::Closing) {
mState = State::Closed;
// Don't have to wait for this
- RefPtr<Promise> ignoredPromise = CloseStreams();
+ RefPtr<Promise> ignoredPromise = CloseStreams(StreamCloseMode::Forced);
}
if (mOpenPromise) {
@@ -529,7 +529,7 @@ already_AddRefed<Promise> SerialPort::Close(ErrorResult& aRv) {
// promise to wait for all (steps 5-8). Our pendingClosePromise is
// effectively resolved once both streams are nulled (step 6), so the
// combined promise just waits for the cancel and abort to finish.
- RefPtr<Promise> combinedPromise = CloseStreams();
+ RefPtr<Promise> combinedPromise = CloseStreams(StreamCloseMode::Graceful);
if (!combinedPromise) {
combinedPromise = Promise::CreateResolvedWithUndefined(global, aRv);
if (NS_WARN_IF(aRv.Failed())) {
@@ -598,7 +598,7 @@ already_AddRefed<Promise> SerialPort::Forget(ErrorResult& aRv) {
if (wasActive) {
// Don't have to wait for this
- RefPtr<Promise> ignoredPromise = CloseStreams();
+ RefPtr<Promise> ignoredPromise = CloseStreams(StreamCloseMode::Graceful);
}
UpdateWorkerRef();
@@ -652,7 +652,7 @@ void SerialPort::MarkForgotten() {
if (wasActive) {
// Don't have to wait for this
- RefPtr<Promise> ignoredPromise = CloseStreams();
+ RefPtr<Promise> ignoredPromise = CloseStreams(StreamCloseMode::Graceful);
}
UpdateWorkerRef();
@@ -767,7 +767,7 @@ void SerialPort::NotifyDisconnected() {
}
mPhysicallyPresent = false;
// Don't have to wait for this
- RefPtr<Promise> ignoredPromise = CloseStreams();
+ RefPtr<Promise> ignoredPromise = CloseStreams(StreamCloseMode::Graceful);
UpdateWorkerRef();
NotifySharingStateChanged(false);
@@ -951,7 +951,7 @@ void SerialPort::SettleClosePromise(nsresult aResult) {
}
}
-already_AddRefed<Promise> SerialPort::CloseStreams() {
+already_AddRefed<Promise> SerialPort::CloseStreams(StreamCloseMode aMode) {
nsIGlobalObject* global = GetRelevantGlobal();
if (!global) {
return nullptr;
@@ -963,8 +963,9 @@ already_AddRefed<Promise> SerialPort::CloseStreams() {
MOZ_LOG(gWebSerialLog, LogLevel::Info,
("SerialPort[%p]::CloseStreams closing streams "
- "(readable=%p, writable=%p)",
- this, mReadable.get(), mWritable.get()));
+ "(readable=%p, writable=%p, mode=%s)",
+ this, mReadable.get(), mWritable.get(),
+ aMode == StreamCloseMode::Forced ? "forced" : "graceful"));
AutoJSAPI jsapi;
if (!jsapi.Init(global)) {
@@ -973,14 +974,33 @@ already_AddRefed<Promise> SerialPort::CloseStreams() {
JSContext* cx = jsapi.cx();
- // Cancel the readable and abort the writable, collecting their promises.
- nsTArray<RefPtr<Promise>> streamPromises;
-
RefPtr<DOMException> exception =
DOMException::Create(NS_ERROR_DOM_NETWORK_ERR, "Port has been closed"_ns);
JS::Rooted<JS::Value> errorVal(cx);
bool hasError = ToJSValue(cx, exception, &errorVal);
+ // Error the streams instead of aborting, so we don't dispatchevents
+ // or runauthor-visible algorithms. The OS resources are released by
+ // mChild->Shutdown() in Shutdown().
+ if (aMode == StreamCloseMode::Forced) {
+ if (mReadable && hasError) {
+ IgnoredErrorResult rv;
+ RefPtr readable = mReadable;
+ readable->ErrorNative(cx, errorVal, rv);
+ }
+ if (mWritable && hasError) {
+ IgnoredErrorResult rv;
+ RefPtr writable = mWritable;
+ writable->ErrorNative(cx, errorVal, rv);
+ }
+ mReadable = nullptr;
+ mWritable = nullptr;
+ return nullptr;
+ }
+
+ // Cancel the readable and abort the writable, collecting their promises.
+ nsTArray<RefPtr<Promise>> streamPromises;
+
if (mReadable && hasError) {
IgnoredErrorResult rv;
RefPtr readable = mReadable;
diff --git a/dom/webserial/SerialPort.h b/dom/webserial/SerialPort.h
index fb319115eaa..3950affdafe 100644
--- a/dom/webserial/SerialPort.h
+++ b/dom/webserial/SerialPort.h
@@ -116,11 +116,21 @@ class SerialPort final : public DOMEventTargetHelper {
private:
~SerialPort() override;
+ enum class StreamCloseMode : uint8_t {
+ // Cancel the readable and abort the writable, running their underlying
+ // source/sink algorithms.
+ Graceful,
+ // Error both streams without running author-observable algorithms or
+ // dispatching events.
+ Forced,
+ };
+
MOZ_CAN_RUN_SCRIPT ReadableStream* CreateReadableStream();
MOZ_CAN_RUN_SCRIPT WritableStream* CreateWritableStream();
void CloseAfterStreamsClosed();
void SettleClosePromise(nsresult aResult);
- MOZ_CAN_RUN_SCRIPT already_AddRefed<Promise> CloseStreams();
+ MOZ_CAN_RUN_SCRIPT already_AddRefed<Promise> CloseStreams(
+ StreamCloseMode aMode);
void NotifySharingStateChanged(bool aConnected);
void UpdateWorkerRef();
Loading diff…
References
On This Page