Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move Zcash protobuf parsing to separate process #21627

Merged
merged 2 commits into from
Jan 29, 2024
Merged

Move Zcash protobuf parsing to separate process #21627

merged 2 commits into from
Jan 29, 2024

Conversation

cypt4
Copy link
Collaborator

@cypt4 cypt4 commented Jan 18, 2024

Introduces BraveWalletUtilsService which is able to provide ZCashDecoder to convert protobufs to mojo structs and pass them to the main process. Resolves brave/brave-browser#34561

Upd. : Updated folder structure according review

  • components/brave_wallet/common/proto/ - zcash protobufs are placed in common dir since they are needed for constructing outgoing messages too
  • components/services/brave_wallet/public/cpp/ - contains in process launcher and service client
  • components/services/brave_wallet/content - out process launcher
  • components/services/brave_wallet/public/interfaces/ - contains zcash_decoder and brave_wallet_utils_service interfaces
  • components/services/brave_wallet/zcash/ - zcash decoder implementation

Submitter Checklist:

  • I confirm that no security/privacy review is needed and no other type of reviews are needed, or that I have requested them
  • There is a ticket for my issue
  • Used Github auto-closing keywords in the PR description above
  • Wrote a good PR/commit description
  • Squashed any review feedback or "fixup" commits before merge, so that history is a record of what happened in the repo, not your PR
  • Added appropriate labels (QA/Yes or QA/No; release-notes/include or release-notes/exclude; OS/...) to the associated issue
  • Checked the PR locally:
    • npm run test -- brave_browser_tests, npm run test -- brave_unit_tests wiki
    • npm run lint, npm run presubmit wiki, npm run gn_check, npm run tslint
  • Ran git rebase master (if needed)

Reviewer Checklist:

  • A security review is not needed, or a link to one is included in the PR description
  • New files have MPL-2.0 license header
  • Adequate test coverage exists to prevent regressions
  • Major classes, functions and non-trivial code blocks are well-commented
  • Changes in component dependencies are properly reflected in gn
  • Code follows the style guide
  • Test plan is specified in PR before merging

After-merge Checklist:

Test Plan:

components/brave_wallet/browser/zcash/decoder/BUILD.gn Outdated Show resolved Hide resolved
if (!result) {
std::move(callback).Run(base::unexpected("Failed to start decoder"));
}
ptr->zcash_decoder_->ParseGetAddressUtxox(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Utxos

@yrliou yrliou requested a review from supermassive January 19, 2024 07:08
@cypt4 cypt4 force-pushed the brave_34561 branch 5 times, most recently from 313fe64 to 2c45224 Compare January 22, 2024 19:43
@cypt4 cypt4 requested a review from supermassive January 23, 2024 13:03
@cypt4 cypt4 marked this pull request as ready for review January 23, 2024 13:11
@cypt4 cypt4 requested review from a team as code owners January 23, 2024 13:11
@@ -898,6 +898,10 @@ Or change later at <ph name="SETTINGS_EXTENIONS_LINK">$2<ex>brave://settings/ext
<message name="IDS_BRAVE_IPFS_ALWAYS_START_INFOBAR_NO" desc="Ignore proposition">
Cancel
</message>
<!-- Brave Wallet -->
<message name="IDS_UTILITY_PROCESS_WALLET_UTILS_NAME" desc="The utility process running wallet utils">
Brave Wallet Utils Service
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I'd rather spell it out if the length is not an issue: Brave Wallet Utility Service

Copy link
Collaborator

@mkarolin mkarolin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

strings++
DEPS++


import("//mojo/public/tools/bindings/mojom.gni")

static_library("zcash_decoder") {
Copy link
Member

@yrliou yrliou Jan 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

component instead of static_library? I think we should have visibility setting for this target too, it should only be accessed by the service lib.

# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at https://mozilla.org/MPL/2.0/.

static_library("lib") {
Copy link
Member

@yrliou yrliou Jan 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

component instead of static_library.

LaunchBraveWalletUtilsService(
brave_wallet_utils_service_.BindNewPipeAndPassReceiver());
brave_wallet_utils_service_.reset_on_disconnect();
brave_wallet_utils_service_.reset_on_idle_timeout(base::Minutes(5));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5 mins seems a bit long for an idle process? What's our use case here and can it be shorter?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Such timeout should somehow relate to wallet's auto-lock timer(maybe just it's default value). Also makes sense to shutdown process when wallet gets locked.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logged follow-up issue brave/brave-browser#35568

# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at https://mozilla.org/MPL/2.0/.

static_library("cpp") {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

component

Copy link
Collaborator

@supermassive supermassive Jan 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • We don't need that many component(). There should be not more than one.
  • We don't need that one component() at all. Just source_set() should be enough as amount of code is relatively small in this service, we have only one consumer and this consumer is not a component() itself

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also let's not invent the wheel and just reuse architecture and layout of these services:
/src/components/services/patch/
/src/components/services/unzip/
/src/services/data_decoder/

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd tried to keep data decoder layout where services/../public/cpp folder contains service client implementation.
But i don't like how data_decoder service manages process launch model since it mixes external static delegate setup with internal buildflags.
I don't think it is a good idea to setup process launch model via static delegate since we would also need to ensure that it is initialized at the moment of usage.
So i've added buildflags in brave_wallet_utils_service to decide what process model to use.
Also data_decoder provides a set of static methods to use, but

  1. It always starts a new process on every such static call which could be surprising. This affects performance.
  2. Number of data_decoder parsing formats is limited, but in our case BraveWalletUtilsService could be extended with other coins format, rust libs, etc..

To overcome this issues, BraveWalletUtilsService acts as a factory for sub-component interfaces:
If client code wants to use separate process, it creates BraveWalletUtilsInstance manually.
If client code wants to reuse general process, it uses GetInstance() singletone.
User should explicitly request which sub-component to use. For ex. call CreateZCashDecoder.

"//brave/components/services/brave_wallet:lib",
"//brave/components/services/brave_wallet/public/interfaces",
"//brave/components/services/brave_wallet/zcash:zcash_decoder",
"//mojo/public/cpp/system",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this used directly? mojo/public/cpp/bindings instead?

#define BRAVE_COMPONENTS_SERVICES_BRAVE_WALLET_CONTENT_BRAVE_WALLET_UTILS_SERVICE_LAUNCHER_H_

#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unused

# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at https://mozilla.org/MPL/2.0/.

static_library("content") {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

component

deps = [
"//brave/app:brave_generated_resources_grit",
"//brave/components/services/brave_wallet/public/interfaces",
"//brave/components/services/brave_wallet/zcash:zcash_decoder",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems not needed

"//brave/components/services/brave_wallet/public/interfaces",
"//brave/components/services/brave_wallet/zcash:zcash_decoder",
"//content/public/browser",
"//mojo/public/cpp/system",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mojo/public/cpp/bindings instead?

};

struct RawTransaction {
array<uint8> data ;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: empty space

Comment on lines 537 to 519
void ZCashRpc::InitializeDecoderAndRunCallback(
base::OnceCallback<void(bool)> callback) {
if (IsConnected()) {
std::move(callback).Run(true);
return;
}

BraveWalletUtilsService::GetInstance()->CreateZCashDecoder(
zcash_decoder_.BindNewEndpointAndPassReceiver(),
base::BindOnce(&ZCashRpc::OnDecoderCreated,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}

void ZCashRpc::OnDecoderCreated(base::OnceCallback<void(bool)> callback) {
std::move(callback).Run(IsConnected());
zcash_decoder_.reset_on_disconnect();
}

bool ZCashRpc::IsConnected() {
return zcash_decoder_.is_bound();
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why ZcashRpc is doing all of this?
Let's follow pattern of how data_decoder is used:

data_decoder::DataDecoder::ParseJsonIsolated(
        fake_response, base::BindOnce(&PhotosService::OnJsonParsed,
                                      weak_factory_.GetWeakPtr(), ""));

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BraveWalletUtilsService could provide various interfaces for different wallet parts, mixing their methods in a single interface would be messy

Comment on lines 21 to 23
GRrpcMessageStreamHandler::GRrpcMessageStreamHandler() = default;
GRrpcMessageStreamHandler::~GRrpcMessageStreamHandler() = default;

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I understand we also should move GRrpcMessageStreamHandler to zcash decoder

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GRrpcMessageStreamHandler is linked to SimpleUrlLoader, it just extracts chunks from incoming stream to decode. Not linked to decoding itself.

@@ -14,6 +14,7 @@
#include "base/functional/callback.h"
#include "base/strings/strcat.h"
#include "base/test/bind.h"
#include "brave/components/brave_wallet/common/proto/protobuf_utils.h"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, for testing

public_deps = [ "//brave/components/api_request_helper" ]
public_deps = [
"//brave/components/api_request_helper",
"//brave/components/services/brave_wallet/public/interfaces",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why this is a public dependency?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needed for tests, moved to test's deps

Comment on lines 28 to 47
std::optional<std::string> ResolveSerializedMessage(
const std::string& grpc_response_body) {
if (grpc_response_body.size() < kGrpcHeaderSize) {
return std::nullopt;
}
if (grpc_response_body[0] != kNoCompression) {
// Compression is not supported yet
return std::nullopt;
}
uint32_t size = 0;
base::ReadBigEndian(
reinterpret_cast<const uint8_t*>(&(grpc_response_body[1])), &size);

if (grpc_response_body.size() != size + kGrpcHeaderSize) {
return std::nullopt;
}

return grpc_response_body.substr(kGrpcHeaderSize);
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this stays in common?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to services/brave_wallet/public as was discussed locally

@@ -0,0 +1,4 @@
include_rules = [
"+content/public/browser/service_process_host.h",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is typically +content/public/browser

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

};

struct GetAddressUtxosResponse {
array<ZCashUtxo> addressUtxos;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

address_utxos

Introduces BraveWalletUtilsService that is able to provide ZCashDecoder
to convert protobufs to mojo structs and pass them to the mai.
Resolves brave/brave-browser#34561

Review fix

Review fix#2

Split service launcher

Review fix#3

Review fix#4
Copy link
Contributor

[puLL-Merge] - brave/brave-core@21627

Description

This PR introduces several key changes to the brave-core repository, primarily focused on the Brave Wallet's ZCash functionality. The goal of these changes seems to be the refactoring of code related to ZCash transactions and the decomposition of responsibility among different components and services. It includes modifications to service communication patterns, updated build instructions, and various code removals and additions across ZCash-related components. There is also a refactor of the utility services in use.

Changes

Changes

app/brave_generated_resources.grd

  • Added IDS_UTILITY_PROCESS_WALLET_UTILS_NAME to provide a user-friendly name to the wallet utility service.

components/brave_wallet/browser/BUILD.gn

  • Removed :zcash_proto dependency.
  • Added dependencies on various brave_wallet services for ZCash functionality.

components/brave_wallet/browser/test/BUILD.gn

  • Added service-related dependencies for ZCash testing.

components/brave_wallet/browser/**/*.cc & .h (Various ZCash related files)

  • Modified to make use of the new mojom interfaces and objects.
  • Removed utility functions for gRPC handling as they have been migrated to the zcash service.

components/services/brave_wallet/**/*

  • Added new service definitions for the Brave Wallet, which involve ZCash utility processing, mojo interface definitions for BraveWalletUtilsService and ZCashDecoder, and the corresponding implementation service launcher logic.
  • Newly created BUILD.gn files to build the services public and zcash, including ZCash service unit tests.

utility/brave_content_utility_client.cc

  • Added registration for the Brave Wallet Utility service at startup.

utility/sources.gni

  • Included new Brave Wallet services in utility build dependencies.

Security Hotspots

  1. components/brave_wallet/browser/**/*.cc & .h

    • Changes in these files should be scrutinized for proper handling of wallet-related data and potential fallback cases where the expected data may not be available or parsing fails.
  2. components/services/brave_wallet/public/mojom/**/*.mojom

    • Mojom interfaces define IPC contracts and should be reviewed to ensure they only expose necessary functionality, especially since they deal with wallet functionality.
  3. utility/brave_content_utility_client.cc

    • Security implications with regard to the startup and lifecycle of utility services should be considered.
  4. components/services/brave_wallet/public/proto/*.proto

    • Proto definitions related to ZCash must be carefully reviewed to ensure that serialization and deserialization of data does not have any vulnerabilities that could be exploited.
  5. components/brave_wallet/public/cpp/utils/protobuf_utils.cc

    • Utility functions for processing protobuf-related data, including those related to gRPC responses, must be thoroughly vetted to prevent possible buffer overflow or parsing issues.

The changes introduce a significant refactor and it is essential to ensure that the introduced services are secure and robust, given the sensitive nature of wallet services. All IPC handlers should have strong validation and error handling to mitigate the risk of corrupt data or malicious exploitation.

@cypt4 cypt4 merged commit 5b8ea34 into master Jan 29, 2024
19 checks passed
@cypt4 cypt4 deleted the brave_34561 branch January 29, 2024 20:26
@github-actions github-actions bot added this to the 1.64.x - Nightly milestone Jan 29, 2024

ZCashDecoder::~ZCashDecoder() = default;

void ZCashDecoder::ParseRawTransaction(const std::string& data,
Copy link
Member

@kdenhartog kdenhartog Jan 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we perform additional data validation checks while we're parsing these structs here since it's still out of process? I checked the rust library and don't see them doing anything like this so it would mainly be a nice to have more than a blocker IMO.

Copy link
Member

@kdenhartog kdenhartog left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No concerns with the PR as it stands. Would be useful to add some additional data validation as pointed out in the comment above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[ZCash]Isolate GRPC validation into separate process
7 participants