Bug 1179025 - Protect against using cursors on a deleted objectStore/index, r=janv.

This commit is contained in:
Ben Turner 2015-07-02 10:47:53 -07:00
parent 02432eb394
commit dc3eb40174
9 changed files with 279 additions and 206 deletions

View File

@ -6248,12 +6248,6 @@ private:
bool
VerifyRequestParams(const RequestParams& aParams) const;
bool
VerifyRequestParams(const OpenCursorParams& aParams) const;
bool
VerifyRequestParams(const CursorRequestParams& aParams) const;
bool
VerifyRequestParams(const SerializedKeyRange& aKeyRange) const;
@ -7550,6 +7544,12 @@ private:
nsRefPtr<FileManager> mFileManager;
PBackgroundParent* mBackgroundParent;
// These should only be touched on the PBackground thread to check whether the
// objectStore or index has been deleted. Holding these saves a hash lookup
// for every call to continue()/advance().
nsRefPtr<FullObjectStoreMetadata> mObjectStoreMetadata;
nsRefPtr<FullIndexMetadata> mIndexMetadata;
const int64_t mObjectStoreId;
const int64_t mIndexId;
@ -7565,7 +7565,8 @@ private:
const Type mType;
const Direction mDirection;
bool mUniqueIndex;
const bool mUniqueIndex;
const bool mIsSameProcessActor;
bool mActorDestroyed;
public:
@ -7575,8 +7576,8 @@ private:
// Only created by TransactionBase.
Cursor(TransactionBase* aTransaction,
Type aType,
int64_t aObjectStoreId,
int64_t aIndexId,
FullObjectStoreMetadata* aObjectStoreMetadata,
FullIndexMetadata* aIndexMetadata,
Direction aDirection);
// Reference counted.
@ -7585,6 +7586,9 @@ private:
MOZ_ASSERT(mActorDestroyed);
}
bool
VerifyRequestParams(const CursorRequestParams& aParams) const;
// Only called by TransactionBase.
bool
Start(const OpenCursorParams& aParams);
@ -13368,115 +13372,6 @@ TransactionBase::VerifyRequestParams(const RequestParams& aParams) const
return true;
}
bool
TransactionBase::VerifyRequestParams(const OpenCursorParams& aParams) const
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(aParams.type() != OpenCursorParams::T__None);
switch (aParams.type()) {
case OpenCursorParams::TObjectStoreOpenCursorParams: {
const ObjectStoreOpenCursorParams& params =
aParams.get_ObjectStoreOpenCursorParams();
nsRefPtr<FullObjectStoreMetadata> objectStoreMetadata =
GetMetadataForObjectStoreId(params.objectStoreId());
if (NS_WARN_IF(!objectStoreMetadata)) {
ASSERT_UNLESS_FUZZING();
return false;
}
if (NS_WARN_IF(!VerifyRequestParams(params.optionalKeyRange()))) {
ASSERT_UNLESS_FUZZING();
return false;
}
break;
}
case OpenCursorParams::TObjectStoreOpenKeyCursorParams: {
const ObjectStoreOpenKeyCursorParams& params =
aParams.get_ObjectStoreOpenKeyCursorParams();
nsRefPtr<FullObjectStoreMetadata> objectStoreMetadata =
GetMetadataForObjectStoreId(params.objectStoreId());
if (NS_WARN_IF(!objectStoreMetadata)) {
ASSERT_UNLESS_FUZZING();
return false;
}
if (NS_WARN_IF(!VerifyRequestParams(params.optionalKeyRange()))) {
ASSERT_UNLESS_FUZZING();
return false;
}
break;
}
case OpenCursorParams::TIndexOpenCursorParams: {
const IndexOpenCursorParams& params = aParams.get_IndexOpenCursorParams();
nsRefPtr<FullObjectStoreMetadata> objectStoreMetadata =
GetMetadataForObjectStoreId(params.objectStoreId());
if (NS_WARN_IF(!objectStoreMetadata)) {
ASSERT_UNLESS_FUZZING();
return false;
}
nsRefPtr<FullIndexMetadata> indexMetadata =
GetMetadataForIndexId(objectStoreMetadata, params.indexId());
if (NS_WARN_IF(!indexMetadata)) {
ASSERT_UNLESS_FUZZING();
return false;
}
if (NS_WARN_IF(!VerifyRequestParams(params.optionalKeyRange()))) {
ASSERT_UNLESS_FUZZING();
return false;
}
break;
}
case OpenCursorParams::TIndexOpenKeyCursorParams: {
const IndexOpenKeyCursorParams& params =
aParams.get_IndexOpenKeyCursorParams();
nsRefPtr<FullObjectStoreMetadata> objectStoreMetadata =
GetMetadataForObjectStoreId(params.objectStoreId());
if (NS_WARN_IF(!objectStoreMetadata)) {
ASSERT_UNLESS_FUZZING();
return false;
}
nsRefPtr<FullIndexMetadata> indexMetadata =
GetMetadataForIndexId(objectStoreMetadata, params.indexId());
if (NS_WARN_IF(!indexMetadata)) {
ASSERT_UNLESS_FUZZING();
return false;
}
if (NS_WARN_IF(!VerifyRequestParams(params.optionalKeyRange()))) {
ASSERT_UNLESS_FUZZING();
return false;
}
break;
}
default:
MOZ_CRASH("Should never get here!");
}
return true;
}
bool
TransactionBase::VerifyRequestParams(const CursorRequestParams& aParams) const
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(aParams.type() != CursorRequestParams::T__None);
switch (aParams.type()) {
case CursorRequestParams::TContinueParams:
break;
case CursorRequestParams::TAdvanceParams:
break;
default:
MOZ_CRASH("Should never get here!");
}
return true;
}
bool
TransactionBase::VerifyRequestParams(const SerializedKeyRange& aParams) const
{
@ -13796,15 +13691,94 @@ PBackgroundIDBCursorParent*
TransactionBase::AllocCursor(const OpenCursorParams& aParams, bool aTrustParams)
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(aParams.type() != OpenCursorParams::T__None);
#ifdef DEBUG
// Always verify parameters in DEBUG builds!
aTrustParams = false;
#endif
if (!aTrustParams && NS_WARN_IF(!VerifyRequestParams(aParams))) {
ASSERT_UNLESS_FUZZING();
return nullptr;
nsRefPtr<FullObjectStoreMetadata> objectStoreMetadata;
nsRefPtr<FullIndexMetadata> indexMetadata;
switch (aParams.type()) {
case OpenCursorParams::TObjectStoreOpenCursorParams: {
const ObjectStoreOpenCursorParams& params =
aParams.get_ObjectStoreOpenCursorParams();
objectStoreMetadata = GetMetadataForObjectStoreId(params.objectStoreId());
if (NS_WARN_IF(!objectStoreMetadata)) {
ASSERT_UNLESS_FUZZING();
return nullptr;
}
if (aTrustParams &&
NS_WARN_IF(!VerifyRequestParams(params.optionalKeyRange()))) {
ASSERT_UNLESS_FUZZING();
return nullptr;
}
break;
}
case OpenCursorParams::TObjectStoreOpenKeyCursorParams: {
const ObjectStoreOpenKeyCursorParams& params =
aParams.get_ObjectStoreOpenKeyCursorParams();
objectStoreMetadata = GetMetadataForObjectStoreId(params.objectStoreId());
if (NS_WARN_IF(!objectStoreMetadata)) {
ASSERT_UNLESS_FUZZING();
return nullptr;
}
if (aTrustParams &&
NS_WARN_IF(!VerifyRequestParams(params.optionalKeyRange()))) {
ASSERT_UNLESS_FUZZING();
return nullptr;
}
break;
}
case OpenCursorParams::TIndexOpenCursorParams: {
const IndexOpenCursorParams& params = aParams.get_IndexOpenCursorParams();
objectStoreMetadata = GetMetadataForObjectStoreId(params.objectStoreId());
if (NS_WARN_IF(!objectStoreMetadata)) {
ASSERT_UNLESS_FUZZING();
return nullptr;
}
indexMetadata =
GetMetadataForIndexId(objectStoreMetadata, params.indexId());
if (NS_WARN_IF(!indexMetadata)) {
ASSERT_UNLESS_FUZZING();
return nullptr;
}
if (aTrustParams &&
NS_WARN_IF(!VerifyRequestParams(params.optionalKeyRange()))) {
ASSERT_UNLESS_FUZZING();
return nullptr;
}
break;
}
case OpenCursorParams::TIndexOpenKeyCursorParams: {
const IndexOpenKeyCursorParams& params =
aParams.get_IndexOpenKeyCursorParams();
objectStoreMetadata = GetMetadataForObjectStoreId(params.objectStoreId());
if (NS_WARN_IF(!objectStoreMetadata)) {
ASSERT_UNLESS_FUZZING();
return nullptr;
}
indexMetadata =
GetMetadataForIndexId(objectStoreMetadata, params.indexId());
if (NS_WARN_IF(!indexMetadata)) {
ASSERT_UNLESS_FUZZING();
return nullptr;
}
if (aTrustParams &&
NS_WARN_IF(!VerifyRequestParams(params.optionalKeyRange()))) {
ASSERT_UNLESS_FUZZING();
return nullptr;
}
break;
}
default:
MOZ_CRASH("Should never get here!");
}
if (NS_WARN_IF(mCommitOrAbortReceived)) {
@ -13819,7 +13793,7 @@ TransactionBase::AllocCursor(const OpenCursorParams& aParams, bool aTrustParams)
int64_t indexId;
Cursor::Direction direction;
switch(type) {
switch (type) {
case OpenCursorParams::TObjectStoreOpenCursorParams: {
const auto& params = aParams.get_ObjectStoreOpenCursorParams();
objectStoreId = params.objectStoreId();
@ -13857,7 +13831,7 @@ TransactionBase::AllocCursor(const OpenCursorParams& aParams, bool aTrustParams)
}
nsRefPtr<Cursor> actor =
new Cursor(this, type, objectStoreId, indexId, direction);
new Cursor(this, type, objectStoreMetadata, indexMetadata, direction);
// Transfer ownership to IPDL.
return actor.forget().take();
@ -14688,26 +14662,32 @@ VersionChangeTransaction::DeallocPBackgroundIDBCursorParent(
Cursor::Cursor(TransactionBase* aTransaction,
Type aType,
int64_t aObjectStoreId,
int64_t aIndexId,
FullObjectStoreMetadata* aObjectStoreMetadata,
FullIndexMetadata* aIndexMetadata,
Direction aDirection)
: mTransaction(aTransaction)
, mBackgroundParent(nullptr)
, mObjectStoreId(aObjectStoreId)
, mIndexId(aIndexId)
, mObjectStoreMetadata(aObjectStoreMetadata)
, mIndexMetadata(aIndexMetadata)
, mObjectStoreId(aObjectStoreMetadata->mCommonMetadata.id())
, mIndexId(aIndexMetadata ? aIndexMetadata->mCommonMetadata.id() : 0)
, mCurrentlyRunningOp(nullptr)
, mType(aType)
, mDirection(aDirection)
, mUniqueIndex(false)
, mUniqueIndex(aIndexMetadata ?
aIndexMetadata->mCommonMetadata.unique() :
false)
, mIsSameProcessActor(!BackgroundParent::IsOtherProcessActor(
aTransaction->GetBackgroundParent()))
, mActorDestroyed(false)
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(aTransaction);
MOZ_ASSERT(aType != OpenCursorParams::T__None);
MOZ_ASSERT(aObjectStoreId);
MOZ_ASSERT(aObjectStoreMetadata);
MOZ_ASSERT_IF(aType == OpenCursorParams::TIndexOpenCursorParams ||
aType == OpenCursorParams::TIndexOpenKeyCursorParams,
aIndexId);
aIndexMetadata);
if (mType == OpenCursorParams::TObjectStoreOpenCursorParams ||
mType == OpenCursorParams::TIndexOpenCursorParams) {
@ -14718,26 +14698,93 @@ Cursor::Cursor(TransactionBase* aTransaction,
MOZ_ASSERT(mBackgroundParent);
}
if (aIndexId) {
MOZ_ASSERT(aType == OpenCursorParams::TIndexOpenCursorParams ||
aType == OpenCursorParams::TIndexOpenKeyCursorParams);
nsRefPtr<FullObjectStoreMetadata> objectStoreMetadata =
aTransaction->GetMetadataForObjectStoreId(aObjectStoreId);
MOZ_ASSERT(objectStoreMetadata);
nsRefPtr<FullIndexMetadata> indexMetadata =
aTransaction->GetMetadataForIndexId(objectStoreMetadata, aIndexId);
MOZ_ASSERT(indexMetadata);
mUniqueIndex = indexMetadata->mCommonMetadata.unique();
}
static_assert(OpenCursorParams::T__None == 0 &&
OpenCursorParams::T__Last == 4,
"Lots of code here assumes only four types of cursors!");
}
bool
Cursor::VerifyRequestParams(const CursorRequestParams& aParams) const
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(aParams.type() != CursorRequestParams::T__None);
MOZ_ASSERT(mObjectStoreMetadata);
MOZ_ASSERT_IF(mType == OpenCursorParams::TIndexOpenCursorParams ||
mType == OpenCursorParams::TIndexOpenKeyCursorParams,
mIndexMetadata);
#ifdef DEBUG
{
nsRefPtr<FullObjectStoreMetadata> objectStoreMetadata =
mTransaction->GetMetadataForObjectStoreId(mObjectStoreId);
if (objectStoreMetadata) {
MOZ_ASSERT(objectStoreMetadata == mObjectStoreMetadata);
} else {
MOZ_ASSERT(mObjectStoreMetadata->mDeleted);
}
if (objectStoreMetadata &&
(mType == OpenCursorParams::TIndexOpenCursorParams ||
mType == OpenCursorParams::TIndexOpenKeyCursorParams)) {
nsRefPtr<FullIndexMetadata> indexMetadata =
mTransaction->GetMetadataForIndexId(objectStoreMetadata, mIndexId);
if (indexMetadata) {
MOZ_ASSERT(indexMetadata == mIndexMetadata);
} else {
MOZ_ASSERT(mIndexMetadata->mDeleted);
}
}
}
#endif
if (NS_WARN_IF(mObjectStoreMetadata->mDeleted) ||
(mIndexMetadata && NS_WARN_IF(mIndexMetadata->mDeleted))) {
ASSERT_UNLESS_FUZZING();
return false;
}
switch (aParams.type()) {
case CursorRequestParams::TContinueParams: {
const Key& key = aParams.get_ContinueParams().key();
if (!key.IsUnset()) {
switch (mDirection) {
case IDBCursor::NEXT:
case IDBCursor::NEXT_UNIQUE:
if (NS_WARN_IF(key <= mKey)) {
ASSERT_UNLESS_FUZZING();
return false;
}
break;
case IDBCursor::PREV:
case IDBCursor::PREV_UNIQUE:
if (NS_WARN_IF(key >= mKey)) {
ASSERT_UNLESS_FUZZING();
return false;
}
break;
default:
MOZ_CRASH("Should never get here!");
}
}
break;
}
case CursorRequestParams::TAdvanceParams:
if (NS_WARN_IF(!aParams.get_AdvanceParams().count())) {
ASSERT_UNLESS_FUZZING();
return false;
}
break;
default:
MOZ_CRASH("Should never get here!");
}
return true;
}
bool
Cursor::Start(const OpenCursorParams& aParams)
{
@ -14863,6 +14910,9 @@ Cursor::ActorDestroy(ActorDestroyReason aWhy)
}
mBackgroundParent = nullptr;
mObjectStoreMetadata = nullptr;
mIndexMetadata = nullptr;
}
bool
@ -14885,6 +14935,24 @@ Cursor::RecvContinue(const CursorRequestParams& aParams)
AssertIsOnBackgroundThread();
MOZ_ASSERT(aParams.type() != CursorRequestParams::T__None);
MOZ_ASSERT(!mActorDestroyed);
MOZ_ASSERT(mObjectStoreMetadata);
MOZ_ASSERT_IF(mType == OpenCursorParams::TIndexOpenCursorParams ||
mType == OpenCursorParams::TIndexOpenKeyCursorParams,
mIndexMetadata);
const bool trustParams =
#ifdef DEBUG
// Always verify parameters in DEBUG builds!
false
#else
mIsSameProcessActor
#endif
;
if (!trustParams && !VerifyRequestParams(aParams)) {
ASSERT_UNLESS_FUZZING();
return false;
}
if (NS_WARN_IF(mCurrentlyRunningOp)) {
ASSERT_UNLESS_FUZZING();
@ -14896,32 +14964,6 @@ Cursor::RecvContinue(const CursorRequestParams& aParams)
return false;
}
if (aParams.type() == CursorRequestParams::TContinueParams) {
const Key& key = aParams.get_ContinueParams().key();
if (!key.IsUnset()) {
switch (mDirection) {
case IDBCursor::NEXT:
case IDBCursor::NEXT_UNIQUE:
if (NS_WARN_IF(key <= mKey)) {
ASSERT_UNLESS_FUZZING();
return false;
}
break;
case IDBCursor::PREV:
case IDBCursor::PREV_UNIQUE:
if (NS_WARN_IF(key >= mKey)) {
ASSERT_UNLESS_FUZZING();
return false;
}
break;
default:
MOZ_CRASH("Should never get here!");
}
}
}
if (mTransaction->IsInvalidated()) {
return true;
}

View File

@ -207,6 +207,31 @@ IDBCursor::DropJSObjects()
mozilla::DropJSObjects(this);
}
bool
IDBCursor::IsSourceDeleted() const
{
AssertIsOnOwningThread();
MOZ_ASSERT(mTransaction);
MOZ_ASSERT(mTransaction->IsOpen());
IDBObjectStore* sourceObjectStore;
if (mType == Type_Index || mType == Type_IndexKey) {
MOZ_ASSERT(mSourceIndex);
if (mSourceIndex->IsDeleted()) {
return true;
}
sourceObjectStore = mSourceIndex->ObjectStore();
MOZ_ASSERT(sourceObjectStore);
} else {
MOZ_ASSERT(mSourceObjectStore);
sourceObjectStore = mSourceObjectStore;
}
return sourceObjectStore->IsDeleted();
}
void
IDBCursor::Reset()
{
@ -392,7 +417,7 @@ IDBCursor::Continue(JSContext* aCx,
return;
}
if (!mHaveValue || mContinueCalled) {
if (IsSourceDeleted() || !mHaveValue || mContinueCalled) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
return;
}
@ -468,18 +493,19 @@ IDBCursor::Advance(uint32_t aCount, ErrorResult &aRv)
{
AssertIsOnOwningThread();
if (!aCount) {
aRv.ThrowTypeError(MSG_INVALID_ADVANCE_COUNT);
return;
}
if (!mTransaction->IsOpen()) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
return;
}
if (!mHaveValue || mContinueCalled) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
return;
}
if (!aCount) {
aRv.ThrowTypeError(MSG_INVALID_ADVANCE_COUNT);
if (IsSourceDeleted() || !mHaveValue || mContinueCalled) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
return;
}
@ -531,13 +557,16 @@ IDBCursor::Update(JSContext* aCx, JS::Handle<JS::Value> aValue,
return nullptr;
}
if (!mHaveValue || mType == Type_ObjectStoreKey || mType == Type_IndexKey) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
if (!mTransaction->IsWriteAllowed()) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR);
return nullptr;
}
if (!mTransaction->IsWriteAllowed()) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR);
if (IsSourceDeleted() ||
!mHaveValue ||
mType == Type_ObjectStoreKey ||
mType == Type_IndexKey) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
return nullptr;
}
@ -645,13 +674,16 @@ IDBCursor::Delete(JSContext* aCx, ErrorResult& aRv)
return nullptr;
}
if (!mHaveValue || mType == Type_ObjectStoreKey || mType == Type_IndexKey) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
if (!mTransaction->IsWriteAllowed()) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR);
return nullptr;
}
if (!mTransaction->IsWriteAllowed()) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR);
if (IsSourceDeleted() ||
!mHaveValue ||
mType == Type_ObjectStoreKey ||
mType == Type_IndexKey) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
return nullptr;
}

View File

@ -196,6 +196,9 @@ private:
void
DropJSObjects();
bool
IsSourceDeleted() const;
};
} // namespace indexedDB

View File

@ -168,6 +168,14 @@ public:
void
NoteDeletion();
bool
IsDeleted() const
{
AssertIsOnOwningThread();
return !!mDeletedMetadata;
}
void
AssertIsOnOwningThread() const
#ifdef DEBUG

View File

@ -268,6 +268,14 @@ public:
void
NoteDeletion();
bool
IsDeleted() const
{
AssertIsOnOwningThread();
return !!mDeletedSpec;
}
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(IDBObjectStore)

View File

@ -1,5 +0,0 @@
[idbcursor_advance_index9.htm]
type: testharness
[IDBCursor.advance() - index - throw InvalidStateError caused by object store been deleted]
expected: FAIL

View File

@ -1,5 +0,0 @@
[idbcursor_advance_objectstore5.htm]
type: testharness
[IDBCursor.advance() - object store - throw InvalidStateError caused by object store been deleted]
expected: FAIL

View File

@ -1,5 +0,0 @@
[idbcursor_continue_index8.htm]
type: testharness
[IDBCursor.continue() - index - throw InvalidStateError caused by object store been deleted]
expected: FAIL

View File

@ -1,5 +0,0 @@
[idbcursor_continue_objectstore6.htm]
type: testharness
[IDBCursor.continue() - object store - throw InvalidStateError caused by object store been deleted]
expected: FAIL