Files
tubestation/dom/indexedDB/IndexedDatabaseInlines.h
Jan Varga bdb79a5323 Bug 1943951 - Restore previous IPC message size limit and introduce a new explicit structured clone size limit to fix a crash; r=nika,smaug
Restore IPC message size limit and introduce explicit structured clone size
limit in IndexedDB

This patch addresses an issue where large arrays of structured clones or keys
(< 64KB each) can accumulate in the IPC message, easily reaching the hard 256
MB IPC limit.

Key Changes:
- Aligned the IPC and IDB-specific IPC message size limits to prevent exceeding
  the hard IPC limit.
- Adjusted the IPC message size calculation in IndexedDB to properly account
  for shared memory fallback for large structured clones, ensuring that only
  necessary data is included in the IPC message.

Note, the way some preferences are handled in IndexedDatabaseManager would
deserve refactoring/cleanup.

Differential Revision: https://phabricator.services.mozilla.com/D235643
2025-02-03 16:36:52 +00:00

198 lines
6.9 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef IndexedDatabaseInlines_h
#define IndexedDatabaseInlines_h
#ifndef mozilla_dom_indexeddatabase_h__
# error Must include IndexedDatabase.h first
#endif
#include "DatabaseFileInfo.h"
#include "mozilla/dom/ToJSValue.h"
#include "mozilla/dom/indexedDB/PBackgroundIDBSharedTypes.h"
#include "mozilla/dom/DOMStringList.h"
#include "mozilla/dom/File.h"
namespace mozilla::dom::indexedDB {
#ifdef NS_BUILD_REFCNT_LOGGING
inline StructuredCloneFileChild::StructuredCloneFileChild(
StructuredCloneFileChild&& aOther)
: StructuredCloneFileBase{std::move(aOther)},
mContents{std::move(aOther.mContents)} {
MOZ_COUNT_CTOR(StructuredCloneFileChild);
}
#endif
inline StructuredCloneFileChild::~StructuredCloneFileChild() {
MOZ_COUNT_DTOR(StructuredCloneFileChild);
}
inline StructuredCloneFileChild::StructuredCloneFileChild(FileType aType)
: StructuredCloneFileBase{aType}, mContents{Nothing()} {
MOZ_COUNT_CTOR(StructuredCloneFileChild);
}
inline StructuredCloneFileChild::StructuredCloneFileChild(
FileType aType, RefPtr<dom::Blob> aBlob)
: StructuredCloneFileBase{aType}, mContents{std::move(aBlob)} {
MOZ_ASSERT(eBlob == aType || eStructuredClone == aType);
MOZ_ASSERT(mContents->as<RefPtr<dom::Blob>>());
MOZ_COUNT_CTOR(StructuredCloneFileChild);
}
inline StructuredCloneFileParent::StructuredCloneFileParent(
FileType aType, SafeRefPtr<DatabaseFileInfo> aFileInfo)
: StructuredCloneFileBase{aType}, mContents{Some(std::move(aFileInfo))} {
MOZ_ASSERT(**mContents);
MOZ_COUNT_CTOR(StructuredCloneFileParent);
}
#ifdef NS_BUILD_REFCNT_LOGGING
inline StructuredCloneFileParent::StructuredCloneFileParent(
StructuredCloneFileParent&& aOther)
: StructuredCloneFileBase{std::move(aOther)},
mContents{std::move(aOther.mContents)} {
MOZ_COUNT_CTOR(StructuredCloneFileParent);
}
#endif
inline StructuredCloneFileParent::~StructuredCloneFileParent() {
MOZ_COUNT_DTOR(StructuredCloneFileParent);
}
inline SafeRefPtr<DatabaseFileInfo> StructuredCloneFileParent::FileInfoPtr()
const {
return (*mContents)->clonePtr();
}
inline RefPtr<dom::Blob> StructuredCloneFileChild::BlobPtr() const {
return mContents->as<RefPtr<dom::Blob>>();
}
template <typename StructuredCloneFile>
inline StructuredCloneReadInfo<StructuredCloneFile>::StructuredCloneReadInfo(
JS::StructuredCloneScope aScope)
: StructuredCloneReadInfoBase(JSStructuredCloneData{aScope}) {
MOZ_COUNT_CTOR(StructuredCloneReadInfo);
}
template <typename StructuredCloneFile>
inline StructuredCloneReadInfo<StructuredCloneFile>::StructuredCloneReadInfo()
: StructuredCloneReadInfo(
JS::StructuredCloneScope::DifferentProcessForIndexedDB) {}
template <typename StructuredCloneFile>
inline StructuredCloneReadInfo<StructuredCloneFile>::StructuredCloneReadInfo(
JSStructuredCloneData&& aData, nsTArray<StructuredCloneFile> aFiles)
: StructuredCloneReadInfoBase{std::move(aData)}, mFiles{std::move(aFiles)} {
MOZ_COUNT_CTOR(StructuredCloneReadInfo);
}
#ifdef NS_BUILD_REFCNT_LOGGING
template <typename StructuredCloneFile>
inline StructuredCloneReadInfo<StructuredCloneFile>::StructuredCloneReadInfo(
StructuredCloneReadInfo&& aOther) noexcept
: StructuredCloneReadInfoBase{std::move(aOther)},
mFiles{std::move(aOther.mFiles)} {
MOZ_COUNT_CTOR(StructuredCloneReadInfo);
}
template <typename StructuredCloneFile>
inline StructuredCloneReadInfo<
StructuredCloneFile>::~StructuredCloneReadInfo() {
MOZ_COUNT_DTOR(StructuredCloneReadInfo);
}
#endif
template <typename StructuredCloneFile>
inline size_t StructuredCloneReadInfo<StructuredCloneFile>::Size() const {
// We do not check the structured clone size against
// IndexedDatabaseManager::MaxStructuredCloneSize here.
// The size has already been validated before being sent from the content
// process to the parent process. At this stage, the parent process has
// either stored the data in the database or written it to a separate file,
// ensuring that size constraints are enforced elsewhere.
//
// If necessary, we could add a warning to flag oversized structured clones
// here. However, failing the request entirely would require additional
// changes, such as making these methods fallible, which would add complexity.
// Serialized structured clone size in bytes. For structured clone sizes >
// IPC::kMessageBufferShmemThreshold, only the size and shared memory handle
// are included in the IPC message. The value 16 is an estimate.
size_t size =
Data().Size() > IPC::kMessageBufferShmemThreshold ? 16 : Data().Size();
for (uint32_t i = 0, count = mFiles.Length(); i < count; ++i) {
// We don't want to calculate the size of files and so on, because are
// mainly file descriptors.
size += sizeof(uint64_t);
}
return size;
}
inline StructuredCloneReadInfoChild::StructuredCloneReadInfoChild(
JSStructuredCloneData&& aData, nsTArray<StructuredCloneFileChild> aFiles,
IDBDatabase* aDatabase)
: StructuredCloneReadInfo{std::move(aData), std::move(aFiles)},
mDatabase{aDatabase} {}
template <typename E, typename Map>
RefPtr<DOMStringList> CreateSortedDOMStringList(const nsTArray<E>& aArray,
const Map& aMap) {
auto list = MakeRefPtr<DOMStringList>();
if (!aArray.IsEmpty()) {
nsTArray<nsString>& mapped = list->StringArray();
mapped.SetCapacity(aArray.Length());
std::transform(aArray.cbegin(), aArray.cend(), MakeBackInserter(mapped),
aMap);
mapped.Sort();
}
return list;
}
template <typename StructuredCloneReadInfoType>
JSObject* StructuredCloneReadCallback(
JSContext* const aCx, JSStructuredCloneReader* const aReader,
const JS::CloneDataPolicy& aCloneDataPolicy, const uint32_t aTag,
const uint32_t aData, void* const aClosure) {
auto* const database = [aClosure]() -> IDBDatabase* {
if constexpr (std::is_same_v<StructuredCloneReadInfoType,
StructuredCloneReadInfoChild>) {
return static_cast<StructuredCloneReadInfoChild*>(aClosure)->Database();
}
Unused << aClosure;
return nullptr;
}();
return CommonStructuredCloneReadCallback(
aCx, aReader, aCloneDataPolicy, aTag, aData,
static_cast<StructuredCloneReadInfoType*>(aClosure), database);
}
template <typename T>
bool WrapAsJSObject(JSContext* const aCx, T& aBaseObject,
JS::MutableHandle<JSObject*> aResult) {
JS::Rooted<JS::Value> wrappedValue(aCx);
if (!ToJSValue(aCx, aBaseObject, &wrappedValue)) {
return false;
}
aResult.set(&wrappedValue.toObject());
return true;
}
} // namespace mozilla::dom::indexedDB
#endif // IndexedDatabaseInlines_h