-
Notifications
You must be signed in to change notification settings - Fork 893
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
Added ComponentContentsVerifier that checks verified_contents.json shipped with a component. #26660
base: master
Are you sure you want to change the base?
Conversation
e876860
to
cb708f8
Compare
c3df34c
to
030307f
Compare
|
||
// Use on MAY_BLOCK sequence. | ||
class ComponentContentsAccessor | ||
: public base::RefCountedThreadSafe<ComponentContentsAccessor> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reported by reviewdog 🐶
[semgrep] Reference counting is occasionally useful but is more often a sign that someone isn't thinking carefully about ownership. Use it when ownership is truly shared (for example, multiple tabs sharing the same renderer process), not for when lifetime management is difficult to reason about.
Source: https://github.com/brave/security-action/blob/main/assets/semgrep_rules/client/refcounted-usage.yaml
Cc @stoletheminerals @thypon @cdesouza-chromium @bridiver
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure about this wording:
Reference counting is occasionally useful but is more often a sign that someone isn't thinking carefully about ownership.
@stoletheminerals I think we need some tuning of the wording here.
components/brave_component_updater/browser/component_contents_verifier.cc
Outdated
Show resolved
Hide resolved
components/brave_component_updater/browser/component_contents_verifier.h
Outdated
Show resolved
Hide resolved
components/brave_shields/core/browser/ad_block_default_resource_provider.cc
Outdated
Show resolved
Hide resolved
components/brave_component_updater/browser/component_contents_verifier.h
Outdated
Show resolved
Hide resolved
components/brave_component_updater/browser/component_contents_verifier.h
Outdated
Show resolved
Hide resolved
components/brave_component_updater/browser/component_contents_verifier.h
Outdated
Show resolved
Hide resolved
scoped_refptr<brave_component_updater::ComponentContentsAccessor> | ||
CreateComponentContentsAccessor(bool with_verifier, | ||
const base::FilePath& component_root) { | ||
#if BUILDFLAG(ENABLE_EXTENSIONS) | ||
if (with_verifier) { | ||
return base::MakeRefCounted<ComponentContentsAccessorImpl>(component_root); | ||
} | ||
#endif | ||
// if there is no extensions enabled then we expect that on these platforms | ||
// the component files are protected by the OS. | ||
return base::MakeRefCounted<ComponentNoChecksContentsAccessorImpl>( | ||
component_root); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have ComponentContentsAccessor
-> ComponentNoChecksContentsAccessorImpl
-> ComponentContentsAccessorImpl
, and then we wrap this all behind a repeating callback to CreateComponentContentsAccessor
.
ComponentContentsAccessorImpl
with ignore_invalid_signature_=true
is close enough to ComponentNoChecksContentsAccessorImpl
.
I'm wondering if subclassing things like this is really a gain. The main difference here is that certain build configurations don't have BUILDFLAG(ENABLE_EXTENSIONS)
. I feel this should all be one single class, namely, ComponentContentsAccessor
, and then a different .cc
for build configs that don't support extension. This would avoid the whole use of inheritance here.
Without inheritance here we don't need a factory function, and without a factory function, we wouldn't need the NoDestructor
class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need this factory because we can't include (and use) code from extensions
on the components
level. But a lot of downloadable components live in components
dir.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, that makes sense. Thanks for clarifying. It seems to me then that this very specific code should be part of something like a delegate, rather than just be subclassing ComponentContentsAccessor
, and that delegate should be passed into ComponentContentsAccessor
however way it gets constructed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To clarify maybe this should be something like this:
std::unique_ptr<brave_component_updater::ComponentContentsAccessor::Delegate>
CreateComponentContentsAccessor(bool with_verifier,
const base::FilePath& component_root) {
and
void SetupComponentContentsVerifier() {
auto factory = base::BindRepeating(CreateComponentContentsAccessor, true);
brave_component_updater::ComponentContentsAccessor::Setup(std::move(factory));
}
What are your thoughts?
Thanks @boocmp for this change. Good work. I think we are nearly there. After going over it, I think the general gist is that we can simplify this quite a bit, by removing the need of inheritance/factory/global-no-destructor. |
components/brave_component_updater/browser/component_contents_verifier.h
Outdated
Show resolved
Hide resolved
components/brave_component_updater/browser/component_contents_verifier.h
Outdated
Show resolved
Hide resolved
components/brave_component_updater/browser/component_contents_verifier.cc
Outdated
Show resolved
Hide resolved
components/brave_shields/core/browser/ad_block_component_filters_provider.cc
Outdated
Show resolved
Hide resolved
components/brave_shields/core/browser/ad_block_default_resource_provider.cc
Outdated
Show resolved
Hide resolved
components/brave_shields/core/browser/ad_block_default_resource_provider.cc
Outdated
Show resolved
Hide resolved
components/brave_shields/core/browser/ad_block_filter_list_catalog_provider.cc
Outdated
Show resolved
Hide resolved
components/brave_component_updater/browser/component_contents_verifier.cc
Outdated
Show resolved
Hide resolved
components/brave_component_updater/browser/component_contents_verifier.h
Outdated
Show resolved
Hide resolved
components/brave_shields/core/browser/ad_block_component_installer.cc
Outdated
Show resolved
Hide resolved
components/brave_component_updater/browser/component_contents_verifier.h
Outdated
Show resolved
Hide resolved
|
||
// Use on MAY_BLOCK sequence. | ||
class ComponentContentsAccessor | ||
: public base::RefCountedThreadSafe<ComponentContentsAccessor> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reported by reviewdog 🐶
[semgrep] Reference counting is occasionally useful but is more often a sign that someone isn't thinking carefully about ownership. Use it when ownership is truly shared (for example, multiple tabs sharing the same renderer process), not for when lifetime management is difficult to reason about.
Source: https://github.com/brave/security-action/blob/main/assets/semgrep_rules/client/refcounted-usage.yaml
Cc @stoletheminerals @thypon @cdesouza-chromium @bridiver
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commented in several places that this does not appear to be an appropriate use of ref counted
const base::FilePath& relative_path); | ||
|
||
private: | ||
friend class base::RefCountedThreadSafe<ComponentContentsAccessor>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reported by reviewdog 🐶
[semgrep] Reference counting is occasionally useful but is more often a sign that someone isn't thinking carefully about ownership. Use it when ownership is truly shared (for example, multiple tabs sharing the same renderer process), not for when lifetime management is difficult to reason about.
Source: https://github.com/brave/security-action/blob/main/assets/semgrep_rules/client/refcounted-usage.yaml
Cc @stoletheminerals @thypon @cdesouza-chromium @bridiver
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to be misplaced
6e404e3
to
32397c9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm with few nits
components/brave_component_updater/browser/component_contents_verifier.h
Outdated
Show resolved
Hide resolved
components/brave_component_updater/browser/component_contents_accessor.h
Outdated
Show resolved
Hide resolved
32397c9
to
a72788d
Compare
// content of the files then accessor doesn't return data from GetFile* | ||
// functions. Use on MAY_BLOCK sequence. | ||
class ComponentContentsAccessor | ||
: public base::RefCountedThreadSafe<ComponentContentsAccessor> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reported by reviewdog 🐶
[semgrep] Reference counting is occasionally useful but is more often a sign that someone isn't thinking carefully about ownership. Use it when ownership is truly shared (for example, multiple tabs sharing the same renderer process), not for when lifetime management is difficult to reason about.
Source: https://github.com/brave/security-action/blob/main/assets/semgrep_rules/client/refcounted-usage.yaml
Cc @stoletheminerals @thypon @cdesouza-chromium @bridiver
const base::FilePath& relative_path); | ||
|
||
private: | ||
friend class base::RefCountedThreadSafe<ComponentContentsAccessor>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reported by reviewdog 🐶
[semgrep] Reference counting is occasionally useful but is more often a sign that someone isn't thinking carefully about ownership. Use it when ownership is truly shared (for example, multiple tabs sharing the same renderer process), not for when lifetime management is difficult to reason about.
Source: https://github.com/brave/security-action/blob/main/assets/semgrep_rules/client/refcounted-usage.yaml
Cc @stoletheminerals @thypon @cdesouza-chromium @bridiver
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If possible we should avoid flagging usage as a friend
// 'verified_contents.json' is missing or signature doesn't match the | ||
// content of the files then accessor doesn't return data from GetFile* | ||
// functions. Use on MAY_BLOCK sequence. | ||
class ComponentContentsAccessor |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit this name is a bit weird imo, maybe something like VerifiedContentsLoader
or VerifiedContentsReader
?
// content of the files then accessor doesn't return data from GetFile* | ||
// functions. Use on MAY_BLOCK sequence. | ||
class ComponentContentsAccessor | ||
: public base::RefCountedThreadSafe<ComponentContentsAccessor> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is this ref counted?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is working around a design issue and there appear to be some thread safety concerns. I think we're adding unnecessary complexity here by wrapping the reading of the data in this class, can't we just use it to verify the contents and only access it on the task runner?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we wanted to continue wrapping the read it could be done without any need for ref counted anyway
|
||
void SetContentsVerifierFactory(ContentsVerifierFactory factory); | ||
|
||
// Uses factory set above to create the verifier. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand why the factory is needed, why can't we just directly create an instance of ContentsVerifier
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because we want to use it in components, but the implementation requires code from extensions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
afaik it's fine to use extensions in components as long as it's not from chrome/browser
|
||
#include "base/feature_list.h" | ||
|
||
namespace component_updater { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this filename doesn't make sense to me with the contents. The feature should be in features.h and this also seems like a strange filename for SetupComponentContentsVerifier
base::RunLoop run_loop; | ||
resource_provider->LoadResources( | ||
base::BindLambdaForTesting([&run_loop](const std::string& resources) { | ||
#if BUILDFLAG(ENABLE_EXTENSIONS) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why does it matter if extensions are enabled for adblock? It's not an extension
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because it uses the chromium code which placed under this flag.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't this have its own buildflag then and use that here?
|
||
#if BUILDFLAG(ENABLE_EXTENSIONS) | ||
|
||
#include "base/command_line.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These headers are not all guarded by enable_extension
in gn. Don't match headers with guards based on how they are used in the file, they should always match the guards in gn. If you don't match them with gn guards then you effectively break gn check because it doesn't understand the preprocessor guards. It's also confusing imo.
ComponentContentsAccessor::ComponentContentsAccessor( | ||
const base::FilePath& component_root) | ||
: component_root_(component_root), | ||
verifier_(CreateContentsVerifier(component_root)) {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we're using this class across multiple threads, but extensions::VerifiedContents
is not thread safe
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
verifier_
is a part of ref counted object and stored as const std::unique_ptr<...>
. It's a readonly object.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't be using ref counted here because this class does not have shared ownership.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Use it when ownership is truly shared (for example, multiple tabs sharing the same renderer process), not for when lifetime management is difficult to reason about."
And also https://www.chromium.org/developers/smart-pointer-guidelines/#when-do-we-use-each-smart-pointer
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re thread safety I think I was looking at the wrong method call somewhere, but that's part of the problem here because calling this class across multiple threads and use of ref counting for lifetime management both contribute to the difficulty of understanding this code.
…ipped with a component.
a72788d
to
83bafe1
Compare
[puLL-Merge] - brave/brave-core@26660 DescriptionThis PR introduces a new feature for verifying the contents of component updates in Brave's ad-blocking system. It adds a new Possible Issues
Security Hotspots
ChangesChanges
sequenceDiagram
participant BraveBrowserMainParts
participant ComponentUpdater
participant AdBlockService
participant ComponentContentsAccessor
participant ContentsVerifier
BraveBrowserMainParts->>ComponentUpdater: SetupComponentContentsVerifier()
ComponentUpdater->>ContentsVerifier: Create
AdBlockService->>ComponentUpdater: Request component update
ComponentUpdater->>ComponentContentsAccessor: Create
ComponentContentsAccessor->>ContentsVerifier: Verify contents
ContentsVerifier-->>ComponentContentsAccessor: Verification result
ComponentContentsAccessor-->>AdBlockService: Provide verified content
AdBlockService->>AdBlockService: Update ad-blocking rules
|
Resolves brave/brave-browser#42274
Submitter Checklist:
QA/Yes
orQA/No
;release-notes/include
orrelease-notes/exclude
;OS/...
) to the associated issuenpm run test -- brave_browser_tests
,npm run test -- brave_unit_tests
wikinpm run presubmit
wiki,npm run gn_check
,npm run tslint
git rebase master
(if needed)Reviewer Checklist:
gn
After-merge Checklist:
changes has landed on
Test Plan: