mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-29 18:47:31 +09:00
No issue - Add range checking to SharedArrayBuffer references.
This avoids a potential crash when juggling SAB allocations.
This commit is contained in:
parent
f1c456c625
commit
788cc4acb2
5 changed files with 57 additions and 27 deletions
|
|
@ -445,6 +445,7 @@ MSG_DEF(JSMSG_SC_UNSUPPORTED_TYPE, 0, JSEXN_TYPEERR, "unsupported type for s
|
||||||
MSG_DEF(JSMSG_SC_NOT_CLONABLE, 1, JSEXN_TYPEERR, "{0} cannot be cloned in this context")
|
MSG_DEF(JSMSG_SC_NOT_CLONABLE, 1, JSEXN_TYPEERR, "{0} cannot be cloned in this context")
|
||||||
MSG_DEF(JSMSG_SC_SAB_TRANSFER, 0, JSEXN_WARN, "SharedArrayBuffer must not be in the transfer list")
|
MSG_DEF(JSMSG_SC_SAB_TRANSFER, 0, JSEXN_WARN, "SharedArrayBuffer must not be in the transfer list")
|
||||||
MSG_DEF(JSMSG_SC_SAB_DISABLED, 0, JSEXN_TYPEERR, "SharedArrayBuffer not cloned - shared memory disabled in receiver")
|
MSG_DEF(JSMSG_SC_SAB_DISABLED, 0, JSEXN_TYPEERR, "SharedArrayBuffer not cloned - shared memory disabled in receiver")
|
||||||
|
MSG_DEF(JSMSG_SC_SAB_TOO_MANY_REFS, 0, JSEXN_TYPEERR, "SharedArrayBuffer has too many references")
|
||||||
|
|
||||||
// Debugger
|
// Debugger
|
||||||
MSG_DEF(JSMSG_ASSIGN_FUNCTION_OR_NULL, 1, JSEXN_TYPEERR, "value assigned to {0} must be a function or null")
|
MSG_DEF(JSMSG_ASSIGN_FUNCTION_OR_NULL, 1, JSEXN_TYPEERR, "value assigned to {0} must be a function or null")
|
||||||
|
|
|
||||||
|
|
@ -5347,25 +5347,31 @@ GetSharedArrayBuffer(JSContext* cx, unsigned argc, Value* vp)
|
||||||
{
|
{
|
||||||
CallArgs args = CallArgsFromVp(argc, vp);
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
JSObject* newObj = nullptr;
|
JSObject* newObj = nullptr;
|
||||||
bool rval = true;
|
|
||||||
|
|
||||||
sharedArrayBufferMailboxLock->lock();
|
{
|
||||||
SharedArrayRawBuffer* buf = sharedArrayBufferMailbox;
|
sharedArrayBufferMailboxLock->lock();
|
||||||
if (buf) {
|
auto unlockMailbox = MakeScopeExit([]() { sharedArrayBufferMailboxLock->unlock(); });
|
||||||
buf->addReference();
|
|
||||||
// Shared memory is enabled globally in the shell: there can't be a worker
|
SharedArrayRawBuffer* buf = sharedArrayBufferMailbox;
|
||||||
// that does not enable it if the main thread has it.
|
if (buf) {
|
||||||
MOZ_ASSERT(cx->compartment()->creationOptions().getSharedMemoryAndAtomicsEnabled());
|
if (!buf->addReference()) {
|
||||||
newObj = SharedArrayBufferObject::New(cx, buf);
|
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_SC_SAB_REFCNT_OFLO);
|
||||||
if (!newObj) {
|
return false;
|
||||||
buf->dropReference();
|
}
|
||||||
rval = false;
|
|
||||||
|
// Shared memory is enabled globally in the shell: there can't be a worker
|
||||||
|
// that does not enable it if the main thread has it.
|
||||||
|
MOZ_ASSERT(cx->compartment()->creationOptions().getSharedMemoryAndAtomicsEnabled());
|
||||||
|
newObj = SharedArrayBufferObject::New(cx, buf);
|
||||||
|
if (!newObj) {
|
||||||
|
buf->dropReference();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sharedArrayBufferMailboxLock->unlock();
|
|
||||||
|
|
||||||
args.rval().setObjectOrNull(newObj);
|
args.rval().setObjectOrNull(newObj);
|
||||||
return rval;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
|
@ -5379,18 +5385,24 @@ SetSharedArrayBuffer(JSContext* cx, unsigned argc, Value* vp)
|
||||||
}
|
}
|
||||||
else if (args.get(0).isObject() && args[0].toObject().is<SharedArrayBufferObject>()) {
|
else if (args.get(0).isObject() && args[0].toObject().is<SharedArrayBufferObject>()) {
|
||||||
newBuffer = args[0].toObject().as<SharedArrayBufferObject>().rawBufferObject();
|
newBuffer = args[0].toObject().as<SharedArrayBufferObject>().rawBufferObject();
|
||||||
newBuffer->addReference();
|
if (!newBuffer->addReference()) {
|
||||||
|
JS_ReportErrorASCII(cx, "Reference count overflow on SharedArrayBuffer");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
JS_ReportErrorASCII(cx, "Only a SharedArrayBuffer can be installed in the global mailbox");
|
JS_ReportErrorASCII(cx, "Only a SharedArrayBuffer can be installed in the global mailbox");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
sharedArrayBufferMailboxLock->lock();
|
{
|
||||||
SharedArrayRawBuffer* oldBuffer = sharedArrayBufferMailbox;
|
sharedArrayBufferMailboxLock->lock();
|
||||||
if (oldBuffer)
|
auto unlockMailbox = MakeScopeExit([]() { sharedArrayBufferMailboxLock->unlock(); });
|
||||||
oldBuffer->dropReference();
|
|
||||||
sharedArrayBufferMailbox = newBuffer;
|
SharedArrayRawBuffer* oldBuffer = sharedArrayBufferMailbox;
|
||||||
sharedArrayBufferMailboxLock->unlock();
|
if (oldBuffer)
|
||||||
|
oldBuffer->dropReference();
|
||||||
|
sharedArrayBufferMailbox = newBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
args.rval().setUndefined();
|
args.rval().setUndefined();
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -166,16 +166,30 @@ SharedArrayRawBuffer::New(JSContext* cx, uint32_t length)
|
||||||
return rawbuf;
|
return rawbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
bool
|
||||||
SharedArrayRawBuffer::addReference()
|
SharedArrayRawBuffer::addReference()
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(this->refcount_ > 0);
|
MOZ_ASSERT(this->refcount_ > 0);
|
||||||
++this->refcount_; // Atomic.
|
|
||||||
|
// Be careful never to overflow the refcount field.
|
||||||
|
for (;;) {
|
||||||
|
uint32_t old_refcount = this->refcount_;
|
||||||
|
uint32_t new_refcount = old_refcount+1;
|
||||||
|
if (new_refcount == 0)
|
||||||
|
return false;
|
||||||
|
if (this->refcount_.compareExchange(old_refcount, new_refcount))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SharedArrayRawBuffer::dropReference()
|
SharedArrayRawBuffer::dropReference()
|
||||||
{
|
{
|
||||||
|
// Normally if the refcount is zero then the memory will have been unmapped
|
||||||
|
// and this test may just crash, but if the memory has been retained for any
|
||||||
|
// reason we will catch the underflow here.
|
||||||
|
MOZ_RELEASE_ASSERT(this->refcount_ > 0);
|
||||||
|
|
||||||
// Drop the reference to the buffer.
|
// Drop the reference to the buffer.
|
||||||
uint32_t refcount = --this->refcount_; // Atomic.
|
uint32_t refcount = --this->refcount_; // Atomic.
|
||||||
if (refcount)
|
if (refcount)
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ class SharedArrayRawBuffer
|
||||||
|
|
||||||
uint32_t refcount() const { return refcount_; }
|
uint32_t refcount() const { return refcount_; }
|
||||||
|
|
||||||
void addReference();
|
[[nodiscard]] bool addReference();
|
||||||
void dropReference();
|
void dropReference();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1201,9 +1201,12 @@ JSStructuredCloneWriter::writeSharedArrayBuffer(HandleObject obj)
|
||||||
Rooted<SharedArrayBufferObject*> sharedArrayBuffer(context(), &CheckedUnwrap(obj)->as<SharedArrayBufferObject>());
|
Rooted<SharedArrayBufferObject*> sharedArrayBuffer(context(), &CheckedUnwrap(obj)->as<SharedArrayBufferObject>());
|
||||||
SharedArrayRawBuffer* rawbuf = sharedArrayBuffer->rawBufferObject();
|
SharedArrayRawBuffer* rawbuf = sharedArrayBuffer->rawBufferObject();
|
||||||
|
|
||||||
// Avoids a race condition where the parent thread frees the buffer
|
// Adding the reference here avoids a race condition where the parent thread frees the buffer
|
||||||
// before the child has accepted the transferable.
|
// before the child has accepted the transferable.
|
||||||
rawbuf->addReference();
|
if (!rawbuf->addReference()) {
|
||||||
|
JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_SAB_TOO_MANY_REFS);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
intptr_t p = reinterpret_cast<intptr_t>(rawbuf);
|
intptr_t p = reinterpret_cast<intptr_t>(rawbuf);
|
||||||
return out.writePair(SCTAG_SHARED_ARRAY_BUFFER_OBJECT, static_cast<uint32_t>(sizeof(p))) &&
|
return out.writePair(SCTAG_SHARED_ARRAY_BUFFER_OBJECT, static_cast<uint32_t>(sizeof(p))) &&
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue