Skip to content

Commit

Permalink
Bug 1634436 - Make DecryptingInputStream implement nsIIPCSerializable…
Browse files Browse the repository at this point in the history
…InputStream. r=baku

Differential Revision: https://phabricator.services.mozilla.com/D75913
  • Loading branch information
sigiesec committed Jun 25, 2020
1 parent 139cc20 commit fde704c
Show file tree
Hide file tree
Showing 7 changed files with 168 additions and 15 deletions.
32 changes: 29 additions & 3 deletions dom/quota/DecryptingInputStream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,22 @@ NS_INTERFACE_MAP_BEGIN(DecryptingInputStreamBase)
NS_INTERFACE_MAP_ENTRY(nsISeekableStream)
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsICloneableInputStream,
mBaseCloneableInputStream || !mBaseStream)
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(
nsIIPCSerializableInputStream,
mBaseIPCSerializableInputStream || !mBaseStream)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
NS_INTERFACE_MAP_END

DecryptingInputStreamBase::DecryptingInputStreamBase(
MovingNotNull<nsCOMPtr<nsIInputStream>> aBaseStream, size_t aBlockSize)
: mBaseStream(std::move(aBaseStream)), mBlockSize(aBlockSize) {
MovingNotNull<nsCOMPtr<nsIInputStream>> aBaseStream, size_t aBlockSize) {
Init(std::move(aBaseStream), aBlockSize);
}

void DecryptingInputStreamBase::Init(
MovingNotNull<nsCOMPtr<nsIInputStream>> aBaseStream, size_t aBlockSize) {
mBlockSize.init(aBlockSize);
mBaseStream.init(std::move(aBaseStream));

const nsCOMPtr<nsISeekableStream> seekableStream =
do_QueryInterface(mBaseStream->get());
MOZ_ASSERT(seekableStream &&
Expand All @@ -35,6 +45,14 @@ DecryptingInputStreamBase::DecryptingInputStreamBase(
SameCOMIdentity(mBaseStream->get(), cloneableInputStream)) {
mBaseCloneableInputStream.init(WrapNotNullUnchecked(cloneableInputStream));
}

const nsCOMPtr<nsIIPCSerializableInputStream> ipcSerializeInputStream =
do_QueryInterface(mBaseStream->get());
if (ipcSerializeInputStream &&
SameCOMIdentity(mBaseStream->get(), ipcSerializeInputStream)) {
mBaseIPCSerializableInputStream.init(
WrapNotNullUnchecked(ipcSerializeInputStream));
}
}

NS_IMETHODIMP DecryptingInputStreamBase::Read(char* aBuf, uint32_t aCount,
Expand All @@ -58,13 +76,21 @@ NS_IMETHODIMP DecryptingInputStreamBase::GetCloneable(bool* aCloneable) {
return NS_OK;
}

void DecryptingInputStreamBase::Serialize(
mozilla::ipc::InputStreamParams& aParams,
FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
uint32_t aMaxSize, uint32_t* aSizeUsed,
mozilla::ipc::ChildToParentStreamActorManager* aManager) {
MOZ_CRASH("Not implemented");
}

size_t DecryptingInputStreamBase::PlainLength() const {
MOZ_ASSERT(mNextByte <= mPlainBytes);
return mPlainBytes - mNextByte;
}

size_t DecryptingInputStreamBase::EncryptedBufferLength() const {
return mBlockSize;
return *mBlockSize;
}

} // namespace mozilla::dom::quota
38 changes: 34 additions & 4 deletions dom/quota/DecryptingInputStream.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "nsCOMPtr.h"
#include "nsICloneableInputStream.h"
#include "nsIInputStream.h"
#include "nsIIPCSerializableInputStream.h"
#include "nsISeekableStream.h"

#include "EncryptedBlock.h"
Expand All @@ -19,7 +20,8 @@ namespace mozilla::dom::quota {

class DecryptingInputStreamBase : public nsIInputStream,
public nsISeekableStream,
public nsICloneableInputStream {
public nsICloneableInputStream,
public nsIIPCSerializableInputStream {
public:
NS_DECL_THREADSAFE_ISUPPORTS

Expand All @@ -31,30 +33,45 @@ class DecryptingInputStreamBase : public nsIInputStream,
using nsICloneableInputStream::GetCloneable;
NS_IMETHOD GetCloneable(bool* aCloneable) final;

using nsIIPCSerializableInputStream::Serialize;
void Serialize(mozilla::ipc::InputStreamParams& aParams,
FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
uint32_t aMaxSize, uint32_t* aSizeUsed,
mozilla::ipc::ChildToParentStreamActorManager* aManager) final;

protected:
DecryptingInputStreamBase(MovingNotNull<nsCOMPtr<nsIInputStream>> aBaseStream,
size_t aBlockSize);

// For deserialization only.
DecryptingInputStreamBase() = default;

virtual ~DecryptingInputStreamBase() = default;

void Init(MovingNotNull<nsCOMPtr<nsIInputStream>> aBaseStream,
size_t aBlockSize);

// Convenience routine to determine how many bytes of plain data
// we currently have in our buffer.
size_t PlainLength() const;

size_t EncryptedBufferLength() const;

InitializedOnce<const NotNull<nsCOMPtr<nsIInputStream>>> mBaseStream;
LazyInitializedOnceEarlyDestructible<const NotNull<nsCOMPtr<nsIInputStream>>>
mBaseStream;
LazyInitializedOnce<const NotNull<nsISeekableStream*>> mBaseSeekableStream;
LazyInitializedOnce<const NotNull<nsICloneableInputStream*>>
mBaseCloneableInputStream;
LazyInitializedOnce<const NotNull<nsIIPCSerializableInputStream*>>
mBaseIPCSerializableInputStream;

// Number of bytes of plain data in mBuffer.
size_t mPlainBytes = 0;

// Next byte of mBuffer to return in ReadSegments().
size_t mNextByte = 0;

const size_t mBlockSize;
LazyInitializedOnceNotNull<const size_t> mBlockSize;

size_t mLastBlockLength = 0;
};
Expand All @@ -72,6 +89,9 @@ class DecryptingInputStream final : public DecryptingInputStreamBase {
size_t aBlockSize, CipherStrategy aCipherStrategy,
typename CipherStrategy::KeyType aKey);

// For deserialization only.
explicit DecryptingInputStream(CipherStrategy aCipherStrategy);

NS_IMETHOD Close() override;
NS_IMETHOD Available(uint64_t* _retval) override;
NS_IMETHOD ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
Expand All @@ -83,6 +103,16 @@ class DecryptingInputStream final : public DecryptingInputStreamBase {

NS_IMETHOD Clone(nsIInputStream** _retval) override;

using DecryptingInputStreamBase::Serialize;
void Serialize(
mozilla::ipc::InputStreamParams& aParams,
FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
uint32_t aMaxSize, uint32_t* aSizeUsed,
mozilla::ipc::ParentToChildStreamActorManager* aManager) override;

bool Deserialize(const mozilla::ipc::InputStreamParams& aParams,
const FileDescriptorArray& aFileDescriptors) override;

private:
~DecryptingInputStream();

Expand All @@ -108,7 +138,7 @@ class DecryptingInputStream final : public DecryptingInputStreamBase {
bool EnsureBuffers();

const CipherStrategy mCipherStrategy;
const typename CipherStrategy::KeyType mKey;
LazyInitializedOnce<const typename CipherStrategy::KeyType> mKey;

// Buffer to hold encrypted data. Must copy here since we need a
// flat buffer to run the decryption process on.
Expand Down
77 changes: 69 additions & 8 deletions dom/quota/DecryptingInputStream_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

#include "CipherStrategy.h"

#include "mozilla/ipc/InputStreamParams.h"
#include "nsFileStreams.h"
#include "nsIAsyncInputStream.h"
#include "nsStreamUtils.h"

Expand Down Expand Up @@ -38,6 +40,12 @@ DecryptingInputStream<CipherStrategy>::~DecryptingInputStream() {
Close();
}

template <typename CipherStrategy>
DecryptingInputStream<CipherStrategy>::DecryptingInputStream(
CipherStrategy aCipherStrategy)
: DecryptingInputStreamBase{},
mCipherStrategy(std::move(aCipherStrategy)) {}

template <typename CipherStrategy>
NS_IMETHODIMP DecryptingInputStream<CipherStrategy>::Close() {
if (!mBaseStream) {
Expand Down Expand Up @@ -183,7 +191,7 @@ nsresult DecryptingInputStream<CipherStrategy>::ParseNextChunk(

// XXX Do we need to know the actual decrypted size?
rv = mCipherStrategy.Cipher(
CipherMode::Decrypt, mKey, mEncryptedBlock->MutableCipherPrefix(),
CipherMode::Decrypt, *mKey, mEncryptedBlock->MutableCipherPrefix(),
mEncryptedBlock->Payload(), AsWritableBytes(Span{mPlainBuffer}));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
Expand Down Expand Up @@ -238,7 +246,7 @@ bool DecryptingInputStream<CipherStrategy>::EnsureBuffers() {
// until the stream is closed.
if (!mEncryptedBlock) {
// XXX Do we need to do this fallible (as the comment above suggests)?
mEncryptedBlock.emplace(mBlockSize);
mEncryptedBlock.emplace(*mBlockSize);

MOZ_ASSERT(mPlainBuffer.IsEmpty());
if (NS_WARN_IF(!mPlainBuffer.SetLength(mEncryptedBlock->MaxPayloadLength(),
Expand Down Expand Up @@ -269,8 +277,8 @@ NS_IMETHODIMP DecryptingInputStream<CipherStrategy>::Tell(
return rv;
}

const auto fullBlocks = basePosition / mBlockSize;
MOZ_ASSERT(0 == basePosition % mBlockSize);
const auto fullBlocks = basePosition / *mBlockSize;
MOZ_ASSERT(0 == basePosition % *mBlockSize);

*aRetval = (fullBlocks - ((mPlainBytes || mLastBlockLength) ? 1 : 0)) *
mEncryptedBlock->MaxPayloadLength() +
Expand Down Expand Up @@ -331,7 +339,7 @@ NS_IMETHODIMP DecryptingInputStream<CipherStrategy>::Seek(const int32_t aWhence,

nsresult rv =
(*mBaseSeekableStream)
->Seek(NS_SEEK_END, -static_cast<int64_t>(mBlockSize));
->Seek(NS_SEEK_END, -static_cast<int64_t>(*mBlockSize));
if (NS_WARN_IF(NS_FAILED(rv))) {
return Err(rv);
}
Expand Down Expand Up @@ -377,7 +385,7 @@ NS_IMETHODIMP DecryptingInputStream<CipherStrategy>::Seek(const int32_t aWhence,

// XXX If we remain in the same block as before, we can skip this.
nsresult rv =
(*mBaseSeekableStream)->Seek(NS_SEEK_SET, baseBlocksOffset * mBlockSize);
(*mBaseSeekableStream)->Seek(NS_SEEK_SET, baseBlocksOffset * *mBlockSize);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
Expand All @@ -400,7 +408,7 @@ NS_IMETHODIMP DecryptingInputStream<CipherStrategy>::Seek(const int32_t aWhence,
return aOffset == 0 ? NS_OK : NS_ERROR_ILLEGAL_VALUE;
}

nsresult rv = (*mBaseSeekableStream)->Seek(NS_SEEK_CUR, -mBlockSize);
nsresult rv = (*mBaseSeekableStream)->Seek(NS_SEEK_CUR, -*mBlockSize);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
Expand Down Expand Up @@ -438,12 +446,65 @@ NS_IMETHODIMP DecryptingInputStream<CipherStrategy>::Clone(

*_retval =
MakeAndAddRef<DecryptingInputStream>(WrapNotNull(std::move(clonedStream)),
mBlockSize, mCipherStrategy, mKey)
*mBlockSize, mCipherStrategy, *mKey)
.take();

return NS_OK;
}

template <typename CipherStrategy>
void DecryptingInputStream<CipherStrategy>::Serialize(
mozilla::ipc::InputStreamParams& aParams,
FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
uint32_t aMaxSize, uint32_t* aSizeUsed,
mozilla::ipc::ParentToChildStreamActorManager* aManager) {
MOZ_ASSERT(mBaseStream);
MOZ_ASSERT(mBaseIPCSerializableInputStream);

mozilla::ipc::InputStreamParams baseStreamParams;
(*mBaseIPCSerializableInputStream)
->Serialize(baseStreamParams, aFileDescriptors, aDelayedStart, aMaxSize,
aSizeUsed, aManager);

MOZ_ASSERT(baseStreamParams.type() ==
mozilla::ipc::InputStreamParams::TFileInputStreamParams);

mozilla::ipc::EncryptedFileInputStreamParams encryptedFileInputStreamParams;
encryptedFileInputStreamParams.fileInputStreamParams() =
std::move(baseStreamParams);
encryptedFileInputStreamParams.key().AppendElements(
mCipherStrategy.SerializeKey(*mKey));
encryptedFileInputStreamParams.blockSize() = *mBlockSize;

aParams = std::move(encryptedFileInputStreamParams);
}

template <typename CipherStrategy>
bool DecryptingInputStream<CipherStrategy>::Deserialize(
const mozilla::ipc::InputStreamParams& aParams,
const FileDescriptorArray& aFileDescriptors) {
MOZ_ASSERT(aParams.type() ==
mozilla::ipc::InputStreamParams::TEncryptedFileInputStreamParams);
const auto& params = aParams.get_EncryptedFileInputStreamParams();

nsCOMPtr<nsIFileInputStream> stream;
nsFileInputStream::Create(nullptr, NS_GET_IID(nsIFileInputStream),
getter_AddRefs(stream));
nsCOMPtr<nsIIPCSerializableInputStream> baseSerializable =
do_QueryInterface(stream);

if (NS_WARN_IF(!baseSerializable->Deserialize(params.fileInputStreamParams(),
aFileDescriptors))) {
return false;
}

Init(WrapNotNull<nsCOMPtr<nsIInputStream>>(std::move(stream)),
params.blockSize());
mKey.init(mCipherStrategy.DeserializeKey(params.key()));

return true;
}

} // namespace mozilla::dom::quota

#endif
16 changes: 16 additions & 0 deletions dom/quota/IPCStreamCipherStrategy.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/* -*- 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 mozilla_dom_quota_IPCStreamCipherStrategy_h
#define mozilla_dom_quota_IPCStreamCipherStrategy_h

#include "mozilla/dom/quota/DummyCipherStrategy.h"

namespace mozilla::dom::quota {
using IPCStreamCipherStrategy = DummyCipherStrategy;
}

#endif
1 change: 1 addition & 0 deletions dom/quota/moz.build
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ EXPORTS.mozilla.dom.quota += [
'EncryptingOutputStream_impl.h',
'FileStreams.h',
'InitializationTypes.h',
'IPCStreamCipherStrategy.h',
'MemoryOutputStream.h',
'OriginScope.h',
'PersistenceType.h',
Expand Down
8 changes: 8 additions & 0 deletions ipc/glue/InputStreamParams.ipdlh
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,14 @@ union InputStreamParams
IPCBlobInputStreamParams;
InputStreamLengthWrapperParams;
IPCRemoteStreamParams;
EncryptedFileInputStreamParams;
};

struct EncryptedFileInputStreamParams
{
FileInputStreamParams fileInputStreamParams;
uint8_t[] key;
uint32_t blockSize;
};

struct BufferedInputStreamParams
Expand Down
11 changes: 11 additions & 0 deletions ipc/glue/InputStreamUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#include "mozilla/dom/IPCBlobInputStream.h"
#include "mozilla/dom/IPCBlobInputStreamChild.h"
#include "mozilla/dom/IPCBlobInputStreamStorage.h"
#include "mozilla/dom/quota/DecryptingInputStream_impl.h"
#include "mozilla/dom/quota/IPCStreamCipherStrategy.h"
#include "mozilla/ipc/IPCStreamDestination.h"
#include "mozilla/ipc/IPCStreamSource.h"
#include "mozilla/InputStreamLengthHelper.h"
Expand Down Expand Up @@ -249,6 +251,9 @@ void InputStreamHelper::PostSerializationActivation(InputStreamParams& aParams,
case InputStreamParams::TIPCBlobInputStreamParams:
break;

case InputStreamParams::TEncryptedFileInputStreamParams:
break;

default:
MOZ_CRASH(
"A new stream? Should decide if it must be processed recursively or "
Expand Down Expand Up @@ -361,6 +366,12 @@ already_AddRefed<nsIInputStream> InputStreamHelper::DeserializeInputStream(
serializable = new InputStreamLengthWrapper();
break;

case InputStreamParams::TEncryptedFileInputStreamParams:
serializable = new dom::quota::DecryptingInputStream<
dom::quota::IPCStreamCipherStrategy>(
dom::quota::IPCStreamCipherStrategy{});
break;

default:
MOZ_ASSERT(false, "Unknown params!");
return nullptr;
Expand Down

0 comments on commit fde704c

Please sign in to comment.