Bug 1076161 - Prevent JS_StealArrayBufferContents from being used with mapped array buffers (r=sfink)

--HG--
extra : rebase_source : 8eaed8849d05daf4e9cdf312b93d6ebec9890302
This commit is contained in:
Luke Wagner 2014-10-08 20:45:50 -05:00
parent c44e6ab410
commit bf601eeade
4 changed files with 24 additions and 5 deletions

View File

@ -425,6 +425,7 @@ MSG_DEF(JSMSG_TYPED_ARRAY_BAD_ARGS, 0, JSEXN_ERR, "invalid arguments")
MSG_DEF(JSMSG_TYPED_ARRAY_BAD_OBJECT, 0, JSEXN_TYPEERR, "invalid object argument")
MSG_DEF(JSMSG_TYPED_ARRAY_BAD_INDEX, 0, JSEXN_ERR, "invalid or out-of-range index")
MSG_DEF(JSMSG_TYPED_ARRAY_NEGATIVE_ARG,1, JSEXN_ERR, "argument {0} must be >= 0")
MSG_DEF(JSMSG_TYPED_ARRAY_DETACHED, 0, JSEXN_TYPEERR, "attempting to access detached ArrayBuffer")
// Shared array buffer
MSG_DEF(JSMSG_SHARED_ARRAY_BAD_OBJECT, 0, JSEXN_TYPEERR, "invalid object argument")

View File

@ -712,8 +712,11 @@ ArrayBufferObject::ensureNonInline(JSContext *cx, Handle<ArrayBufferObject*> buf
}
/* static */ ArrayBufferObject::BufferContents
ArrayBufferObject::stealContents(JSContext *cx, Handle<ArrayBufferObject*> buffer)
ArrayBufferObject::stealContents(JSContext *cx, Handle<ArrayBufferObject*> buffer,
bool hasStealableContents)
{
MOZ_ASSERT_IF(hasStealableContents, buffer->hasStealableContents());
if (!buffer->canNeuter(cx)) {
js_ReportOverRecursed(cx);
return BufferContents::createUnowned(nullptr);
@ -724,7 +727,7 @@ ArrayBufferObject::stealContents(JSContext *cx, Handle<ArrayBufferObject*> buffe
if (!newContents)
return BufferContents::createUnowned(nullptr);
if (buffer->hasStealableContents()) {
if (hasStealableContents) {
// Return the old contents and give the neutered buffer a pointer to
// freshly allocated memory that we will never write to and should
// never get committed.
@ -1167,7 +1170,19 @@ JS_StealArrayBufferContents(JSContext *cx, HandleObject objArg)
}
Rooted<ArrayBufferObject*> buffer(cx, &obj->as<ArrayBufferObject>());
return ArrayBufferObject::stealContents(cx, buffer).data();
if (buffer->isNeutered()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
return nullptr;
}
// The caller assumes that a plain malloc'd buffer is returned.
// hasStealableContents is true for mapped buffers, so we must additionally
// require that the buffer is plain. In the future, we could consider
// returning something that handles releasing the memory.
bool hasStealableContents = buffer->hasStealableContents() &&
buffer->bufferKind() == ArrayBufferObject::PLAIN_BUFFER;
return ArrayBufferObject::stealContents(cx, buffer, hasStealableContents).data();
}
JS_PUBLIC_API(JSObject *)

View File

@ -194,7 +194,9 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
static void objectMoved(JSObject *obj, const JSObject *old);
static BufferContents stealContents(JSContext *cx, Handle<ArrayBufferObject*> buffer);
static BufferContents stealContents(JSContext *cx,
Handle<ArrayBufferObject*> buffer,
bool hasStealableContents);
bool hasStealableContents() const {
// Inline elements strictly adhere to the corresponding buffer.

View File

@ -1169,8 +1169,9 @@ JSStructuredCloneWriter::transferOwnership()
// lend itself well to generic manipulation via proxies.
Rooted<ArrayBufferObject *> arrayBuffer(context(), &CheckedUnwrap(obj)->as<ArrayBufferObject>());
size_t nbytes = arrayBuffer->byteLength();
bool hasStealableContents = arrayBuffer->hasStealableContents();
ArrayBufferObject::BufferContents bufContents =
ArrayBufferObject::stealContents(context(), arrayBuffer);
ArrayBufferObject::stealContents(context(), arrayBuffer, hasStealableContents);
if (!bufContents)
return false; // Destructor will clean up the already-transferred data.
content = bufContents.data();